~junaidali/charms/trusty/plumgrid-gateway/oil_bug

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/charmhelpers/__init__.py

  • Committer: bbaqar at plumgrid
  • Date: 2016-05-18 09:55:23 UTC
  • mfrom: (27.1.4 plumgrid-gateway)
  • Revision ID: bbaqar@plumgrid.com-20160518095523-fnxwexqpi8jkkb3b
Merge - Charmhelpers sync and improved pg-restart

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2014-2015 Canonical Limited.
2
 
#
3
 
# This file is part of charm-helpers.
4
 
#
5
 
# charm-helpers is free software: you can redistribute it and/or modify
6
 
# it under the terms of the GNU Lesser General Public License version 3 as
7
 
# published by the Free Software Foundation.
8
 
#
9
 
# charm-helpers is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU Lesser General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU Lesser General Public License
15
 
# along with charm-helpers.  If not, see <http://www.gnu.org/licenses/>.
16
 
 
17
 
# Copyright 2012 Canonical Ltd.  This software is licensed under the
18
 
# GNU Affero General Public License version 3 (see the file LICENSE).
19
 
 
20
 
import warnings
21
 
warnings.warn("contrib.charmhelpers is deprecated", DeprecationWarning)  # noqa
22
 
 
23
 
import operator
24
 
import tempfile
25
 
import time
26
 
import yaml
27
 
import subprocess
28
 
 
29
 
import six
30
 
if six.PY3:
31
 
    from urllib.request import urlopen
32
 
    from urllib.error import (HTTPError, URLError)
33
 
else:
34
 
    from urllib2 import (urlopen, HTTPError, URLError)
35
 
 
36
 
"""Helper functions for writing Juju charms in Python."""
37
 
 
38
 
__metaclass__ = type
39
 
__all__ = [
40
 
    # 'get_config',             # core.hookenv.config()
41
 
    # 'log',                    # core.hookenv.log()
42
 
    # 'log_entry',              # core.hookenv.log()
43
 
    # 'log_exit',               # core.hookenv.log()
44
 
    # 'relation_get',           # core.hookenv.relation_get()
45
 
    # 'relation_set',           # core.hookenv.relation_set()
46
 
    # 'relation_ids',           # core.hookenv.relation_ids()
47
 
    # 'relation_list',          # core.hookenv.relation_units()
48
 
    # 'config_get',             # core.hookenv.config()
49
 
    # 'unit_get',               # core.hookenv.unit_get()
50
 
    # 'open_port',              # core.hookenv.open_port()
51
 
    # 'close_port',             # core.hookenv.close_port()
52
 
    # 'service_control',        # core.host.service()
53
 
    'unit_info',              # client-side, NOT IMPLEMENTED
54
 
    'wait_for_machine',       # client-side, NOT IMPLEMENTED
55
 
    'wait_for_page_contents',  # client-side, NOT IMPLEMENTED
56
 
    'wait_for_relation',      # client-side, NOT IMPLEMENTED
57
 
    'wait_for_unit',          # client-side, NOT IMPLEMENTED
58
 
]
59
 
 
60
 
 
61
 
SLEEP_AMOUNT = 0.1
62
 
 
63
 
 
64
 
# We create a juju_status Command here because it makes testing much,
65
 
# much easier.
66
 
def juju_status():
67
 
    subprocess.check_call(['juju', 'status'])
68
 
 
69
 
# re-implemented as charmhelpers.fetch.configure_sources()
70
 
# def configure_source(update=False):
71
 
#    source = config_get('source')
72
 
#    if ((source.startswith('ppa:') or
73
 
#         source.startswith('cloud:') or
74
 
#         source.startswith('http:'))):
75
 
#        run('add-apt-repository', source)
76
 
#    if source.startswith("http:"):
77
 
#        run('apt-key', 'import', config_get('key'))
78
 
#    if update:
79
 
#        run('apt-get', 'update')
80
 
 
81
 
 
82
 
# DEPRECATED: client-side only
83
 
def make_charm_config_file(charm_config):
84
 
    charm_config_file = tempfile.NamedTemporaryFile(mode='w+')
85
 
    charm_config_file.write(yaml.dump(charm_config))
86
 
    charm_config_file.flush()
87
 
    # The NamedTemporaryFile instance is returned instead of just the name
88
 
    # because we want to take advantage of garbage collection-triggered
89
 
    # deletion of the temp file when it goes out of scope in the caller.
90
 
    return charm_config_file
91
 
 
92
 
 
93
 
# DEPRECATED: client-side only
94
 
def unit_info(service_name, item_name, data=None, unit=None):
95
 
    if data is None:
96
 
        data = yaml.safe_load(juju_status())
97
 
    service = data['services'].get(service_name)
98
 
    if service is None:
99
 
        # XXX 2012-02-08 gmb:
100
 
        #     This allows us to cope with the race condition that we
