summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--cloudinit/config/cc_landscape.py8
-rw-r--r--cloudinit/distros/__init__.py64
-rw-r--r--cloudinit/distros/fedora.py2
-rw-r--r--cloudinit/distros/ubuntu.py5
-rw-r--r--config/cloud.cfg10
-rw-r--r--doc/examples/cloud-config-user-groups.txt11
-rw-r--r--tests/unittests/test_datasource/test_configdrive.py5
-rw-r--r--tests/unittests/test_distros/test_user_data_normalize.py30
9 files changed, 96 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index 672482ba..d03c0293 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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',