Merge lp:~harlowja/cloud-init/fix-resets into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Joshua Harlow
Status: Merged
Merged at revision: 703
Proposed branch: lp:~harlowja/cloud-init/fix-resets
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 310 lines (+169/-63)
6 files modified
cloudinit/stages.py (+28/-3)
tests/data/user_data.1.txt (+15/-0)
tests/unittests/test_merging.py (+62/-0)
tests/unittests/test_runs/test_merge_run.py (+52/-0)
tests/unittests/test_util.py (+0/-59)
tools/run-pep8 (+12/-1)
To merge this branch: bzr merge lp:~harlowja/cloud-init/fix-resets
Reviewer Review Type Date Requested Status
Scott Moser Approve
Review via email: mp+133603@code.launchpad.net

Description of the change

Tried test on non-patched branch. It fails. On new fixed 'reset' branch it works.

To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

Thanks!
please go ahead and push to turnk

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cloudinit/stages.py'
2--- cloudinit/stages.py 2012-09-24 18:45:31 +0000
3+++ cloudinit/stages.py 2012-11-09 00:35:23 +0000
4@@ -36,6 +36,8 @@
5 from cloudinit.handlers import shell_script as ss_part
6 from cloudinit.handlers import upstart_job as up_part
7
8+from cloudinit.sources import DataSourceNone
9+
10 from cloudinit import cloud
11 from cloudinit import config
12 from cloudinit import distros
13@@ -58,8 +60,16 @@
14 self._cfg = None
15 self._paths = None
16 self._distro = None
17- # Created only when a fetch occurs
18- self.datasource = None
19+ # Changed only when a fetch occurs
20+ self.datasource = DataSourceNone.DataSourceNone({}, None, None)
21+
22+ def _reset(self, ds=False):
23+ # Recreated on access
24+ self._cfg = None
25+ self._paths = None
26+ self._distro = None
27+ if ds:
28+ self.datasource = DataSourceNone.DataSourceNone({}, None, None)
29
30 @property
31 def distro(self):
32@@ -236,7 +246,7 @@
33 self.datasource = ds
34 # Ensure we adjust our path members datasource
35 # now that we have one (thus allowing ipath to be used)
36- self.paths.datasource = ds
37+ self._reset()
38 return ds
39
40 def _get_instance_subdirs(self):
41@@ -296,6 +306,10 @@
42 util.write_file(iid_fn, "%s\n" % iid)
43 util.write_file(os.path.join(dp, 'previous-instance-id'),
44 "%s\n" % (previous_iid))
45+ # Ensure needed components are regenerated
46+ # after change of instance which may cause
47+ # change of configuration
48+ self._reset()
49 return iid
50
51 def fetch(self):
52@@ -409,6 +423,17 @@
53 handlers.call_end(mod, data, frequency)
54 called.append(mod)
55
56+ # Perform post-consumption adjustments so that
57+ # modules that run during the init stage reflect
58+ # this consumed set.
59+ #
60+ # They will be recreated on future access...
61+ self._reset()
62+ # Note(harlowja): the 'active' datasource will have
63+ # references to the previous config, distro, paths
64+ # objects before the load of the userdata happened,
65+ # this is expected.
66+
67
68 class Modules(object):
69 def __init__(self, init, cfg_files=None):
70
71=== added file 'tests/data/user_data.1.txt'
72--- tests/data/user_data.1.txt 1970-01-01 00:00:00 +0000
73+++ tests/data/user_data.1.txt 2012-11-09 00:35:23 +0000
74@@ -0,0 +1,15 @@
75+#cloud-config
76+write_files:
77+- content: blah
78+ path: /etc/blah.ini
79+ permissions: 493
80+
81+system_info:
82+ package_mirrors:
83+ - arches: [i386, amd64, blah]
84+ failsafe:
85+ primary: http://my.archive.mydomain.com/ubuntu
86+ security: http://my.security.mydomain.com/ubuntu
87+ search:
88+ primary: []
89+ security: []
90
91=== added file 'tests/unittests/test_merging.py'
92--- tests/unittests/test_merging.py 1970-01-01 00:00:00 +0000
93+++ tests/unittests/test_merging.py 2012-11-09 00:35:23 +0000
94@@ -0,0 +1,62 @@
95+from mocker import MockerTestCase
96+
97+from cloudinit import util
98+
99+
100+class TestMergeDict(MockerTestCase):
101+ def test_simple_merge(self):
102+ """Test simple non-conflict merge."""
103+ source = {"key1": "value1"}
104+ candidate = {"key2": "value2"}
105+ result = util.mergedict(source, candidate)
106+ self.assertEqual({"key1": "value1", "key2": "value2"}, result)
107+
108+ def test_nested_merge(self):
109+ """Test nested merge."""
110+ source = {"key1": {"key1.1": "value1.1"}}
111+ candidate = {"key1": {"key1.2": "value1.2"}}
112+ result = util.mergedict(source, candidate)
113+ self.assertEqual(
114+ {"key1": {"key1.1": "value1.1", "key1.2": "value1.2"}}, result)
115+
116+ def test_merge_does_not_override(self):
117+ """Test that candidate doesn't override source."""
118+ source = {"key1": "value1", "key2": "value2"}
119+ candidate = {"key1": "value2", "key2": "NEW VALUE"}
120+ result = util.mergedict(source, candidate)
121+ self.assertEqual(source, result)
122+
123+ def test_empty_candidate(self):
124+ """Test empty candidate doesn't change source."""
125+ source = {"key": "value"}
126+ candidate = {}
127+ result = util.mergedict(source, candidate)
128+ self.assertEqual(source, result)
129+
130+ def test_empty_source(self):
131+ """Test empty source is replaced by candidate."""
132+ source = {}
133+ candidate = {"key": "value"}
134+ result = util.mergedict(source, candidate)
135+ self.assertEqual(candidate, result)
136+
137+ def test_non_dict_candidate(self):
138+ """Test non-dict candidate is discarded."""
139+ source = {"key": "value"}
140+ candidate = "not a dict"
141+ result = util.mergedict(source, candidate)
142+ self.assertEqual(source, result)
143+
144+ def test_non_dict_source(self):
145+ """Test non-dict source is not modified with a dict candidate."""
146+ source = "not a dict"
147+ candidate = {"key": "value"}
148+ result = util.mergedict(source, candidate)
149+ self.assertEqual(source, result)
150+
151+ def test_neither_dict(self):
152+ """Test if neither candidate or source is dict source wins."""
153+ source = "source"
154+ candidate = "candidate"
155+ result = util.mergedict(source, candidate)
156+ self.assertEqual(source, result)
157
158=== added file 'tests/unittests/test_runs/test_merge_run.py'
159--- tests/unittests/test_runs/test_merge_run.py 1970-01-01 00:00:00 +0000
160+++ tests/unittests/test_runs/test_merge_run.py 2012-11-09 00:35:23 +0000
161@@ -0,0 +1,52 @@
162+import os
163+
164+from tests.unittests import helpers
165+
166+from cloudinit.settings import (PER_INSTANCE)
167+from cloudinit import stages
168+from cloudinit import util
169+
170+
171+class TestSimpleRun(helpers.FilesystemMockingTestCase):
172+ def _patchIn(self, root):
173+ self.restore()
174+ self.patchOS(root)
175+ self.patchUtils(root)
176+
177+ def test_none_ds(self):
178+ new_root = self.makeDir()
179+ self.replicateTestRoot('simple_ubuntu', new_root)
180+ cfg = {
181+ 'datasource_list': ['None'],
182+ 'cloud_init_modules': ['write-files'],
183+ }
184+ ud = self.readResource('user_data.1.txt')
185+ cloud_cfg = util.yaml_dumps(cfg)
186+ util.ensure_dir(os.path.join(new_root, 'etc', 'cloud'))
187+ util.write_file(os.path.join(new_root, 'etc',
188+ 'cloud', 'cloud.cfg'), cloud_cfg)
189+ self._patchIn(new_root)
190+
191+ # Now start verifying whats created
192+ initer = stages.Init()
193+ initer.read_cfg()
194+ initer.initialize()
195+ initer.fetch()
196+ initer.datasource.userdata_raw = ud
197+ iid = initer.instancify()
198+ initer.update()
199+ initer.cloudify().run('consume_userdata',
200+ initer.consume_userdata,
201+ args=[PER_INSTANCE],
202+ freq=PER_INSTANCE)
203+ mirrors = initer.distro.get_option('package_mirrors')
204+ self.assertEquals(1, len(mirrors))
205+ mirror = mirrors[0]
206+ self.assertEquals(mirror['arches'], ['i386', 'amd64', 'blah'])
207+ mods = stages.Modules(initer)
208+ (which_ran, failures) = mods.run_section('cloud_init_modules')
209+ self.assertTrue(len(failures) == 0)
210+ self.assertTrue(os.path.exists('/etc/blah.ini'))
211+ self.assertIn('write-files', which_ran)
212+ contents = util.load_file('/etc/blah.ini')
213+ self.assertEquals(contents, 'blah')
214
215=== modified file 'tests/unittests/test_util.py'
216--- tests/unittests/test_util.py 2012-09-28 20:31:50 +0000
217+++ tests/unittests/test_util.py 2012-11-09 00:35:23 +0000
218@@ -28,65 +28,6 @@
219 self.restored.append(path)
220
221
222-class TestMergeDict(MockerTestCase):
223- def test_simple_merge(self):
224- """Test simple non-conflict merge."""
225- source = {"key1": "value1"}
226- candidate = {"key2": "value2"}
227- result = util.mergedict(source, candidate)
228- self.assertEqual({"key1": "value1", "key2": "value2"}, result)
229-
230- def test_nested_merge(self):
231- """Test nested merge."""
232- source = {"key1": {"key1.1": "value1.1"}}
233- candidate = {"key1": {"key1.2": "value1.2"}}
234- result = util.mergedict(source, candidate)
235- self.assertEqual(
236- {"key1": {"key1.1": "value1.1", "key1.2": "value1.2"}}, result)
237-
238- def test_merge_does_not_override(self):
239- """Test that candidate doesn't override source."""
240- source = {"key1": "value1", "key2": "value2"}
241- candidate = {"key1": "value2", "key2": "NEW VALUE"}
242- result = util.mergedict(source, candidate)
243- self.assertEqual(source, result)
244-
245- def test_empty_candidate(self):
246- """Test empty candidate doesn't change source."""
247- source = {"key": "value"}
248- candidate = {}
249- result = util.mergedict(source, candidate)
250- self.assertEqual(source, result)
251-
252- def test_empty_source(self):
253- """Test empty source is replaced by candidate."""
254- source = {}
255- candidate = {"key": "value"}
256- result = util.mergedict(source, candidate)
257- self.assertEqual(candidate, result)
258-
259- def test_non_dict_candidate(self):
260- """Test non-dict candidate is discarded."""
261- source = {"key": "value"}
262- candidate = "not a dict"
263- result = util.mergedict(source, candidate)
264- self.assertEqual(source, result)
265-
266- def test_non_dict_source(self):
267- """Test non-dict source is not modified with a dict candidate."""
268- source = "not a dict"
269- candidate = {"key": "value"}
270- result = util.mergedict(source, candidate)
271- self.assertEqual(source, result)
272-
273- def test_neither_dict(self):
274- """Test if neither candidate or source is dict source wins."""
275- source = "source"
276- candidate = "candidate"
277- result = util.mergedict(source, candidate)
278- self.assertEqual(source, result)
279-
280-
281 class TestGetCfgOptionListOrStr(TestCase):
282 def test_not_found_no_default(self):
283 """None is returned if key is not found and no default given."""
284
285=== modified file 'tools/run-pep8'
286--- tools/run-pep8 2012-10-23 16:58:32 +0000
287+++ tools/run-pep8 2012-11-09 00:35:23 +0000
288@@ -21,10 +21,21 @@
289 base=`pwd`/tools/
290 fi
291
292+IGNORE="E501" # Line too long (these are caught by pylint)
293+
294+# King Arthur: Be quiet! ... Be Quiet! I Order You to Be Quiet.
295+IGNORE="$IGNORE,E121" # Continuation line indentation is not a multiple of four
296+IGNORE="$IGNORE,E123" # Closing bracket does not match indentation of opening bracket's line
297+IGNORE="$IGNORE,E124" # Closing bracket missing visual indentation
298+IGNORE="$IGNORE,E125" # Continuation line does not distinguish itself from next logical line
299+IGNORE="$IGNORE,E126" # Continuation line over-indented for hanging indent
300+IGNORE="$IGNORE,E127" # Continuation line over-indented for visual indent
301+IGNORE="$IGNORE,E128" # Continuation line under-indented for visual indent
302+
303 cmd=(
304 ${base}/hacking.py
305
306- --ignore=E501 # Line too long (these are caught by pylint)
307+ --ignore="$IGNORE"
308
309 "${files[@]}"
310 )