~james-page/charms/trusty/mongodb/pymongo-3.x

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/core/host.py

  • Committer: Liam Young
  • Date: 2015-08-26 13:09:04 UTC
  • mfrom: (75.1.2 mongodb)
  • Revision ID: liam.young@canonical.com-20150826130904-w552or2k709pa427
[1chb1n, r=gnuoy] Sync hooks/charmhelpers for liberty cloud archive enablement.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
import os
25
25
import re
26
26
import pwd
 
27
import glob
27
28
import grp
28
29
import random
29
30
import string
62
63
    return service_result
63
64
 
64
65
 
 
66
def service_pause(service_name, init_dir=None):
 
67
    """Pause a system service.
 
68
 
 
69
    Stop it, and prevent it from starting again at boot."""
 
70
    if init_dir is None:
 
71
        init_dir = "/etc/init"
 
72
    stopped = service_stop(service_name)
 
73
    # XXX: Support systemd too
 
74
    override_path = os.path.join(
 
75
        init_dir, '{}.override'.format(service_name))
 
76
    with open(override_path, 'w') as fh:
 
77
        fh.write("manual\n")
 
78
    return stopped
 
79
 
 
80
 
 
81
def service_resume(service_name, init_dir=None):
 
82
    """Resume a system service.
 
83
 
 
84
    Reenable starting again at boot. Start the service"""
 
85
    # XXX: Support systemd too
 
86
    if init_dir is None:
 
87
        init_dir = "/etc/init"
 
88
    override_path = os.path.join(
 
89
        init_dir, '{}.override'.format(service_name))
 
90
    if os.path.exists(override_path):
 
91
        os.unlink(override_path)
 
92
    started = service_start(service_name)
 
93
    return started
 
94
 
 
95
 
65
96
def service(action, service_name):
66
97
    """Control a system service"""
67
98
    cmd = ['service', service_name, action]
90
121
            ['service', service_name, 'status'],
91
122
            stderr=subprocess.STDOUT).decode('UTF-8')
92
123
    except subprocess.CalledProcessError as e:
93
 
        return 'unrecognized service' not in e.output
 
124
        return b'unrecognized service' not in e.output
94
125
    else:
95
126
        return True
96
127
 
117
148
    return user_info
118
149
 
119
150
 
 
151
def user_exists(username):
 
152
    """Check if a user exists"""
 
153
    try:
 
154
        pwd.getpwnam(username)
 
155
        user_exists = True
 
156
    except KeyError:
 
157
        user_exists = False
 
158
    return user_exists
 
159
 
 
160
 
120
161
def add_group(group_name, system_group=False):
121
162
    """Add a group to the system"""
122
163
    try:
139
180
 
140
181
def add_user_to_group(username, group):
141
182
    """Add a user to a group"""
142
 
    cmd = [
143
 
        'gpasswd', '-a',
144
 
        username,
145
 
        group
146
 
    ]
 
183
    cmd = ['gpasswd', '-a', username, group]
147
184
    log("Adding user {} to group {}".format(username, group))
148
185
    subprocess.check_call(cmd)
149
186
 
253
290
    return system_mounts
254
291
 
255
292
 
 
293
def fstab_mount(mountpoint):
 
294
    """Mount filesystem using fstab"""
 
295
    cmd_args = ['mount', mountpoint]
 
296
    try:
 
297
        subprocess.check_output(cmd_args)
 
298
    except subprocess.CalledProcessError as e:
 
299
        log('Error unmounting {}\n{}'.format(mountpoint, e.output))
 
300
        return False
 
301
    return True
 
302
 
 
303
 
256
304
def file_hash(path, hash_type='md5'):
257
305
    """
258
306
    Generate a hash checksum of the contents of 'path' or None if not found.
269
317
        return None
270
318
 
271
319
 
 
320
def path_hash(path):
 
321
    """
 
322
    Generate a hash checksum of all files matching 'path'. Standard wildcards
 
323
    like '*' and '?' are supported, see documentation for the 'glob' module for
 
324
    more information.
 
325
 
 
326
    :return: dict: A { filename: hash } dictionary for all matched files.
 
327
                   Empty if none found.
 
328
    """
 
329
    return {
 
330
        filename: file_hash(filename)
 
331
        for filename in glob.iglob(path)
 
332
    }
 
333
 
 
334
 
272
335
def check_hash(path, checksum, hash_type='md5'):
273
336
    """
274
337
    Validate a file using a cryptographic checksum.
296
359
 
297
360
        @restart_on_change({
298
361
            '/etc/ceph/ceph.conf': [ 'cinder-api', 'cinder-volume' ]
 
362
            '/etc/apache/sites-enabled/*': [ 'apache2' ]
299
363
            })
300
 
        def ceph_client_changed():
 
364
        def config_changed():
301
365
            pass  # your code here
302
366
 
303
367
    In this example, the cinder-api and cinder-volume services
304
368
    would be restarted if /etc/ceph/ceph.conf is changed by the
305
 
    ceph_client_changed function.
 
369
    ceph_client_changed function. The apache2 service would be
 
370
    restarted if any file matching the pattern got changed, created
 
371
    or removed. Standard wildcards are supported, see documentation
 
372
    for the 'glob' module for more information.
