diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | cloudinit/config/cc_landscape.py | 8 | ||||
-rw-r--r-- | cloudinit/distros/__init__.py | 64 | ||||
-rw-r--r-- | cloudinit/distros/fedora.py | 2 | ||||
-rw-r--r-- | cloudinit/distros/ubuntu.py | 5 | ||||
-rw-r--r-- | config/cloud.cfg | 10 | ||||
-rw-r--r-- | doc/examples/cloud-config-user-groups.txt | 11 | ||||
-rw-r--r-- | tests/unittests/test_datasource/test_configdrive.py | 5 | ||||
-rw-r--r-- | tests/unittests/test_distros/test_user_data_normalize.py | 30 |
9 files changed, 96 insertions, 44 deletions
@@ -1,6 +1,11 @@ 0.7.1: - sysvinit: fix missing dependency in cloud-init job for RHEL 5.6 - config-drive: map hostname to local-hostname (LP: #1061964) + - landscape: install landscape-client package if not installed. + only take action if cloud-config is present (LP: #1066115) + - cc_landscape: restart landscape after install or config (LP: #1070345) + - multipart/archive. do not fail on unknown headers in multipart + mime or cloud-archive config (LP: #1065116). 0.7.0: - add a 'exception_cb' argument to 'wait_for_url'. If provided, this method will be called back with the exception received and the message. diff --git a/cloudinit/config/cc_landscape.py b/cloudinit/config/cc_landscape.py index 7cfb8296..56ab0ce3 100644 --- a/cloudinit/config/cc_landscape.py +++ b/cloudinit/config/cc_landscape.py @@ -59,6 +59,10 @@ def handle(_name, cfg, cloud, log, _args): raise RuntimeError(("'landscape' key existed in config," " but not a dictionary type," " is a %s instead"), util.obj_name(ls_cloudcfg)) + if not ls_cloudcfg: + return + + cloud.distro.install_packages(["landscape-client"]) merge_data = [ LSC_BUILTIN_CFG, @@ -79,8 +83,8 @@ def handle(_name, cfg, cloud, log, _args): util.write_file(lsc_client_fn, contents.getvalue()) log.debug("Wrote landscape config file to %s", lsc_client_fn) - if ls_cloudcfg: - util.write_file(LS_DEFAULT_FILE, "RUN=1\n") + util.write_file(LS_DEFAULT_FILE, "RUN=1\n") + util.subp(["service", "landscape-client", "restart"]) def merge_together(objs): diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py index 21efe8d9..6ef63442 100644 --- a/cloudinit/distros/__init__.py +++ b/cloudinit/distros/__init__.py @@ -37,10 +37,7 @@ LOG = logging.getLogger(__name__) class Distro(object): - __metaclass__ = abc.ABCMeta - default_user = None - default_user_groups = None def __init__(self, name, cfg, paths): self._paths = paths @@ -176,22 +173,10 @@ class Distro(object): return False def get_default_user(self): - if not self.default_user: - return None - user_cfg = { - 'name': self.default_user, - 'plain_text_passwd': self.default_user, - 'home': "/home/%s" % (self.default_user), - 'shell': "/bin/bash", - 'lock_passwd': True, - 'gecos': "%s" % (self.default_user.title()), - 'sudo': "ALL=(ALL) NOPASSWD:ALL", - } - def_groups = self.default_user_groups - if not def_groups: - def_groups = [] - user_cfg['groups'] = util.uniq_merge_sorted(def_groups) - return user_cfg + return self.get_option('default_user') + + def get_default_user_groups(self): + return self.get_option('default_user_groups') def create_user(self, name, **kwargs): """ @@ -251,7 +236,7 @@ class Distro(object): if util.is_user(name): LOG.warn("User %s already exists, skipping." % name) else: - LOG.debug("Creating name %s" % name) + LOG.debug("Adding user named %s", name) try: util.subp(adduser_cmd, logstring=x_adduser_cmd) except Exception as e: @@ -299,6 +284,39 @@ class Distro(object): return True + def ensure_sudo_dir(self, path, sudo_base='/etc/sudoers'): + # Ensure the dir is included and that + # it actually exists as a directory + sudoers_contents = '' + if os.path.exists(sudo_base): + sudoers_contents = util.load_file(sudo_base) + found_include = False + for line in sudoers_contents.splitlines(): + line = line.strip() + include_match = re.search(r"^#includedir\s+(.*)$", line) + if not include_match: + continue + included_dir = include_match.group(1).strip() + if not included_dir: + continue + included_dir = os.path.abspath(included_dir) + if included_dir == path: + found_include = True + break + if not found_include: + sudoers_contents += "\n#includedir %s\n" % (path) + try: + if not os.path.exists(sudo_base): + util.write_file(sudo_base, sudoers_contents, 0440) + else: + with open(sudo_base, 'a') as f: + f.write(sudoers_contents) + LOG.debug("added '#includedir %s' to %s" % (path, sudo_base)) + except IOError as e: + util.logexc(LOG, "Failed to write %s" % sudo_base, e) + raise e + util.ensure_dir(path, 0755) + def write_sudo_rules(self, user, rules, @@ -314,9 +332,10 @@ class Distro(object): content += "%s %s\n" % (user, rule) content += "\n" + self.ensure_sudo_dir(os.path.dirname(sudo_file)) + if not os.path.exists(sudo_file): util.write_file(sudo_file, content, 0440) - else: try: with open(sudo_file, 'a') as f: @@ -439,7 +458,7 @@ def _normalize_groups(grp_cfg): # configuration. # # The output is a dictionary of user -# names => user config which is the standard +# names => user config which is the standard # form used in the rest of cloud-init. Note # the default user will have a special config # entry 'default' which will be marked as true @@ -504,6 +523,7 @@ def _normalize_users(u_cfg, def_user_cfg=None): # Pickup what the default 'real name' is # and any groups that are provided by the # default config + def_user_cfg = def_user_cfg.copy() def_user = def_user_cfg.pop('name') def_groups = def_user_cfg.pop('groups', []) # Pickup any config + groups for that user name diff --git a/cloudinit/distros/fedora.py b/cloudinit/distros/fedora.py index f65a820d..c777845d 100644 --- a/cloudinit/distros/fedora.py +++ b/cloudinit/distros/fedora.py @@ -28,4 +28,4 @@ LOG = logging.getLogger(__name__) class Distro(rhel.Distro): - default_user = 'ec2-user' + pass diff --git a/cloudinit/distros/ubuntu.py b/cloudinit/distros/ubuntu.py index 4e697f82..c527f248 100644 --- a/cloudinit/distros/ubuntu.py +++ b/cloudinit/distros/ubuntu.py @@ -28,7 +28,4 @@ LOG = logging.getLogger(__name__) class Distro(debian.Distro): - - default_user = 'ubuntu' - default_user_groups = ("adm,audio,cdrom,dialout,floppy,video," - "plugdev,dip,netdev,sudo") + pass diff --git a/config/cloud.cfg b/config/cloud.cfg index b3411d11..f6c9065a 100644 --- a/config/cloud.cfg +++ b/config/cloud.cfg @@ -1,7 +1,9 @@ # The top level settings are used as module # and system configuration. -# Implement for Ubuntu only: create the default 'ubuntu' user +# A set of users which may be applied and/or used by various modules +# when a 'default' entry is found it will reference the 'default_user' +# from the distro configuration specified below users: - default @@ -71,6 +73,12 @@ cloud_final_modules: system_info: # This will affect which distro class gets used distro: ubuntu + # Default user name + that default users groups (if added/used) + default_user: + name: Ubuntu + lock_passwd: True + gecos: Ubuntu + groups: [adm, audio, cdrom, dialout, floppy, video, plugdev, dip, netdev] # Other config here will be given to the distro class and/or path classes paths: cloud_dir: /var/lib/cloud/ diff --git a/doc/examples/cloud-config-user-groups.txt b/doc/examples/cloud-config-user-groups.txt index 1a46c540..de5f321b 100644 --- a/doc/examples/cloud-config-user-groups.txt +++ b/doc/examples/cloud-config-user-groups.txt @@ -96,3 +96,14 @@ users: # foobar: ... # # users[0] (the first user in users) overrides the user directive. +# +# The 'default' user above references the distro's config: +# system_info: +# default_user: +# name: Ubuntu +# plain_text_passwd: 'ubuntu' +# home: /home/ubuntu +# shell: /bin/bash +# lock_passwd: True +# gecos: Ubuntu +# groups: [adm, audio, cdrom, dialout, floppy, video, plugdev, dip, netdev] diff --git a/tests/unittests/test_datasource/test_configdrive.py b/tests/unittests/test_datasource/test_configdrive.py index 4fa13db8..00379e03 100644 --- a/tests/unittests/test_datasource/test_configdrive.py +++ b/tests/unittests/test_datasource/test_configdrive.py @@ -6,11 +6,10 @@ import os.path import mocker from mocker import MockerTestCase -from cloudinit.sources import DataSourceConfigDrive as ds +from cloudinit import helpers from cloudinit import settings +from cloudinit.sources import DataSourceConfigDrive as ds from cloudinit import util -from cloudinit import helpers - PUBKEY = u'ssh-rsa AAAAB3NzaC1....sIkJhq8wdX+4I3A4cYbYP ubuntu@server-460\n' diff --git a/tests/unittests/test_distros/test_user_data_normalize.py b/tests/unittests/test_distros/test_user_data_normalize.py index 9d6fb996..8f0d8896 100644 --- a/tests/unittests/test_distros/test_user_data_normalize.py +++ b/tests/unittests/test_distros/test_user_data_normalize.py @@ -4,19 +4,27 @@ from cloudinit import distros from cloudinit import helpers from cloudinit import settings +bcfg = { + 'name': 'bob', + 'plain_text_passwd': 'ubuntu', + 'home': "/home/ubuntu", + 'shell': "/bin/bash", + 'lock_passwd': True, + 'gecos': "Ubuntu", + 'groups': ["foo"] +} + class TestUGNormalize(MockerTestCase): - def _make_distro(self, dtype, def_user=None, def_groups=None): + def _make_distro(self, dtype, def_user=None): cfg = dict(settings.CFG_BUILTIN) cfg['system_info']['distro'] = dtype paths = helpers.Paths(cfg['system_info']['paths']) distro_cls = distros.fetch(dtype) - distro = distro_cls(dtype, cfg['system_info'], paths) if def_user: - distro.default_user = def_user - if def_groups: - distro.default_user_groups = def_groups + cfg['system_info']['default_user'] = def_user.copy() + distro = distro_cls(dtype, cfg['system_info'], paths) return distro def _norm(self, cfg, distro): @@ -71,7 +79,7 @@ class TestUGNormalize(MockerTestCase): self.assertEquals({}, users) def test_users_simple_dict(self): - distro = self._make_distro('ubuntu', 'bob') + distro = self._make_distro('ubuntu', bcfg) ug_cfg = { 'users': { 'default': True, @@ -95,7 +103,7 @@ class TestUGNormalize(MockerTestCase): self.assertIn('bob', users) def test_users_simple_dict_no(self): - distro = self._make_distro('ubuntu', 'bob') + distro = self._make_distro('ubuntu', bcfg) ug_cfg = { 'users': { 'default': False, @@ -137,7 +145,7 @@ class TestUGNormalize(MockerTestCase): self.assertEquals({'default': False}, users['bob']) def test_users_old_user(self): - distro = self._make_distro('ubuntu', 'bob') + distro = self._make_distro('ubuntu', bcfg) ug_cfg = { 'user': 'zetta', 'users': 'default' @@ -185,7 +193,7 @@ class TestUGNormalize(MockerTestCase): self.assertEquals({}, groups) def test_users_dict_default_additional(self): - distro = self._make_distro('ubuntu', 'bob') + distro = self._make_distro('ubuntu', bcfg) ug_cfg = { 'users': [ {'name': 'default', 'blah': True} @@ -201,7 +209,7 @@ class TestUGNormalize(MockerTestCase): users['bob']['default']) def test_users_dict_extract(self): - distro = self._make_distro('ubuntu', 'bob') + distro = self._make_distro('ubuntu', bcfg) ug_cfg = { 'users': [ 'default', @@ -228,7 +236,7 @@ class TestUGNormalize(MockerTestCase): self.assertEquals(config, expected_config) def test_users_dict_default(self): - distro = self._make_distro('ubuntu', 'bob') + distro = self._make_distro('ubuntu', bcfg) ug_cfg = { 'users': [ 'default', |