~gandelman-a/charms/precise/nova-vmware/trunk

« back to all changes in this revision

Viewing changes to hooks/lib/utils.py

  • Committer: Adam Gandelman
  • Date: 2013-10-09 00:52:24 UTC
  • Revision ID: adamg@canonical.com-20131009005224-ub1yu8wdkch45xka
Init new repo.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Copyright 2012 Canonical Ltd.
 
3
#
 
4
# This file is sourced from lp:openstack-charm-helpers
 
5
#
 
6
# Authors:
 
7
#  James Page <james.page@ubuntu.com>
 
8
#  Paul Collins <paul.collins@canonical.com>
 
9
#  Adam Gandelman <adamg@ubuntu.com>
 
10
#
 
11
 
 
12
import json
 
13
import os
 
14
import subprocess
 
15
import socket
 
16
import sys
 
17
 
 
18
 
 
19
def do_hooks(hooks):
 
20
    hook = os.path.basename(sys.argv[0])
 
21
 
 
22
    try:
 
23
        hook_func = hooks[hook]
 
24
    except KeyError:
 
25
        juju_log('INFO',
 
26
                 "This charm doesn't know how to handle '{}'.".format(hook))
 
27
    else:
 
28
        hook_func()
 
29
 
 
30
 
 
31
def install(*pkgs):
 
32
    cmd = [
 
33
        'apt-get',
 
34
        '-y',
 
35
        'install'
 
36
          ]
 
37
    for pkg in pkgs:
 
38
        cmd.append(pkg)
 
39
    subprocess.check_call(cmd)
 
40
 
 
41
TEMPLATES_DIR = 'templates'
 
42
 
 
43
try:
 
44
    import jinja2
 
45
except ImportError:
 
46
    install('python-jinja2')
 
47
    import jinja2
 
48
 
 
49
try:
 
50
    import dns.resolver
 
51
except ImportError:
 
52
    install('python-dnspython')
 
53
    import dns.resolver
 
54
 
 
55
 
 
56
def render_template(template_name, context, template_dir=TEMPLATES_DIR):
 
57
    templates = jinja2.Environment(
 
58
                    loader=jinja2.FileSystemLoader(template_dir)
 
59
                    )
 
60
    template = templates.get_template(template_name)
 
61
    return template.render(context)
 
62
 
 
63
CLOUD_ARCHIVE = \
 
64
""" # Ubuntu Cloud Archive
 
65
deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
 
66
"""
 
67
 
 
68
CLOUD_ARCHIVE_POCKETS = {
 
69
    'folsom': 'precise-updates/folsom',
 
70
    'folsom/updates': 'precise-updates/folsom',
 
71
    'folsom/proposed': 'precise-proposed/folsom',
 
72
    'grizzly': 'precise-updates/grizzly',
 
73
    'grizzly/updates': 'precise-updates/grizzly',
 
74
    'grizzly/proposed': 'precise-proposed/grizzly'
 
75
    }
 
76
 
 
77
 
 
78
def configure_source():
 
79
    source = str(config_get('openstack-origin'))
 
80
    if not source:
 
81
        return
 
82
    if source.startswith('ppa:'):
 
83
        cmd = [
 
84
            'add-apt-repository',
 
85
            source
 
86
            ]
 
87
        subprocess.check_call(cmd)
 
88
    if source.startswith('cloud:'):
 
89
        # CA values should be formatted as cloud:ubuntu-openstack/pocket, eg:
 
90
        #   cloud:precise-folsom/updates or cloud:precise-folsom/proposed
 
91
        install('ubuntu-cloud-keyring')
 
92
        pocket = source.split(':')[1]
 
93
        pocket = pocket.split('-')[1]
 
94
        with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt:
 
95
            apt.write(CLOUD_ARCHIVE.format(CLOUD_ARCHIVE_POCKETS[pocket]))
 
96
    if source.startswith('deb'):
 
97
        l = len(source.split('|'))
 
98
        if l == 2:
 
99
            (apt_line, key) = source.split('|')
 
100
            cmd = [
 
101
                'apt-key',
 
102
                'adv', '--keyserver keyserver.ubuntu.com',
 
103
                '--recv-keys', key
 
104
                ]
 
105
            subprocess.check_call(cmd)
 
106
        elif l == 1:
 
107
            apt_line = source
 
108
 
 
109
        with open('/etc/apt/sources.list.d/quantum.list', 'w') as apt:
 
110
            apt.write(apt_line + "\n")
 
111
    cmd = [
 
112
        'apt-get',
 
113
        'update'
 
114
        ]
 
115
    subprocess.check_call(cmd)
 
116
 
 
117
# Protocols
 
118
TCP = 'TCP'
 
119
UDP = 'UDP'
 
120
 
 
121
 
 
122
def expose(port, protocol='TCP'):
 
123
    cmd = [
 
124
        'open-port',
 
125
        '{}/{}'.format(port, protocol)
 
126
        ]
 
127
    subprocess.check_call(cmd)
 
128
 
 
129
 
 
130
def juju_log(severity, message):
 
131
    cmd = [
 
132
        'juju-log',
 
133
        '--log-level', severity,
 
134
        message
 
135
        ]
 
136
    subprocess.check_call(cmd)
 
137
 
 
138
 
 
139
cache = {}
 
140
 
 
141
 
 
142
def cached(func):
 
143
    def wrapper(*args, **kwargs):
 
144
        global cache
 
145
        key = str((func, args, kwargs))
 
146
        try:
 
147
            return cache[key]
 
148
        except KeyError:
 
149
            res = func(*args, **kwargs)
 
150
            cache[key] = res
 
151
            return res
 
152
    return wrapper
 
153
 
 
154
 
 
155
@cached
 
