summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Moser <smoser@brickies.net>2016-08-23 16:48:39 -0400
committerScott Moser <smoser@brickies.net>2016-08-23 16:48:39 -0400
commitbbcffb40f8e721f8d5ff396a8fd3f0337f299394 (patch)
tree1ba65a8b98cef85e89f7414040ff2848e54641aa
parentdbae06eec6a25592593f19f4f40bd03668098d9c (diff)
parent8a929e66f2fe2aaed968ec23aeaf6d3b3c68cb65 (diff)
downloadvyos-cloud-init-bbcffb40f8e721f8d5ff396a8fd3f0337f299394.tar.gz
vyos-cloud-init-bbcffb40f8e721f8d5ff396a8fd3f0337f299394.zip
merge trunk at 0.7.7~bzr1182
-rw-r--r--ChangeLog4
-rw-r--r--cloudinit/config/cc_seed_random.py2
-rw-r--r--cloudinit/distros/__init__.py24
-rw-r--r--cloudinit/settings.py1
-rw-r--r--cloudinit/sources/DataSourceBigstep.py13
-rw-r--r--cloudinit/util.py15
-rw-r--r--config/cloud.cfg2
-rw-r--r--doc/examples/cloud-config-seed-random.txt32
-rwxr-xr-xsystemd/cloud-init-generator22
-rw-r--r--systemd/cloud-init-local.service4
-rw-r--r--systemd/cloud-init.service6
-rw-r--r--tests/unittests/test_handler/test_handler_seed_random.py14
-rw-r--r--tests/unittests/test_util.py10
13 files changed, 122 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index a80a5d5f..ebaacf6a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -85,6 +85,10 @@
unless it is already a file (LP: #1543025).
- Enable password changing via a hashed string [Alex Sirbu]
- Added BigStep datasource [Alex Sirbu]
+ - No longer run pollinate in seed_random (LP: #1554152)
+ - groups: add defalt user to 'lxd' group. Create groups listed
+ for a user if they do not exist. (LP: #1539317)
+ - dmi data: fix failure of reading dmi data for unset dmi values
0.7.6:
- open 0.7.6
diff --git a/cloudinit/config/cc_seed_random.py b/cloudinit/config/cc_seed_random.py
index 3288a853..1b011216 100644
--- a/cloudinit/config/cc_seed_random.py
+++ b/cloudinit/config/cc_seed_random.py
@@ -83,7 +83,7 @@ def handle(name, cfg, cloud, log, _args):
len(seed_data), seed_path)
util.append_file(seed_path, seed_data)
- command = mycfg.get('command', ['pollinate', '-q'])
+ command = mycfg.get('command', None)
req = mycfg.get('command_required', False)
try:
env = os.environ.copy()
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index a73acae5..e8220985 100644
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -319,6 +319,11 @@ class Distro(object):
LOG.info("User %s already exists, skipping." % name)
return
+ if 'create_groups' in kwargs:
+ create_groups = kwargs.pop('create_groups')
+ else:
+ create_groups = True
+
adduser_cmd = ['useradd', name]
log_adduser_cmd = ['useradd', name]
@@ -346,6 +351,19 @@ class Distro(object):
redact_opts = ['passwd']
+ groups = kwargs.get('groups')
+ if groups:
+ if isinstance(groups, (list, tuple)):
+ kwargs['groups'] = ",".join(groups)
+ else:
+ groups = groups.split(",")
+
+ if create_groups:
+ for group in kwargs.get('groups').split(","):
+ if not util.is_group(group):
+ self.create_group(group)
+ LOG.debug("created group %s for user %s", name, group)
+
# Check the values and create the command
for key, val in kwargs.items():
@@ -534,8 +552,10 @@ class Distro(object):
util.logexc(LOG, "Failed to append sudoers file %s", sudo_file)
raise e
- def create_group(self, name, members):
+ def create_group(self, name, members=None):
group_add_cmd = ['groupadd', name]
+ if not members:
+ members = []
# Check if group exists, and then add it doesn't
if util.is_group(name):
@@ -545,7 +565,7 @@ class Distro(object):
util.subp(group_add_cmd)
LOG.info("Created new group %s" % name)
except Exception:
- util.logexc("Failed to create group %s", name)
+ util.logexc(LOG, "Failed to create group %s", name)
# Add members to the group, if so defined
if len(members) > 0:
diff --git a/cloudinit/settings.py b/cloudinit/settings.py
index b61e5613..8c258ea1 100644
--- a/cloudinit/settings.py
+++ b/cloudinit/settings.py
@@ -42,6 +42,7 @@ CFG_BUILTIN = {
'CloudSigma',
'CloudStack',
'SmartOS',
+ 'Bigstep',
# At the end to act as a 'catch' when none of the above work...
'None',
],
diff --git a/cloudinit/sources/DataSourceBigstep.py b/cloudinit/sources/DataSourceBigstep.py
index c22ffdb6..b5ee4129 100644
--- a/cloudinit/sources/DataSourceBigstep.py
+++ b/cloudinit/sources/DataSourceBigstep.py
@@ -5,6 +5,7 @@
#
import json
+import errno
from cloudinit import log as logging
from cloudinit import sources
@@ -23,6 +24,8 @@ class DataSourceBigstep(sources.DataSource):
def get_data(self, apply_filter=False):
url = get_url_from_file()
+ if url is None:
+ return False
response = url_helper.readurl(url)
decoded = json.loads(response.contents)
self.metadata = decoded["metadata"]
@@ -32,7 +35,15 @@ class DataSourceBigstep(sources.DataSource):
def get_url_from_file():
- content = util.load_file("/var/lib/cloud/data/seed/bigstep/url")
+ try:
+ content = util.load_file("/var/lib/cloud/data/seed/bigstep/url")
+ except IOError as e:
+ # If the file doesn't exist, then the server probably isn't a Bigstep
+ # instance; otherwise, another problem exists which needs investigation
+ if e.errno == errno.ENOENT:
+ return None
+ else:
+ raise
return content
# Used to match classes to dependencies
diff --git a/cloudinit/util.py b/cloudinit/util.py
index e7407ea4..20916e53 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -2140,13 +2140,19 @@ def _read_dmi_syspath(key):
LOG.debug("did not find %s", dmi_key_path)
return None
- key_data = load_file(dmi_key_path)
+ key_data = load_file(dmi_key_path, decode=False)
if not key_data:
LOG.debug("%s did not return any data", dmi_key_path)
return None
- LOG.debug("dmi data %s returned %s", dmi_key_path, key_data)
- return key_data.strip()
+ # uninitialized dmi values show as all \xff and /sys appends a '\n'.
+ # in that event, return a string of '.' in the same length.
+ if key_data == b'\xff' * (len(key_data) - 1) + b'\n':
+ key_data = b""
+
+ str_data = key_data.decode('utf8').strip()
+ LOG.debug("dmi data %s returned %s", dmi_key_path, str_data)
+ return str_data
except Exception:
logexc(LOG, "failed read of %s", dmi_key_path)
@@ -2162,6 +2168,9 @@ def _call_dmidecode(key, dmidecode_path):
cmd = [dmidecode_path, "--string", key]
(result, _err) = subp(cmd)
LOG.debug("dmidecode returned '%s' for '%s'", result, key)
+ result = result.strip()
+ if result.replace(".", "") == "":
+ return ""
return result
except (IOError, OSError) as _err:
LOG.debug('failed dmidecode cmd: %s\n%s', cmd, _err.message)
diff --git a/config/cloud.cfg b/config/cloud.cfg
index 795df19f..a6afcc83 100644
--- a/config/cloud.cfg
+++ b/config/cloud.cfg
@@ -89,7 +89,7 @@ system_info:
name: ubuntu
lock_passwd: True
gecos: Ubuntu
- groups: [adm, audio, cdrom, dialout, dip, floppy, netdev, plugdev, sudo, video]
+ groups: [adm, audio, cdrom, dialout, dip, floppy, lxd, netdev, plugdev, sudo, video]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/bash
# Other config here will be given to the distro class and/or path classes
diff --git a/doc/examples/cloud-config-seed-random.txt b/doc/examples/cloud-config-seed-random.txt
new file mode 100644
index 00000000..08f69a9f
--- /dev/null
+++ b/doc/examples/cloud-config-seed-random.txt
@@ -0,0 +1,32 @@
+#cloud-config
+#
+# random_seed is a dictionary.
+#
+# The config module will write seed data from the datasource
+# to 'file' described below.
+#
+# Entries in this dictionary are:
+# file: the file to write random data to (default is /dev/urandom)
+# data: this data will be written to 'file' before data from
+# the datasource
+# encoding: this will be used to decode 'data' provided.
+# allowed values are 'encoding', 'raw', 'base64', 'b64'
+# 'gzip', or 'gz'. Default is 'raw'
+#
+# command: execute this command to seed random.
+# the command will have RANDOM_SEED_FILE in its environment
+# set to the value of 'file' above.
+# command_required: default False
+# if true, and 'command' is not available to be run
+# then exception is raised and cloud-init will record failure.
+# Otherwise, only debug error is mentioned.
+#
+# Note: command could be ['pollinate',
+# '--server=http://local.pollinate.server']
+# which would have pollinate populate /dev/urandom from provided server
+seed_random:
+ file: '/dev/urandom'
+ data: 'my random string'
+ encoding: 'raw'
+ command: ['sh', '-c', 'dd if=/dev/urandom of=$RANDOM_SEED_FILE']
+ command_required: True
diff --git a/systemd/cloud-init-generator b/systemd/cloud-init-generator
index 9d1e22f0..2d319695 100755
--- a/systemd/cloud-init-generator
+++ b/systemd/cloud-init-generator
@@ -3,7 +3,7 @@ set -f
LOG=""
DEBUG_LEVEL=1
-LOG_D="/run"
+LOG_D="/run/cloud-init"
ENABLE="enabled"
DISABLE="disabled"
CLOUD_SYSTEM_TARGET="/lib/systemd/system/cloud-init.target"
@@ -17,7 +17,8 @@ debug() {
[ "$lvl" -gt "$DEBUG_LEVEL" ] && return
if [ -z "$LOG" ]; then
local log="$LOG_D/${0##*/}.log"
- { : > "$log"; } >/dev/null 2>&1 && LOG="$log" ||
+ { [ -d "$LOG_D" ] || mkdir -p "$LOG_D"; } &&
+ { : > "$log"; } >/dev/null 2>&1 && LOG="$log" ||
LOG="/dev/kmsg"
fi
echo "$@" >> "$LOG"
@@ -32,15 +33,16 @@ etc_file() {
}
read_proc_cmdline() {
- if [ "$CONTAINER" = "lxc" ]; then
- _RET_MSG="ignored: \$container=$CONTAINER"
- _RET=""
- return 0
- fi
-
- if systemd-detect-virt --container --quiet; then
- _RET_MSG="ignored: detect-virt is container"
+ # return /proc/cmdline for non-container, and /proc/1/cmdline for container
+ local ctname="systemd"
+ if [ -n "$CONTAINER" ] && ctname=$CONTAINER ||
+ systemd-detect-virt --container --quiet; then
+ if { _RET=$(tr '\0' ' ' < /proc/1/cmdline); } 2>/dev/null; then
+ _RET_MSG="container[$ctname]: pid 1 cmdline"
+ return
+ fi
_RET=""
+ _RET_MSG="container[$ctname]: pid 1 cmdline not available"
return 0
fi
diff --git a/systemd/cloud-init-local.service b/systemd/cloud-init-local.service
index 73aa46f6..475a2e11 100644
--- a/systemd/cloud-init-local.service
+++ b/systemd/cloud-init-local.service
@@ -1,7 +1,11 @@
[Unit]
Description=Initial cloud-init job (pre-networking)
+DefaultDependencies=no
Wants=local-fs.target
After=local-fs.target
+Conflicts=shutdown.target
+Before=network-pre.target
+Before=shutdown.target
[Service]
Type=oneshot
diff --git a/systemd/cloud-init.service b/systemd/cloud-init.service
index 1f656f7f..6fb655e6 100644
--- a/systemd/cloud-init.service
+++ b/systemd/cloud-init.service
@@ -1,8 +1,8 @@
[Unit]
Description=Initial cloud-init job (metadata service crawler)
-After=local-fs.target network-online.target cloud-init-local.service
-Before=sshd.service sshd-keygen.service systemd-user-sessions.service
-Requires=network-online.target
+After=cloud-init-local.service networking.service
+Before=network-online.target sshd.service sshd-keygen.service systemd-user-sessions.service
+Requires=networking.service
Wants=local-fs.target cloud-init-local.service sshd.service sshd-keygen.service
[Service]
diff --git a/tests/unittests/test_handler/test_handler_seed_random.py b/tests/unittests/test_handler/test_handler_seed_random.py
index 34d11f21..98bc9b81 100644
--- a/tests/unittests/test_handler/test_handler_seed_random.py
+++ b/tests/unittests/test_handler/test_handler_seed_random.py
@@ -170,28 +170,30 @@ class TestRandomSeed(t_help.TestCase):
contents = util.load_file(self._seed_file)
self.assertEquals('tiny-tim-was-here-so-was-josh', contents)
- def test_seed_command_not_provided_pollinate_available(self):
+ def test_seed_command_provided_and_available(self):
c = self._get_cloud('ubuntu', {})
self.whichdata = {'pollinate': '/usr/bin/pollinate'}
- cc_seed_random.handle('test', {}, c, LOG, [])
+ cfg = {'random_seed': {'command': ['pollinate', '-q']}}
+ cc_seed_random.handle('test', cfg, c, LOG, [])
subp_args = [f['args'] for f in self.subp_called]
self.assertIn(['pollinate', '-q'], subp_args)
- def test_seed_command_not_provided_pollinate_not_available(self):
+ def test_seed_command_not_provided(self):
c = self._get_cloud('ubuntu', {})
self.whichdata = {}
cc_seed_random.handle('test', {}, c, LOG, [])
# subp should not have been called as which would say not available
- self.assertEquals(self.subp_called, list())
+ self.assertFalse(self.subp_called)
def test_unavailable_seed_command_and_required_raises_error(self):
c = self._get_cloud('ubuntu', {})
self.whichdata = {}
+ cfg = {'random_seed': {'command': ['THIS_NO_COMMAND'],
+ 'command_required': True}}
self.assertRaises(ValueError, cc_seed_random.handle,
- 'test', {'random_seed': {'command_required': True}},
- c, LOG, [])
+ 'test', cfg, c, LOG, [])
def test_seed_command_and_required(self):
c = self._get_cloud('ubuntu', {})
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 95990165..37a984ac 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -385,6 +385,16 @@ class TestReadDMIData(helpers.FilesystemMockingTestCase):
self.patch_mapping({})
self.assertEqual(None, util.read_dmi_data('expect-fail'))
+ def test_dots_returned_instead_of_foxfox(self):
+ # uninitialized dmi values show as \xff, return those as .
+ my_len = 32
+ dmi_value = b'\xff' * my_len + b'\n'
+ expected = ""
+ dmi_key = 'system-product-name'
+ sysfs_key = 'product_name'
+ self._create_sysfs_file(sysfs_key, dmi_value)
+ self.assertEqual(expected, util.read_dmi_data(dmi_key))
+
class TestMultiLog(helpers.FilesystemMockingTestCase):