Merge lp:~ubuntudotcom1/maas/kill-all-the-configs-cluster into lp:~maas-committers/maas/trunk
- kill-all-the-configs-cluster
- Merge into trunk
Proposed by
ubuntudotcom1
Status: | Merged | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 4066 | ||||||||||||
Proposed branch: | lp:~ubuntudotcom1/maas/kill-all-the-configs-cluster | ||||||||||||
Merge into: | lp:~maas-committers/maas/trunk | ||||||||||||
Prerequisite: | lp:~ubuntudotcom1/maas/kill-all-the-configs-region | ||||||||||||
Diff against target: |
3136 lines (+512/-861) 37 files modified
.gitignore (+2/-0) etc/demo_maas_cluster.conf (+0/-8) etc/maas/pserv.yaml (+0/-24) etc/maas_cluster.conf (+0/-5) services/clusterd/run (+0/-5) setup.py (+1/-3) src/maasserver/clusterrpc/tests/test_boot_images.py (+19/-5) src/provisioningserver/__main__.py (+3/-0) src/provisioningserver/boot/install_grub.py (+8/-5) src/provisioningserver/boot/tests/test_install_grub.py (+11/-4) src/provisioningserver/boot/tests/test_tftppath.py (+16/-9) src/provisioningserver/boot/tftppath.py (+11/-6) src/provisioningserver/cluster_config.py (+7/-41) src/provisioningserver/config.py (+0/-31) src/provisioningserver/diskless.py (+16/-8) src/provisioningserver/drivers/osystem/custom.py (+8/-5) src/provisioningserver/drivers/osystem/tests/test_custom.py (+14/-6) src/provisioningserver/import_images/boot_resources.py (+20/-6) src/provisioningserver/import_images/tests/test_boot_resources.py (+26/-16) src/provisioningserver/plugin.py (+26/-24) src/provisioningserver/pserv_services/tests/test_tftp.py (+11/-7) src/provisioningserver/pserv_services/tftp.py (+8/-4) src/provisioningserver/rpc/boot_images.py (+11/-7) src/provisioningserver/rpc/clusterservice.py (+12/-11) src/provisioningserver/rpc/tags.py (+20/-5) src/provisioningserver/rpc/tests/test_boot_images.py (+17/-6) src/provisioningserver/rpc/tests/test_clusterservice.py (+46/-33) src/provisioningserver/rpc/tests/test_tags.py (+16/-7) src/provisioningserver/tests/test_cluster_config.py (+72/-31) src/provisioningserver/tests/test_config.py (+0/-453) src/provisioningserver/tests/test_diskless.py (+26/-13) src/provisioningserver/tests/test_plugin.py (+19/-34) src/provisioningserver/tests/test_upgrade_cluster.py (+25/-10) src/provisioningserver/upgrade_cluster.py (+15/-9) src/provisioningserver/utils/__init__.py (+3/-2) src/provisioningserver/utils/script.py (+6/-7) src/provisioningserver/utils/tests/test_utils.py (+17/-11) |
||||||||||||
To merge this branch: | bzr merge lp:~ubuntudotcom1/maas/kill-all-the-configs-cluster | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email: mp+254970@code.launchpad.net |
Commit message
Config changes applied according to new config backend in -cluster-admin. branch.
Description of the change
Config changes applied according to new config backend in -cluster-admin. branch.
To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote : | # |
Revision history for this message
Gavin Panella (allenap) wrote : | # |
Looks good. I have a few comments, but they're not blockers.
I am interested in what your plan is for upgrading from pserv.yaml. Is that entirely happening in packaging?
review:
Approve
Revision history for this message
Gavin Panella (allenap) wrote : | # |
This has been superseded by lp:~allenap/maas/kill-all-the-configs-cluster (which builds on this).
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.gitignore' |
2 | --- .gitignore 2015-04-10 09:45:46 +0000 |
3 | +++ .gitignore 2015-05-04 14:27:25 +0000 |
4 | @@ -22,6 +22,8 @@ |
5 | /docs/_autosummary |
6 | /docs/_build |
7 | /docs/api.rst |
8 | +/etc/maas/regiond.conf |
9 | +/etc/maas/clusterd.conf |
10 | /eggs |
11 | /include |
12 | /lib |
13 | |
14 | === removed file 'etc/demo_maas_cluster.conf' |
15 | --- etc/demo_maas_cluster.conf 2015-03-12 18:13:14 +0000 |
16 | +++ etc/demo_maas_cluster.conf 1970-01-01 00:00:00 +0000 |
17 | @@ -1,8 +0,0 @@ |
18 | -# This is the version of maas_cluster.conf that's used when running from a |
19 | -# branch. The region controller will serve HTTP on a different port from a |
20 | -# packaged MAAS, and the master cluster controller (running on the same |
21 | -# development machine) has a fixed UUID. |
22 | -# It is also carefully crafted so it works as both a bash script and a |
23 | -# Python script. |
24 | -MAAS_URL="http://0.0.0.0:5240/MAAS/" |
25 | -CLUSTER_UUID="adfd3977-f251-4f2c-8d61-745dbd690bf2" |
26 | |
27 | === removed file 'etc/maas/pserv.yaml' |
28 | --- etc/maas/pserv.yaml 2015-04-24 13:27:39 +0000 |
29 | +++ etc/maas/pserv.yaml 1970-01-01 00:00:00 +0000 |
30 | @@ -1,24 +0,0 @@ |
31 | -## |
32 | -## Provisioning Server (pserv) configuration. |
33 | -## |
34 | - |
35 | -## Where to log. This log can be rotated by sending SIGUSR1 to the |
36 | -## running server. |
37 | -# |
38 | -# logfile: "pserv.log" |
39 | -logfile: "/dev/null" |
40 | - |
41 | -## TFTP configuration. |
42 | -# |
43 | -tftp: |
44 | - # The "root" setting has been replaced by "resource_root". The old setting |
45 | - # is used one final time when upgrading a pre-14.04 cluster controller to a |
46 | - # 14.04 version. After that upgrade, it can be removed. |
47 | - # |
48 | - # resource_root: /var/lib/maas/boot-resources/current/ |
49 | - |
50 | - # port: 69 |
51 | - port: 5244 |
52 | - ## The URL to be contacted to generate PXE configurations. |
53 | - # generator: http://localhost/MAAS/api/1.0/pxeconfig/ |
54 | - generator: http://localhost:5240/MAAS/api/1.0/pxeconfig/ |
55 | |
56 | === removed file 'etc/maas_cluster.conf' |
57 | --- etc/maas_cluster.conf 2015-03-12 18:13:14 +0000 |
58 | +++ etc/maas_cluster.conf 1970-01-01 00:00:00 +0000 |
59 | @@ -1,5 +0,0 @@ |
60 | -# This file is used by the cluster controller startup script: |
61 | -# `maas-provision start-cluster-controller` |
62 | -# to get the URL to the MAAS region controller's API. Normally, packaging |
63 | -# will update this file automatically but it may also be configured manually. |
64 | -MAAS_URL=http://localhost/MAAS |
65 | |
66 | === modified file 'services/clusterd/run' |
67 | --- services/clusterd/run 2015-04-10 09:45:46 +0000 |
68 | +++ services/clusterd/run 2015-05-04 14:27:25 +0000 |
69 | @@ -21,11 +21,6 @@ |
70 | script="$(readlink -f bin/twistd.cluster)" |
71 | config="$(readlink -f etc/maas/pserv.yaml)" |
72 | |
73 | -# Obtain the development setting for CLUSTER_UUID. |
74 | -. etc/demo_maas_cluster.conf |
75 | -export CLUSTER_UUID |
76 | -export MAAS_URL |
77 | - |
78 | exec $(command -v authbind && echo --deep) \ |
79 | "${script}" --nodaemon --pidfile="" maas-clusterd \ |
80 | --introspect="unix:${here}/introspect:lockfile=0" \ |
81 | |
82 | === modified file 'setup.py' |
83 | --- setup.py 2015-05-04 14:27:25 +0000 |
84 | +++ setup.py 2015-05-04 14:27:25 +0000 |
85 | @@ -64,9 +64,7 @@ |
86 | |
87 | data_files=[ |
88 | ('/etc/maas', |
89 | - ['etc/maas/pserv.yaml', |
90 | - 'etc/maas/drivers.yaml', |
91 | - 'etc/maas_cluster.conf', |
92 | + ['etc/maas/drivers.yaml', |
93 | 'contrib/maas-http.conf']), |
94 | ('/etc/maas/templates/uefi', |
95 | glob('etc/maas/templates/uefi/*.template')), |
96 | |
97 | === modified file 'src/maasserver/clusterrpc/tests/test_boot_images.py' |
98 | --- src/maasserver/clusterrpc/tests/test_boot_images.py 2015-03-25 15:33:23 +0000 |
99 | +++ src/maasserver/clusterrpc/tests/test_boot_images.py 2015-05-04 14:27:25 +0000 |
100 | @@ -7,7 +7,7 @@ |
101 | absolute_import, |
102 | print_function, |
103 | unicode_literals, |
104 | - ) |
105 | +) |
106 | |
107 | str = None |
108 | |
109 | @@ -37,6 +37,10 @@ |
110 | compose_image_path, |
111 | locate_tftp_path, |
112 | ) |
113 | +from provisioningserver.cluster_config import ( |
114 | + CLUSTER_CONFIG, |
115 | + set_config_cluster_variable, |
116 | +) |
117 | from provisioningserver.rpc import ( |
118 | boot_images, |
119 | clusterservice, |
120 | @@ -45,6 +49,7 @@ |
121 | make_boot_image_storage_params, |
122 | make_image, |
123 | ) |
124 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
125 | from twisted.internet.defer import succeed |
126 | |
127 | |
128 | @@ -141,11 +146,14 @@ |
129 | |
130 | def setUp(self): |
131 | super(TestGetBootImages, self).setUp() |
132 | + self.useFixture(ClusterConfigurationFixture()) |
133 | resource_dir = self.make_dir() |
134 | self.tftproot = os.path.join(resource_dir, 'current') |
135 | os.mkdir(self.tftproot) |
136 | self.patch(boot_images, 'CACHED_BOOT_IMAGES', None) |
137 | - self.patch(boot_images, 'BOOT_RESOURCES_STORAGE', resource_dir) |
138 | + set_config_cluster_variable( |
139 | + CLUSTER_CONFIG.DB_boot_resources_storage, |
140 | + self.tftproot) |
141 | |
142 | def test_returns_boot_images(self): |
143 | nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED) |
144 | @@ -170,11 +178,14 @@ |
145 | |
146 | def setUp(self): |
147 | super(TestGetAvailableBootImages, self).setUp() |
148 | + self.useFixture(ClusterConfigurationFixture()) |
149 | resource_dir = self.make_dir() |
150 | self.tftproot = os.path.join(resource_dir, 'current') |
151 | os.mkdir(self.tftproot) |
152 | self.patch(boot_images, 'CACHED_BOOT_IMAGES', None) |
153 | - self.patch(boot_images, 'BOOT_RESOURCES_STORAGE', resource_dir) |
154 | + set_config_cluster_variable( |
155 | + CLUSTER_CONFIG.DB_boot_resources_storage, |
156 | + self.tftproot) |
157 | |
158 | def test_returns_boot_images_for_one_cluster(self): |
159 | factory.make_NodeGroup().accept() |
160 | @@ -260,11 +271,14 @@ |
161 | |
162 | def setUp(self): |
163 | super(TestGetBootImagesFor, self).setUp() |
164 | + self.useFixture(ClusterConfigurationFixture()) |
165 | resource_dir = self.make_dir() |
166 | self.tftproot = os.path.join(resource_dir, 'current') |
167 | os.mkdir(self.tftproot) |
168 | self.patch(boot_images, 'CACHED_BOOT_IMAGES', None) |
169 | - self.patch(boot_images, 'BOOT_RESOURCES_STORAGE', resource_dir) |
170 | + set_config_cluster_variable( |
171 | + CLUSTER_CONFIG.DB_boot_resources_storage, |
172 | + self.tftproot) |
173 | |
174 | def make_boot_images(self): |
175 | purposes = ['install', 'commissioning', 'xinstall'] |
176 | @@ -279,7 +293,7 @@ |
177 | return [ |
178 | make_image(param, purpose) |
179 | for purpose in purposes |
180 | - ] |
181 | + ] |
182 | |
183 | def test_returns_boot_images_matching_subarchitecture(self): |
184 | nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED) |
185 | |
186 | === modified file 'src/provisioningserver/__main__.py' |
187 | --- src/provisioningserver/__main__.py 2015-03-30 18:05:57 +0000 |
188 | +++ src/provisioningserver/__main__.py 2015-05-04 14:27:25 +0000 |
189 | @@ -14,6 +14,7 @@ |
190 | |
191 | __metaclass__ = type |
192 | |
193 | + |
194 | from provisioningserver import security |
195 | import provisioningserver.boot.install_bootloader |
196 | import provisioningserver.boot.install_grub |
197 | @@ -42,6 +43,8 @@ |
198 | |
199 | |
200 | main = MainScript(__doc__) |
201 | + |
202 | + |
203 | for name, command in sorted(script_commands.items()): |
204 | main.register(name, command) |
205 | main() |
206 | |
207 | === modified file 'src/provisioningserver/boot/install_grub.py' |
208 | --- src/provisioningserver/boot/install_grub.py 2015-02-24 20:11:09 +0000 |
209 | +++ src/provisioningserver/boot/install_grub.py 2015-05-04 14:27:25 +0000 |
210 | @@ -7,7 +7,7 @@ |
211 | absolute_import, |
212 | print_function, |
213 | unicode_literals, |
214 | - ) |
215 | +) |
216 | |
217 | str = None |
218 | |
219 | @@ -15,12 +15,15 @@ |
220 | __all__ = [ |
221 | "add_arguments", |
222 | "run", |
223 | - ] |
224 | +] |
225 | |
226 | import os.path |
227 | |
228 | from provisioningserver.boot.install_bootloader import make_destination |
229 | -from provisioningserver.config import Config |
230 | +from provisioningserver.cluster_config import ( |
231 | + CLUSTER_CONFIG, |
232 | + get_config_cluster_variable, |
233 | +) |
234 | from provisioningserver.utils.fs import write_text_file |
235 | |
236 | |
237 | @@ -44,7 +47,7 @@ |
238 | """Install a GRUB2 pre-boot loader config into the TFTP |
239 | directory structure. |
240 | """ |
241 | - config = Config.load(args.config_file) |
242 | - grubroot = os.path.join(config["tftp"]["resource_root"], 'grub') |
243 | + grubroot = os.path.join(get_config_cluster_variable( |
244 | + CLUSTER_CONFIG.DB_tftp_resource_root), 'grub') |
245 | destination_path = make_destination(grubroot) |
246 | write_text_file(os.path.join(destination_path, 'grub.cfg'), CONFIG_FILE) |
247 | |
248 | === modified file 'src/provisioningserver/boot/tests/test_install_grub.py' |
249 | --- src/provisioningserver/boot/tests/test_install_grub.py 2014-08-13 21:49:35 +0000 |
250 | +++ src/provisioningserver/boot/tests/test_install_grub.py 2015-05-04 14:27:25 +0000 |
251 | @@ -7,7 +7,7 @@ |
252 | absolute_import, |
253 | print_function, |
254 | unicode_literals, |
255 | - ) |
256 | +) |
257 | |
258 | str = None |
259 | |
260 | @@ -20,7 +20,11 @@ |
261 | from maastesting.testcase import MAASTestCase |
262 | import provisioningserver.boot.install_grub |
263 | from provisioningserver.boot.tftppath import locate_tftp_path |
264 | -from provisioningserver.testing.config import set_tftp_root |
265 | +from provisioningserver.cluster_config import ( |
266 | + CLUSTER_CONFIG, |
267 | + set_config_cluster_variable, |
268 | +) |
269 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
270 | from provisioningserver.utils.script import MainScript |
271 | from testtools.matchers import FileExists |
272 | |
273 | @@ -28,14 +32,17 @@ |
274 | class TestInstallGrub(MAASTestCase): |
275 | |
276 | def test_integration(self): |
277 | + self.useFixture(ClusterConfigurationFixture()) |
278 | tftproot = self.make_dir() |
279 | - config_fixture = self.useFixture(set_tftp_root(tftproot)) |
280 | + set_config_cluster_variable( |
281 | + CLUSTER_CONFIG.DB_tftp_resource_root, |
282 | + tftproot) |
283 | |
284 | action = factory.make_name("action") |
285 | script = MainScript(action) |
286 | script.register(action, provisioningserver.boot.install_grub) |
287 | script.execute( |
288 | - ("--config-file", config_fixture.filename, action)) |
289 | + ("--config-file", "clusterd.conf", action)) |
290 | |
291 | config_filename = os.path.join('grub', 'grub.cfg') |
292 | self.assertThat( |
293 | |
294 | === modified file 'src/provisioningserver/boot/tests/test_tftppath.py' |
295 | --- src/provisioningserver/boot/tests/test_tftppath.py 2015-03-25 15:33:23 +0000 |
296 | +++ src/provisioningserver/boot/tests/test_tftppath.py 2015-05-04 14:27:25 +0000 |
297 | @@ -7,7 +7,7 @@ |
298 | absolute_import, |
299 | print_function, |
300 | unicode_literals, |
301 | - ) |
302 | +) |
303 | |
304 | str = None |
305 | |
306 | @@ -21,7 +21,6 @@ |
307 | from maastesting.matchers import MockCalledOnceWith |
308 | from maastesting.testcase import MAASTestCase |
309 | from mock import Mock |
310 | -from provisioningserver import config |
311 | from provisioningserver.boot import tftppath |
312 | from provisioningserver.boot.tftppath import ( |
313 | compose_image_path, |
314 | @@ -35,6 +34,10 @@ |
315 | locate_tftp_path, |
316 | maas_meta_last_modified, |
317 | ) |
318 | +from provisioningserver.cluster_config import ( |
319 | + CLUSTER_CONFIG, |
320 | + get_config_cluster_variable, |
321 | +) |
322 | from provisioningserver.drivers.osystem import OperatingSystemRegistry |
323 | from provisioningserver.import_images.boot_image_mapping import ( |
324 | BootImageMapping, |
325 | @@ -48,7 +51,10 @@ |
326 | make_boot_image_storage_params, |
327 | make_image, |
328 | ) |
329 | -from provisioningserver.testing.config import set_tftp_root |
330 | +from provisioningserver.testing.config import ( |
331 | + ClusterConfigurationFixture, |
332 | + set_tftp_root, |
333 | +) |
334 | from provisioningserver.testing.os import make_osystem |
335 | from testtools.matchers import ( |
336 | Not, |
337 | @@ -102,12 +108,13 @@ |
338 | self.assertIsNone(observed) |
339 | |
340 | def test_maas_meta_last_modified_defaults_tftproot(self): |
341 | + self.useFixture(ClusterConfigurationFixture()) |
342 | path = factory.make_file(self.tftproot, name="maas.meta") |
343 | maas_meta_file_path = self.patch(tftppath, 'maas_meta_file_path') |
344 | maas_meta_file_path.return_value = path |
345 | maas_meta_last_modified() |
346 | - expected_path = os.path.join( |
347 | - config.BOOT_RESOURCES_STORAGE, 'current') |
348 | + expected_path = get_config_cluster_variable( |
349 | + CLUSTER_CONFIG.DB_tftp_resource_root) |
350 | self.assertThat(maas_meta_file_path, MockCalledOnceWith(expected_path)) |
351 | |
352 | def test_maas_meta_last_modified_reraises_non_ENOENT(self): |
353 | @@ -299,7 +306,7 @@ |
354 | resource = dict( |
355 | subarches=factory.make_name("subarch"), |
356 | other_item=factory.make_name("other"), |
357 | - ) |
358 | + ) |
359 | image = make_image_spec() |
360 | mapping = set_resource(image_spec=image, resource=resource) |
361 | metadata = mapping.dump_json() |
362 | @@ -313,7 +320,7 @@ |
363 | "subarchitecture": image.subarch, |
364 | "release": image.release, |
365 | "label": image.label, |
366 | - } |
367 | + } |
368 | extracted_data = extract_metadata(metadata, params) |
369 | |
370 | # We only expect the supported_subarches key from the resource data. |
371 | @@ -323,7 +330,7 @@ |
372 | def test_extract_metadata_handles_missing_subarch(self): |
373 | resource = dict( |
374 | other_item=factory.make_name("other"), |
375 | - ) |
376 | + ) |
377 | image = make_image_spec() |
378 | mapping = set_resource(image_spec=image, resource=resource) |
379 | metadata = mapping.dump_json() |
380 | @@ -337,7 +344,7 @@ |
381 | "subarchitecture": image.subarch, |
382 | "release": image.release, |
383 | "label": image.label, |
384 | - } |
385 | + } |
386 | self.assertEqual({}, extract_metadata(metadata, params)) |
387 | |
388 | def _make_path(self): |
389 | |
390 | === modified file 'src/provisioningserver/boot/tftppath.py' |
391 | --- src/provisioningserver/boot/tftppath.py 2015-03-25 15:33:23 +0000 |
392 | +++ src/provisioningserver/boot/tftppath.py 2015-05-04 14:27:25 +0000 |
393 | @@ -7,7 +7,7 @@ |
394 | absolute_import, |
395 | print_function, |
396 | unicode_literals, |
397 | - ) |
398 | +) |
399 | |
400 | str = None |
401 | |
402 | @@ -17,13 +17,16 @@ |
403 | 'list_boot_images', |
404 | 'list_subdirs', |
405 | 'locate_tftp_path', |
406 | - ] |
407 | +] |
408 | |
409 | import errno |
410 | from itertools import chain |
411 | import os.path |
412 | |
413 | -from provisioningserver import config |
414 | +from provisioningserver.cluster_config import ( |
415 | + CLUSTER_CONFIG, |
416 | + get_config_cluster_variable, |
417 | +) |
418 | from provisioningserver.drivers.osystem import ( |
419 | BOOT_IMAGE_PURPOSE, |
420 | OperatingSystemRegistry, |
421 | @@ -137,7 +140,7 @@ |
422 | subarch=params["subarchitecture"], |
423 | release=params["release"], |
424 | label=params["label"], |
425 | - ) |
426 | + ) |
427 | try: |
428 | # On upgrade from 1.5 to 1.6, the subarches does not exist in the |
429 | # maas.meta file . Without this catch boot images will fail to |
430 | @@ -206,10 +209,12 @@ |
431 | or None if the file doesn't exist. |
432 | |
433 | :param tftproot: Optional tftp root dir, defaults to |
434 | - provisioningserver.config.BOOT_RESOURCES_STORAGE |
435 | + 'tftp-root' in the cluster Config backend. Please refer to the |
436 | + 'maas-provision config --tftp-root' command to set this directory |
437 | """ |
438 | if tftproot is None: |
439 | - tftproot = os.path.join(config.BOOT_RESOURCES_STORAGE, 'current') |
440 | + tftproot = get_config_cluster_variable( |
441 | + CLUSTER_CONFIG.DB_tftp_resource_root) |
442 | meta_file = maas_meta_file_path(tftproot) |
443 | try: |
444 | return os.path.getmtime(meta_file) |
445 | |
446 | === modified file 'src/provisioningserver/cluster_config.py' |
447 | --- src/provisioningserver/cluster_config.py 2015-04-02 18:44:12 +0000 |
448 | +++ src/provisioningserver/cluster_config.py 2015-05-04 14:27:25 +0000 |
449 | @@ -13,13 +13,10 @@ |
450 | |
451 | __metaclass__ = type |
452 | __all__ = [ |
453 | - 'get_cluster_uuid', |
454 | - 'get_maas_url', |
455 | - "get_cluster_variable", |
456 | "get_config_cluster_variable", |
457 | - "set_config_cluster_variable", ] |
458 | - |
459 | -from os import environ |
460 | + "get_tftp_generator", |
461 | + "set_config_cluster_variable", |
462 | + "CLUSTER_CONFIG", ] |
463 | |
464 | from provisioningserver.config import ClusterConfiguration |
465 | |
466 | @@ -34,7 +31,7 @@ |
467 | DB_tftpport = 'tftp_port' |
468 | |
469 | |
470 | -# New get function for ClusterConfiguration backend |
471 | +# Get function for ClusterConfiguration backend |
472 | def get_config_cluster_variable(var): |
473 | """Obtain the given environment variable from clusterd config""" |
474 | with ClusterConfiguration.open() as config: |
475 | @@ -52,37 +49,6 @@ |
476 | """Return the `tftp_generator` setting, which is |
477 | <maas url>/api/1.0/pxeconfig/ |
478 | """ |
479 | - return '/'.join(get_cluster_variable(CLUSTER_CONFIG.DB_maas_url), |
480 | - 'api', '1.0', 'pxeconfig') |
481 | - |
482 | - |
483 | -# Old get function for config file (via env variables) backend, |
484 | -# to be removed in follow-up branch. This branch is a prerequisite branch for |
485 | -# a follow-up branch, where this function will be removed. Both |
486 | -# the new and old versions of this function have been included |
487 | -# in this intermediate branch at the request of the package |
488 | -# maintainers. |
489 | -def get_cluster_variable(var): |
490 | - """Obtain the given environment variable from maas_cluster.conf. |
491 | - |
492 | - If the variable is not set, it probably means that whatever script |
493 | - started the current process neglected to run maas_cluster.conf. |
494 | - In that case, fail helpfully but utterly. |
495 | - """ |
496 | - value = environ.get(var) |
497 | - if value is None: |
498 | - raise AssertionError( |
499 | - "%s is not set. This probably means that the script which " |
500 | - "started this program failed to source maas_cluster.conf." |
501 | - % var) |
502 | - return value |
503 | - |
504 | - |
505 | -def get_cluster_uuid(): |
506 | - """Return the `CLUSTER_UUID` setting.""" |
507 | - return get_cluster_variable('CLUSTER_UUID') |
508 | - |
509 | - |
510 | -def get_maas_url(): |
511 | - """Return the `MAAS_URL` setting.""" |
512 | - return get_cluster_variable('MAAS_URL') |
513 | + return '/'.join(( |
514 | + get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url), |
515 | + 'api', '1.0', 'pxeconfig')) |
516 | |
517 | === modified file 'src/provisioningserver/config.py' |
518 | --- src/provisioningserver/config.py 2015-04-04 00:40:18 +0000 |
519 | +++ src/provisioningserver/config.py 2015-05-04 14:27:25 +0000 |
520 | @@ -52,7 +52,6 @@ |
521 | |
522 | __metaclass__ = type |
523 | __all__ = [ |
524 | - "BOOT_RESOURCES_STORAGE", |
525 | "BootSources", |
526 | "Config", |
527 | "ConfigBase", |
528 | @@ -100,11 +99,6 @@ |
529 | ) |
530 | import yaml |
531 | |
532 | -# Path to the directory on the cluster controller where boot resources are |
533 | -# stored. This used to be configurable in bootresources.yaml, and may become |
534 | -# configurable again in the future. |
535 | -BOOT_RESOURCES_STORAGE = '/var/lib/maas/boot-resources/' |
536 | - |
537 | # Default result for cluster UUID if not set |
538 | UUID_NOT_SET = '** UUID NOT SET **' |
539 | |
540 | @@ -205,30 +199,6 @@ |
541 | vhost = String(if_missing="/") |
542 | |
543 | |
544 | -class ConfigTFTP(Schema): |
545 | - """Configuration validator for the TFTP service.""" |
546 | - |
547 | - if_key_missing = None |
548 | - |
549 | - # Obsolete: old TFTP root directory. This is retained for the purpose of |
550 | - # deriving new, Simplestreams-based import configuration from previously |
551 | - # imported boot images. |
552 | - # The last time this is needed is for upgrading an older cluster |
553 | - # controller to the Ubuntu 14.04 version of MAAS. After installation of |
554 | - # the 14.04 version, this setting is never used. |
555 | - root = String(if_missing="/var/lib/maas/tftp") |
556 | - |
557 | - # TFTP root directory, managed by the Simplestreams-based import script. |
558 | - # The import script maintains "current" as a symlink pointing to the most |
559 | - # recent images. |
560 | - # XXX jtv 2014-05-22: Redundant with BOOT_RESOURCES_STORAGE. |
561 | - resource_root = String( |
562 | - if_missing=os.path.join(BOOT_RESOURCES_STORAGE, 'current/')) |
563 | - |
564 | - port = Int(min=1, max=65535, if_missing=69) |
565 | - generator = String(if_missing=b"http://localhost/MAAS/api/1.0/pxeconfig/") |
566 | - |
567 | - |
568 | class ConfigLegacyEphemeral(Schema): |
569 | """Legacy `ephemeral` section in `pserv.yaml` prior to MAAS 1.5. |
570 | |
571 | @@ -415,7 +385,6 @@ |
572 | logfile = String(if_empty=b"pserv.log", if_missing=b"pserv.log") |
573 | oops = ConfigOops |
574 | broker = ConfigBroker |
575 | - tftp = ConfigTFTP |
576 | rpc = ConfigRPC |
577 | boot = ConfigLegacyBoot |
578 | |
579 | |
580 | === modified file 'src/provisioningserver/diskless.py' |
581 | --- src/provisioningserver/diskless.py 2015-03-25 15:33:23 +0000 |
582 | +++ src/provisioningserver/diskless.py 2015-05-04 14:27:25 +0000 |
583 | @@ -7,7 +7,7 @@ |
584 | absolute_import, |
585 | print_function, |
586 | unicode_literals, |
587 | - ) |
588 | +) |
589 | |
590 | str = None |
591 | |
592 | @@ -15,17 +15,21 @@ |
593 | __all__ = [ |
594 | 'create_diskless_disk', |
595 | 'delete_diskless_disk', |
596 | - ] |
597 | +] |
598 | |
599 | import os |
600 | from textwrap import dedent |
601 | |
602 | -from provisioningserver import config |
603 | +from provisioningserver.cluster_config import ( |
604 | + CLUSTER_CONFIG, |
605 | + get_config_cluster_variable, |
606 | +) |
607 | from provisioningserver.drivers.diskless import DisklessDriverRegistry |
608 | from provisioningserver.drivers.osystem import ( |
609 | BOOT_IMAGE_PURPOSE, |
610 | OperatingSystemRegistry, |
611 | ) |
612 | +from provisioningserver.import_images.boot_resources import two_dir_levels_up |
613 | from provisioningserver.logger import get_maas_logger |
614 | from provisioningserver.utils.fs import ( |
615 | atomic_symlink, |
616 | @@ -48,7 +52,8 @@ |
617 | currently in use disk for diskless booting. |
618 | """ |
619 | return os.path.join( |
620 | - config.BOOT_RESOURCES_STORAGE, 'diskless', 'store') |
621 | + two_dir_levels_up(get_config_cluster_variable( |
622 | + CLUSTER_CONFIG.DB_boot_resources_storage)), 'diskless', 'store') |
623 | |
624 | |
625 | def compose_diskless_link_path(system_id): |
626 | @@ -100,7 +105,9 @@ |
627 | def get_diskless_tgt_path(): |
628 | """Return path to maas-diskless.tgt.""" |
629 | return os.path.join( |
630 | - config.BOOT_RESOURCES_STORAGE, 'diskless', 'maas-diskless.tgt') |
631 | + two_dir_levels_up(get_config_cluster_variable( |
632 | + CLUSTER_CONFIG.DB_boot_resources_storage)), |
633 | + 'diskless', 'maas-diskless.tgt') |
634 | |
635 | |
636 | def tgt_entry(system_id, image): |
637 | @@ -145,7 +152,7 @@ |
638 | '/usr/sbin/tgt-admin', |
639 | '--conf', get_diskless_tgt_path(), |
640 | '--update', 'ALL', |
641 | - ]) |
642 | + ]) |
643 | |
644 | |
645 | def update_diskless_tgt(): |
646 | @@ -153,7 +160,7 @@ |
647 | symlinks in the diskless store. Reloads the tgt config.""" |
648 | tgt_path = get_diskless_tgt_path() |
649 | tgt_config = compose_diskless_tgt_config() |
650 | - atomic_write(tgt_config, tgt_path, mode=0644) |
651 | + atomic_write(tgt_config, tgt_path, mode=0o644) |
652 | reload_diskless_tgt() |
653 | |
654 | |
655 | @@ -184,7 +191,8 @@ |
656 | "OS doesn't support diskless booting: %s" % osystem_name) |
657 | root_path, _ = osystem.get_xinstall_parameters() |
658 | return os.path.join( |
659 | - config.BOOT_RESOURCES_STORAGE, 'current', |
660 | + get_config_cluster_variable( |
661 | + CLUSTER_CONFIG.DB_boot_resources_storage), |
662 | osystem_name, arch, subarch, release, label, root_path) |
663 | |
664 | |
665 | |
666 | === modified file 'src/provisioningserver/drivers/osystem/custom.py' |
667 | --- src/provisioningserver/drivers/osystem/custom.py 2015-03-25 15:33:23 +0000 |
668 | +++ src/provisioningserver/drivers/osystem/custom.py 2015-05-04 14:27:25 +0000 |
669 | @@ -7,18 +7,21 @@ |
670 | absolute_import, |
671 | print_function, |
672 | unicode_literals, |
673 | - ) |
674 | +) |
675 | |
676 | str = None |
677 | |
678 | __metaclass__ = type |
679 | __all__ = [ |
680 | "CustomOS", |
681 | - ] |
682 | +] |
683 | |
684 | import os |
685 | |
686 | -from provisioningserver.config import BOOT_RESOURCES_STORAGE |
687 | +from provisioningserver.cluster_config import ( |
688 | + CLUSTER_CONFIG, |
689 | + get_config_cluster_variable, |
690 | +) |
691 | from provisioningserver.drivers.osystem import ( |
692 | BOOT_IMAGE_PURPOSE, |
693 | OperatingSystem, |
694 | @@ -55,8 +58,8 @@ |
695 | |
696 | def get_xinstall_parameters(self, arch, subarch, release, label): |
697 | """Returns the xinstall image name and type for given image.""" |
698 | - path = os.path.join( |
699 | - BOOT_RESOURCES_STORAGE, 'current', 'custom', |
700 | + path = os.path.join(get_config_cluster_variable( |
701 | + CLUSTER_CONFIG.DB_boot_resources_storage), 'custom', |
702 | arch, subarch, release, label) |
703 | if os.path.exists(os.path.join(path, 'root-dd')): |
704 | return "root-dd", "dd-tgz" |
705 | |
706 | === modified file 'src/provisioningserver/drivers/osystem/tests/test_custom.py' |
707 | --- src/provisioningserver/drivers/osystem/tests/test_custom.py 2015-03-25 15:33:23 +0000 |
708 | +++ src/provisioningserver/drivers/osystem/tests/test_custom.py 2015-05-04 14:27:25 +0000 |
709 | @@ -7,7 +7,7 @@ |
710 | absolute_import, |
711 | print_function, |
712 | unicode_literals, |
713 | - ) |
714 | +) |
715 | |
716 | str = None |
717 | |
718 | @@ -19,26 +19,34 @@ |
719 | |
720 | from maastesting.factory import factory |
721 | from maastesting.testcase import MAASTestCase |
722 | -from provisioningserver.drivers.osystem import custom |
723 | +from provisioningserver.cluster_config import ( |
724 | + CLUSTER_CONFIG, |
725 | + set_config_cluster_variable, |
726 | +) |
727 | from provisioningserver.drivers.osystem.custom import ( |
728 | BOOT_IMAGE_PURPOSE, |
729 | CustomOS, |
730 | ) |
731 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
732 | |
733 | |
734 | class TestCustomOS(MAASTestCase): |
735 | |
736 | def make_resource_path(self, filename): |
737 | + self.useFixture(ClusterConfigurationFixture()) |
738 | tmpdir = self.make_dir() |
739 | arch = factory.make_name('arch') |
740 | subarch = factory.make_name('subarch') |
741 | release = factory.make_name('release') |
742 | label = factory.make_name('label') |
743 | + current_dir = os.path.join(tmpdir, 'current') + '/' |
744 | dirpath = os.path.join( |
745 | - tmpdir, 'current', 'custom', arch, subarch, release, label) |
746 | + current_dir, 'custom', arch, subarch, release, label) |
747 | os.makedirs(dirpath) |
748 | factory.make_file(dirpath, filename) |
749 | - self.patch(custom, 'BOOT_RESOURCES_STORAGE', tmpdir) |
750 | + set_config_cluster_variable( |
751 | + CLUSTER_CONFIG.DB_boot_resources_storage, |
752 | + current_dir) |
753 | return arch, subarch, release, label |
754 | |
755 | def test_get_boot_image_purposes(self): |
756 | @@ -54,7 +62,7 @@ |
757 | self.assertIsInstance(expected, list) |
758 | self.assertEqual(expected, [ |
759 | BOOT_IMAGE_PURPOSE.XINSTALL, |
760 | - ]) |
761 | + ]) |
762 | |
763 | def test_is_release_supported(self): |
764 | osystem = CustomOS() |
765 | @@ -62,7 +70,7 @@ |
766 | supported = [ |
767 | osystem.is_release_supported(release) |
768 | for release in releases |
769 | - ] |
770 | + ] |
771 | self.assertEqual([True, True, True], supported) |
772 | |
773 | def test_get_default_release(self): |
774 | |
775 | === modified file 'src/provisioningserver/import_images/boot_resources.py' |
776 | --- src/provisioningserver/import_images/boot_resources.py 2015-03-25 15:33:23 +0000 |
777 | +++ src/provisioningserver/import_images/boot_resources.py 2015-05-04 14:27:25 +0000 |
778 | @@ -5,7 +5,7 @@ |
779 | absolute_import, |
780 | print_function, |
781 | unicode_literals, |
782 | - ) |
783 | +) |
784 | |
785 | str = None |
786 | |
787 | @@ -15,16 +15,19 @@ |
788 | 'main', |
789 | 'main_with_services', |
790 | 'make_arg_parser', |
791 | - ] |
792 | +] |
793 | |
794 | from argparse import ArgumentParser |
795 | import errno |
796 | import os |
797 | from textwrap import dedent |
798 | |
799 | -import provisioningserver |
800 | from provisioningserver.boot import BootMethodRegistry |
801 | from provisioningserver.boot.tftppath import list_boot_images |
802 | +from provisioningserver.cluster_config import ( |
803 | + CLUSTER_CONFIG, |
804 | + get_config_cluster_variable, |
805 | +) |
806 | from provisioningserver.config import BootSources |
807 | from provisioningserver.import_images.cleanup import ( |
808 | cleanup_snapshots_and_cache, |
809 | @@ -48,6 +51,16 @@ |
810 | from provisioningserver.utils.shell import call_and_check |
811 | |
812 | |
813 | +def two_dir_levels_up(path): |
814 | + # NOTE: Syntax along the lines of: |
815 | + # os.path.normpath(os.path.join( |
816 | + # path, os.path.pardir, os.path.pardir)) |
817 | + # will NOT work here, as the classes that use these file paths |
818 | + # to NOT support paths with 'os.path.pardir' segments. Thus |
819 | + # we must manually resolve the path here. |
820 | + return os.path.split(os.path.split(path)[0])[0] |
821 | + |
822 | + |
823 | class NoConfigFile(Exception): |
824 | """Raised when the config file for the script doesn't exist.""" |
825 | |
826 | @@ -81,7 +94,7 @@ |
827 | subarch, |
828 | release, |
829 | label |
830 | - ) |
831 | + ) |
832 | entry = dedent("""\ |
833 | <target {prefix}:{target_name}> |
834 | readonly 1 |
835 | @@ -191,7 +204,7 @@ |
836 | '/usr/sbin/tgt-admin', |
837 | '--conf', targets_conf, |
838 | '--update', 'ALL', |
839 | - ]) |
840 | + ]) |
841 | |
842 | |
843 | def read_sources(sources_yaml): |
844 | @@ -245,7 +258,8 @@ |
845 | "any boot images available.") |
846 | return |
847 | |
848 | - storage = provisioningserver.config.BOOT_RESOURCES_STORAGE |
849 | + storage = two_dir_levels_up(get_config_cluster_variable( |
850 | + CLUSTER_CONFIG.DB_boot_resources_storage)) |
851 | meta_file_content = image_descriptions.dump_json() |
852 | if meta_contains(storage, meta_file_content): |
853 | maaslog.info( |
854 | |
855 | === modified file 'src/provisioningserver/import_images/tests/test_boot_resources.py' |
856 | --- src/provisioningserver/import_images/tests/test_boot_resources.py 2015-03-25 15:33:23 +0000 |
857 | +++ src/provisioningserver/import_images/tests/test_boot_resources.py 2015-05-04 14:27:25 +0000 |
858 | @@ -7,7 +7,7 @@ |
859 | absolute_import, |
860 | print_function, |
861 | unicode_literals, |
862 | - ) |
863 | +) |
864 | |
865 | str = None |
866 | |
867 | @@ -39,14 +39,20 @@ |
868 | import mock |
869 | from mock import call |
870 | from provisioningserver.boot import BootMethodRegistry |
871 | -import provisioningserver.config |
872 | +from provisioningserver.cluster_config import ( |
873 | + CLUSTER_CONFIG, |
874 | + set_config_cluster_variable, |
875 | +) |
876 | from provisioningserver.config import BootSources |
877 | from provisioningserver.import_images import boot_resources |
878 | from provisioningserver.import_images.boot_image_mapping import ( |
879 | BootImageMapping, |
880 | ) |
881 | from provisioningserver.import_images.testing.factory import make_image_spec |
882 | -from provisioningserver.testing.config import BootSourcesFixture |
883 | +from provisioningserver.testing.config import ( |
884 | + BootSourcesFixture, |
885 | + ClusterConfigurationFixture, |
886 | +) |
887 | from provisioningserver.utils.fs import write_text_file |
888 | from testtools.content import Content |
889 | from testtools.content_type import UTF8_TEXT |
890 | @@ -195,9 +201,13 @@ |
891 | |
892 | def setUp(self): |
893 | super(TestMain, self).setUp() |
894 | + self.useFixture(ClusterConfigurationFixture()) |
895 | self.storage = self.make_dir() |
896 | - self.patch( |
897 | - provisioningserver.config, 'BOOT_RESOURCES_STORAGE', self.storage) |
898 | + current_dir = os.path.join(self.storage, 'current') + os.sep |
899 | + os.makedirs(current_dir) |
900 | + set_config_cluster_variable(CLUSTER_CONFIG.DB_boot_resources_storage, |
901 | + current_dir) |
902 | + os.rmdir(current_dir) |
903 | # Forcing arch to amd64 causes pxelinux.0 to be installed, giving more |
904 | # test coverage. |
905 | self.image = make_image_spec(arch='amd64') |
906 | @@ -232,9 +242,9 @@ |
907 | 'updated': 'Tue, 25 Mar 2014 16:19:49 +0000', |
908 | 'format': 'products:1.0', |
909 | 'products': [product], |
910 | - }, |
911 | }, |
912 | - } |
913 | + }, |
914 | + } |
915 | write_text_file(index_file, json.dumps(index)) |
916 | return index_file |
917 | |
918 | @@ -251,7 +261,7 @@ |
919 | image_spec.release, |
920 | image_spec.subarch, |
921 | filename, |
922 | - ] |
923 | + ] |
924 | native_path = os.path.join(repo, *path) |
925 | os.makedirs(os.path.dirname(native_path)) |
926 | contents = ("Contents: %s" % filename).encode('utf-8') |
927 | @@ -318,7 +328,7 @@ |
928 | os_release = '%d.%.2s' % ( |
929 | randint(1, 99), |
930 | ('04' if randint(0, 1) == 0 else '10'), |
931 | - ) |
932 | + ) |
933 | repo = self.make_dir() |
934 | index_dir = os.path.join(repo, 'streams', 'v1') |
935 | os.makedirs(index_dir) |
936 | @@ -327,7 +337,7 @@ |
937 | os_release, |
938 | image_spec.arch, |
939 | image_spec.subarch, |
940 | - ) |
941 | + ) |
942 | version = '20140317' |
943 | download_file, sha = self.make_download_file(repo, image_spec, version) |
944 | self.make_simplestreams_product_index( |
945 | @@ -350,9 +360,9 @@ |
946 | 'subarches': [self.subarch], |
947 | 'labels': [self.label], |
948 | }, |
949 | - ], |
950 | + ], |
951 | }, |
952 | - ] |
953 | + ] |
954 | sources_file = self.make_file( |
955 | 'sources.yaml', contents=yaml.safe_dump(sources)) |
956 | return self.make_args(sources_file=sources_file) |
957 | @@ -541,9 +551,9 @@ |
958 | 'subarches': [factory.make_name("subarch")], |
959 | 'labels': [factory.make_name("label")], |
960 | }, |
961 | - ], |
962 | + ], |
963 | }, |
964 | - ] |
965 | + ] |
966 | parsed_sources = boot_resources.parse_sources(yaml.safe_dump(sources)) |
967 | self.assertEqual(sources, parsed_sources) |
968 | |
969 | @@ -577,9 +587,9 @@ |
970 | 'subarches': [factory.make_name("subarch")], |
971 | 'labels': [factory.make_name("label")], |
972 | }, |
973 | - ], |
974 | + ], |
975 | }, |
976 | - ], |
977 | + ], |
978 | boot_resources.import_images(sources) |
979 | self.assertThat( |
980 | fake_write_all_keyrings, MockCalledWith(mock.ANY, sources)) |
981 | |
982 | === modified file 'src/provisioningserver/plugin.py' |
983 | --- src/provisioningserver/plugin.py 2015-04-29 06:19:04 +0000 |
984 | +++ src/provisioningserver/plugin.py 2015-05-04 14:27:25 +0000 |
985 | @@ -7,7 +7,7 @@ |
986 | absolute_import, |
987 | print_function, |
988 | unicode_literals, |
989 | - ) |
990 | +) |
991 | |
992 | str = None |
993 | |
994 | @@ -17,10 +17,14 @@ |
995 | ] |
996 | |
997 | from errno import ENOPROTOOPT |
998 | -import os |
999 | import socket |
1000 | from socket import error as socket_error |
1001 | |
1002 | +from provisioningserver.cluster_config import ( |
1003 | + CLUSTER_CONFIG, |
1004 | + get_config_cluster_variable, |
1005 | + get_tftp_generator, |
1006 | +) |
1007 | from provisioningserver.utils.debug import ( |
1008 | register_sigusr2_thread_dump_handler, |
1009 | ) |
1010 | @@ -93,7 +97,7 @@ |
1011 | """Command line options for the provisioning server.""" |
1012 | |
1013 | optParameters = [ |
1014 | - ["config-file", "c", "pserv.yaml", "Configuration file to load."], |
1015 | + ["config-file", "c", "clusterd.conf", "Configuration file to load."], |
1016 | ["introspect", None, None, |
1017 | ("Allow introspection, allowing unhindered access to the internals " |
1018 | "of MAAS. This should probably only be used for debugging. Supply " |
1019 | @@ -128,8 +132,6 @@ |
1020 | from provisioningserver.pserv_services.image import ( |
1021 | BootImageEndpointService) |
1022 | from twisted.internet.endpoints import AdoptedStreamServerEndpoint |
1023 | - from provisioningserver import config |
1024 | - |
1025 | port = 5248 # config["port"] |
1026 | # Make a socket with SO_REUSEPORT set so that we can run multiple we |
1027 | # applications. This is easier to do from outside of Twisted as there's |
1028 | @@ -157,59 +159,58 @@ |
1029 | site_endpoint.socket = s # Prevent garbage collection. |
1030 | |
1031 | image_service = BootImageEndpointService( |
1032 | - resource_root=os.path.join( |
1033 | - config.BOOT_RESOURCES_STORAGE, "current"), |
1034 | + resource_root=get_config_cluster_variable( |
1035 | + CLUSTER_CONFIG.DB_boot_resources_storage), |
1036 | endpoint=site_endpoint) |
1037 | image_service.setName("image_service") |
1038 | return image_service |
1039 | |
1040 | - def _makeTFTPService(self, tftp_config): |
1041 | + def _makeTFTPService(self, tftp_root, tftp_port, tftp_generator): |
1042 | """Create the dynamic TFTP service.""" |
1043 | from provisioningserver.pserv_services.tftp import TFTPService |
1044 | tftp_service = TFTPService( |
1045 | - resource_root=tftp_config['resource_root'], |
1046 | - port=tftp_config['port'], generator=tftp_config['generator']) |
1047 | + resource_root=tftp_root, port=tftp_port, generator=tftp_generator) |
1048 | tftp_service.setName("tftp") |
1049 | return tftp_service |
1050 | |
1051 | def _makeImageDownloadService(self, rpc_service): |
1052 | - from provisioningserver.cluster_config import get_cluster_uuid |
1053 | from provisioningserver.pserv_services.image_download_service \ |
1054 | import ImageDownloadService |
1055 | image_download_service = ImageDownloadService( |
1056 | - rpc_service, reactor, get_cluster_uuid()) |
1057 | + rpc_service, reactor, get_config_cluster_variable( |
1058 | + CLUSTER_CONFIG.DB_cluster_uuid)) |
1059 | image_download_service.setName("image_download") |
1060 | return image_download_service |
1061 | |
1062 | def _makeLeaseUploadService(self, rpc_service): |
1063 | - from provisioningserver.cluster_config import get_cluster_uuid |
1064 | from provisioningserver.pserv_services.lease_upload_service \ |
1065 | import LeaseUploadService |
1066 | lease_upload_service = LeaseUploadService( |
1067 | - rpc_service, reactor, get_cluster_uuid()) |
1068 | + rpc_service, reactor, get_config_cluster_variable( |
1069 | + CLUSTER_CONFIG.DB_cluster_uuid)) |
1070 | lease_upload_service.setName("lease_upload") |
1071 | return lease_upload_service |
1072 | |
1073 | def _makeNodePowerMonitorService(self): |
1074 | - from provisioningserver.cluster_config import get_cluster_uuid |
1075 | from provisioningserver.pserv_services.node_power_monitor_service \ |
1076 | import NodePowerMonitorService |
1077 | - node_monitor = NodePowerMonitorService(get_cluster_uuid(), reactor) |
1078 | + node_monitor = NodePowerMonitorService(get_config_cluster_variable( |
1079 | + CLUSTER_CONFIG.DB_cluster_uuid), reactor) |
1080 | node_monitor.setName("node_monitor") |
1081 | return node_monitor |
1082 | |
1083 | - def _makeRPCService(self, rpc_config): |
1084 | + def _makeRPCService(self): |
1085 | from provisioningserver.rpc.clusterservice import ClusterClientService |
1086 | rpc_service = ClusterClientService(reactor) |
1087 | rpc_service.setName("rpc") |
1088 | return rpc_service |
1089 | |
1090 | def _makeDHCPProbeService(self, rpc_service): |
1091 | - from provisioningserver.cluster_config import get_cluster_uuid |
1092 | from provisioningserver.pserv_services.dhcp_probe_service \ |
1093 | import DHCPProbeService |
1094 | dhcp_probe_service = DHCPProbeService( |
1095 | - rpc_service, reactor, get_cluster_uuid()) |
1096 | + rpc_service, reactor, |
1097 | + get_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid)) |
1098 | dhcp_probe_service.setName("dhcp_probe") |
1099 | return dhcp_probe_service |
1100 | |
1101 | @@ -226,17 +227,18 @@ |
1102 | register_sigusr2_thread_dump_handler() |
1103 | |
1104 | from provisioningserver import services |
1105 | - from provisioningserver.config import Config |
1106 | - |
1107 | - config = Config.load(options["config-file"]) |
1108 | |
1109 | image_service = self._makeImageService() |
1110 | image_service.setServiceParent(services) |
1111 | |
1112 | - tftp_service = self._makeTFTPService(config["tftp"]) |
1113 | + tftp_service = self._makeTFTPService( |
1114 | + get_config_cluster_variable(CLUSTER_CONFIG.DB_tftp_resource_root), |
1115 | + get_config_cluster_variable(CLUSTER_CONFIG.DB_tftpport), |
1116 | + get_tftp_generator()) |
1117 | + |
1118 | tftp_service.setServiceParent(services) |
1119 | |
1120 | - rpc_service = self._makeRPCService(config["rpc"]) |
1121 | + rpc_service = self._makeRPCService() |
1122 | rpc_service.setServiceParent(services) |
1123 | |
1124 | node_monitor = self._makeNodePowerMonitorService() |
1125 | |
1126 | === modified file 'src/provisioningserver/pserv_services/tests/test_tftp.py' |
1127 | --- src/provisioningserver/pserv_services/tests/test_tftp.py 2015-04-24 20:41:48 +0000 |
1128 | +++ src/provisioningserver/pserv_services/tests/test_tftp.py 2015-05-04 14:27:25 +0000 |
1129 | @@ -30,7 +30,6 @@ |
1130 | urlparse, |
1131 | ) |
1132 | |
1133 | -from fixtures import EnvironmentVariable |
1134 | from maastesting.factory import factory |
1135 | from maastesting.matchers import ( |
1136 | MockCalledOnceWith, |
1137 | @@ -50,6 +49,7 @@ |
1138 | IPV4_LINK_LOCAL, |
1139 | IPV6_LINK_LOCAL, |
1140 | ) |
1141 | +from provisioningserver import cluster_config |
1142 | from provisioningserver.boot import BytesReader |
1143 | from provisioningserver.boot.pxe import PXEBootMethod |
1144 | from provisioningserver.boot.tests.test_pxe import compose_config_path |
1145 | @@ -63,6 +63,7 @@ |
1146 | UDPServer, |
1147 | ) |
1148 | from provisioningserver.rpc.testing import TwistedLoggerFixture |
1149 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
1150 | from provisioningserver.tests.test_kernel_opts import make_kernel_parameters |
1151 | from testtools import ExpectedException |
1152 | from testtools.matchers import ( |
1153 | @@ -127,6 +128,7 @@ |
1154 | |
1155 | def setUp(self): |
1156 | super(TestTFTPBackend, self).setUp() |
1157 | + self.useFixture(ClusterConfigurationFixture()) |
1158 | from provisioningserver import boot |
1159 | self.patch(boot, "find_mac_via_arp") |
1160 | self.patch(tftp_module, 'log_request') |
1161 | @@ -219,7 +221,8 @@ |
1162 | |
1163 | @inlineCallbacks |
1164 | def test_get_reader_converts_404s_to_tftp_error(self): |
1165 | - self.useFixture(EnvironmentVariable("CLUSTER_UUID", "foobar")) |
1166 | + cluster_config.set_config_cluster_variable( |
1167 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, factory.make_UUID()) |
1168 | |
1169 | backend = TFTPBackend(self.make_dir(), "http://example.com/") |
1170 | get_page = self.patch(backend, 'get_page') |
1171 | @@ -230,7 +233,8 @@ |
1172 | |
1173 | @inlineCallbacks |
1174 | def test_get_reader_converts_other_exceptions_to_tftp_error(self): |
1175 | - self.useFixture(EnvironmentVariable("CLUSTER_UUID", "foobar")) |
1176 | + cluster_config.set_config_cluster_variable( |
1177 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, factory.make_UUID()) |
1178 | |
1179 | exception_type = factory.make_exception_type() |
1180 | exception_message = factory.make_string() |
1181 | @@ -257,8 +261,8 @@ |
1182 | # For paths matching PXEBootMethod.match_path, TFTPBackend.get_reader() |
1183 | # returns a Deferred that will yield a BytesReader. |
1184 | cluster_uuid = factory.make_UUID() |
1185 | - get_cluster_uuid = self.patch(tftp_module, 'get_cluster_uuid') |
1186 | - get_cluster_uuid.return_value = cluster_uuid |
1187 | + cluster_config.set_config_cluster_variable( |
1188 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, cluster_uuid) |
1189 | mac = factory.make_mac_address("-") |
1190 | config_path = compose_config_path(mac) |
1191 | backend = TFTPBackend(self.make_dir(), b"http://example.com/") |
1192 | @@ -356,8 +360,8 @@ |
1193 | # arch field of the parameters (mapping from pxe to maas |
1194 | # namespace). |
1195 | cluster_uuid = factory.make_UUID() |
1196 | - get_cluster_uuid = self.patch(tftp_module, 'get_cluster_uuid') |
1197 | - get_cluster_uuid.return_value = cluster_uuid |
1198 | + cluster_config.set_config_cluster_variable( |
1199 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, cluster_uuid) |
1200 | config_path = "pxelinux.cfg/default-arm" |
1201 | backend = TFTPBackend(self.make_dir(), b"http://example.com/") |
1202 | # python-tx-tftp sets up call context so that backends can discover |
1203 | |
1204 | === modified file 'src/provisioningserver/pserv_services/tftp.py' |
1205 | --- src/provisioningserver/pserv_services/tftp.py 2015-04-24 20:39:18 +0000 |
1206 | +++ src/provisioningserver/pserv_services/tftp.py 2015-05-04 14:27:25 +0000 |
1207 | @@ -7,7 +7,7 @@ |
1208 | absolute_import, |
1209 | print_function, |
1210 | unicode_literals, |
1211 | - ) |
1212 | +) |
1213 | |
1214 | str = None |
1215 | |
1216 | @@ -15,7 +15,7 @@ |
1217 | __all__ = [ |
1218 | "TFTPBackend", |
1219 | "TFTPService", |
1220 | - ] |
1221 | +] |
1222 | |
1223 | from functools import partial |
1224 | import httplib |
1225 | @@ -35,7 +35,10 @@ |
1226 | BootMethodRegistry, |
1227 | get_remote_mac, |
1228 | ) |
1229 | -from provisioningserver.cluster_config import get_cluster_uuid |
1230 | +from provisioningserver.cluster_config import ( |
1231 | + CLUSTER_CONFIG, |
1232 | + get_config_cluster_variable, |
1233 | +) |
1234 | from provisioningserver.drivers import ArchitectureRegistry |
1235 | from provisioningserver.events import ( |
1236 | EVENT_TYPES, |
1237 | @@ -223,7 +226,8 @@ |
1238 | params["local"] = local_host |
1239 | remote_host, remote_port = tftp.get_remote_address() |
1240 | params["remote"] = remote_host |
1241 | - params["cluster_uuid"] = get_cluster_uuid() |
1242 | + params["cluster_uuid"] = get_config_cluster_variable( |
1243 | + CLUSTER_CONFIG.DB_cluster_uuid) |
1244 | d = self.get_boot_method_reader(boot_method, params) |
1245 | return d |
1246 | |
1247 | |
1248 | === modified file 'src/provisioningserver/rpc/boot_images.py' |
1249 | --- src/provisioningserver/rpc/boot_images.py 2015-02-24 13:52:12 +0000 |
1250 | +++ src/provisioningserver/rpc/boot_images.py 2015-05-04 14:27:25 +0000 |
1251 | @@ -7,7 +7,7 @@ |
1252 | absolute_import, |
1253 | print_function, |
1254 | unicode_literals, |
1255 | - ) |
1256 | +) |
1257 | |
1258 | str = None |
1259 | |
1260 | @@ -16,15 +16,17 @@ |
1261 | "import_boot_images", |
1262 | "list_boot_images", |
1263 | "is_import_boot_images_running", |
1264 | - ] |
1265 | +] |
1266 | |
1267 | -import os |
1268 | from urlparse import urlparse |
1269 | |
1270 | from provisioningserver import concurrency |
1271 | from provisioningserver.auth import get_maas_user_gpghome |
1272 | from provisioningserver.boot import tftppath |
1273 | -from provisioningserver.config import BOOT_RESOURCES_STORAGE |
1274 | +from provisioningserver.cluster_config import ( |
1275 | + CLUSTER_CONFIG, |
1276 | + get_config_cluster_variable, |
1277 | +) |
1278 | from provisioningserver.import_images import boot_resources |
1279 | from provisioningserver.utils.env import environment_variables |
1280 | from provisioningserver.utils.twisted import synchronous |
1281 | @@ -41,10 +43,12 @@ |
1282 | of IO, as this function is called often. To update the cache call |
1283 | `reload_boot_images`. |
1284 | """ |
1285 | + |
1286 | global CACHED_BOOT_IMAGES |
1287 | if CACHED_BOOT_IMAGES is None: |
1288 | CACHED_BOOT_IMAGES = tftppath.list_boot_images( |
1289 | - os.path.join(BOOT_RESOURCES_STORAGE, 'current')) |
1290 | + get_config_cluster_variable( |
1291 | + CLUSTER_CONFIG.DB_boot_resources_storage)) |
1292 | return CACHED_BOOT_IMAGES |
1293 | |
1294 | |
1295 | @@ -53,7 +57,7 @@ |
1296 | most up-to-date boot images list.""" |
1297 | global CACHED_BOOT_IMAGES |
1298 | CACHED_BOOT_IMAGES = tftppath.list_boot_images( |
1299 | - os.path.join(BOOT_RESOURCES_STORAGE, 'current')) |
1300 | + get_config_cluster_variable(CLUSTER_CONFIG.DB_boot_resources_storage)) |
1301 | |
1302 | |
1303 | def get_hosts_from_sources(sources): |
1304 | @@ -74,7 +78,7 @@ |
1305 | """ |
1306 | variables = { |
1307 | 'GNUPGHOME': get_maas_user_gpghome(), |
1308 | - } |
1309 | + } |
1310 | if http_proxy is not None: |
1311 | variables['http_proxy'] = http_proxy |
1312 | if https_proxy is not None: |
1313 | |
1314 | === modified file 'src/provisioningserver/rpc/clusterservice.py' |
1315 | --- src/provisioningserver/rpc/clusterservice.py 2015-04-22 16:51:55 +0000 |
1316 | +++ src/provisioningserver/rpc/clusterservice.py 2015-05-04 14:27:25 +0000 |
1317 | @@ -7,7 +7,7 @@ |
1318 | absolute_import, |
1319 | print_function, |
1320 | unicode_literals, |
1321 | - ) |
1322 | +) |
1323 | |
1324 | str = None |
1325 | |
1326 | @@ -27,8 +27,8 @@ |
1327 | from apiclient.utils import ascii_url |
1328 | from provisioningserver import concurrency |
1329 | from provisioningserver.cluster_config import ( |
1330 | - get_cluster_uuid, |
1331 | - get_maas_url, |
1332 | + CLUSTER_CONFIG, |
1333 | + get_config_cluster_variable, |
1334 | ) |
1335 | from provisioningserver.drivers import ( |
1336 | ArchitectureRegistry, |
1337 | @@ -137,7 +137,8 @@ |
1338 | Implementation of |
1339 | :py:class:`~provisioningserver.rpc.cluster.Identify`. |
1340 | """ |
1341 | - return {b"ident": get_cluster_uuid().decode("ascii")} |
1342 | + return {b"ident": get_config_cluster_variable( |
1343 | + CLUSTER_CONFIG.DB_cluster_uuid).decode("ascii")} |
1344 | |
1345 | @cluster.Authenticate.responder |
1346 | def authenticate(self, message): |
1347 | @@ -194,8 +195,8 @@ |
1348 | 'architectures': [ |
1349 | {'name': arch.name, 'description': arch.description} |
1350 | for _, arch in ArchitectureRegistry |
1351 | - ], |
1352 | - } |
1353 | + ], |
1354 | + } |
1355 | |
1356 | @cluster.ListOperatingSystems.responder |
1357 | def list_operating_systems(self): |
1358 | @@ -258,7 +259,7 @@ |
1359 | osystem, interfaces, auto_interfaces, ips_mapping=ips_mapping, |
1360 | gateways_mapping=gateways_mapping, disable_ipv4=disable_ipv4, |
1361 | nameservers=nameservers, netmasks=netmasks), |
1362 | - } |
1363 | + } |
1364 | |
1365 | @cluster.PowerOn.responder |
1366 | def power_on(self, system_id, hostname, power_type, context): |
1367 | @@ -523,9 +524,9 @@ |
1368 | returnValue(digest == digest_local) |
1369 | |
1370 | def registerWithRegion(self): |
1371 | - uuid = get_cluster_uuid() |
1372 | + uuid = get_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid) |
1373 | networks = discover_networks() |
1374 | - url = get_maas_url() |
1375 | + url = get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url) |
1376 | |
1377 | def cb_register(_): |
1378 | log.msg( |
1379 | @@ -660,7 +661,7 @@ |
1380 | scheme_ports = { |
1381 | 'https': 443, |
1382 | 'http': 80, |
1383 | - } |
1384 | + } |
1385 | defaultPort = scheme_ports.get(scheme, 80) |
1386 | |
1387 | if '[' in netloc: |
1388 | @@ -775,7 +776,7 @@ |
1389 | @staticmethod |
1390 | def _get_rpc_info_url(): |
1391 | """Return the URL to the RPC infomation page on the region.""" |
1392 | - url = urlparse(get_maas_url()) |
1393 | + url = urlparse(get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url)) |
1394 | url = url._replace(path="%s/rpc/" % url.path.rstrip("/")) |
1395 | url = url.geturl() |
1396 | return ascii_url(url) |
1397 | |
1398 | === modified file 'src/provisioningserver/rpc/tags.py' |
1399 | --- src/provisioningserver/rpc/tags.py 2015-03-25 15:33:23 +0000 |
1400 | +++ src/provisioningserver/rpc/tags.py 2015-05-04 14:27:25 +0000 |
1401 | @@ -7,7 +7,7 @@ |
1402 | absolute_import, |
1403 | print_function, |
1404 | unicode_literals, |
1405 | - ) |
1406 | +) |
1407 | |
1408 | str = None |
1409 | |
1410 | @@ -22,13 +22,26 @@ |
1411 | MAASOAuth, |
1412 | ) |
1413 | from provisioningserver.cluster_config import ( |
1414 | - get_cluster_uuid, |
1415 | - get_maas_url, |
1416 | + CLUSTER_CONFIG, |
1417 | + get_config_cluster_variable, |
1418 | + set_config_cluster_variable, |
1419 | ) |
1420 | from provisioningserver.tags import process_node_tags |
1421 | from provisioningserver.utils.twisted import synchronous |
1422 | |
1423 | |
1424 | +def get_maas_url(): |
1425 | + return get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url) |
1426 | + |
1427 | + |
1428 | +def get_cluster_uuid(): |
1429 | + return get_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid) |
1430 | + |
1431 | + |
1432 | +def set_maas_url(value): |
1433 | + return set_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url, value) |
1434 | + |
1435 | + |
1436 | @synchronous |
1437 | def evaluate_tag(tag_name, tag_definition, tag_nsmap, credentials): |
1438 | """Evaluate `tag_definition` against this cluster's nodes' details. |
1439 | @@ -40,7 +53,9 @@ |
1440 | """ |
1441 | client = MAASClient( |
1442 | auth=MAASOAuth(*credentials), dispatcher=MAASDispatcher(), |
1443 | - base_url=get_maas_url()) |
1444 | + base_url=get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url)) |
1445 | process_node_tags( |
1446 | tag_name=tag_name, tag_definition=tag_definition, tag_nsmap=tag_nsmap, |
1447 | - client=client, nodegroup_uuid=get_cluster_uuid()) |
1448 | + client=client, |
1449 | + nodegroup_uuid=get_config_cluster_variable( |
1450 | + CLUSTER_CONFIG.DB_cluster_uuid)) |
1451 | |
1452 | === modified file 'src/provisioningserver/rpc/tests/test_boot_images.py' |
1453 | --- src/provisioningserver/rpc/tests/test_boot_images.py 2015-03-25 15:33:23 +0000 |
1454 | +++ src/provisioningserver/rpc/tests/test_boot_images.py 2015-05-04 14:27:25 +0000 |
1455 | @@ -7,7 +7,7 @@ |
1456 | absolute_import, |
1457 | print_function, |
1458 | unicode_literals, |
1459 | - ) |
1460 | +) |
1461 | |
1462 | str = None |
1463 | |
1464 | @@ -29,7 +29,10 @@ |
1465 | ) |
1466 | from provisioningserver import concurrency |
1467 | from provisioningserver.boot import tftppath |
1468 | -from provisioningserver.config import BOOT_RESOURCES_STORAGE |
1469 | +from provisioningserver.cluster_config import ( |
1470 | + CLUSTER_CONFIG, |
1471 | + get_config_cluster_variable, |
1472 | +) |
1473 | from provisioningserver.import_images import boot_resources |
1474 | from provisioningserver.rpc import boot_images |
1475 | from provisioningserver.rpc.boot_images import ( |
1476 | @@ -40,7 +43,10 @@ |
1477 | list_boot_images, |
1478 | reload_boot_images, |
1479 | ) |
1480 | -from provisioningserver.testing.config import BootSourcesFixture |
1481 | +from provisioningserver.testing.config import ( |
1482 | + BootSourcesFixture, |
1483 | + ClusterConfigurationFixture, |
1484 | +) |
1485 | from provisioningserver.testing.testcase import PservTestCase |
1486 | from provisioningserver.utils.twisted import pause |
1487 | from testtools.matchers import Equals |
1488 | @@ -54,16 +60,20 @@ |
1489 | 'http://%s:%s/images-stream/streams/v1/index.json' % ( |
1490 | host, randint(1, 1000)) |
1491 | for host in hosts |
1492 | - ] |
1493 | + ] |
1494 | sources = [ |
1495 | {'url': url, 'selections': []} |
1496 | for url in urls |
1497 | - ] |
1498 | + ] |
1499 | return sources, hosts |
1500 | |
1501 | |
1502 | class TestListBootImages(PservTestCase): |
1503 | |
1504 | + def setUp(self): |
1505 | + super(TestListBootImages, self).setUp() |
1506 | + self.useFixture(ClusterConfigurationFixture()) |
1507 | + |
1508 | def test__calls_list_boot_images_with_boot_resource_storage(self): |
1509 | self.patch(boot_images, 'CACHED_BOOT_IMAGES', None) |
1510 | mock_list_boot_images = self.patch(tftppath, 'list_boot_images') |
1511 | @@ -71,7 +81,8 @@ |
1512 | self.assertThat( |
1513 | mock_list_boot_images, |
1514 | MockCalledOnceWith( |
1515 | - os.path.join(BOOT_RESOURCES_STORAGE, "current"))) |
1516 | + get_config_cluster_variable( |
1517 | + CLUSTER_CONFIG.DB_boot_resources_storage))) |
1518 | |
1519 | def test__calls_list_boot_images_when_cache_is_None(self): |
1520 | self.patch(boot_images, 'CACHED_BOOT_IMAGES', None) |
1521 | |
1522 | === modified file 'src/provisioningserver/rpc/tests/test_clusterservice.py' |
1523 | --- src/provisioningserver/rpc/tests/test_clusterservice.py 2015-04-22 16:51:55 +0000 |
1524 | +++ src/provisioningserver/rpc/tests/test_clusterservice.py 2015-05-04 14:27:25 +0000 |
1525 | @@ -7,7 +7,7 @@ |
1526 | absolute_import, |
1527 | print_function, |
1528 | unicode_literals, |
1529 | - ) |
1530 | +) |
1531 | |
1532 | str = None |
1533 | |
1534 | @@ -49,13 +49,12 @@ |
1535 | Mock, |
1536 | sentinel, |
1537 | ) |
1538 | -from provisioningserver import concurrency |
1539 | +from provisioningserver import ( |
1540 | + cluster_config, |
1541 | + concurrency, |
1542 | +) |
1543 | from provisioningserver.boot import tftppath |
1544 | from provisioningserver.boot.tests.test_tftppath import make_osystem |
1545 | -from provisioningserver.cluster_config import ( |
1546 | - get_cluster_uuid, |
1547 | - get_maas_url, |
1548 | -) |
1549 | from provisioningserver.dhcp.testing.config import make_subnet_config |
1550 | from provisioningserver.drivers.osystem import ( |
1551 | OperatingSystem, |
1552 | @@ -106,6 +105,7 @@ |
1553 | StubOS, |
1554 | ) |
1555 | from provisioningserver.security import set_shared_secret_on_filesystem |
1556 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
1557 | from testtools import ExpectedException |
1558 | from testtools.deferredruntest import extract_result |
1559 | from testtools.matchers import ( |
1560 | @@ -150,10 +150,11 @@ |
1561 | self.assertIsNotNone(responder) |
1562 | |
1563 | def test_identify_reports_cluster_uuid(self): |
1564 | + self.useFixture(ClusterConfigurationFixture()) |
1565 | example_uuid = factory.make_UUID() |
1566 | |
1567 | - get_cluster_uuid = self.patch(clusterservice, "get_cluster_uuid") |
1568 | - get_cluster_uuid.return_value = example_uuid |
1569 | + cluster_config.set_config_cluster_variable( |
1570 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, example_uuid) |
1571 | |
1572 | d = call_responder(Cluster(), cluster.Identify, {}) |
1573 | |
1574 | @@ -239,6 +240,7 @@ |
1575 | |
1576 | @inlineCallbacks |
1577 | def test_list_boot_images_with_things_to_report(self): |
1578 | + self.useFixture(ClusterConfigurationFixture()) |
1579 | # tftppath.list_boot_images()'s return value matches the |
1580 | # response schema that ListBootImages declares, and is |
1581 | # serialised correctly. |
1582 | @@ -258,7 +260,11 @@ |
1583 | for options in product(osystems, archs, subarchs, releases, labels): |
1584 | os.makedirs(os.path.join(current_dir, *options)) |
1585 | make_osystem(self, options[0], purposes) |
1586 | - self.patch(boot_images, 'BOOT_RESOURCES_STORAGE', tftpdir) |
1587 | + |
1588 | + cluster_config.set_config_cluster_variable( |
1589 | + cluster_config.CLUSTER_CONFIG.DB_tftp_resource_root, |
1590 | + os.path.join(tftpdir, 'current/')) |
1591 | + |
1592 | self.patch(boot_images, 'CACHED_BOOT_IMAGES', None) |
1593 | |
1594 | expected_images = [ |
1595 | @@ -272,7 +278,7 @@ |
1596 | } |
1597 | for osystem, arch, subarch, release, label, purpose in product( |
1598 | osystems, archs, subarchs, releases, labels, purposes) |
1599 | - ] |
1600 | + ] |
1601 | for expected_image in expected_images: |
1602 | if expected_image['purpose'] == 'xinstall': |
1603 | expected_image['xinstall_path'] = 'root-tgz' |
1604 | @@ -343,7 +349,7 @@ |
1605 | 'sources': [], |
1606 | 'http_proxy': parsed_proxy, |
1607 | 'https_proxy': parsed_proxy, |
1608 | - }) |
1609 | + }) |
1610 | |
1611 | self.assertThat( |
1612 | import_boot_images, |
1613 | @@ -465,9 +471,13 @@ |
1614 | self.assertThat(service.clock, Is(sentinel.reactor)) |
1615 | |
1616 | def test__get_rpc_info_url(self): |
1617 | + self.useFixture(ClusterConfigurationFixture()) |
1618 | + |
1619 | maas_url = "http://%s/%s/" % ( |
1620 | factory.make_hostname(), factory.make_name("path")) |
1621 | - self.useFixture(EnvironmentVariable("MAAS_URL", maas_url)) |
1622 | + cluster_config.set_config_cluster_variable( |
1623 | + cluster_config.CLUSTER_CONFIG.DB_maas_url, |
1624 | + maas_url) |
1625 | expected_rpc_info_url = maas_url + "rpc/" |
1626 | observed_rpc_info_url = ClusterClientService._get_rpc_info_url() |
1627 | self.assertThat(observed_rpc_info_url, Equals(expected_rpc_info_url)) |
1628 | @@ -1199,15 +1209,18 @@ |
1629 | |
1630 | @inlineCallbacks |
1631 | def test_registerWithRegion_end_to_end(self): |
1632 | + self.useFixture(ClusterConfigurationFixture()) |
1633 | fixture = self.useFixture(MockLiveClusterToRegionRPCFixture()) |
1634 | protocol, connecting = fixture.makeEventLoop() |
1635 | self.addCleanup((yield connecting)) |
1636 | yield getRegionClient() |
1637 | self.assertThat( |
1638 | protocol.Register, MockCalledOnceWith( |
1639 | - protocol, uuid=get_cluster_uuid(), |
1640 | + protocol, uuid=cluster_config.get_config_cluster_variable( |
1641 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid), |
1642 | networks=discover_networks(), |
1643 | - url=urlparse(get_maas_url()))) |
1644 | + url=urlparse(cluster_config.get_config_cluster_variable( |
1645 | + cluster_config.CLUSTER_CONFIG.DB_maas_url)))) |
1646 | |
1647 | |
1648 | class TestClusterProtocol_ListSupportedArchitectures(MAASTestCase): |
1649 | @@ -1438,9 +1451,9 @@ |
1650 | 'ips_mapping': {mac: [factory.make_ipv4_address()]}, |
1651 | 'gateways_mapping': {mac: [factory.make_ipv4_address()]}, |
1652 | 'nameservers': [], |
1653 | - }, |
1654 | + }, |
1655 | 'disable_ipv4': factory.pick_bool(), |
1656 | - } |
1657 | + } |
1658 | |
1659 | def test__is_registered(self): |
1660 | protocol = Cluster() |
1661 | @@ -1654,7 +1667,7 @@ |
1662 | yield call_responder(Cluster(), self.command, { |
1663 | 'omapi_key': omapi_key, |
1664 | 'subnet_configs': subnet_configs, |
1665 | - }) |
1666 | + }) |
1667 | |
1668 | self.assertThat(DHCPServer, MockCalledOnceWith(omapi_key)) |
1669 | self.assertThat(configure, MockCalledOnceWith( |
1670 | @@ -1675,7 +1688,7 @@ |
1671 | yield call_responder(Cluster(), self.command, { |
1672 | 'omapi_key': factory.make_name('key'), |
1673 | 'subnet_configs': [], |
1674 | - }) |
1675 | + }) |
1676 | self.assertFalse(concurrency.dhcp.locked) |
1677 | |
1678 | @inlineCallbacks |
1679 | @@ -1692,7 +1705,7 @@ |
1680 | yield call_responder(Cluster(), self.command, { |
1681 | 'omapi_key': omapi_key, |
1682 | 'subnet_configs': subnet_configs, |
1683 | - }) |
1684 | + }) |
1685 | |
1686 | |
1687 | class TestClusterProtocol_CreateHostMaps(MAASTestCase): |
1688 | @@ -1905,7 +1918,7 @@ |
1689 | "password": password, |
1690 | "prefix_filter": prefix_filter, |
1691 | "accept_all": True, |
1692 | - }) |
1693 | + }) |
1694 | self.assertThat( |
1695 | mock_deferToThread, MockCalledOnceWith( |
1696 | clusterservice.probe_virsh_and_enlist, |
1697 | @@ -1923,7 +1936,7 @@ |
1698 | "password": None, |
1699 | "prefix_filter": prefix_filter, |
1700 | "accept_all": True, |
1701 | - }) |
1702 | + }) |
1703 | self.assertThat( |
1704 | mock_deferToThread, MockCalledOnceWith( |
1705 | clusterservice.probe_virsh_and_enlist, |
1706 | @@ -1940,7 +1953,7 @@ |
1707 | "poweraddr": poweraddr, |
1708 | "prefix_filter": prefix_filter, |
1709 | "accept_all": True, |
1710 | - }) |
1711 | + }) |
1712 | self.assertThat( |
1713 | mock_deferToThread, MockCalledOnceWith( |
1714 | clusterservice.probe_virsh_and_enlist, |
1715 | @@ -1962,7 +1975,7 @@ |
1716 | "password": password, |
1717 | "prefix_filter": prefix_filter, |
1718 | "accept_all": True, |
1719 | - }) |
1720 | + }) |
1721 | self.assertThat( |
1722 | clusterservice.maaslog.error, |
1723 | MockAnyCall( |
1724 | @@ -1998,7 +2011,7 @@ |
1725 | "protocol": protocol, |
1726 | "prefix_filter": prefix_filter, |
1727 | "accept_all": True, |
1728 | - }) |
1729 | + }) |
1730 | self.assertThat( |
1731 | mock_deferToThread, MockCalledOnceWith( |
1732 | clusterservice.probe_vsphere_and_enlist, |
1733 | @@ -2024,7 +2037,7 @@ |
1734 | "protocol": None, |
1735 | "prefix_filter": prefix_filter, |
1736 | "accept_all": True, |
1737 | - }) |
1738 | + }) |
1739 | self.assertThat( |
1740 | mock_deferToThread, MockCalledOnceWith( |
1741 | clusterservice.probe_vsphere_and_enlist, |
1742 | @@ -2049,7 +2062,7 @@ |
1743 | "password": password, |
1744 | "prefix_filter": prefix_filter, |
1745 | "accept_all": True, |
1746 | - }) |
1747 | + }) |
1748 | self.assertThat( |
1749 | mock_deferToThread, MockCalledOnceWith( |
1750 | clusterservice.probe_vsphere_and_enlist, |
1751 | @@ -2076,7 +2089,7 @@ |
1752 | "password": password, |
1753 | "prefix_filter": prefix_filter, |
1754 | "accept_all": True, |
1755 | - }) |
1756 | + }) |
1757 | |
1758 | self.assertThat( |
1759 | clusterservice.maaslog.error, |
1760 | @@ -2108,7 +2121,7 @@ |
1761 | "password": password, |
1762 | "prefix_filter": prefix_filter, |
1763 | "accept_all": True, |
1764 | - }) |
1765 | + }) |
1766 | self.assertThat( |
1767 | mock_deferToThread, MockCalledOnceWith( |
1768 | clusterservice.probe_esxi_and_enlist, |
1769 | @@ -2133,7 +2146,7 @@ |
1770 | "password": password, |
1771 | "prefix_filter": prefix_filter, |
1772 | "accept_all": True, |
1773 | - }) |
1774 | + }) |
1775 | self.assertThat( |
1776 | clusterservice.maaslog.error, |
1777 | MockAnyCall( |
1778 | @@ -2169,7 +2182,7 @@ |
1779 | "password": password, |
1780 | "power_control": power_control, |
1781 | "accept_all": True, |
1782 | - }) |
1783 | + }) |
1784 | |
1785 | self.assertThat( |
1786 | find_ip_via_arp, MockCalledOnceWith(mac)) |
1787 | @@ -2195,7 +2208,7 @@ |
1788 | "password": password, |
1789 | "power_control": power_control, |
1790 | "accept_all": True, |
1791 | - }) |
1792 | + }) |
1793 | |
1794 | self.assertThat( |
1795 | maaslog.warning, |
1796 | @@ -2221,7 +2234,7 @@ |
1797 | "password": password, |
1798 | "power_control": power_control, |
1799 | "accept_all": True, |
1800 | - }) |
1801 | + }) |
1802 | |
1803 | self.assertThat( |
1804 | mock_deferToThread, MockCalledOnceWith( |
1805 | @@ -2251,7 +2264,7 @@ |
1806 | "password": password, |
1807 | "power_control": power_control, |
1808 | "accept_all": True, |
1809 | - }) |
1810 | + }) |
1811 | self.assertThat( |
1812 | clusterservice.maaslog.error, |
1813 | MockAnyCall( |
1814 | |
1815 | === modified file 'src/provisioningserver/rpc/tests/test_tags.py' |
1816 | --- src/provisioningserver/rpc/tests/test_tags.py 2015-03-25 15:33:23 +0000 |
1817 | +++ src/provisioningserver/rpc/tests/test_tags.py 2015-05-04 14:27:25 +0000 |
1818 | @@ -7,13 +7,14 @@ |
1819 | absolute_import, |
1820 | print_function, |
1821 | unicode_literals, |
1822 | - ) |
1823 | +) |
1824 | |
1825 | str = None |
1826 | |
1827 | __metaclass__ = type |
1828 | __all__ = [] |
1829 | |
1830 | + |
1831 | from apiclient.maas_client import ( |
1832 | MAASClient, |
1833 | MAASDispatcher, |
1834 | @@ -26,17 +27,25 @@ |
1835 | ANY, |
1836 | sentinel, |
1837 | ) |
1838 | +from provisioningserver import cluster_config |
1839 | from provisioningserver.rpc import tags |
1840 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
1841 | |
1842 | |
1843 | class TestEvaluateTag(MAASTestCase): |
1844 | |
1845 | def setUp(self): |
1846 | super(TestEvaluateTag, self).setUp() |
1847 | - get_maas_url = self.patch_autospec(tags, "get_maas_url") |
1848 | - get_maas_url.return_value = sentinel.maas_url |
1849 | - get_cluster_uuid = self.patch_autospec(tags, "get_cluster_uuid") |
1850 | - get_cluster_uuid.return_value = sentinel.cluster_uuid |
1851 | + self.useFixture(ClusterConfigurationFixture()) |
1852 | + |
1853 | + self.mock_cluster_uuid = factory.make_UUID() |
1854 | + self.mock_url = factory.make_simple_http_url() |
1855 | + |
1856 | + cluster_config.set_config_cluster_variable( |
1857 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, |
1858 | + self.mock_cluster_uuid) |
1859 | + cluster_config.set_config_cluster_variable( |
1860 | + cluster_config.CLUSTER_CONFIG.DB_maas_url, self.mock_url) |
1861 | |
1862 | def test__calls_process_node_tags(self): |
1863 | credentials = "aaa", "bbb", "ccc" |
1864 | @@ -49,7 +58,7 @@ |
1865 | tag_name=sentinel.tag_name, |
1866 | tag_definition=sentinel.tag_definition, |
1867 | tag_nsmap=sentinel.tag_nsmap, client=ANY, |
1868 | - nodegroup_uuid=sentinel.cluster_uuid)) |
1869 | + nodegroup_uuid=self.mock_cluster_uuid)) |
1870 | |
1871 | def test__constructs_client_with_credentials(self): |
1872 | consumer_key = factory.make_name("ckey") |
1873 | @@ -66,7 +75,7 @@ |
1874 | |
1875 | client = tags.process_node_tags.call_args[1]["client"] |
1876 | self.assertIsInstance(client, MAASClient) |
1877 | - self.assertEqual(sentinel.maas_url, client.url) |
1878 | + self.assertEqual(self.mock_url, client.url) |
1879 | self.assertIsInstance(client.dispatcher, MAASDispatcher) |
1880 | self.assertIsInstance(client.auth, MAASOAuth) |
1881 | self.assertThat(tags.MAASOAuth, MockCalledOnceWith( |
1882 | |
1883 | === modified file 'src/provisioningserver/tests/test_cluster_config.py' |
1884 | --- src/provisioningserver/tests/test_cluster_config.py 2015-03-25 15:33:23 +0000 |
1885 | +++ src/provisioningserver/tests/test_cluster_config.py 2015-05-04 14:27:25 +0000 |
1886 | @@ -7,42 +7,83 @@ |
1887 | absolute_import, |
1888 | print_function, |
1889 | unicode_literals, |
1890 | - ) |
1891 | +) |
1892 | |
1893 | str = None |
1894 | |
1895 | __metaclass__ = type |
1896 | __all__ = [] |
1897 | |
1898 | -from fixtures import EnvironmentVariableFixture |
1899 | +import os |
1900 | + |
1901 | from maastesting.factory import factory |
1902 | from maastesting.testcase import MAASTestCase |
1903 | -from provisioningserver.cluster_config import ( |
1904 | - get_cluster_uuid, |
1905 | - get_cluster_variable, |
1906 | - get_maas_url, |
1907 | -) |
1908 | - |
1909 | - |
1910 | -class TestClusterConfig(MAASTestCase): |
1911 | - |
1912 | - def test_get_cluster_variable_reads_env(self): |
1913 | - var = factory.make_name('variable') |
1914 | - value = factory.make_name('value') |
1915 | - self.useFixture(EnvironmentVariableFixture(var, value)) |
1916 | - self.assertEqual(value, get_cluster_variable(var)) |
1917 | - |
1918 | - def test_get_cluster_variable_fails_if_not_set(self): |
1919 | - self.assertRaises( |
1920 | - AssertionError, |
1921 | - get_cluster_variable, factory.make_name('nonexistent-variable')) |
1922 | - |
1923 | - def test_get_cluster_uuid_reads_CLUSTER_UUID(self): |
1924 | - uuid = factory.make_name('uuid') |
1925 | - self.useFixture(EnvironmentVariableFixture('CLUSTER_UUID', uuid)) |
1926 | - self.assertEqual(uuid, get_cluster_uuid()) |
1927 | - |
1928 | - def test_get_maas_url_reads_MAAS_URL(self): |
1929 | - maas_url = factory.make_name('maas_url') |
1930 | - self.useFixture(EnvironmentVariableFixture('MAAS_URL', maas_url)) |
1931 | - self.assertEqual(maas_url, get_maas_url()) |
1932 | +from provisioningserver import cluster_config |
1933 | +from provisioningserver.config import UUID_NOT_SET |
1934 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
1935 | + |
1936 | + |
1937 | +class TestClusterConfigTFTPGenerator(MAASTestCase): |
1938 | + """Tests for the get_tftp_generator() function.""" |
1939 | + |
1940 | + def test_get_tftp_generator(self): |
1941 | + self.useFixture(ClusterConfigurationFixture()) |
1942 | + random_path = factory.make_simple_http_url() |
1943 | + cluster_config.set_config_cluster_variable( |
1944 | + cluster_config.CLUSTER_CONFIG.DB_maas_url, random_path) |
1945 | + |
1946 | + observed = cluster_config.get_tftp_generator() |
1947 | + expected = os.path.join(random_path, 'api', '1.0', 'pxeconfig') |
1948 | + self.assertEqual(observed, expected) |
1949 | + |
1950 | + |
1951 | +class TestClusterConfigDatabaseOptions(MAASTestCase): |
1952 | + """Tests for the database options in `cluster_config`.""" |
1953 | + |
1954 | + def setUp(self): |
1955 | + super(TestClusterConfigDatabaseOptions, self).setUp() |
1956 | + self.useFixture(ClusterConfigurationFixture()) |
1957 | + |
1958 | + options_and_defaults = { |
1959 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid: UUID_NOT_SET, |
1960 | + cluster_config.CLUSTER_CONFIG.DB_maas_url: |
1961 | + "http://localhost:5240/MAAS", |
1962 | + cluster_config.CLUSTER_CONFIG.DB_tftp_resource_root: |
1963 | + "/var/lib/maas/boot-resources/current/", |
1964 | + cluster_config.CLUSTER_CONFIG.DB_boot_resources_storage: |
1965 | + "/var/lib/maas/boot-resources/current/", |
1966 | + cluster_config.CLUSTER_CONFIG.DB_tftpport: 69, |
1967 | + } |
1968 | + |
1969 | + scenarios = tuple( |
1970 | + (name, {"option": name, "default": default}) |
1971 | + for name, default in options_and_defaults.viewitems() |
1972 | + ) |
1973 | + |
1974 | + def test__default(self): |
1975 | + self.assertEqual( |
1976 | + self.default, |
1977 | + cluster_config.get_config_cluster_variable(self.option)) |
1978 | + |
1979 | + def test__set_and_get(self): |
1980 | + # NOTE: test_values cannot be a class attribute factory |
1981 | + # since make_dir() requires a reference to 'self' for the |
1982 | + # TempDirectory fixture. |
1983 | + test_values = { |
1984 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid: factory.make_UUID(), |
1985 | + cluster_config.CLUSTER_CONFIG.DB_maas_url: |
1986 | + factory.make_simple_http_url(), |
1987 | + cluster_config.CLUSTER_CONFIG.DB_tftp_resource_root: |
1988 | + self.make_dir(), |
1989 | + cluster_config.CLUSTER_CONFIG.DB_boot_resources_storage: |
1990 | + self.make_dir(), |
1991 | + cluster_config.CLUSTER_CONFIG.DB_tftpport: factory.pick_port(), |
1992 | + } |
1993 | + |
1994 | + example_value = test_values[self.option] |
1995 | + |
1996 | + cluster_config.set_config_cluster_variable(self.option, example_value) |
1997 | + |
1998 | + self.assertEqual(example_value, |
1999 | + cluster_config.get_config_cluster_variable( |
2000 | + self.option)) |
2001 | |
2002 | === modified file 'src/provisioningserver/tests/test_config.py' |
2003 | --- src/provisioningserver/tests/test_config.py 2015-05-04 14:27:25 +0000 |
2004 | +++ src/provisioningserver/tests/test_config.py 2015-05-04 14:27:25 +0000 |
2005 | @@ -15,24 +15,17 @@ |
2006 | __all__ = [] |
2007 | |
2008 | import contextlib |
2009 | -from copy import deepcopy |
2010 | -import errno |
2011 | -from functools import partial |
2012 | -from getpass import getuser |
2013 | -from io import BytesIO |
2014 | from operator import methodcaller |
2015 | import os.path |
2016 | import random |
2017 | import re |
2018 | import sqlite3 |
2019 | -from textwrap import dedent |
2020 | from uuid import uuid4 |
2021 | |
2022 | from fixtures import EnvironmentVariableFixture |
2023 | import formencode |
2024 | import formencode.validators |
2025 | from formencode.validators import Invalid |
2026 | -from maastesting import root |
2027 | from maastesting.factory import factory |
2028 | from maastesting.matchers import ( |
2029 | MockCalledOnceWith, |
2030 | @@ -41,11 +34,7 @@ |
2031 | from maastesting.testcase import MAASTestCase |
2032 | from mock import sentinel |
2033 | from provisioningserver.config import ( |
2034 | - BootSources, |
2035 | ClusterConfiguration, |
2036 | - Config, |
2037 | - ConfigBase, |
2038 | - ConfigMeta, |
2039 | Configuration, |
2040 | ConfigurationDatabase, |
2041 | ConfigurationFile, |
2042 | @@ -56,17 +45,13 @@ |
2043 | UUID, |
2044 | ) |
2045 | from provisioningserver.path import get_path |
2046 | -from provisioningserver.testing.config import ConfigFixtureBase |
2047 | from provisioningserver.utils.fs import FileLockProxy |
2048 | from testtools import ExpectedException |
2049 | from testtools.matchers import ( |
2050 | - DirExists, |
2051 | FileContains, |
2052 | FileExists, |
2053 | Is, |
2054 | - MatchesException, |
2055 | MatchesStructure, |
2056 | - Raises, |
2057 | ) |
2058 | from twisted.python.filepath import FilePath |
2059 | import yaml |
2060 | @@ -224,444 +209,6 @@ |
2061 | "url: %s" % url) |
2062 | |
2063 | |
2064 | -class ExampleConfig(ConfigBase, formencode.Schema): |
2065 | - """An example configuration schema. |
2066 | - |
2067 | - It derives from :class:`ConfigBase` and has a metaclass derived from |
2068 | - :class:`ConfigMeta`, just as a "real" schema must. |
2069 | - """ |
2070 | - |
2071 | - class __metaclass__(ConfigMeta): |
2072 | - envvar = "MAAS_TESTING_SETTINGS" |
2073 | - default = "example.yaml" |
2074 | - |
2075 | - something = formencode.validators.String(if_missing="*missing*") |
2076 | - |
2077 | - |
2078 | -class ExampleConfigFixture(ConfigFixtureBase): |
2079 | - """A fixture to help with testing :class:`ExampleConfig`.""" |
2080 | - |
2081 | - schema = ExampleConfig |
2082 | - |
2083 | - |
2084 | -class TestConfigFixtureBase(MAASTestCase): |
2085 | - """Tests for `ConfigFixtureBase`.""" |
2086 | - |
2087 | - def exercise_fixture(self, fixture): |
2088 | - # ConfigFixtureBase arranges a minimal configuration on disk, |
2089 | - # and exports the configuration filename to the environment so |
2090 | - # that subprocesses can find it. |
2091 | - with fixture: |
2092 | - self.assertThat(fixture.dir, DirExists()) |
2093 | - self.assertThat(fixture.filename, FileExists()) |
2094 | - self.assertEqual( |
2095 | - {fixture.schema.envvar: fixture.filename}, |
2096 | - fixture.environ) |
2097 | - self.assertEqual( |
2098 | - fixture.filename, os.environ[fixture.schema.envvar]) |
2099 | - with open(fixture.filename, "rb") as stream: |
2100 | - self.assertEqual(fixture.config, yaml.safe_load(stream)) |
2101 | - |
2102 | - def test_use_minimal(self): |
2103 | - # With no arguments, ConfigFixtureBase arranges a minimal |
2104 | - # configuration. |
2105 | - fixture = ExampleConfigFixture() |
2106 | - self.exercise_fixture(fixture) |
2107 | - |
2108 | - def test_use_with_config(self): |
2109 | - # Given a configuration, ConfigFixtureBase can arrange a minimal |
2110 | - # global configuration with the additional options merged in. |
2111 | - something = self.getUniqueString("something") |
2112 | - fixture = ExampleConfigFixture({"something": something}) |
2113 | - self.assertEqual(something, fixture.config["something"]) |
2114 | - self.exercise_fixture(fixture) |
2115 | - |
2116 | - |
2117 | -class TestConfigMeta_DEFAULT_FILENAME(MAASTestCase): |
2118 | - """Tests for `provisioningserver.config.ConfigBase.DEFAULT_FILENAME`.""" |
2119 | - |
2120 | - def set_envvar(self, filepath=None): |
2121 | - """Continue this test with a given environment variable.""" |
2122 | - self.useFixture(EnvironmentVariableFixture( |
2123 | - ExampleConfig.envvar, filepath)) |
2124 | - |
2125 | - def set_MAAS_CONFIG_DIR(self, dirpath=None): |
2126 | - """Continue this test with a given `MAAS_CONFIG_DIR`.""" |
2127 | - self.useFixture(EnvironmentVariableFixture("MAAS_CONFIG_DIR", dirpath)) |
2128 | - |
2129 | - def make_config(self): |
2130 | - """Create a config file in a directory of its own.""" |
2131 | - return self.make_file(name=ExampleConfig.default) |
2132 | - |
2133 | - def test_gets_filename_from_MAAS_PROVISIONING_SETTNGS(self): |
2134 | - dummy_filename = factory.make_name("config") |
2135 | - self.set_MAAS_CONFIG_DIR(None) |
2136 | - self.set_envvar(dummy_filename) |
2137 | - self.assertEqual(dummy_filename, ExampleConfig.DEFAULT_FILENAME) |
2138 | - |
2139 | - def test_falls_back_to_MAAS_CONFIG_DIR(self): |
2140 | - config_file = self.make_config() |
2141 | - self.set_MAAS_CONFIG_DIR(os.path.dirname(config_file)) |
2142 | - self.set_envvar(None) |
2143 | - self.assertEqual(config_file, ExampleConfig.DEFAULT_FILENAME) |
2144 | - |
2145 | - def test_MAAS_PROVISIONING_SETTINGS_trumps_MAAS_CONFIG_DIR(self): |
2146 | - provisioning_settings = factory.make_name("config") |
2147 | - self.set_MAAS_CONFIG_DIR(os.path.dirname(self.make_config())) |
2148 | - self.set_envvar(provisioning_settings) |
2149 | - self.assertEqual( |
2150 | - provisioning_settings, |
2151 | - ExampleConfig.DEFAULT_FILENAME) |
2152 | - |
2153 | - def test_defaults_to_global_config(self): |
2154 | - self.set_MAAS_CONFIG_DIR(None) |
2155 | - self.set_envvar(None) |
2156 | - self.assertEqual( |
2157 | - '/etc/maas/%s' % ExampleConfig.default, |
2158 | - ExampleConfig.DEFAULT_FILENAME) |
2159 | - |
2160 | - def test_set(self): |
2161 | - dummy_filename = factory.make_name("config") |
2162 | - ExampleConfig.DEFAULT_FILENAME = dummy_filename |
2163 | - self.assertEqual(dummy_filename, ExampleConfig.DEFAULT_FILENAME) |
2164 | - |
2165 | - def test_delete(self): |
2166 | - self.set_MAAS_CONFIG_DIR(None) |
2167 | - self.set_envvar(None) |
2168 | - ExampleConfig.DEFAULT_FILENAME = factory.make_name("config") |
2169 | - del ExampleConfig.DEFAULT_FILENAME |
2170 | - # The filename reverts; see test_get_with_environment_empty. |
2171 | - self.assertEqual( |
2172 | - "/etc/maas/%s" % ExampleConfig.default, |
2173 | - ExampleConfig.DEFAULT_FILENAME) |
2174 | - # The delete does not fail when called multiple times. |
2175 | - del ExampleConfig.DEFAULT_FILENAME |
2176 | - |
2177 | - |
2178 | -class TestConfigBase(MAASTestCase): |
2179 | - """Tests for `provisioningserver.config.ConfigBase`.""" |
2180 | - |
2181 | - def make_config_data(self): |
2182 | - """Return random config data for `ExampleConfig`.""" |
2183 | - return {'something': factory.make_name('value')} |
2184 | - |
2185 | - def make_config_file(self, name=None, data=None): |
2186 | - """Write a YAML config file, and return its path.""" |
2187 | - if name is None: |
2188 | - name = factory.make_name('config') + '.yaml' |
2189 | - if data is None: |
2190 | - data = self.make_config_data() |
2191 | - return self.make_file(name=name, contents=yaml.safe_dump(data)) |
2192 | - |
2193 | - def test_get_defaults_returns_default_config(self): |
2194 | - # The default configuration is production-ready. |
2195 | - observed = ExampleConfig.get_defaults() |
2196 | - self.assertEqual({"something": "*missing*"}, observed) |
2197 | - |
2198 | - def test_get_defaults_ignores_settings(self): |
2199 | - self.useFixture(ExampleConfigFixture(self.make_config_data())) |
2200 | - observed = ExampleConfig.get_defaults() |
2201 | - self.assertEqual({"something": "*missing*"}, observed) |
2202 | - |
2203 | - def test_parse(self): |
2204 | - # Configuration can be parsed from a snippet of YAML. |
2205 | - observed = ExampleConfig.parse(b'something: "important"\n') |
2206 | - self.assertEqual("important", observed["something"]) |
2207 | - |
2208 | - def test_load(self): |
2209 | - # Configuration can be loaded and parsed from a file. |
2210 | - config = dedent(""" |
2211 | - something: "important" |
2212 | - """) |
2213 | - filename = self.make_file(contents=config) |
2214 | - observed = ExampleConfig.load(filename) |
2215 | - self.assertEqual({"something": "important"}, observed) |
2216 | - |
2217 | - def test_load_defaults_to_default_filename(self): |
2218 | - data = self.make_config_data() |
2219 | - filename = self.make_config_file(name='config.yaml', data=data) |
2220 | - self.patch(ExampleConfig, 'DEFAULT_FILENAME', filename) |
2221 | - self.assertEqual(data, ExampleConfig.load()) |
2222 | - |
2223 | - def test_load_from_cache_loads_config(self): |
2224 | - data = self.make_config_data() |
2225 | - filename = self.make_config_file(data=data) |
2226 | - self.assertEqual(data, ExampleConfig.load_from_cache(filename)) |
2227 | - |
2228 | - def test_load_from_cache_uses_defaults(self): |
2229 | - filename = self.make_file(contents='') |
2230 | - self.assertEqual( |
2231 | - ExampleConfig.get_defaults(), |
2232 | - ExampleConfig.load_from_cache(filename)) |
2233 | - |
2234 | - def test_load_from_cache_caches_each_file_separately(self): |
2235 | - config1 = self.make_file(contents=yaml.safe_dump({'something': "1"})) |
2236 | - config2 = self.make_file(contents=yaml.safe_dump({'something': "2"})) |
2237 | - |
2238 | - self.assertEqual( |
2239 | - {"something": "1"}, |
2240 | - ExampleConfig.load_from_cache(config1)) |
2241 | - self.assertEqual( |
2242 | - {"something": "2"}, |
2243 | - ExampleConfig.load_from_cache(config2)) |
2244 | - |
2245 | - def test_load_from_cache_reloads_from_cache_not_from_file(self): |
2246 | - # A config loaded by Config.load_from_cache() is never reloaded. |
2247 | - filename = self.make_config_file() |
2248 | - config_before = ExampleConfig.load_from_cache(filename) |
2249 | - os.unlink(filename) |
2250 | - config_after = ExampleConfig.load_from_cache(filename) |
2251 | - self.assertEqual(config_before, config_after) |
2252 | - |
2253 | - def test_load_from_cache_caches_immutable_copy(self): |
2254 | - filename = self.make_config_file() |
2255 | - |
2256 | - first_load = ExampleConfig.load_from_cache(filename) |
2257 | - second_load = ExampleConfig.load_from_cache(filename) |
2258 | - |
2259 | - self.assertEqual(first_load, second_load) |
2260 | - self.assertIsNot(first_load, second_load) |
2261 | - first_load['something'] = factory.make_name('newthing') |
2262 | - self.assertNotEqual(first_load['something'], second_load['something']) |
2263 | - |
2264 | - def test_flush_cache_without_filename_empties_cache(self): |
2265 | - filename = self.make_config_file() |
2266 | - ExampleConfig.load_from_cache(filename) |
2267 | - os.unlink(filename) |
2268 | - ExampleConfig.flush_cache() |
2269 | - error = self.assertRaises( |
2270 | - IOError, |
2271 | - ExampleConfig.load_from_cache, filename) |
2272 | - self.assertEqual(errno.ENOENT, error.errno) |
2273 | - |
2274 | - def test_flush_cache_flushes_specific_file(self): |
2275 | - filename = self.make_config_file() |
2276 | - ExampleConfig.load_from_cache(filename) |
2277 | - os.unlink(filename) |
2278 | - ExampleConfig.flush_cache(filename) |
2279 | - error = self.assertRaises( |
2280 | - IOError, |
2281 | - ExampleConfig.load_from_cache, filename) |
2282 | - self.assertEqual(errno.ENOENT, error.errno) |
2283 | - |
2284 | - def test_flush_cache_retains_other_files(self): |
2285 | - flushed_file = self.make_config_file() |
2286 | - cached_file = self.make_config_file() |
2287 | - ExampleConfig.load_from_cache(flushed_file) |
2288 | - cached_config = ExampleConfig.load_from_cache(cached_file) |
2289 | - os.unlink(cached_file) |
2290 | - ExampleConfig.flush_cache(flushed_file) |
2291 | - self.assertEqual( |
2292 | - cached_config, |
2293 | - ExampleConfig.load_from_cache(cached_file)) |
2294 | - |
2295 | - def test_flush_cache_ignores_uncached_files(self): |
2296 | - data = self.make_config_data() |
2297 | - filename = self.make_config_file(data=data) |
2298 | - ExampleConfig.flush_cache(filename) |
2299 | - self.assertEqual(data, ExampleConfig.load_from_cache(filename)) |
2300 | - |
2301 | - def test_field(self): |
2302 | - self.assertIs(ExampleConfig, ExampleConfig.field()) |
2303 | - self.assertIs( |
2304 | - ExampleConfig.fields["something"], |
2305 | - ExampleConfig.field("something")) |
2306 | - |
2307 | - def test_save_and_load_interoperate(self): |
2308 | - something = self.getUniqueString() |
2309 | - saved_file = self.make_file() |
2310 | - |
2311 | - ExampleConfig.save({'something': something}, saved_file) |
2312 | - loaded_config = ExampleConfig.load(saved_file) |
2313 | - self.assertEqual(something, loaded_config['something']) |
2314 | - |
2315 | - def test_save_saves_yaml_file(self): |
2316 | - config = {'something': self.getUniqueString()} |
2317 | - saved_file = self.make_file() |
2318 | - |
2319 | - ExampleConfig.save(config, saved_file) |
2320 | - |
2321 | - with open(saved_file, 'rb') as written_file: |
2322 | - loaded_config = yaml.safe_load(written_file) |
2323 | - self.assertEqual(config, loaded_config) |
2324 | - |
2325 | - def test_save_defaults_to_default_filename(self): |
2326 | - something = self.getUniqueString() |
2327 | - filename = self.make_file(name="config.yaml") |
2328 | - self.patch(ExampleConfig, 'DEFAULT_FILENAME', filename) |
2329 | - |
2330 | - ExampleConfig.save({'something': something}) |
2331 | - |
2332 | - self.assertEqual( |
2333 | - {'something': something}, |
2334 | - ExampleConfig.load(filename)) |
2335 | - |
2336 | - def test_create_backup_creates_backup(self): |
2337 | - something = self.getUniqueString() |
2338 | - filename = self.make_file(name="config.yaml") |
2339 | - config = {'something': something} |
2340 | - yaml_config = yaml.safe_dump(config) |
2341 | - self.patch(ExampleConfig, 'DEFAULT_FILENAME', filename) |
2342 | - ExampleConfig.save(config) |
2343 | - |
2344 | - ExampleConfig.create_backup('test') |
2345 | - |
2346 | - backup_name = "%s.%s.bak" % (filename, 'test') |
2347 | - self.assertThat(backup_name, FileContains(yaml_config)) |
2348 | - |
2349 | - |
2350 | -class TestConfig(MAASTestCase): |
2351 | - """Tests for `provisioningserver.config.Config`.""" |
2352 | - |
2353 | - default_production_config = { |
2354 | - 'broker': { |
2355 | - 'host': 'localhost', |
2356 | - 'port': 5673, |
2357 | - 'username': getuser(), |
2358 | - 'password': 'test', |
2359 | - 'vhost': '/', |
2360 | - }, |
2361 | - 'logfile': 'pserv.log', |
2362 | - 'oops': { |
2363 | - 'directory': '', |
2364 | - 'reporter': '', |
2365 | - }, |
2366 | - 'rpc': {}, |
2367 | - 'tftp': { |
2368 | - 'generator': 'http://localhost/MAAS/api/1.0/pxeconfig/', |
2369 | - 'port': 69, |
2370 | - # The "root" setting is obsolete; resource_root replaces it. |
2371 | - 'root': "/var/lib/maas/tftp", |
2372 | - 'resource_root': "/var/lib/maas/boot-resources/current/", |
2373 | - }, |
2374 | - # Legacy section. Became unused in MAAS 1.5. |
2375 | - 'boot': { |
2376 | - 'architectures': None, |
2377 | - 'ephemeral': { |
2378 | - 'images_directory': None, |
2379 | - 'releases': None, |
2380 | - }, |
2381 | - }, |
2382 | - } |
2383 | - |
2384 | - default_development_config = deepcopy(default_production_config) |
2385 | - default_development_config.update(logfile="/dev/null") |
2386 | - default_development_config["tftp"].update( |
2387 | - port=5244, generator="http://localhost:5240/MAAS/api/1.0/pxeconfig/") |
2388 | - |
2389 | - def test_get_defaults_returns_default_config(self): |
2390 | - # The default configuration is production-ready. |
2391 | - observed = Config.get_defaults() |
2392 | - self.assertEqual(self.default_production_config, observed) |
2393 | - |
2394 | - def test_load_example(self): |
2395 | - # The example configuration is designed for development. |
2396 | - filename = os.path.join(root, "etc", "maas", "pserv.yaml") |
2397 | - self.assertEqual( |
2398 | - self.default_development_config, |
2399 | - Config.load(filename)) |
2400 | - |
2401 | - def test_oops_directory_without_reporter(self): |
2402 | - # It is an error to omit the OOPS reporter if directory is specified. |
2403 | - config = ( |
2404 | - 'oops:\n' |
2405 | - ' directory: /tmp/oops\n' |
2406 | - ) |
2407 | - expected = MatchesException( |
2408 | - formencode.Invalid, "oops: You must give a value for reporter") |
2409 | - self.assertThat( |
2410 | - partial(Config.parse, config), |
2411 | - Raises(expected)) |
2412 | - |
2413 | - def test_accepts_1_4_config_file(self): |
2414 | - # A config file that was valid with MAAS 1.4 still loads, even though |
2415 | - # its "boot" section is no longer used. |
2416 | - broker_password = factory.make_name('pass') |
2417 | - config = Config.parse(dedent("""\ |
2418 | - logfile: "/dev/null" |
2419 | - oops: |
2420 | - directory: "logs/oops" |
2421 | - reporter: "maas-pserv" |
2422 | - broker: |
2423 | - host: "localhost" |
2424 | - port: 5673 |
2425 | - username: brokeruser |
2426 | - password: "%s" |
2427 | - vhost: "/" |
2428 | - tftp: |
2429 | - root: /var/lib/maas/tftp |
2430 | - port: 5244 |
2431 | - generator: http://localhost:5240/api/1.0/pxeconfig/ |
2432 | - boot: |
2433 | - architectures: ['i386', 'armhf'] |
2434 | - ephemeral: |
2435 | - images_directory: /var/lib/maas/ephemeral |
2436 | - releases: ['precise', 'saucy'] |
2437 | - """) % broker_password) |
2438 | - # This does not fail. |
2439 | - self.assertEqual(broker_password, config['broker']['password']) |
2440 | - |
2441 | - |
2442 | -class TestBootSources(MAASTestCase): |
2443 | - """Tests for `provisioningserver.config.BootSources`.""" |
2444 | - |
2445 | - default_source = { |
2446 | - 'url': ( |
2447 | - 'http://maas.ubuntu.com/images/ephemeral-v2/releases/' |
2448 | - ), |
2449 | - 'keyring': ( |
2450 | - '/usr/share/keyrings/ubuntu-cloudimage-keyring.gpg'), |
2451 | - 'keyring_data': None, |
2452 | - 'selections': [ |
2453 | - { |
2454 | - 'os': '*', |
2455 | - 'release': '*', |
2456 | - 'labels': ['*'], |
2457 | - 'arches': ['*'], |
2458 | - 'subarches': ['*'], |
2459 | - }, |
2460 | - ], |
2461 | - } |
2462 | - |
2463 | - def make_source(self): |
2464 | - """Create a dict defining an arbitrary `BootSource`.""" |
2465 | - return { |
2466 | - 'url': 'http://example.com/' + factory.make_name('path'), |
2467 | - 'keyring': factory.make_name('keyring'), |
2468 | - 'keyring_data': factory.make_string(), |
2469 | - 'selections': [{ |
2470 | - 'os': factory.make_name('os'), |
2471 | - 'release': factory.make_name('release'), |
2472 | - 'labels': [factory.make_name('label')], |
2473 | - 'arches': [factory.make_name('arch')], |
2474 | - 'subarches': [factory.make_name('sub') for _ in range(3)], |
2475 | - }], |
2476 | - } |
2477 | - |
2478 | - def test_parse_parses_source(self): |
2479 | - sources = [self.make_source()] |
2480 | - self.assertEqual( |
2481 | - sources, |
2482 | - BootSources.parse(BytesIO(yaml.safe_dump(sources)))) |
2483 | - |
2484 | - def test_parse_parses_multiple_sources(self): |
2485 | - sources = [self.make_source() for _ in range(2)] |
2486 | - self.assertEqual( |
2487 | - sources, |
2488 | - BootSources.parse(BytesIO(yaml.safe_dump(sources)))) |
2489 | - |
2490 | - def test_parse_uses_defaults(self): |
2491 | - self.assertEqual( |
2492 | - [self.default_source], |
2493 | - BootSources.parse(BytesIO(b'[{}]'))) |
2494 | - |
2495 | - def test_load_parses_file(self): |
2496 | - sources = [self.make_source()] |
2497 | - self.assertEqual( |
2498 | - sources, |
2499 | - BootSources.load(self.make_file(contents=yaml.safe_dump(sources)))) |
2500 | - |
2501 | - |
2502 | ############################################################################### |
2503 | # New configuration API follows. |
2504 | ############################################################################### |
2505 | |
2506 | === modified file 'src/provisioningserver/tests/test_diskless.py' |
2507 | --- src/provisioningserver/tests/test_diskless.py 2015-03-25 15:33:23 +0000 |
2508 | +++ src/provisioningserver/tests/test_diskless.py 2015-05-04 14:27:25 +0000 |
2509 | @@ -7,7 +7,7 @@ |
2510 | absolute_import, |
2511 | print_function, |
2512 | unicode_literals, |
2513 | - ) |
2514 | +) |
2515 | |
2516 | str = None |
2517 | |
2518 | @@ -24,9 +24,11 @@ |
2519 | ) |
2520 | from maastesting.testcase import MAASTestCase |
2521 | from mock import sentinel |
2522 | -from provisioningserver import ( |
2523 | - config, |
2524 | - diskless, |
2525 | +from provisioningserver import diskless |
2526 | +from provisioningserver.cluster_config import ( |
2527 | + CLUSTER_CONFIG, |
2528 | + get_config_cluster_variable, |
2529 | + set_config_cluster_variable, |
2530 | ) |
2531 | from provisioningserver.diskless import ( |
2532 | compose_diskless_link_path, |
2533 | @@ -54,6 +56,7 @@ |
2534 | BOOT_IMAGE_PURPOSE, |
2535 | OperatingSystemRegistry, |
2536 | ) |
2537 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
2538 | from provisioningserver.testing.os import FakeOS |
2539 | from provisioningserver.utils.testing import RegistryFixture |
2540 | from testtools.matchers import ( |
2541 | @@ -71,13 +74,18 @@ |
2542 | |
2543 | def setUp(self): |
2544 | super(DisklessTestMixin, self).setUp() |
2545 | + self.useFixture(ClusterConfigurationFixture()) |
2546 | # Ensure the global registry is empty for each test run. |
2547 | self.useFixture(RegistryFixture()) |
2548 | |
2549 | def configure_resource_storage(self): |
2550 | resource_dir = self.make_dir() |
2551 | os.mkdir(os.path.join(resource_dir, 'diskless')) |
2552 | - self.patch(config, 'BOOT_RESOURCES_STORAGE', resource_dir) |
2553 | + current_dir = os.path.join(resource_dir, 'current') + '/' |
2554 | + os.mkdir(current_dir) |
2555 | + set_config_cluster_variable( |
2556 | + CLUSTER_CONFIG.DB_boot_resources_storage, |
2557 | + current_dir) |
2558 | return resource_dir |
2559 | |
2560 | def configure_diskless_storage(self): |
2561 | @@ -116,8 +124,12 @@ |
2562 | class TestHelpers(MAASTestCase, DisklessTestMixin): |
2563 | |
2564 | def test_get_diskless_store(self): |
2565 | - storage_dir = factory.make_name('storage') |
2566 | - self.patch(config, 'BOOT_RESOURCES_STORAGE', storage_dir) |
2567 | + storage_dir = self.make_dir() |
2568 | + current_dir = os.path.join(storage_dir, 'current') + '/' |
2569 | + os.mkdir(current_dir) |
2570 | + set_config_cluster_variable( |
2571 | + CLUSTER_CONFIG.DB_boot_resources_storage, |
2572 | + current_dir) |
2573 | self.assertEqual( |
2574 | os.path.join(storage_dir, 'diskless', 'store'), |
2575 | get_diskless_store()) |
2576 | @@ -241,7 +253,7 @@ |
2577 | '%s</target>\n' % entry |
2578 | for entry in tgt_output.split('</target>\n') |
2579 | if entry != "" |
2580 | - ]) |
2581 | + ]) |
2582 | |
2583 | def test_reload_diskless_tgt(self): |
2584 | tgt_path = factory.make_name('tgt_path') |
2585 | @@ -255,7 +267,7 @@ |
2586 | '/usr/sbin/tgt-admin', |
2587 | '--conf', tgt_path, |
2588 | '--update', 'ALL', |
2589 | - ])) |
2590 | + ])) |
2591 | |
2592 | def test_update_diskless_tgt_calls_atomic_write(self): |
2593 | tgt_path = factory.make_name('tgt_path') |
2594 | @@ -269,7 +281,7 @@ |
2595 | update_diskless_tgt() |
2596 | self.assertThat( |
2597 | mock_write, |
2598 | - MockCalledOnceWith(tgt_config, tgt_path, mode=0644)) |
2599 | + MockCalledOnceWith(tgt_config, tgt_path, mode=0o644)) |
2600 | |
2601 | |
2602 | class TestComposeSourcePath(MAASTestCase, DisklessTestMixin): |
2603 | @@ -299,7 +311,8 @@ |
2604 | mock_xi_params.return_value = (root_path, 'tgz') |
2605 | self.assertEqual( |
2606 | os.path.join( |
2607 | - config.BOOT_RESOURCES_STORAGE, 'current', os_name, |
2608 | + get_config_cluster_variable( |
2609 | + CLUSTER_CONFIG.DB_boot_resources_storage), os_name, |
2610 | arch, subarch, release, label, root_path), |
2611 | compose_source_path(os_name, arch, subarch, release, label)) |
2612 | |
2613 | @@ -337,7 +350,7 @@ |
2614 | driver_options = { |
2615 | factory.make_name('arg'): factory.make_name('value') |
2616 | for _ in range(3) |
2617 | - } |
2618 | + } |
2619 | create_diskless_disk( |
2620 | driver.name, driver_options, |
2621 | system_id, sentinel.osystem, sentinel.arch, |
2622 | @@ -451,7 +464,7 @@ |
2623 | driver_options = { |
2624 | factory.make_name('arg'): factory.make_name('value') |
2625 | for _ in range(3) |
2626 | - } |
2627 | + } |
2628 | delete_diskless_disk(driver.name, driver_options, system_id) |
2629 | self.assertThat( |
2630 | mock_delete, |
2631 | |
2632 | === modified file 'src/provisioningserver/tests/test_plugin.py' |
2633 | --- src/provisioningserver/tests/test_plugin.py 2015-04-29 06:19:04 +0000 |
2634 | +++ src/provisioningserver/tests/test_plugin.py 2015-05-04 14:27:25 +0000 |
2635 | @@ -7,7 +7,7 @@ |
2636 | absolute_import, |
2637 | print_function, |
2638 | unicode_literals, |
2639 | - ) |
2640 | +) |
2641 | |
2642 | str = None |
2643 | |
2644 | @@ -16,13 +16,16 @@ |
2645 | |
2646 | import os |
2647 | |
2648 | -from fixtures import EnvironmentVariableFixture |
2649 | -from maastesting.factory import factory |
2650 | from maastesting.testcase import ( |
2651 | MAASTestCase, |
2652 | MAASTwistedRunTest, |
2653 | ) |
2654 | import provisioningserver |
2655 | +from provisioningserver.cluster_config import ( |
2656 | + CLUSTER_CONFIG, |
2657 | + get_config_cluster_variable, |
2658 | + get_tftp_generator, |
2659 | +) |
2660 | from provisioningserver.plugin import ( |
2661 | Options, |
2662 | ProvisioningRealm, |
2663 | @@ -43,6 +46,7 @@ |
2664 | TFTPBackend, |
2665 | TFTPService, |
2666 | ) |
2667 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
2668 | from testtools.deferredruntest import assert_fails_with |
2669 | from testtools.matchers import ( |
2670 | AfterPreprocessing, |
2671 | @@ -56,7 +60,6 @@ |
2672 | from twisted.cred.error import UnauthorizedLogin |
2673 | from twisted.internet.defer import inlineCallbacks |
2674 | from twisted.web.resource import IResource |
2675 | -import yaml |
2676 | |
2677 | |
2678 | class TestOptions(MAASTestCase): |
2679 | @@ -64,7 +67,7 @@ |
2680 | |
2681 | def test_defaults(self): |
2682 | options = Options() |
2683 | - expected = {"config-file": "pserv.yaml", "introspect": None} |
2684 | + expected = {"config-file": "clusterd.conf", "introspect": None} |
2685 | self.assertEqual(expected, options.defaults) |
2686 | |
2687 | def test_parse_minimal_options(self): |
2688 | @@ -81,17 +84,9 @@ |
2689 | |
2690 | def setUp(self): |
2691 | super(TestProvisioningServiceMaker, self).setUp() |
2692 | + self.useFixture(ClusterConfigurationFixture()) |
2693 | self.patch(provisioningserver, "services", MultiService()) |
2694 | self.tempdir = self.make_dir() |
2695 | - self.useFixture( |
2696 | - EnvironmentVariableFixture( |
2697 | - "CLUSTER_UUID", factory.make_UUID())) |
2698 | - |
2699 | - def write_config(self, config): |
2700 | - config_filename = os.path.join(self.tempdir, "config.yaml") |
2701 | - with open(config_filename, "wb") as stream: |
2702 | - yaml.safe_dump(config, stream) |
2703 | - return config_filename |
2704 | |
2705 | def test_init(self): |
2706 | service_maker = ProvisioningServiceMaker("Harry", "Hill") |
2707 | @@ -103,14 +98,13 @@ |
2708 | Only the site service is created when no options are given. |
2709 | """ |
2710 | options = Options() |
2711 | - options["config-file"] = self.write_config({}) |
2712 | service_maker = ProvisioningServiceMaker("Harry", "Hill") |
2713 | service = service_maker.makeService(options) |
2714 | self.assertIsInstance(service, MultiService) |
2715 | expected_services = [ |
2716 | "dhcp_probe", "image_download", "lease_upload", |
2717 | "node_monitor", "rpc", "tftp", "image_service" |
2718 | - ] |
2719 | + ] |
2720 | self.assertItemsEqual(expected_services, service.namedServices) |
2721 | self.assertEqual( |
2722 | len(service.namedServices), len(service.services), |
2723 | @@ -119,7 +113,6 @@ |
2724 | |
2725 | def test_image_download_service(self): |
2726 | options = Options() |
2727 | - options["config-file"] = self.write_config({}) |
2728 | service_maker = ProvisioningServiceMaker("Harry", "Hill") |
2729 | service = service_maker.makeService(options) |
2730 | image_service = service.getServiceNamed("image_download") |
2731 | @@ -127,7 +120,6 @@ |
2732 | |
2733 | def test_node_monitor_service(self): |
2734 | options = Options() |
2735 | - options["config-file"] = self.write_config({}) |
2736 | service_maker = ProvisioningServiceMaker("Harry", "Hill") |
2737 | service = service_maker.makeService(options) |
2738 | node_monitor = service.getServiceNamed("node_monitor") |
2739 | @@ -135,7 +127,6 @@ |
2740 | |
2741 | def test_dhcp_probe_service(self): |
2742 | options = Options() |
2743 | - options["config-file"] = self.write_config({}) |
2744 | service_maker = ProvisioningServiceMaker("Spike", "Milligan") |
2745 | service = service_maker.makeService(options) |
2746 | dhcp_probe = service.getServiceNamed("dhcp_probe") |
2747 | @@ -143,15 +134,7 @@ |
2748 | |
2749 | def test_tftp_service(self): |
2750 | # A TFTP service is configured and added to the top-level service. |
2751 | - config = { |
2752 | - "tftp": { |
2753 | - "generator": "http://candlemass/solitude", |
2754 | - "resource_root": self.tempdir, |
2755 | - "port": factory.pick_port(), |
2756 | - }, |
2757 | - } |
2758 | options = Options() |
2759 | - options["config-file"] = self.write_config(config) |
2760 | service_maker = ProvisioningServiceMaker("Harry", "Hill") |
2761 | service = service_maker.makeService(options) |
2762 | tftp_service = service.getServiceNamed("tftp") |
2763 | @@ -161,24 +144,25 @@ |
2764 | IsInstance(TFTPBackend), |
2765 | AfterPreprocessing( |
2766 | lambda backend: backend.base.path, |
2767 | - Equals(config["tftp"]["resource_root"])), |
2768 | + Equals(os.path.split( |
2769 | + get_config_cluster_variable( |
2770 | + CLUSTER_CONFIG.DB_tftp_resource_root))[0])), |
2771 | AfterPreprocessing( |
2772 | lambda backend: backend.generator_url.geturl(), |
2773 | - Equals(config["tftp"]["generator"]))) |
2774 | + Equals(get_tftp_generator()))) |
2775 | |
2776 | self.assertThat( |
2777 | tftp_service, MatchesStructure( |
2778 | backend=expected_backend, |
2779 | - port=Equals(config["tftp"]["port"]), |
2780 | + port=Equals(get_config_cluster_variable( |
2781 | + CLUSTER_CONFIG.DB_tftpport)), |
2782 | )) |
2783 | |
2784 | def test_image_service(self): |
2785 | - from provisioningserver import config |
2786 | from twisted.web.server import Site |
2787 | from twisted.python.filepath import FilePath |
2788 | |
2789 | options = Options() |
2790 | - options["config-file"] = self.write_config({}) |
2791 | service_maker = ProvisioningServiceMaker("Harry", "Hill") |
2792 | service = service_maker.makeService(options) |
2793 | image_service = service.getServiceNamed("image_service") |
2794 | @@ -189,8 +173,9 @@ |
2795 | "images", request=None) |
2796 | self.assertThat(root, IsInstance(FilePath)) |
2797 | |
2798 | - resource_root = os.path.join( |
2799 | - config.BOOT_RESOURCES_STORAGE, "current") |
2800 | + resource_root = os.path.split( |
2801 | + get_config_cluster_variable( |
2802 | + CLUSTER_CONFIG.DB_tftp_resource_root))[0] |
2803 | |
2804 | self.assertEqual(resource_root, root.path) |
2805 | |
2806 | |
2807 | === modified file 'src/provisioningserver/tests/test_upgrade_cluster.py' |
2808 | --- src/provisioningserver/tests/test_upgrade_cluster.py 2015-03-25 15:33:23 +0000 |
2809 | +++ src/provisioningserver/tests/test_upgrade_cluster.py 2015-05-04 14:27:25 +0000 |
2810 | @@ -7,7 +7,7 @@ |
2811 | absolute_import, |
2812 | print_function, |
2813 | unicode_literals, |
2814 | - ) |
2815 | +) |
2816 | |
2817 | str = None |
2818 | |
2819 | @@ -27,11 +27,13 @@ |
2820 | from maastesting.testcase import MAASTestCase |
2821 | from maastesting.utils import sample_binary_data |
2822 | from mock import Mock |
2823 | -from provisioningserver import ( |
2824 | - config, |
2825 | - upgrade_cluster, |
2826 | -) |
2827 | +from provisioningserver import upgrade_cluster |
2828 | from provisioningserver.boot.tftppath import list_subdirs |
2829 | +from provisioningserver.cluster_config import ( |
2830 | + CLUSTER_CONFIG, |
2831 | + set_config_cluster_variable, |
2832 | +) |
2833 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
2834 | from provisioningserver.utils.fs import read_text_file |
2835 | from testtools.matchers import ( |
2836 | DirExists, |
2837 | @@ -86,9 +88,14 @@ |
2838 | class TestMakeMAASOwnBootResources(MAASTestCase): |
2839 | """Tests for the `make_maas_own_boot_resources` upgrade.""" |
2840 | |
2841 | + def setUp(self): |
2842 | + super(TestMakeMAASOwnBootResources, self).setUp() |
2843 | + self.useFixture(ClusterConfigurationFixture()) |
2844 | + |
2845 | def configure_storage(self, storage_dir): |
2846 | """Create a storage config.""" |
2847 | - self.patch(config, 'BOOT_RESOURCES_STORAGE', storage_dir) |
2848 | + set_config_cluster_variable( |
2849 | + CLUSTER_CONFIG.DB_boot_resources_storage, storage_dir) |
2850 | |
2851 | def test__calls_chown_if_boot_resources_dir_exists(self): |
2852 | self.patch(upgrade_cluster, 'check_call') |
2853 | @@ -102,7 +109,9 @@ |
2854 | def test__skips_chown_if_boot_resources_dir_does_not_exist(self): |
2855 | self.patch(upgrade_cluster, 'check_call') |
2856 | storage_dir = os.path.join(self.make_dir(), factory.make_name('none')) |
2857 | + os.mkdir(storage_dir) |
2858 | self.configure_storage(storage_dir) |
2859 | + os.rmdir(storage_dir) |
2860 | upgrade_cluster.make_maas_own_boot_resources() |
2861 | self.assertThat(upgrade_cluster.check_call, MockNotCalled()) |
2862 | |
2863 | @@ -203,12 +212,18 @@ |
2864 | class TestMigrateArchitecturesIntoUbuntuDirectory(MAASTestCase): |
2865 | """Tests for the `migrate_architectures_into_ubuntu_directory` upgrade.""" |
2866 | |
2867 | + def setUp(self): |
2868 | + super(TestMigrateArchitecturesIntoUbuntuDirectory, self).setUp() |
2869 | + self.useFixture(ClusterConfigurationFixture()) |
2870 | + |
2871 | def configure_storage(self, storage_dir, make_current_dir=True): |
2872 | """Create a storage config.""" |
2873 | - if make_current_dir: |
2874 | - current_dir = os.path.join(storage_dir, "current") |
2875 | - os.mkdir(current_dir) |
2876 | - self.patch(config, 'BOOT_RESOURCES_STORAGE', storage_dir) |
2877 | + current_dir = os.path.join(storage_dir, "current") |
2878 | + os.makedirs(current_dir) |
2879 | + set_config_cluster_variable( |
2880 | + CLUSTER_CONFIG.DB_boot_resources_storage, current_dir) |
2881 | + if not make_current_dir: |
2882 | + os.rmdir(current_dir) |
2883 | |
2884 | def test__list_subdirs_under_current_directory(self): |
2885 | self.patch(upgrade_cluster, 'list_subdirs').return_value = ['ubuntu'] |
2886 | |
2887 | === modified file 'src/provisioningserver/upgrade_cluster.py' |
2888 | --- src/provisioningserver/upgrade_cluster.py 2015-03-26 00:12:12 +0000 |
2889 | +++ src/provisioningserver/upgrade_cluster.py 2015-05-04 14:27:25 +0000 |
2890 | @@ -22,7 +22,7 @@ |
2891 | absolute_import, |
2892 | print_function, |
2893 | unicode_literals, |
2894 | - ) |
2895 | +) |
2896 | |
2897 | str = None |
2898 | |
2899 | @@ -30,7 +30,7 @@ |
2900 | __all__ = [ |
2901 | 'add_arguments', |
2902 | 'run', |
2903 | - ] |
2904 | +] |
2905 | |
2906 | import os |
2907 | from os import makedirs |
2908 | @@ -38,12 +38,15 @@ |
2909 | from subprocess import check_call |
2910 | from textwrap import dedent |
2911 | |
2912 | -from provisioningserver import config |
2913 | from provisioningserver.auth import get_maas_user_gpghome |
2914 | from provisioningserver.boot.tftppath import ( |
2915 | drill_down, |
2916 | list_subdirs, |
2917 | ) |
2918 | +from provisioningserver.cluster_config import ( |
2919 | + CLUSTER_CONFIG, |
2920 | + get_config_cluster_variable, |
2921 | +) |
2922 | from provisioningserver.import_images.boot_resources import ( |
2923 | update_targets_conf, |
2924 | write_targets_conf, |
2925 | @@ -57,8 +60,10 @@ |
2926 | def make_maas_own_boot_resources(): |
2927 | """Upgrade hook: make the `maas` user the owner of the boot resources.""" |
2928 | # This reduces the privileges required for importing and managing images. |
2929 | - if os.path.isdir(config.BOOT_RESOURCES_STORAGE): |
2930 | - check_call(['chown', '-R', 'maas', config.BOOT_RESOURCES_STORAGE]) |
2931 | + boot_resources_storage = get_config_cluster_variable( |
2932 | + CLUSTER_CONFIG.DB_boot_resources_storage) |
2933 | + if os.path.isdir(boot_resources_storage): |
2934 | + check_call(['chown', '-R', 'maas', boot_resources_storage]) |
2935 | |
2936 | |
2937 | def create_gnupg_home(): |
2938 | @@ -146,8 +151,8 @@ |
2939 | """Remove paths that contain directories with more levels. We don't want |
2940 | to move other operating systems under the ubuntu directory.""" |
2941 | for arch, subarch, release, label in paths: |
2942 | - path = os.path.join( |
2943 | - config.BOOT_RESOURCES_STORAGE, 'current', |
2944 | + path = os.path.join(get_config_cluster_variable( |
2945 | + CLUSTER_CONFIG.DB_boot_resources_storage), |
2946 | arch, subarch, release, label) |
2947 | if len(list_subdirs(path)) == 0: |
2948 | yield (arch, subarch, release, label) |
2949 | @@ -165,7 +170,8 @@ |
2950 | folders have structure arch/subarch/release/label and move them into |
2951 | ubuntu folder. Making the final path ubuntu/arch/subarch/release/label. |
2952 | """ |
2953 | - current_dir = os.path.join(config.BOOT_RESOURCES_STORAGE, "current") |
2954 | + current_dir = get_config_cluster_variable( |
2955 | + CLUSTER_CONFIG.DB_boot_resources_storage) |
2956 | if not os.path.isdir(current_dir): |
2957 | return |
2958 | # If ubuntu folder already exists, then no reason to continue |
2959 | @@ -213,7 +219,7 @@ |
2960 | create_gnupg_home, |
2961 | retire_bootresources_yaml, |
2962 | migrate_architectures_into_ubuntu_directory, |
2963 | - ] |
2964 | +] |
2965 | |
2966 | |
2967 | def add_arguments(parser): |
2968 | |
2969 | === modified file 'src/provisioningserver/utils/__init__.py' |
2970 | --- src/provisioningserver/utils/__init__.py 2015-03-30 18:05:57 +0000 |
2971 | +++ src/provisioningserver/utils/__init__.py 2015-05-04 14:27:25 +0000 |
2972 | @@ -97,7 +97,7 @@ |
2973 | """ |
2974 | # Avoid circular dependencies. |
2975 | from provisioningserver.rpc.region import CreateNode |
2976 | - from provisioningserver.cluster_config import get_cluster_uuid |
2977 | + from provisioningserver import cluster_config |
2978 | |
2979 | for elapsed, remaining, wait in retries(15, 5, reactor): |
2980 | try: |
2981 | @@ -116,7 +116,8 @@ |
2982 | try: |
2983 | response = yield client( |
2984 | CreateNode, |
2985 | - cluster_uuid=get_cluster_uuid(), |
2986 | + cluster_uuid=cluster_config.get_config_cluster_variable( |
2987 | + cluster_config.CLUSTER_CONFIG.DB_cluster_uuid), |
2988 | architecture=arch, |
2989 | power_type=power_type, |
2990 | power_parameters=json.dumps(power_parameters), |
2991 | |
2992 | === modified file 'src/provisioningserver/utils/script.py' |
2993 | --- src/provisioningserver/utils/script.py 2015-02-24 13:52:12 +0000 |
2994 | +++ src/provisioningserver/utils/script.py 2015-05-04 14:27:25 +0000 |
2995 | @@ -7,7 +7,7 @@ |
2996 | absolute_import, |
2997 | print_function, |
2998 | unicode_literals, |
2999 | - ) |
3000 | +) |
3001 | |
3002 | str = None |
3003 | |
3004 | @@ -16,7 +16,7 @@ |
3005 | 'ActionScript', |
3006 | 'AtomicWriteScript', |
3007 | 'MainScript', |
3008 | - ] |
3009 | +] |
3010 | |
3011 | from argparse import ArgumentParser |
3012 | from os import fdopen |
3013 | @@ -24,6 +24,7 @@ |
3014 | from subprocess import CalledProcessError |
3015 | import sys |
3016 | |
3017 | +from provisioningserver.config import ClusterConfiguration |
3018 | from provisioningserver.utils.fs import atomic_write |
3019 | |
3020 | |
3021 | @@ -92,20 +93,18 @@ |
3022 | |
3023 | The `--config-file` option defaults to the value of |
3024 | `MAAS_PROVISIONING_SETTINGS` in the process's environment, or absent |
3025 | - that, `$MAAS_CONFIG_DIR/pserv.yaml` (normally /etc/maas/pserv.yaml for |
3026 | - packaged installations, or when running from branch, the equivalent |
3027 | + that, or when running from branch, the equivalent |
3028 | inside that branch). |
3029 | """ |
3030 | |
3031 | def __init__(self, description): |
3032 | # Avoid circular imports. |
3033 | - from provisioningserver.config import Config |
3034 | |
3035 | super(MainScript, self).__init__(description) |
3036 | self.parser.add_argument( |
3037 | "-c", "--config-file", metavar="FILENAME", |
3038 | help="Configuration file to load [%(default)s].", |
3039 | - default=Config.DEFAULT_FILENAME) |
3040 | + default=ClusterConfiguration.default) |
3041 | |
3042 | |
3043 | class AtomicWriteScript: |
3044 | @@ -141,7 +140,7 @@ |
3045 | if args.mode is not None: |
3046 | mode = int(args.mode, 8) |
3047 | else: |
3048 | - mode = 0600 |
3049 | + mode = 0o600 |
3050 | atomic_write( |
3051 | content, args.filename, overwrite=not args.no_overwrite, |
3052 | mode=mode) |
3053 | |
3054 | === modified file 'src/provisioningserver/utils/tests/test_utils.py' |
3055 | --- src/provisioningserver/utils/tests/test_utils.py 2015-03-30 18:05:57 +0000 |
3056 | +++ src/provisioningserver/utils/tests/test_utils.py 2015-05-04 14:27:25 +0000 |
3057 | @@ -34,12 +34,17 @@ |
3058 | sentinel, |
3059 | ) |
3060 | import provisioningserver |
3061 | +from provisioningserver.cluster_config import ( |
3062 | + CLUSTER_CONFIG, |
3063 | + set_config_cluster_variable, |
3064 | +) |
3065 | from provisioningserver.rpc import region |
3066 | from provisioningserver.rpc.exceptions import ( |
3067 | CommissionNodeFailed, |
3068 | NodeAlreadyExists, |
3069 | ) |
3070 | from provisioningserver.rpc.testing import MockLiveClusterToRegionRPCFixture |
3071 | +from provisioningserver.testing.config import ClusterConfigurationFixture |
3072 | from provisioningserver.testing.testcase import PservTestCase |
3073 | import provisioningserver.utils |
3074 | from provisioningserver.utils import ( |
3075 | @@ -411,6 +416,10 @@ |
3076 | |
3077 | class TestCreateNode(PservTestCase): |
3078 | |
3079 | + def setUp(self): |
3080 | + super(TestCreateNode, self).setUp() |
3081 | + self.useFixture(ClusterConfigurationFixture()) |
3082 | + |
3083 | run_tests_with = MAASTwistedRunTest.make_factory(timeout=5) |
3084 | |
3085 | def prepare_region_rpc(self): |
3086 | @@ -438,14 +447,14 @@ |
3087 | 'power_control': None, |
3088 | 'system_id': uuid |
3089 | } |
3090 | - get_cluster_uuid = self.patch( |
3091 | - provisioningserver.cluster_config, 'get_cluster_uuid') |
3092 | - get_cluster_uuid.return_value = 'cluster-' + factory.make_UUID() |
3093 | + test_uuid = factory.make_UUID() |
3094 | + set_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid, test_uuid) |
3095 | + |
3096 | yield create_node( |
3097 | macs, arch, power_type, power_parameters, hostname=hostname) |
3098 | self.assertThat( |
3099 | protocol.CreateNode, MockCalledOnceWith( |
3100 | - protocol, cluster_uuid=get_cluster_uuid.return_value, |
3101 | + protocol, cluster_uuid=test_uuid, |
3102 | architecture=arch, power_type=power_type, |
3103 | power_parameters=json.dumps(power_parameters), |
3104 | mac_addresses=macs, hostname=hostname)) |
3105 | @@ -483,9 +492,9 @@ |
3106 | system_id = factory.make_name("system-id") |
3107 | protocol.CreateNode.return_value = defer.succeed( |
3108 | {"system_id": system_id}) |
3109 | - get_cluster_uuid = self.patch( |
3110 | - provisioningserver.cluster_config, 'get_cluster_uuid') |
3111 | - get_cluster_uuid.return_value = 'cluster-' + factory.make_UUID() |
3112 | + |
3113 | + test_uuid = factory.make_UUID() |
3114 | + set_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid, test_uuid) |
3115 | |
3116 | uuid = 'node-' + factory.make_UUID() |
3117 | arch = factory.make_name('architecture') |
3118 | @@ -506,7 +515,7 @@ |
3119 | macs_with_duplicate, arch, power_type, power_parameters) |
3120 | self.assertThat( |
3121 | protocol.CreateNode, MockCalledOnceWith( |
3122 | - protocol, cluster_uuid=get_cluster_uuid.return_value, |
3123 | + protocol, cluster_uuid=test_uuid, |
3124 | architecture=arch, power_type=power_type, |
3125 | power_parameters=json.dumps(power_parameters), |
3126 | mac_addresses=macs, hostname=None)) |
3127 | @@ -517,9 +526,6 @@ |
3128 | self.addCleanup((yield connecting)) |
3129 | system_id = factory.make_name("system-id") |
3130 | maaslog = self.patch(provisioningserver.utils, 'maaslog') |
3131 | - get_cluster_uuid = self.patch( |
3132 | - provisioningserver.utils, 'get_cluster_uuid') |
3133 | - get_cluster_uuid.return_value = 'cluster-' + factory.make_UUID() |
3134 | |
3135 | uuid = 'node-' + factory.make_UUID() |
3136 | macs = sorted(factory.make_mac_address() for _ in range(3)) |
There's a minor conflict in src/provisionin gserver/ plugin. py.