101
 
        #     have between deploying a service and having it come up in
102
 
        #     `juju status`. We could probably do with cleaning it up so
103
 
        #     that it fails a bit more noisily after a while.
104
 
        return ''
105
 
    units = service['units']
106
 
    if unit is not None:
107
 
        item = units[unit][item_name]
108
 
    else:
109
 
        # It might seem odd to sort the units here, but we do it to
110
 
        # ensure that when no unit is specified, the first unit for the
111
 
        # service (or at least the one with the lowest number) is the
112
 
        # one whose data gets returned.
113
 
        sorted_unit_names = sorted(units.keys())
114
 
        item = units[sorted_unit_names[0]][item_name]
115
 
    return item
116
 
 
117
 
 
118
 
# DEPRECATED: client-side only
119
 
def get_machine_data():
120
 
    return yaml.safe_load(juju_status())['machines']
121
 
 
122
 
 
123
 
# DEPRECATED: client-side only
124
 
def wait_for_machine(num_machines=1, timeout=300):
125
 
    """Wait `timeout` seconds for `num_machines` machines to come up.
126
 
 
127
 
    This wait_for... function can be called by other wait_for functions
128
 
    whose timeouts might be too short in situations where only a bare
129
 
    Juju setup has been bootstrapped.
130
 
 
131
 
    :return: A tuple of (num_machines, time_taken). This is used for
132
 
             testing.
133
 
    """
134
 
    # You may think this is a hack, and you'd be right. The easiest way
135
 
    # to tell what environment we're working in (LXC vs EC2) is to check
136
 
    # the dns-name of the first machine. If it's localhost we're in LXC
137
 
    # and we can just return here.
138
 
    if get_machine_data()[0]['dns-name'] == 'localhost':
139
 
        return 1, 0
140
 
    start_time = time.time()
141
 
    while True:
142
 
        # Drop the first machine, since it's the Zookeeper and that's
143
 
        # not a machine that we need to wait for. This will only work
144
 
        # for EC2 environments, which is why we return early above if
145
 
        # we're in LXC.
146
 
        machine_data = get_machine_data()
147
 
        non_zookeeper_machines = [
148
 
            machine_data[key] for key in list(machine_data.keys())[1:]]
149
 
        if len(non_zookeeper_machines) >= num_machines:
150
 
            all_machines_running = True
151
 
            for machine in non_zookeeper_machines:
152
 
                if machine.get('instance-state') != 'running':
153
 
                    all_machines_running = False
154
 
                    break
155
 
            if all_machines_running:
156
 
                break
157
 
        if time.time() - start_time >= timeout:
158
 
            raise RuntimeError('timeout waiting for service to start')
159
 
        time.sleep(SLEEP_AMOUNT)
160
 
    return num_machines, time.time() - start_time
161
 
 
162
 
 
163
 
# DEPRECATED: client-side only
164
 
def wait_for_unit(service_name, timeout=480):
165
 
    """Wait `timeout` seconds for a given service name to come up."""
166
 
    wait_for_machine(num_machines=1)
167
 
    start_time = time.time()
168
 
    while True:
169
 
        state = unit_info(service_name, 'agent-state')
170
 
        if 'error' in state or state == 'started':
171
 
            break
172
 
        if time.time() - start_time >= timeout:
173
 
            raise RuntimeError('timeout waiting for service to start')
174
 
        time.sleep(SLEEP_AMOUNT)
175
 
    if state != 'started':
176
 
        raise RuntimeError('unit did not start, agent-state: ' + state)
177
 
 
178
 
 
179
 
# DEPRECATED: client-side only
180
 
def wait_for_relation(service_name, relation_name, timeout=120):
181
 
    """Wait `timeout` seconds for a given relation to come up."""
182
 
    start_time = time.time()
183
 
    while True:
184
 
        relation = unit_info(service_name, 'relations').get(relation_name)
185
 
        if relation is not None and relation['state'] == 'up':
186
 
            break
187
 
        if time.time() - start_time >= timeout:
188
 
            raise RuntimeError('timeout waiting for relation to be up')
189
 
        time.sleep(SLEEP_AMOUNT)
190
 
 
191
 
 
192
 
# DEPRECATED: client-side only
193
 
def wait_for_page_contents(url, contents, timeout=120, validate=None):
194
 
    if validate is None:
195
 
        validate = operator.contains
196
 
    start_time = time.time()
197
 
    while True:
198
 
        try:
199
 
            stream = urlopen(url)
200
 
        except (HTTPError, URLError):
201
 
            pass
202
 
        else:
203
 
            page = stream.read()
204
 
            if validate(page, contents):
205
 
                return page
206
 
        if time.time() - start_time >= timeout:
207
 
            raise RuntimeError('timeout waiting for contents of ' + url)
208
 
        time.sleep(SLEEP_AMOUNT)