diff options
author | Scott Moser <smoser@ubuntu.com> | 2012-11-07 10:23:32 -0500 |
---|---|---|
committer | Scott Moser <smoser@ubuntu.com> | 2012-11-07 10:23:32 -0500 |
commit | 8ada8c1f625be5365a5116c458476c7deeae8818 (patch) | |
tree | a2f3b4c968a3fd4cbc76ad59ce70563485ea8171 | |
parent | 0da58fe113726c7654bca54b365d95044b44ef87 (diff) | |
parent | ce5a554672f4ffbc383af08a35d22a1dd89ce41f (diff) | |
download | vyos-cloud-init-8ada8c1f625be5365a5116c458476c7deeae8818.tar.gz vyos-cloud-init-8ada8c1f625be5365a5116c458476c7deeae8818.zip |
merge from trunk
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | cloudinit/config/cc_landscape.py | 1 | ||||
-rw-r--r-- | cloudinit/distros/__init__.py | 62 | ||||
-rw-r--r-- | cloudinit/distros/fedora.py | 2 | ||||
-rw-r--r-- | cloudinit/distros/ubuntu.py | 5 | ||||
-rw-r--r-- | cloudinit/handlers/__init__.py | 15 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceAltCloud.py | 19 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceConfigDrive.py | 20 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceMAAS.py | 5 | ||||
-rw-r--r-- | cloudinit/sources/DataSourceOVF.py | 5 | ||||
-rw-r--r-- | cloudinit/user_data.py | 2 | ||||
-rw-r--r-- | cloudinit/util.py | 10 | ||||
-rw-r--r-- | config/cloud.cfg | 10 | ||||
-rw-r--r-- | doc/examples/cloud-config-user-groups.txt | 11 | ||||
-rw-r--r-- | tests/data/roots/simple_ubuntu/etc/networks/interfaces | 3 | ||||
-rw-r--r-- | tests/unittests/helpers.py | 104 | ||||
-rw-r--r-- | tests/unittests/test_distros/test_user_data_normalize.py | 30 | ||||
-rw-r--r-- | tests/unittests/test_filters/test_launch_index.py | 12 | ||||
-rw-r--r-- | tests/unittests/test_runs/test_simple_run.py | 86 | ||||
-rwxr-xr-x | tools/Z99-cloud-locale-test.sh | 4 | ||||
-rwxr-xr-x | tools/run-pep8 | 2 |
21 files changed, 339 insertions, 75 deletions
@@ -3,6 +3,12 @@ - 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). + - tools/Z99-cloud-locale-test.sh: avoid warning when user's shell is + zsh (LP: #1073077) + - fix stack trace when unknown user-data input had unicode (LP: #1075756) - split 'apt-update-upgrade' config module into 'apt-configure' and 'package-update-upgrade-install'. The 'package-update-upgrade-install' will be a cross distro module. diff --git a/cloudinit/config/cc_landscape.py b/cloudinit/config/cc_landscape.py index 331559f4..56ab0ce3 100644 --- a/cloudinit/config/cc_landscape.py +++ b/cloudinit/config/cc_landscape.py @@ -84,6 +84,7 @@ def handle(_name, cfg, cloud, log, _args): log.debug("Wrote landscape config file to %s", lsc_client_fn) 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 c848b909..2fbb0e9b 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,7 @@ 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 create_user(self, name, **kwargs): """ @@ -251,7 +233,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 +281,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,13 +329,13 @@ 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: - f.write(content) + util.append_file(sudo_file, content) except IOError as e: util.logexc(LOG, "Failed to write %s" % sudo_file, e) raise e @@ -504,6 +519,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/cloudinit/handlers/__init__.py b/cloudinit/handlers/__init__.py index 99caed1f..8d6dcd4d 100644 --- a/cloudinit/handlers/__init__.py +++ b/cloudinit/handlers/__init__.py @@ -160,6 +160,19 @@ def _extract_first_or_bytes(blob, size): return start +def _escape_string(text): + try: + return text.encode("string-escape") + except TypeError: + try: + # Unicode doesn't support string-escape... + return text.encode('unicode-escape') + except TypeError: + # Give up... + pass + return text + + def walker_callback(pdata, ctype, filename, payload): if ctype in PART_CONTENT_TYPES: walker_handle_handler(pdata, ctype, filename, payload) @@ -171,7 +184,7 @@ def walker_callback(pdata, ctype, filename, payload): elif payload: # Extract the first line or 24 bytes for displaying in the log start = _extract_first_or_bytes(payload, 24) - details = "'%s...'" % (start.encode("string-escape")) + details = "'%s...'" % (_escape_string(start)) if ctype == NOT_MULTIPART_TYPE: LOG.warning("Unhandled non-multipart (%s) userdata: %s", ctype, details) diff --git a/cloudinit/sources/DataSourceAltCloud.py b/cloudinit/sources/DataSourceAltCloud.py index 69c376a5..d7e1204f 100644 --- a/cloudinit/sources/DataSourceAltCloud.py +++ b/cloudinit/sources/DataSourceAltCloud.py @@ -73,13 +73,11 @@ def read_user_data_callback(mount_dir): # First try deltacloud_user_data_file. On failure try user_data_file. try: - with open(deltacloud_user_data_file, 'r') as user_data_f: - user_data = user_data_f.read().strip() - except: + user_data = util.load_file(deltacloud_user_data_file).strip() + except IOError: try: - with open(user_data_file, 'r') as user_data_f: - user_data = user_data_f.read().strip() - except: + user_data = util.load_file(user_data_file).strip() + except IOError: util.logexc(LOG, ('Failed accessing user data file.')) return None @@ -157,11 +155,10 @@ class DataSourceAltCloud(sources.DataSource): if os.path.exists(CLOUD_INFO_FILE): try: - cloud_info = open(CLOUD_INFO_FILE) - cloud_type = cloud_info.read().strip().upper() - cloud_info.close() - except: - util.logexc(LOG, 'Unable to access cloud info file.') + cloud_type = util.load_file(CLOUD_INFO_FILE).strip().upper() + except IOError: + util.logexc(LOG, 'Unable to access cloud info file at %s.', + CLOUD_INFO_FILE) return False else: cloud_type = self.get_cloud_type() diff --git a/cloudinit/sources/DataSourceConfigDrive.py b/cloudinit/sources/DataSourceConfigDrive.py index 4af2e5ae..9729cfb9 100644 --- a/cloudinit/sources/DataSourceConfigDrive.py +++ b/cloudinit/sources/DataSourceConfigDrive.py @@ -307,19 +307,19 @@ def read_config_drive_dir_v2(source_dir, version="2012-08-10"): found = False if os.path.isfile(fpath): try: - with open(fpath) as fp: - data = fp.read() - except Exception as exc: - raise BrokenConfigDriveDir("failed to read: %s" % fpath) + data = util.load_file(fpath) + except IOError: + raise BrokenConfigDriveDir("Failed to read: %s" % fpath) found = True elif required: - raise NonConfigDriveDir("missing mandatory %s" % fpath) + raise NonConfigDriveDir("Missing mandatory path: %s" % fpath) if found and process: try: data = process(data) except Exception as exc: - raise BrokenConfigDriveDir("failed to process: %s" % fpath) + raise BrokenConfigDriveDir(("Failed to process " + "path: %s") % fpath) if found: results[name] = data @@ -335,8 +335,7 @@ def read_config_drive_dir_v2(source_dir, version="2012-08-10"): # do not use os.path.join here, as content_path starts with / cpath = os.path.sep.join((source_dir, "openstack", "./%s" % item['content_path'])) - with open(cpath) as fp: - return(fp.read()) + return util.load_file(cpath) files = {} try: @@ -350,7 +349,7 @@ def read_config_drive_dir_v2(source_dir, version="2012-08-10"): if item: results['network_config'] = read_content_path(item) except Exception as exc: - raise BrokenConfigDriveDir("failed to read file %s: %s" % (item, exc)) + raise BrokenConfigDriveDir("Failed to read file %s: %s" % (item, exc)) # to openstack, user can specify meta ('nova boot --meta=key=value') and # those will appear under metadata['meta']. @@ -465,8 +464,7 @@ def get_previous_iid(paths): # hasn't declared itself found. fname = os.path.join(paths.get_cpath('data'), 'instance-id') try: - with open(fname) as fp: - return fp.read() + return util.load_file(fname) except IOError: return None diff --git a/cloudinit/sources/DataSourceMAAS.py b/cloudinit/sources/DataSourceMAAS.py index e187aec9..b55d8a21 100644 --- a/cloudinit/sources/DataSourceMAAS.py +++ b/cloudinit/sources/DataSourceMAAS.py @@ -336,8 +336,7 @@ if __name__ == "__main__": 'token_secret': args.tsec, 'consumer_secret': args.csec} if args.config: - with open(args.config) as fp: - cfg = util.load_yaml(fp.read()) + cfg = util.read_conf(args.config) if 'datasource' in cfg: cfg = cfg['datasource']['MAAS'] for key in creds.keys(): @@ -346,7 +345,7 @@ if __name__ == "__main__": def geturl(url, headers_cb): req = urllib2.Request(url, data=None, headers=headers_cb(url)) - return(urllib2.urlopen(req).read()) + return (urllib2.urlopen(req).read()) def printurl(url, headers_cb): print "== %s ==\n%s\n" % (url, geturl(url, headers_cb)) diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py index 771e64eb..e90150c6 100644 --- a/cloudinit/sources/DataSourceOVF.py +++ b/cloudinit/sources/DataSourceOVF.py @@ -204,9 +204,8 @@ def transport_iso9660(require_iso=True): try: # See if we can read anything at all...?? - with open(fullp, 'rb') as fp: - fp.read(512) - except: + util.peek_file(fullp, 512) + except IOError: continue try: diff --git a/cloudinit/user_data.py b/cloudinit/user_data.py index 803ffc3a..58827e3d 100644 --- a/cloudinit/user_data.py +++ b/cloudinit/user_data.py @@ -224,7 +224,7 @@ class UserDataProcessor(object): for header in list(ent.keys()): if header in ('content', 'filename', 'type', 'launch-index'): continue - msg.add_header(header, ent['header']) + msg.add_header(header, ent[header]) self._attach_part(append_msg, msg) diff --git a/cloudinit/util.py b/cloudinit/util.py index f5a7ac12..7890a3d6 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -983,6 +983,12 @@ def find_devs_with(criteria=None, oformat='device', return entries +def peek_file(fname, max_bytes): + LOG.debug("Peeking at %s (max_bytes=%s)", fname, max_bytes) + with open(fname, 'rb') as ifh: + return ifh.read(max_bytes) + + def load_file(fname, read_cb=None, quiet=False): LOG.debug("Reading from %s (quiet=%s)", fname, quiet) ofh = StringIO() @@ -1328,6 +1334,10 @@ def uptime(): return uptime_str +def append_file(path, content): + write_file(path, content, omode="ab", mode=None) + + def ensure_file(path, mode=0644): write_file(path, content='', omode="ab", mode=mode) diff --git a/config/cloud.cfg b/config/cloud.cfg index 51a05821..05bb4eef 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 @@ -72,6 +74,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/data/roots/simple_ubuntu/etc/networks/interfaces b/tests/data/roots/simple_ubuntu/etc/networks/interfaces new file mode 100644 index 00000000..77efa67d --- /dev/null +++ b/tests/data/roots/simple_ubuntu/etc/networks/interfaces @@ -0,0 +1,3 @@ +auto lo +iface lo inet loopback + diff --git a/tests/unittests/helpers.py b/tests/unittests/helpers.py index d0f09e70..2c5dcad2 100644 --- a/tests/unittests/helpers.py +++ b/tests/unittests/helpers.py @@ -3,6 +3,38 @@ import os from mocker import MockerTestCase from cloudinit import helpers as ch +from cloudinit import util + +import shutil + + +# Makes the old path start +# with new base instead of whatever +# it previously had +def rebase_path(old_path, new_base): + if old_path.startswith(new_base): + # Already handled... + return old_path + # Retarget the base of that path + # to the new base instead of the + # old one... + path = os.path.join(new_base, old_path.lstrip("/")) + path = os.path.abspath(path) + return path + + +# Can work on anything that takes a path as arguments +def retarget_many_wrapper(new_base, am, old_func): + def wrapper(*args, **kwds): + n_args = list(args) + nam = am + if am == -1: + nam = len(n_args) + for i in range(0, nam): + path = args[i] + n_args[i] = rebase_path(path, new_base) + return old_func(*n_args, **kwds) + return wrapper class ResourceUsingTestCase(MockerTestCase): @@ -40,3 +72,75 @@ class ResourceUsingTestCase(MockerTestCase): 'templates_dir': self.resourceLocation(), }) return cp + + +class FilesystemMockingTestCase(ResourceUsingTestCase): + def __init__(self, methodName="runTest"): + ResourceUsingTestCase.__init__(self, methodName) + self.patched_funcs = [] + + def replicateTestRoot(self, example_root, target_root): + real_root = self.resourceLocation() + real_root = os.path.join(real_root, 'roots', example_root) + for (dir_path, _dirnames, filenames) in os.walk(real_root): + real_path = dir_path + make_path = rebase_path(real_path[len(real_root):], target_root) + util.ensure_dir(make_path) + for f in filenames: + real_path = util.abs_join(real_path, f) + make_path = util.abs_join(make_path, f) + shutil.copy(real_path, make_path) + + def tearDown(self): + self.restore() + ResourceUsingTestCase.tearDown(self) + + def restore(self): + for (mod, f, func) in self.patched_funcs: + setattr(mod, f, func) + self.patched_funcs = [] + + def patchUtils(self, new_root): + patch_funcs = { + util: [('write_file', 1), + ('load_file', 1), + ('ensure_dir', 1), + ('chmod', 1), + ('delete_dir_contents', 1), + ('del_file', 1), + ('sym_link', -1)], + } + for (mod, funcs) in patch_funcs.items(): + for (f, am) in funcs: + func = getattr(mod, f) + trap_func = retarget_many_wrapper(new_root, am, func) + setattr(mod, f, trap_func) + self.patched_funcs.append((mod, f, func)) + + # Handle subprocess calls + func = getattr(util, 'subp') + + def nsubp(*_args, **_kwargs): + return ('', '') + + setattr(util, 'subp', nsubp) + self.patched_funcs.append((util, 'subp', func)) + + def null_func(*_args, **_kwargs): + return None + + for f in ['chownbyid', 'chownbyname']: + func = getattr(util, f) + setattr(util, f, null_func) + self.patched_funcs.append((util, f, func)) + + def patchOS(self, new_root): + patch_funcs = { + os.path: ['isfile', 'exists', 'islink', 'isdir'], + } + for (mod, funcs) in patch_funcs.items(): + for f in funcs: + func = getattr(mod, f) + trap_func = retarget_many_wrapper(new_root, 1, func) + setattr(mod, f, trap_func) + self.patched_funcs.append((mod, f, func)) 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', diff --git a/tests/unittests/test_filters/test_launch_index.py b/tests/unittests/test_filters/test_launch_index.py index 7ca7cbb6..1e9b9053 100644 --- a/tests/unittests/test_filters/test_launch_index.py +++ b/tests/unittests/test_filters/test_launch_index.py @@ -1,6 +1,14 @@ import copy +import os +import sys -import helpers as th +top_dir = os.path.join(os.path.dirname(__file__), os.pardir, "helpers.py") +top_dir = os.path.abspath(top_dir) +if os.path.exists(top_dir): + sys.path.insert(0, os.path.dirname(top_dir)) + + +import helpers import itertools @@ -18,7 +26,7 @@ def count_messages(root): return am -class TestLaunchFilter(th.ResourceUsingTestCase): +class TestLaunchFilter(helpers.ResourceUsingTestCase): def assertCounts(self, message, expected_counts): orig_message = copy.deepcopy(message) diff --git a/tests/unittests/test_runs/test_simple_run.py b/tests/unittests/test_runs/test_simple_run.py new file mode 100644 index 00000000..1e852e1e --- /dev/null +++ b/tests/unittests/test_runs/test_simple_run.py @@ -0,0 +1,86 @@ +import os +import sys + +# Allow running this test individually +top_dir = os.path.join(os.path.dirname(__file__), os.pardir, "helpers.py") +top_dir = os.path.abspath(top_dir) +if os.path.exists(top_dir): + sys.path.insert(0, os.path.dirname(top_dir)) + + +import helpers + +from cloudinit.settings import (PER_INSTANCE) +from cloudinit import stages +from cloudinit import util + + +class TestSimpleRun(helpers.FilesystemMockingTestCase): + def _patchIn(self, root): + self.restore() + self.patchOS(root) + self.patchUtils(root) + + def _pp_root(self, root, repatch=True): + self.restore() + for (dirpath, dirnames, filenames) in os.walk(root): + print(dirpath) + for f in filenames: + joined = os.path.join(dirpath, f) + if os.path.islink(joined): + print("f %s - (symlink)" % (f)) + else: + print("f %s" % (f)) + for d in dirnames: + joined = os.path.join(dirpath, d) + if os.path.islink(joined): + print("d %s - (symlink)" % (d)) + else: + print("d %s" % (d)) + if repatch: + self._patchIn(root) + + def test_none_ds(self): + new_root = self.makeDir() + self.replicateTestRoot('simple_ubuntu', new_root) + cfg = { + 'datasource_list': ['None'], + 'write_files': [{ + 'path': '/etc/blah.ini', + 'content': 'blah', + 'permissions': 0755, + }], + 'cloud_init_modules': ['write-files'], + } + cloud_cfg = util.yaml_dumps(cfg) + util.ensure_dir(os.path.join(new_root, 'etc', 'cloud')) + util.write_file(os.path.join(new_root, 'etc', + 'cloud', 'cloud.cfg'), cloud_cfg) + self._patchIn(new_root) + + # Now start verifying whats created + initer = stages.Init() + initer.read_cfg() + initer.initialize() + self.assertTrue(os.path.exists("/var/lib/cloud")) + for d in ['scripts', 'seed', 'instances', 'handlers', 'sem', 'data']: + self.assertTrue(os.path.isdir(os.path.join("/var/lib/cloud", d))) + + initer.fetch() + iid = initer.instancify() + self.assertEquals(iid, 'iid-datasource-none') + initer.update() + self.assertTrue(os.path.islink("var/lib/cloud/instance")) + + initer.cloudify().run('consume_userdata', + initer.consume_userdata, + args=[PER_INSTANCE], + freq=PER_INSTANCE) + + mods = stages.Modules(initer) + (which_ran, failures) = mods.run_section('cloud_init_modules') + self.assertTrue(len(failures) == 0) + self.assertTrue(os.path.exists('/etc/blah.ini')) + self.assertIn('write-files', which_ran) + contents = util.load_file('/etc/blah.ini') + self.assertEquals(contents, 'blah') diff --git a/tools/Z99-cloud-locale-test.sh b/tools/Z99-cloud-locale-test.sh index 8ad485e8..4012beeb 100755 --- a/tools/Z99-cloud-locale-test.sh +++ b/tools/Z99-cloud-locale-test.sh @@ -22,7 +22,7 @@ locale_warn() { case "$w1" in locale:) bad_names="${bad_names} ${w4}";; *) - key=${w1%%=*} + key=${w1%%\=*} val=${w1#*=} val=${val#\"} val=${val%\"} @@ -31,7 +31,7 @@ locale_warn() { done for bad in $bad_names; do for var in ${vars}; do - [ "${bad}" = "${var%=*}" ] || continue + [ "${bad}" = "${var%\=*}" ] || continue value=${var#*=} [ "${bad_lcs#* ${value}}" = "${bad_lcs}" ] && bad_lcs="${bad_lcs} ${value}" diff --git a/tools/run-pep8 b/tools/run-pep8 index ea46c117..ad55d420 100755 --- a/tools/run-pep8 +++ b/tools/run-pep8 @@ -1,6 +1,6 @@ #!/bin/bash -ci_files='cloud*.py cloudinit/*.py cloudinit/config/*.py' +ci_files='cloudinit/*.py cloudinit/config/*.py' test_files=$(find tests -name "*.py") def_files="$ci_files $test_files" |