306
373
    """
307
374
    def wrap(f):
308
375
        def wrapped_f(*args, **kwargs):
309
 
            checksums = {}
310
 
            for path in restart_map:
311
 
                checksums[path] = file_hash(path)
 
376
            checksums = {path: path_hash(path) for path in restart_map}
312
377
            f(*args, **kwargs)
313
378
            restarts = []
314
379
            for path in restart_map:
315
 
                if checksums[path] != file_hash(path):
 
380
                if path_hash(path) != checksums[path]:
316
381
                    restarts += restart_map[path]
317
382
            services_list = list(OrderedDict.fromkeys(restarts))
318
383
            if not stopstart:
339
404
def pwgen(length=None):
340
405
    """Generate a random pasword."""
341
406
    if length is None:
 
407
        # A random length is ok to use a weak PRNG
342
408
        length = random.choice(range(35, 45))
343
409
    alphanumeric_chars = [
344
410
        l for l in (string.ascii_letters + string.digits)
345
411
        if l not in 'l0QD1vAEIOUaeiou']
 
412
    # Use a crypto-friendly PRNG (e.g. /dev/urandom) for making the
 
413
    # actual password
 
414
    random_generator = random.SystemRandom()
346
415
    random_chars = [
347
 
        random.choice(alphanumeric_chars) for _ in range(length)]
 
416
        random_generator.choice(alphanumeric_chars) for _ in range(length)]
348
417
    return(''.join(random_chars))
349
418
 
350
419
 
351
 
def list_nics(nic_type):
 
420
def is_phy_iface(interface):
 
421
    """Returns True if interface is not virtual, otherwise False."""
 
422
    if interface:
 
423
        sys_net = '/sys/class/net'
 
424
        if os.path.isdir(sys_net):
 
425
            for iface in glob.glob(os.path.join(sys_net, '*')):
 
426
                if '/virtual/' in os.path.realpath(iface):
 
427
                    continue
 
428
 
 
429
                if interface == os.path.basename(iface):
 
430
                    return True
 
431
 
 
432
    return False
 
433
 
 
434
 
 
435
def get_bond_master(interface):
 
436
    """Returns bond master if interface is bond slave otherwise None.
 
437
 
 
438
    NOTE: the provided interface is expected to be physical
 
439
    """
 
440
    if interface:
 
441
        iface_path = '/sys/class/net/%s' % (interface)
 
442
        if os.path.exists(iface_path):
 
443
            if '/virtual/' in os.path.realpath(iface_path):
 
444
                return None
 
445
 
 
446
            master = os.path.join(iface_path, 'master')
 
447
            if os.path.exists(master):
 
448
                master = os.path.realpath(master)
 
449
                # make sure it is a bond master
 
450
                if os.path.exists(os.path.join(master, 'bonding')):
 
451
                    return os.path.basename(master)
 
452
 
 
453
    return None
 
454
 
 
455
 
 
456
def list_nics(nic_type=None):
352
457
    '''Return a list of nics of given type(s)'''
353
458
    if isinstance(nic_type, six.string_types):
354
459
        int_types = [nic_type]
355
460
    else:
356
461
        int_types = nic_type
 
462
 
357
463
    interfaces = []
358
 
    for int_type in int_types:
359
 
        cmd = ['ip', 'addr', 'show', 'label', int_type + '*']
 
464
    if nic_type:
 
465
        for int_type in int_types:
 
466
            cmd = ['ip', 'addr', 'show', 'label', int_type + '*']
 
467
            ip_output = subprocess.check_output(cmd).decode('UTF-8')
 
468
            ip_output = ip_output.split('\n')
 
469
            ip_output = (line for line in ip_output if line)
 
470
            for line in ip_output:
 
471
                if line.split()[1].startswith(int_type):
 
472
                    matched = re.search('.*: (' + int_type +
 
473
                                        r'[0-9]+\.[0-9]+)@.*', line)
 
474
                    if matched:
 
475
                        iface = matched.groups()[0]
 
476
                    else:
 
477
                        iface = line.split()[1].replace(":", "")
 
478
 
 
479
                    if iface not in interfaces:
 
480
                        interfaces.append(iface)
 
481
    else:
 
482
        cmd = ['ip', 'a']
360
483
        ip_output = subprocess.check_output(cmd).decode('UTF-8').split('\n')
361
 
        ip_output = (line for line in ip_output if line)
 
484
        ip_output = (line.strip() for line in ip_output if line)
 
485
 
 
486
        key = re.compile('^[0-9]+:\s+(.+):')
362
487
        for line in ip_output:
363
 
            if line.split()[1].startswith(int_type):
364
 
                matched = re.search('.*: (' + int_type + r'[0-9]+\.[0-9]+)@.*', line)
365
 
                if matched:
366
 
                    interface = matched.groups()[0]
367
 
                else:
368
 
                    interface = line.split()[1].replace(":", "")
369
 
                interfaces.append(interface)
 
488
            matched = re.search(key, line)
 
489
            if matched:
 
490
                iface = matched.group(1)
 
491
                iface = iface.partition("@")[0]
 
492
                if iface not in interfaces:
 
493
                    interfaces.append(iface)
370
494
 
371
495
    return interfaces
372
496