Merge lp:~smoser/cloud-init/trunk.mcollective-cleanup into lp:~cloud-init-dev/cloud-init/trunk
- trunk.mcollective-cleanup
- Merge into trunk
Proposed by
Scott Moser
Status: | Merged |
---|---|
Merge reported by: | Scott Moser |
Merged at revision: | not available |
Proposed branch: | lp:~smoser/cloud-init/trunk.mcollective-cleanup |
Merge into: | lp:~cloud-init-dev/cloud-init/trunk |
Diff against target: |
298 lines (+176/-62) 2 files modified
cloudinit/config/cc_mcollective.py (+52/-44) tests/unittests/test_handler/test_handler_mcollective.py (+124/-18) |
To merge this branch: | bzr merge lp:~smoser/cloud-init/trunk.mcollective-cleanup |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Needs Fixing | |
Sergii Golovatiuk (community) | Approve | ||
cloud-init Commiters | Pending | ||
Review via email: mp+300394@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
- 1258. By Scott Moser
-
move most of handle to apply_config, change tests.
- 1259. By Scott Moser
-
test dictionary in config
- 1260. By Scott Moser
-
whitespace
Revision history for this message
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:1260
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
review:
Needs Fixing
(continuous-integration)
Revision history for this message
Scott Moser (smoser) wrote : | # |
this got merged at 4264783ae982e48
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'cloudinit/config/cc_mcollective.py' |
2 | --- cloudinit/config/cc_mcollective.py 2016-07-14 15:28:46 +0000 |
3 | +++ cloudinit/config/cc_mcollective.py 2016-07-19 15:17:25 +0000 |
4 | @@ -36,67 +36,75 @@ |
5 | LOG = logging.getLogger(__name__) |
6 | |
7 | |
8 | -def configure(config): |
9 | +def configure(config, server_cfg=SERVER_CFG, |
10 | + pubcert_file=PUBCERT_FILE, pricert_file=PRICERT_FILE): |
11 | # Read server.cfg values from the |
12 | # original file in order to be able to mix the rest up |
13 | try: |
14 | - mcollective_config = ConfigObj(SERVER_CFG, file_error=True) |
15 | + mcollective_config = ConfigObj(server_cfg, file_error=True) |
16 | + existed = True |
17 | except IOError: |
18 | - LOG.warn("Did not find file %s", SERVER_CFG) |
19 | - mcollective_config = ConfigObj(config) |
20 | - else: |
21 | - for (cfg_name, cfg) in config.items(): |
22 | - if cfg_name == 'public-cert': |
23 | - util.write_file(PUBCERT_FILE, cfg, mode=0o644) |
24 | - mcollective_config[ |
25 | - 'plugin.ssl_server_public'] = PUBCERT_FILE |
26 | - mcollective_config['securityprovider'] = 'ssl' |
27 | - elif cfg_name == 'private-cert': |
28 | - util.write_file(PRICERT_FILE, cfg, mode=0o600) |
29 | - mcollective_config[ |
30 | - 'plugin.ssl_server_private'] = PRICERT_FILE |
31 | - mcollective_config['securityprovider'] = 'ssl' |
32 | + LOG.debug("Did not find file %s", server_cfg) |
33 | + mcollective_config = ConfigObj() |
34 | + existed = False |
35 | + |
36 | + for (cfg_name, cfg) in config.items(): |
37 | + if cfg_name == 'public-cert': |
38 | + util.write_file(pubcert_file, cfg, mode=0o644) |
39 | + mcollective_config[ |
40 | + 'plugin.ssl_server_public'] = pubcert_file |
41 | + mcollective_config['securityprovider'] = 'ssl' |
42 | + elif cfg_name == 'private-cert': |
43 | + util.write_file(pricert_file, cfg, mode=0o600) |
44 | + mcollective_config[ |
45 | + 'plugin.ssl_server_private'] = pricert_file |
46 | + mcollective_config['securityprovider'] = 'ssl' |
47 | + else: |
48 | + if isinstance(cfg, six.string_types): |
49 | + # Just set it in the 'main' section |
50 | + mcollective_config[cfg_name] = cfg |
51 | + elif isinstance(cfg, (dict)): |
52 | + # Iterate through the config items, create a section if |
53 | + # it is needed and then add/or create items as needed |
54 | + if cfg_name not in mcollective_config.sections: |
55 | + mcollective_config[cfg_name] = {} |
56 | + for (o, v) in cfg.items(): |
57 | + mcollective_config[cfg_name][o] = v |
58 | else: |
59 | - if isinstance(cfg, six.string_types): |
60 | - # Just set it in the 'main' section |
61 | - mcollective_config[cfg_name] = cfg |
62 | - elif isinstance(cfg, (dict)): |
63 | - # Iterate through the config items, create a section if |
64 | - # it is needed and then add/or create items as needed |
65 | - if cfg_name not in mcollective_config.sections: |
66 | - mcollective_config[cfg_name] = {} |
67 | - for (o, v) in cfg.items(): |
68 | - mcollective_config[cfg_name][o] = v |
69 | - else: |
70 | - # Otherwise just try to convert it to a string |
71 | - mcollective_config[cfg_name] = str(cfg) |
72 | + # Otherwise just try to convert it to a string |
73 | + mcollective_config[cfg_name] = str(cfg) |
74 | + |
75 | + if existed: |
76 | # We got all our config as wanted we'll rename |
77 | # the previous server.cfg and create our new one |
78 | - util.rename(SERVER_CFG, "%s.old" % (SERVER_CFG)) |
79 | + util.rename(server_cfg, "%s.old" % (server_cfg)) |
80 | |
81 | # Now we got the whole file, write to disk... |
82 | contents = BytesIO() |
83 | mcollective_config.write(contents) |
84 | - contents = contents.getvalue() |
85 | - util.write_file(SERVER_CFG, contents, mode=0o644) |
86 | + util.write_file(server_cfg, contents.getvalue(), mode=0o644) |
87 | + |
88 | + |
89 | +def apply_config(config, install_packages): |
90 | + # Start by installing the mcollective package ... |
91 | + install_packages(("mcollective",)) |
92 | + |
93 | + # ... and then update the mcollective configuration |
94 | + if 'conf' in config: |
95 | + configure(config=config['conf']) |
96 | + |
97 | + # restart mcollective to handle updated config |
98 | + util.subp(['service', 'mcollective', 'restart'], capture=False) |
99 | + return True |
100 | |
101 | |
102 | def handle(name, cfg, cloud, log, _args): |
103 | - |
104 | # If there isn't a mcollective key in the configuration don't do anything |
105 | if 'mcollective' not in cfg: |
106 | log.debug(("Skipping module named %s, " |
107 | "no 'mcollective' key in configuration"), name) |
108 | return |
109 | |
110 | - mcollective_cfg = cfg['mcollective'] |
111 | - |
112 | - # Start by installing the mcollective package ... |
113 | - cloud.distro.install_packages(("mcollective",)) |
114 | - |
115 | - # ... and then update the mcollective configuration |
116 | - if 'conf' in mcollective_cfg: |
117 | - configure(config=mcollective_cfg['conf']) |
118 | - |
119 | - # Start mcollective |
120 | - util.subp(['service', 'mcollective', 'start'], capture=False) |
121 | + return apply_config( |
122 | + config=cfg['mcollective'], |
123 | + install_packages=cloud.distro.install_packages) |
124 | |
125 | === modified file 'tests/unittests/test_handler/test_handler_mcollective.py' |
126 | --- tests/unittests/test_handler/test_handler_mcollective.py 2016-07-14 15:28:46 +0000 |
127 | +++ tests/unittests/test_handler/test_handler_mcollective.py 2016-07-19 15:17:25 +0000 |
128 | @@ -1,10 +1,11 @@ |
129 | from cloudinit.config import cc_mcollective |
130 | from cloudinit import util |
131 | |
132 | -from .. import helpers |
133 | +from ..helpers import mock, FilesystemMockingTestCase, TestCase |
134 | |
135 | import configobj |
136 | import logging |
137 | +import os |
138 | import shutil |
139 | from six import BytesIO |
140 | import tempfile |
141 | @@ -12,11 +13,43 @@ |
142 | LOG = logging.getLogger(__name__) |
143 | |
144 | |
145 | -class TestConfig(helpers.FilesystemMockingTestCase): |
146 | +STOCK_CONFIG = """\ |
147 | +main_collective = mcollective |
148 | +collectives = mcollective |
149 | +libdir = /usr/share/mcollective/plugins |
150 | +logfile = /var/log/mcollective.log |
151 | +loglevel = info |
152 | +daemonize = 1 |
153 | + |
154 | +# Plugins |
155 | +securityprovider = psk |
156 | +plugin.psk = unset |
157 | + |
158 | +connector = activemq |
159 | +plugin.activemq.pool.size = 1 |
160 | +plugin.activemq.pool.1.host = stomp1 |
161 | +plugin.activemq.pool.1.port = 61613 |
162 | +plugin.activemq.pool.1.user = mcollective |
163 | +plugin.activemq.pool.1.password = marionette |
164 | + |
165 | +# Facts |
166 | +factsource = yaml |
167 | +plugin.yaml = /etc/mcollective/facts.yaml |
168 | +""" |
169 | + |
170 | + |
171 | +class TestConfig(FilesystemMockingTestCase): |
172 | def setUp(self): |
173 | super(TestConfig, self).setUp() |
174 | self.tmp = tempfile.mkdtemp() |
175 | self.addCleanup(shutil.rmtree, self.tmp) |
176 | + # "./": make os.path.join behave correctly with abs path as second arg |
177 | + self.server_cfg = os.path.join( |
178 | + self.tmp, "./" + cc_mcollective.SERVER_CFG) |
179 | + self.pubcert_file = os.path.join( |
180 | + self.tmp, "./" + cc_mcollective.PUBCERT_FILE) |
181 | + self.pricert_file = os.path.join( |
182 | + self.tmp, self.tmp, "./" + cc_mcollective.PRICERT_FILE) |
183 | |
184 | def test_basic_config(self): |
185 | cfg = { |
186 | @@ -38,23 +71,96 @@ |
187 | }, |
188 | }, |
189 | } |
190 | + expected = cfg['mcollective']['conf'] |
191 | + |
192 | self.patchUtils(self.tmp) |
193 | cc_mcollective.configure(cfg['mcollective']['conf']) |
194 | - contents = util.load_file("/etc/mcollective/server.cfg", decode=False) |
195 | + contents = util.load_file(cc_mcollective.SERVER_CFG, decode=False) |
196 | contents = configobj.ConfigObj(BytesIO(contents)) |
197 | - expected = { |
198 | - 'loglevel': 'debug', |
199 | - 'connector': 'rabbitmq', |
200 | - 'logfile': '/var/log/mcollective.log', |
201 | - 'ttl': '4294957', |
202 | - 'collectives': 'mcollective', |
203 | - 'main_collective': 'mcollective', |
204 | - 'securityprovider': 'psk', |
205 | - 'daemonize': '1', |
206 | - 'factsource': 'yaml', |
207 | - 'direct_addressing': '1', |
208 | - 'plugin.psk': 'unset', |
209 | - 'libdir': '/usr/share/mcollective/plugins', |
210 | - 'identity': '1', |
211 | - } |
212 | self.assertEqual(expected, dict(contents)) |
213 | + |
214 | + def test_existing_config_is_saved(self): |
215 | + cfg = {'loglevel': 'warn'} |
216 | + util.write_file(self.server_cfg, STOCK_CONFIG) |
217 | + cc_mcollective.configure(config=cfg, server_cfg=self.server_cfg) |
218 | + self.assertTrue(os.path.exists(self.server_cfg)) |
219 | + self.assertTrue(os.path.exists(self.server_cfg + ".old")) |
220 | + self.assertEqual(util.load_file(self.server_cfg + ".old"), |
221 | + STOCK_CONFIG) |
222 | + |
223 | + def test_existing_updated(self): |
224 | + cfg = {'loglevel': 'warn'} |
225 | + util.write_file(self.server_cfg, STOCK_CONFIG) |
226 | + cc_mcollective.configure(config=cfg, server_cfg=self.server_cfg) |
227 | + cfgobj = configobj.ConfigObj(self.server_cfg) |
228 | + self.assertEqual(cfg['loglevel'], cfgobj['loglevel']) |
229 | + |
230 | + def test_dictionary_in_config(self): |
231 | + cfg = {'loglevel': 'debug', 'subfoo': {'subkey': 'subval'}} |
232 | + cc_mcollective.configure(config=cfg, server_cfg=self.server_cfg) |
233 | + cfgobj = configobj.ConfigObj(self.server_cfg) |
234 | + self.assertEqual(cfg['loglevel'], cfgobj['loglevel']) |
235 | + contents = util.load_file(self.server_cfg) |
236 | + self.assertIn('[subfoo]', contents) |
237 | + self.assertEqual(cfgobj['subfoo']['subkey'], 'subval') |
238 | + |
239 | + def test_certificats_written(self): |
240 | + # check public-cert and private-cert keys in config get written |
241 | + cfg = {'loglevel': 'debug', |
242 | + 'public-cert': "this is my public-certificate", |
243 | + 'private-cert': "secret private certificate"} |
244 | + |
245 | + cc_mcollective.configure( |
246 | + config=cfg, server_cfg=self.server_cfg, |
247 | + pricert_file=self.pricert_file, pubcert_file=self.pubcert_file) |
248 | + |
249 | + found = configobj.ConfigObj(self.server_cfg) |
250 | + |
251 | + # make sure these didnt get written in |
252 | + self.assertFalse('public-cert' in found) |
253 | + self.assertFalse('private-cert' in found) |
254 | + |
255 | + # these need updating to the specified paths |
256 | + self.assertEqual(found['plugin.ssl_server_public'], self.pubcert_file) |
257 | + self.assertEqual(found['plugin.ssl_server_private'], self.pricert_file) |
258 | + |
259 | + # and the security provider should be ssl |
260 | + self.assertEqual(found['securityprovider'], 'ssl') |
261 | + |
262 | + self.assertEqual( |
263 | + util.load_file(self.pricert_file), cfg['private-cert']) |
264 | + self.assertEqual( |
265 | + util.load_file(self.pubcert_file), cfg['public-cert']) |
266 | + |
267 | + |
268 | +class TestApplyConfig(TestCase): |
269 | + def setUp(self): |
270 | + super(TestApplyConfig, self).setUp() |
271 | + self.installed_packages = [] |
272 | + |
273 | + def _install_packages(self, pkglist): |
274 | + self.installed_packages.extend(pkglist) |
275 | + |
276 | + @mock.patch("cloudinit.config.cc_mcollective.util.subp") |
277 | + @mock.patch("cloudinit.config.cc_mcollective.configure") |
278 | + def test_with_conf_configure_called(self, configure, subp): |
279 | + mycfg = {'conf': {'loglevel': 'warn'}} |
280 | + cc_mcollective.apply_config( |
281 | + mycfg, install_packages=self._install_packages) |
282 | + self.assertTrue(configure.called_once) |
283 | + self.assertEqual(configure.call_args_list, |
284 | + [mock.call(config=mycfg['conf'])]) |
285 | + self.assertEqual(subp.call_args_list[0][0][0], |
286 | + ['service', 'mcollective', 'restart']) |
287 | + self.assertEqual(self.installed_packages, ['mcollective']) |
288 | + |
289 | + @mock.patch("cloudinit.config.cc_mcollective.util.subp") |
290 | + @mock.patch("cloudinit.config.cc_mcollective.configure") |
291 | + def test_without_conf_configure_not_called(self, configure, subp): |
292 | + mycfg = {'foo': 'bar'} |
293 | + cc_mcollective.apply_config( |
294 | + mycfg, install_packages=self._install_packages) |
295 | + self.assertFalse(configure.called) |
296 | + self.assertEqual(subp.call_args_list[0][0][0], |
297 | + ['service', 'mcollective', 'restart']) |
298 | + self.assertEqual(self.installed_packages, ['mcollective']) |
Refactoring looks good to me. It doesn't break anything. Also, Scott added more unit tests which is really good.