Merge lp:~ubuntudotcom1/maas/kill-all-the-configs-cluster into lp:maas/trunk

Proposed by ubuntudotcom1 on 2015-04-01
Status: Merged
Merged at revision: 4066
Proposed branch: lp:~ubuntudotcom1/maas/kill-all-the-configs-cluster
Merge into: lp: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
Reviewer Review Type Date Requested Status
Gavin Panella (community) 2015-04-01 Approve on 2015-04-27
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.
3633. By ubuntudotcom1 on 2015-04-02

Merge.

3634. By ubuntudotcom1 on 2015-04-09

Merge trunk.

3635. By ubuntudotcom1 on 2015-04-10

Minor cleanup.

3636. By ubuntudotcom1 on 2015-04-10

Merge trunk.

3637. By ubuntudotcom1 on 2015-04-10

Merge -region.

3638. By ubuntudotcom1 on 2015-04-10

Removed last refs to config.BOOT_RESOURCES_STORAGE, and fixed tests that patched config.BOOT_RESOURCES_STORAGE.

3639. By ubuntudotcom1 on 2015-04-17

.gitignore.

Gavin Panella (allenap) wrote :

There's a minor conflict in src/provisioningserver/plugin.py.

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
3640. By ubuntudotcom1 on 2015-05-04

Merge -region.

3641. By ubuntudotcom1 on 2015-05-04

Address comments.

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))