156
def relation_ids(relation):
 
157
    cmd = [
 
158
        'relation-ids',
 
159
        relation
 
160
        ]
 
161
    result = str(subprocess.check_output(cmd)).split()
 
162
    if result == "":
 
163
        return None
 
164
    else:
 
165
        return result
 
166
 
 
167
 
 
168
@cached
 
169
def relation_list(rid):
 
170
    cmd = [
 
171
        'relation-list',
 
172
        '-r', rid,
 
173
        ]
 
174
    result = str(subprocess.check_output(cmd)).split()
 
175
    if result == "":
 
176
        return None
 
177
    else:
 
178
        return result
 
179
 
 
180
 
 
181
@cached
 
182
def relation_get(attribute, unit=None, rid=None):
 
183
    cmd = [
 
184
        'relation-get',
 
185
        ]
 
186
    if rid:
 
187
        cmd.append('-r')
 
188
        cmd.append(rid)
 
189
    cmd.append(attribute)
 
190
    if unit:
 
191
        cmd.append(unit)
 
192
    value = subprocess.check_output(cmd).strip()  # IGNORE:E1103
 
193
    if value == "":
 
194
        return None
 
195
    else:
 
196
        return value
 
197
 
 
198
 
 
199
@cached
 
200
def relation_get_dict(relation_id=None, remote_unit=None):
 
201
    """Obtain all relation data as dict by way of JSON"""
 
202
    cmd = [
 
203
        'relation-get', '--format=json'
 
204
        ]
 
205
    if relation_id:
 
206
        cmd.append('-r')
 
207
        cmd.append(relation_id)
 
208
    if remote_unit:
 
209
        remote_unit_orig = os.getenv('JUJU_REMOTE_UNIT', None)
 
210
        os.environ['JUJU_REMOTE_UNIT'] = remote_unit
 
211
    j = subprocess.check_output(cmd)
 
212
    if remote_unit and remote_unit_orig:
 
213
        os.environ['JUJU_REMOTE_UNIT'] = remote_unit_orig
 
214
    d = json.loads(j)
 
215
    settings = {}
 
216
    # convert unicode to strings
 
217
    for k, v in d.iteritems():
 
218
        settings[str(k)] = str(v)
 
219
    return settings
 
220
 
 
221
 
 
222
def relation_set(**kwargs):
 
223
    cmd = [
 
224
        'relation-set'
 
225
        ]
 
226
    args = []
 
227
    for k, v in kwargs.items():
 
228
        if k == 'rid':
 
229
            if v:
 
230
                cmd.append('-r')
 
231
                cmd.append(v)
 
232
        else:
 
233
            args.append('{}={}'.format(k, v))
 
234
    cmd += args
 
235
    subprocess.check_call(cmd)
 
236
 
 
237
 
 
238
@cached
 
239
def unit_get(attribute):
 
240
    cmd = [
 
241
        'unit-get',
 
242
        attribute
 
243
        ]
 
244
    value = subprocess.check_output(cmd).strip()  # IGNORE:E1103
 
245
    if value == "":
 
246
        return None
 
247
    else:
 
248
        return value
 
249
 
 
250
 
 
251
@cached
 
252
def config_get(attribute):
 
253
    cmd = [
 
254
        'config-get',
 
255
        '--format',
 
256
        'json',
 
257
        ]
 
258
    out = subprocess.check_output(cmd).strip()  # IGNORE:E1103
 
259
    cfg = json.loads(out)
 
260
 
 
261
    try:
 
262
        return cfg[attribute]
 
263
    except KeyError:
 
264
        return None
 
265
 
 
266
 
 
267
@cached
 
268
def get_unit_hostname():
 
269
    return socket.gethostname()
 
270
 
 
271
 
 
272
@cached
 
273
def get_host_ip(hostname=unit_get('private-address')):
 
274
    try:
 
275
        # Test to see if already an IPv4 address
 
276
        socket.inet_aton(hostname)
 
277
        return hostname
 
278
    except socket.error:
 
279
        answers = dns.resolver.query(hostname, 'A')
 
280
        if answers:
 
281
            return answers[0].address
 
282
    return None
 
283
 
 
284
 
 
285
def _svc_control(service, action):
 
286
    subprocess.check_call(['service', service, action])
 
287
 
 
288
 
 
289
def restart(*services):
 
290
    for service in services:
 
291
        _svc_control(service, 'restart')
 
292
 
 
293
 
 
294
def stop(*services):
 
295
    for service in services:
 
296
        _svc_control(service, 'stop')
 
297
 
 
298
 
 
299
def start(*services):
 
300
    for service in services:
 
301
        _svc_control(service, 'start')
 
302
 
 
303
 
 
304
def reload(*services):
 
305
    for service in services:
 
306
        try:
 
307
            _svc_control(service, 'reload')
 
308
        except subprocess.CalledProcessError:
 
309
            # Reload failed - either service does not support reload
 
310
            # or it was not running - restart will fixup most things
 
311
            _svc_control(service, 'restart')
 
312
 
 
313
 
 
314
def running(service):
 
315
    try:
 
316
        output = subprocess.check_output(['service', service, 'status'])
 
317
    except subprocess.CalledProcessError:
 
318
        return False
 
319
    else:
 
320
        if ("start/running" in output or
 
321
            "is running" in output):
 
322
            return True
 
323
        else:
 
324
            return False
 
325
 
 
326
 
 
327
def is_relation_made(relation, key='private-address'):
 
328
    for r_id in (relation_ids(relation) or []):
 
329
        for unit in (relation_list(r_id) or []):
 
330
            if relation_get(key, rid=r_id, unit=unit):
 
331
                return True
 
332
    return False