cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #00143
[Merge] lp:~harlowja/cloud-init/fix-resets into lp:cloud-init
Joshua Harlow has proposed merging lp:~harlowja/cloud-init/fix-resets into lp:cloud-init.
Requested reviews:
cloud init development team (cloud-init-dev)
Related bugs:
Bug #1076811 in cloud-init: "Cloud-init modules do not reflect loaded config"
https://bugs.launchpad.net/cloud-init/+bug/1076811
For more details, see:
https://code.launchpad.net/~harlowja/cloud-init/fix-resets/+merge/133603
Tried test on non-patched branch. It fails. On new fixed 'reset' branch it works.
--
https://code.launchpad.net/~harlowja/cloud-init/fix-resets/+merge/133603
Your team cloud init development team is requested to review the proposed merge of lp:~harlowja/cloud-init/fix-resets into lp:cloud-init.
=== modified file 'cloudinit/stages.py'
--- cloudinit/stages.py 2012-09-24 18:45:31 +0000
+++ cloudinit/stages.py 2012-11-09 00:35:23 +0000
@@ -36,6 +36,8 @@
from cloudinit.handlers import shell_script as ss_part
from cloudinit.handlers import upstart_job as up_part
+from cloudinit.sources import DataSourceNone
+
from cloudinit import cloud
from cloudinit import config
from cloudinit import distros
@@ -58,8 +60,16 @@
self._cfg = None
self._paths = None
self._distro = None
- # Created only when a fetch occurs
- self.datasource = None
+ # Changed only when a fetch occurs
+ self.datasource = DataSourceNone.DataSourceNone({}, None, None)
+
+ def _reset(self, ds=False):
+ # Recreated on access
+ self._cfg = None
+ self._paths = None
+ self._distro = None
+ if ds:
+ self.datasource = DataSourceNone.DataSourceNone({}, None, None)
@property
def distro(self):
@@ -236,7 +246,7 @@
self.datasource = ds
# Ensure we adjust our path members datasource
# now that we have one (thus allowing ipath to be used)
- self.paths.datasource = ds
+ self._reset()
return ds
def _get_instance_subdirs(self):
@@ -296,6 +306,10 @@
util.write_file(iid_fn, "%s\n" % iid)
util.write_file(os.path.join(dp, 'previous-instance-id'),
"%s\n" % (previous_iid))
+ # Ensure needed components are regenerated
+ # after change of instance which may cause
+ # change of configuration
+ self._reset()
return iid
def fetch(self):
@@ -409,6 +423,17 @@
handlers.call_end(mod, data, frequency)
called.append(mod)
+ # Perform post-consumption adjustments so that
+ # modules that run during the init stage reflect
+ # this consumed set.
+ #
+ # They will be recreated on future access...
+ self._reset()
+ # Note(harlowja): the 'active' datasource will have
+ # references to the previous config, distro, paths
+ # objects before the load of the userdata happened,
+ # this is expected.
+
class Modules(object):
def __init__(self, init, cfg_files=None):
=== added file 'tests/data/user_data.1.txt'
--- tests/data/user_data.1.txt 1970-01-01 00:00:00 +0000
+++ tests/data/user_data.1.txt 2012-11-09 00:35:23 +0000
@@ -0,0 +1,15 @@
+#cloud-config
+write_files:
+- content: blah
+ path: /etc/blah.ini
+ permissions: 493
+
+system_info:
+ package_mirrors:
+ - arches: [i386, amd64, blah]
+ failsafe:
+ primary: http://my.archive.mydomain.com/ubuntu
+ security: http://my.security.mydomain.com/ubuntu
+ search:
+ primary: []
+ security: []
=== added file 'tests/unittests/test_merging.py'
--- tests/unittests/test_merging.py 1970-01-01 00:00:00 +0000
+++ tests/unittests/test_merging.py 2012-11-09 00:35:23 +0000
@@ -0,0 +1,62 @@
+from mocker import MockerTestCase
+
+from cloudinit import util
+
+
+class TestMergeDict(MockerTestCase):
+ def test_simple_merge(self):
+ """Test simple non-conflict merge."""
+ source = {"key1": "value1"}
+ candidate = {"key2": "value2"}
+ result = util.mergedict(source, candidate)
+ self.assertEqual({"key1": "value1", "key2": "value2"}, result)
+
+ def test_nested_merge(self):
+ """Test nested merge."""
+ source = {"key1": {"key1.1": "value1.1"}}
+ candidate = {"key1": {"key1.2": "value1.2"}}
+ result = util.mergedict(source, candidate)
+ self.assertEqual(
+ {"key1": {"key1.1": "value1.1", "key1.2": "value1.2"}}, result)
+
+ def test_merge_does_not_override(self):
+ """Test that candidate doesn't override source."""
+ source = {"key1": "value1", "key2": "value2"}
+ candidate = {"key1": "value2", "key2": "NEW VALUE"}
+ result = util.mergedict(source, candidate)
+ self.assertEqual(source, result)
+
+ def test_empty_candidate(self):
+ """Test empty candidate doesn't change source."""
+ source = {"key": "value"}
+ candidate = {}
+ result = util.mergedict(source, candidate)
+ self.assertEqual(source, result)
+
+ def test_empty_source(self):
+ """Test empty source is replaced by candidate."""
+ source = {}
+ candidate = {"key": "value"}
+ result = util.mergedict(source, candidate)
+ self.assertEqual(candidate, result)
+
+ def test_non_dict_candidate(self):
+ """Test non-dict candidate is discarded."""
+ source = {"key": "value"}
+ candidate = "not a dict"
+ result = util.mergedict(source, candidate)
+ self.assertEqual(source, result)
+
+ def test_non_dict_source(self):
+ """Test non-dict source is not modified with a dict candidate."""
+ source = "not a dict"
+ candidate = {"key": "value"}
+ result = util.mergedict(source, candidate)
+ self.assertEqual(source, result)
+
+ def test_neither_dict(self):
+ """Test if neither candidate or source is dict source wins."""
+ source = "source"
+ candidate = "candidate"
+ result = util.mergedict(source, candidate)
+ self.assertEqual(source, result)
=== added file 'tests/unittests/test_runs/test_merge_run.py'
--- tests/unittests/test_runs/test_merge_run.py 1970-01-01 00:00:00 +0000
+++ tests/unittests/test_runs/test_merge_run.py 2012-11-09 00:35:23 +0000
@@ -0,0 +1,52 @@
+import os
+
+from tests.unittests 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 test_none_ds(self):
+ new_root = self.makeDir()
+ self.replicateTestRoot('simple_ubuntu', new_root)
+ cfg = {
+ 'datasource_list': ['None'],
+ 'cloud_init_modules': ['write-files'],
+ }
+ ud = self.readResource('user_data.1.txt')
+ 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()
+ initer.fetch()
+ initer.datasource.userdata_raw = ud
+ iid = initer.instancify()
+ initer.update()
+ initer.cloudify().run('consume_userdata',
+ initer.consume_userdata,
+ args=[PER_INSTANCE],
+ freq=PER_INSTANCE)
+ mirrors = initer.distro.get_option('package_mirrors')
+ self.assertEquals(1, len(mirrors))
+ mirror = mirrors[0]
+ self.assertEquals(mirror['arches'], ['i386', 'amd64', 'blah'])
+ 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')
=== modified file 'tests/unittests/test_util.py'
--- tests/unittests/test_util.py 2012-09-28 20:31:50 +0000
+++ tests/unittests/test_util.py 2012-11-09 00:35:23 +0000
@@ -28,65 +28,6 @@
self.restored.append(path)
-class TestMergeDict(MockerTestCase):
- def test_simple_merge(self):
- """Test simple non-conflict merge."""
- source = {"key1": "value1"}
- candidate = {"key2": "value2"}
- result = util.mergedict(source, candidate)
- self.assertEqual({"key1": "value1", "key2": "value2"}, result)
-
- def test_nested_merge(self):
- """Test nested merge."""
- source = {"key1": {"key1.1": "value1.1"}}
- candidate = {"key1": {"key1.2": "value1.2"}}
- result = util.mergedict(source, candidate)
- self.assertEqual(
- {"key1": {"key1.1": "value1.1", "key1.2": "value1.2"}}, result)
-
- def test_merge_does_not_override(self):
- """Test that candidate doesn't override source."""
- source = {"key1": "value1", "key2": "value2"}
- candidate = {"key1": "value2", "key2": "NEW VALUE"}
- result = util.mergedict(source, candidate)
- self.assertEqual(source, result)
-
- def test_empty_candidate(self):
- """Test empty candidate doesn't change source."""
- source = {"key": "value"}
- candidate = {}
- result = util.mergedict(source, candidate)
- self.assertEqual(source, result)
-
- def test_empty_source(self):
- """Test empty source is replaced by candidate."""
- source = {}
- candidate = {"key": "value"}
- result = util.mergedict(source, candidate)
- self.assertEqual(candidate, result)
-
- def test_non_dict_candidate(self):
- """Test non-dict candidate is discarded."""
- source = {"key": "value"}
- candidate = "not a dict"
- result = util.mergedict(source, candidate)
- self.assertEqual(source, result)
-
- def test_non_dict_source(self):
- """Test non-dict source is not modified with a dict candidate."""
- source = "not a dict"
- candidate = {"key": "value"}
- result = util.mergedict(source, candidate)
- self.assertEqual(source, result)
-
- def test_neither_dict(self):
- """Test if neither candidate or source is dict source wins."""
- source = "source"
- candidate = "candidate"
- result = util.mergedict(source, candidate)
- self.assertEqual(source, result)
-
-
class TestGetCfgOptionListOrStr(TestCase):
def test_not_found_no_default(self):
"""None is returned if key is not found and no default given."""
=== modified file 'tools/run-pep8'
--- tools/run-pep8 2012-10-23 16:58:32 +0000
+++ tools/run-pep8 2012-11-09 00:35:23 +0000
@@ -21,10 +21,21 @@
base=`pwd`/tools/
fi
+IGNORE="E501" # Line too long (these are caught by pylint)
+
+# King Arthur: Be quiet! ... Be Quiet! I Order You to Be Quiet.
+IGNORE="$IGNORE,E121" # Continuation line indentation is not a multiple of four
+IGNORE="$IGNORE,E123" # Closing bracket does not match indentation of opening bracket's line
+IGNORE="$IGNORE,E124" # Closing bracket missing visual indentation
+IGNORE="$IGNORE,E125" # Continuation line does not distinguish itself from next logical line
+IGNORE="$IGNORE,E126" # Continuation line over-indented for hanging indent
+IGNORE="$IGNORE,E127" # Continuation line over-indented for visual indent
+IGNORE="$IGNORE,E128" # Continuation line under-indented for visual indent
+
cmd=(
${base}/hacking.py
- --ignore=E501 # Line too long (these are caught by pylint)
+ --ignore="$IGNORE"
"${files[@]}"
)