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