bigdata-dev team mailing list archive
-
bigdata-dev team
-
Mailing list archive
-
Message #00445
[Merge] lp:~kos.tsakalozos/charm-helpers/merge-addusers into lp:~bigdata-dev/charm-helpers/framework
Konstantinos Tsakalozos has proposed merging lp:~kos.tsakalozos/charm-helpers/merge-addusers into lp:~bigdata-dev/charm-helpers/framework.
Requested reviews:
Cory Johns (johnsca)
For more details, see:
https://code.launchpad.net/~kos.tsakalozos/charm-helpers/merge-addusers/+merge/279766
Merge of host.py upstream with our bigdata-dev fork (host.py includes the adduser method).
--
Your team Juju Big Data Development is subscribed to branch lp:~bigdata-dev/charm-helpers/framework.
=== modified file 'charmhelpers/core/host.py'
--- charmhelpers/core/host.py 2015-05-13 20:47:37 +0000
+++ charmhelpers/core/host.py 2015-12-07 12:51:05 +0000
@@ -24,6 +24,7 @@
import os
import re
import pwd
+import glob
import grp
import random
import string
@@ -62,6 +63,56 @@
return service_result
+def service_pause(service_name, init_dir="/etc/init", initd_dir="/etc/init.d"):
+ """Pause a system service.
+
+ Stop it, and prevent it from starting again at boot."""
+ stopped = True
+ if service_running(service_name):
+ stopped = service_stop(service_name)
+ upstart_file = os.path.join(init_dir, "{}.conf".format(service_name))
+ sysv_file = os.path.join(initd_dir, service_name)
+ if os.path.exists(upstart_file):
+ override_path = os.path.join(
+ init_dir, '{}.override'.format(service_name))
+ with open(override_path, 'w') as fh:
+ fh.write("manual\n")
+ elif os.path.exists(sysv_file):
+ subprocess.check_call(["update-rc.d", service_name, "disable"])
+ else:
+ # XXX: Support SystemD too
+ raise ValueError(
+ "Unable to detect {0} as either Upstart {1} or SysV {2}".format(
+ service_name, upstart_file, sysv_file))
+ return stopped
+
+
+def service_resume(service_name, init_dir="/etc/init",
+ initd_dir="/etc/init.d"):
+ """Resume a system service.
+
+ Reenable starting again at boot. Start the service"""
+ upstart_file = os.path.join(init_dir, "{}.conf".format(service_name))
+ sysv_file = os.path.join(initd_dir, service_name)
+ if os.path.exists(upstart_file):
+ override_path = os.path.join(
+ init_dir, '{}.override'.format(service_name))
+ if os.path.exists(override_path):
+ os.unlink(override_path)
+ elif os.path.exists(sysv_file):
+ subprocess.check_call(["update-rc.d", service_name, "enable"])
+ else:
+ # XXX: Support SystemD too
+ raise ValueError(
+ "Unable to detect {0} as either Upstart {1} or SysV {2}".format(
+ service_name, upstart_file, sysv_file))
+
+ started = service_running(service_name)
+ if not started:
+ started = service_start(service_name)
+ return started
+
+
def service(action, service_name):
"""Control a system service"""
cmd = ['service', service_name, action]
@@ -95,8 +146,22 @@
return True
-def adduser(username, password=None, shell='/bin/bash', system_user=False, group=None, groups=None):
- """Add a user to the system"""
+def adduser(username, password=None, shell='/bin/bash', system_user=False,
+ primary_group=None, secondary_groups=None):
+ """
+ Add a user to the system.
+
+ Will log but otherwise succeed if the user already exists.
+
+ :param str username: Username to create
+ :param str password: Password for user; if ``None``, create a system user
+ :param str shell: The default shell for the user
+ :param bool system_user: Whether to create a login or system user
+ :param str primary_group: Primary group for user; defaults to their username
+ :param list secondary_groups: Optional list of additional groups
+
+ :returns: The password database entry struct, as returned by `pwd.getpwnam`
+ """
try:
user_info = pwd.getpwnam(username)
log('user {0} already exists!'.format(username))
@@ -111,16 +176,32 @@
'--shell', shell,
'--password', password,
])
- if group:
- cmd.extend(['-g', group])
- if groups:
- cmd.extend(['-G', ','.join(groups)])
+ if not primary_group:
+ try:
+ grp.getgrnam(username)
+ primary_group = username # avoid "group exists" error
+ except KeyError:
+ pass
+ if primary_group:
+ cmd.extend(['-g', primary_group])
+ if secondary_groups:
+ cmd.extend(['-G', ','.join(secondary_groups)])
cmd.append(username)
subprocess.check_call(cmd)
user_info = pwd.getpwnam(username)
return user_info
+def user_exists(username):
+ """Check if a user exists"""
+ try:
+ pwd.getpwnam(username)
+ user_exists = True
+ except KeyError:
+ user_exists = False
+ return user_exists
+
+
def add_group(group_name, system_group=False):
"""Add a group to the system"""
try:
@@ -262,6 +343,17 @@
return system_mounts
+def fstab_mount(mountpoint):
+ """Mount filesystem using fstab"""
+ cmd_args = ['mount', mountpoint]
+ try:
+ subprocess.check_output(cmd_args)
+ except subprocess.CalledProcessError as e:
+ log('Error unmounting {}\n{}'.format(mountpoint, e.output))
+ return False
+ return True
+
+
def file_hash(path, hash_type='md5'):
"""
Generate a hash checksum of the contents of 'path' or None if not found.
@@ -278,6 +370,21 @@
return None
+def path_hash(path):
+ """
+ Generate a hash checksum of all files matching 'path'. Standard wildcards
+ like '*' and '?' are supported, see documentation for the 'glob' module for
+ more information.
+
+ :return: dict: A { filename: hash } dictionary for all matched files.
+ Empty if none found.
+ """
+ return {
+ filename: file_hash(filename)
+ for filename in glob.iglob(path)
+ }
+
+
def check_hash(path, checksum, hash_type='md5'):
"""
Validate a file using a cryptographic checksum.
@@ -367,6 +474,7 @@
int_types = [nic_type]
else:
int_types = nic_type
+
interfaces = []
for int_type in int_types:
cmd = ['ip', 'addr', 'show', 'label', int_type + '*']
@@ -439,7 +547,14 @@
os.chdir(cur)
-def chownr(path, owner, group, follow_links=True):
+def chownr(path, owner, group, follow_links=True, chowntopdir=False):
+ """
+ Recursively change user and group ownership of files and directories
+ in given path. Doesn't chown path itself by default, only its children.
+
+ :param bool follow_links: Also Chown links if True
+ :param bool chowntopdir: Also chown path itself if True
+ """
uid = pwd.getpwnam(owner).pw_uid
gid = grp.getgrnam(group).gr_gid
if follow_links:
@@ -447,6 +562,10 @@
else:
chown = os.lchown
+ if chowntopdir:
+ broken_symlink = os.path.lexists(path) and not os.path.exists(path)
+ if not broken_symlink:
+ chown(path, uid, gid)
for root, dirs, files in os.walk(path):
for name in dirs + files:
full = os.path.join(root, name)
@@ -461,3 +580,18 @@
def cpu_arch():
return subprocess.check_output(['uname', '-p']).strip()
+
+def get_total_ram():
+ '''The total amount of system RAM in bytes.
+
+ This is what is reported by the OS, and may be overcommitted when
+ there are multiple containers hosted on the same machine.
+ '''
+ with open('/proc/meminfo', 'r') as f:
+ for line in f.readlines():
+ if line:
+ key, value, unit = line.split()
+ if key == 'MemTotal:':
+ assert unit == 'kB', 'Unknown unit'
+ return int(value) * 1024 # Classic, not KiB.
+ raise NotImplementedError()
Follow ups