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

Proposed by ubuntudotcom1
Status: Merged
Merged at revision: 4066
Proposed branch: lp:~ubuntudotcom1/maas/kill-all-the-configs-cluster
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~ubuntudotcom1/maas/kill-all-the-configs-region
Diff against target: 3136 lines (+512/-861)
37 files modified
.gitignore (+2/-0)
etc/demo_maas_cluster.conf (+0/-8)
etc/maas/pserv.yaml (+0/-24)
etc/maas_cluster.conf (+0/-5)
services/clusterd/run (+0/-5)
setup.py (+1/-3)
src/maasserver/clusterrpc/tests/test_boot_images.py (+19/-5)
src/provisioningserver/__main__.py (+3/-0)
src/provisioningserver/boot/install_grub.py (+8/-5)
src/provisioningserver/boot/tests/test_install_grub.py (+11/-4)
src/provisioningserver/boot/tests/test_tftppath.py (+16/-9)
src/provisioningserver/boot/tftppath.py (+11/-6)
src/provisioningserver/cluster_config.py (+7/-41)
src/provisioningserver/config.py (+0/-31)
src/provisioningserver/diskless.py (+16/-8)
src/provisioningserver/drivers/osystem/custom.py (+8/-5)
src/provisioningserver/drivers/osystem/tests/test_custom.py (+14/-6)
src/provisioningserver/import_images/boot_resources.py (+20/-6)
src/provisioningserver/import_images/tests/test_boot_resources.py (+26/-16)
src/provisioningserver/plugin.py (+26/-24)
src/provisioningserver/pserv_services/tests/test_tftp.py (+11/-7)
src/provisioningserver/pserv_services/tftp.py (+8/-4)
src/provisioningserver/rpc/boot_images.py (+11/-7)
src/provisioningserver/rpc/clusterservice.py (+12/-11)
src/provisioningserver/rpc/tags.py (+20/-5)
src/provisioningserver/rpc/tests/test_boot_images.py (+17/-6)
src/provisioningserver/rpc/tests/test_clusterservice.py (+46/-33)
src/provisioningserver/rpc/tests/test_tags.py (+16/-7)
src/provisioningserver/tests/test_cluster_config.py (+72/-31)
src/provisioningserver/tests/test_config.py (+0/-453)
src/provisioningserver/tests/test_diskless.py (+26/-13)
src/provisioningserver/tests/test_plugin.py (+19/-34)
src/provisioningserver/tests/test_upgrade_cluster.py (+25/-10)
src/provisioningserver/upgrade_cluster.py (+15/-9)
src/provisioningserver/utils/__init__.py (+3/-2)
src/provisioningserver/utils/script.py (+6/-7)
src/provisioningserver/utils/tests/test_utils.py (+17/-11)
To merge this branch: bzr merge lp:~ubuntudotcom1/maas/kill-all-the-configs-cluster
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+254970@code.launchpad.net

Commit message

Config changes applied according to new config backend in -cluster-admin. branch.

Description of the change

Config changes applied according to new config backend in -cluster-admin. branch.

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

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

Revision history for this message
Gavin Panella (allenap) wrote :

Looks good. I have a few comments, but they're not blockers.

I am interested in what your plan is for upgrading from pserv.yaml. Is that entirely happening in packaging?

review: Approve
Revision history for this message
Gavin Panella (allenap) wrote :

This has been superseded by lp:~allenap/maas/kill-all-the-configs-cluster (which builds on this).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.gitignore'
--- .gitignore 2015-04-10 09:45:46 +0000
+++ .gitignore 2015-05-04 14:27:25 +0000
@@ -22,6 +22,8 @@
22/docs/_autosummary22/docs/_autosummary
23/docs/_build23/docs/_build
24/docs/api.rst24/docs/api.rst
25/etc/maas/regiond.conf
26/etc/maas/clusterd.conf
25/eggs27/eggs
26/include28/include
27/lib29/lib
2830
=== removed file 'etc/demo_maas_cluster.conf'
--- etc/demo_maas_cluster.conf 2015-03-12 18:13:14 +0000
+++ etc/demo_maas_cluster.conf 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
1# This is the version of maas_cluster.conf that's used when running from a
2# branch. The region controller will serve HTTP on a different port from a
3# packaged MAAS, and the master cluster controller (running on the same
4# development machine) has a fixed UUID.
5# It is also carefully crafted so it works as both a bash script and a
6# Python script.
7MAAS_URL="http://0.0.0.0:5240/MAAS/"
8CLUSTER_UUID="adfd3977-f251-4f2c-8d61-745dbd690bf2"
90
=== removed file 'etc/maas/pserv.yaml'
--- etc/maas/pserv.yaml 2015-04-24 13:27:39 +0000
+++ etc/maas/pserv.yaml 1970-01-01 00:00:00 +0000
@@ -1,24 +0,0 @@
1##
2## Provisioning Server (pserv) configuration.
3##
4
5## Where to log. This log can be rotated by sending SIGUSR1 to the
6## running server.
7#
8# logfile: "pserv.log"
9logfile: "/dev/null"
10
11## TFTP configuration.
12#
13tftp:
14 # The "root" setting has been replaced by "resource_root". The old setting
15 # is used one final time when upgrading a pre-14.04 cluster controller to a
16 # 14.04 version. After that upgrade, it can be removed.
17 #
18 # resource_root: /var/lib/maas/boot-resources/current/
19
20 # port: 69
21 port: 5244
22 ## The URL to be contacted to generate PXE configurations.
23 # generator: http://localhost/MAAS/api/1.0/pxeconfig/
24 generator: http://localhost:5240/MAAS/api/1.0/pxeconfig/
250
=== removed file 'etc/maas_cluster.conf'
--- etc/maas_cluster.conf 2015-03-12 18:13:14 +0000
+++ etc/maas_cluster.conf 1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
1# This file is used by the cluster controller startup script:
2# `maas-provision start-cluster-controller`
3# to get the URL to the MAAS region controller's API. Normally, packaging
4# will update this file automatically but it may also be configured manually.
5MAAS_URL=http://localhost/MAAS
60
=== modified file 'services/clusterd/run'
--- services/clusterd/run 2015-04-10 09:45:46 +0000
+++ services/clusterd/run 2015-05-04 14:27:25 +0000
@@ -21,11 +21,6 @@
21script="$(readlink -f bin/twistd.cluster)"21script="$(readlink -f bin/twistd.cluster)"
22config="$(readlink -f etc/maas/pserv.yaml)"22config="$(readlink -f etc/maas/pserv.yaml)"
2323
24# Obtain the development setting for CLUSTER_UUID.
25. etc/demo_maas_cluster.conf
26export CLUSTER_UUID
27export MAAS_URL
28
29exec $(command -v authbind && echo --deep) \24exec $(command -v authbind && echo --deep) \
30 "${script}" --nodaemon --pidfile="" maas-clusterd \25 "${script}" --nodaemon --pidfile="" maas-clusterd \
31 --introspect="unix:${here}/introspect:lockfile=0" \26 --introspect="unix:${here}/introspect:lockfile=0" \
3227
=== modified file 'setup.py'
--- setup.py 2015-05-04 14:27:25 +0000
+++ setup.py 2015-05-04 14:27:25 +0000
@@ -64,9 +64,7 @@
6464
65 data_files=[65 data_files=[
66 ('/etc/maas',66 ('/etc/maas',
67 ['etc/maas/pserv.yaml',67 ['etc/maas/drivers.yaml',
68 'etc/maas/drivers.yaml',
69 'etc/maas_cluster.conf',
70 'contrib/maas-http.conf']),68 'contrib/maas-http.conf']),
71 ('/etc/maas/templates/uefi',69 ('/etc/maas/templates/uefi',
72 glob('etc/maas/templates/uefi/*.template')),70 glob('etc/maas/templates/uefi/*.template')),
7371
=== modified file 'src/maasserver/clusterrpc/tests/test_boot_images.py'
--- src/maasserver/clusterrpc/tests/test_boot_images.py 2015-03-25 15:33:23 +0000
+++ src/maasserver/clusterrpc/tests/test_boot_images.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -37,6 +37,10 @@
37 compose_image_path,37 compose_image_path,
38 locate_tftp_path,38 locate_tftp_path,
39)39)
40from provisioningserver.cluster_config import (
41 CLUSTER_CONFIG,
42 set_config_cluster_variable,
43)
40from provisioningserver.rpc import (44from provisioningserver.rpc import (
41 boot_images,45 boot_images,
42 clusterservice,46 clusterservice,
@@ -45,6 +49,7 @@
45 make_boot_image_storage_params,49 make_boot_image_storage_params,
46 make_image,50 make_image,
47)51)
52from provisioningserver.testing.config import ClusterConfigurationFixture
48from twisted.internet.defer import succeed53from twisted.internet.defer import succeed
4954
5055
@@ -141,11 +146,14 @@
141146
142 def setUp(self):147 def setUp(self):
143 super(TestGetBootImages, self).setUp()148 super(TestGetBootImages, self).setUp()
149 self.useFixture(ClusterConfigurationFixture())
144 resource_dir = self.make_dir()150 resource_dir = self.make_dir()
145 self.tftproot = os.path.join(resource_dir, 'current')151 self.tftproot = os.path.join(resource_dir, 'current')
146 os.mkdir(self.tftproot)152 os.mkdir(self.tftproot)
147 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)153 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)
148 self.patch(boot_images, 'BOOT_RESOURCES_STORAGE', resource_dir)154 set_config_cluster_variable(
155 CLUSTER_CONFIG.DB_boot_resources_storage,
156 self.tftproot)
149157
150 def test_returns_boot_images(self):158 def test_returns_boot_images(self):
151 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED)159 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED)
@@ -170,11 +178,14 @@
170178
171 def setUp(self):179 def setUp(self):
172 super(TestGetAvailableBootImages, self).setUp()180 super(TestGetAvailableBootImages, self).setUp()
181 self.useFixture(ClusterConfigurationFixture())
173 resource_dir = self.make_dir()182 resource_dir = self.make_dir()
174 self.tftproot = os.path.join(resource_dir, 'current')183 self.tftproot = os.path.join(resource_dir, 'current')
175 os.mkdir(self.tftproot)184 os.mkdir(self.tftproot)
176 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)185 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)
177 self.patch(boot_images, 'BOOT_RESOURCES_STORAGE', resource_dir)186 set_config_cluster_variable(
187 CLUSTER_CONFIG.DB_boot_resources_storage,
188 self.tftproot)
178189
179 def test_returns_boot_images_for_one_cluster(self):190 def test_returns_boot_images_for_one_cluster(self):
180 factory.make_NodeGroup().accept()191 factory.make_NodeGroup().accept()
@@ -260,11 +271,14 @@
260271
261 def setUp(self):272 def setUp(self):
262 super(TestGetBootImagesFor, self).setUp()273 super(TestGetBootImagesFor, self).setUp()
274 self.useFixture(ClusterConfigurationFixture())
263 resource_dir = self.make_dir()275 resource_dir = self.make_dir()
264 self.tftproot = os.path.join(resource_dir, 'current')276 self.tftproot = os.path.join(resource_dir, 'current')
265 os.mkdir(self.tftproot)277 os.mkdir(self.tftproot)
266 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)278 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)
267 self.patch(boot_images, 'BOOT_RESOURCES_STORAGE', resource_dir)279 set_config_cluster_variable(
280 CLUSTER_CONFIG.DB_boot_resources_storage,
281 self.tftproot)
268282
269 def make_boot_images(self):283 def make_boot_images(self):
270 purposes = ['install', 'commissioning', 'xinstall']284 purposes = ['install', 'commissioning', 'xinstall']
@@ -279,7 +293,7 @@
279 return [293 return [
280 make_image(param, purpose)294 make_image(param, purpose)
281 for purpose in purposes295 for purpose in purposes
282 ]296 ]
283297
284 def test_returns_boot_images_matching_subarchitecture(self):298 def test_returns_boot_images_matching_subarchitecture(self):
285 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED)299 nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED)
286300
=== modified file 'src/provisioningserver/__main__.py'
--- src/provisioningserver/__main__.py 2015-03-30 18:05:57 +0000
+++ src/provisioningserver/__main__.py 2015-05-04 14:27:25 +0000
@@ -14,6 +14,7 @@
1414
15__metaclass__ = type15__metaclass__ = type
1616
17
17from provisioningserver import security18from provisioningserver import security
18import provisioningserver.boot.install_bootloader19import provisioningserver.boot.install_bootloader
19import provisioningserver.boot.install_grub20import provisioningserver.boot.install_grub
@@ -42,6 +43,8 @@
4243
4344
44main = MainScript(__doc__)45main = MainScript(__doc__)
46
47
45for name, command in sorted(script_commands.items()):48for name, command in sorted(script_commands.items()):
46 main.register(name, command)49 main.register(name, command)
47main()50main()
4851
=== modified file 'src/provisioningserver/boot/install_grub.py'
--- src/provisioningserver/boot/install_grub.py 2015-02-24 20:11:09 +0000
+++ src/provisioningserver/boot/install_grub.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -15,12 +15,15 @@
15__all__ = [15__all__ = [
16 "add_arguments",16 "add_arguments",
17 "run",17 "run",
18 ]18]
1919
20import os.path20import os.path
2121
22from provisioningserver.boot.install_bootloader import make_destination22from provisioningserver.boot.install_bootloader import make_destination
23from provisioningserver.config import Config23from provisioningserver.cluster_config import (
24 CLUSTER_CONFIG,
25 get_config_cluster_variable,
26)
24from provisioningserver.utils.fs import write_text_file27from provisioningserver.utils.fs import write_text_file
2528
2629
@@ -44,7 +47,7 @@
44 """Install a GRUB2 pre-boot loader config into the TFTP47 """Install a GRUB2 pre-boot loader config into the TFTP
45 directory structure.48 directory structure.
46 """49 """
47 config = Config.load(args.config_file)50 grubroot = os.path.join(get_config_cluster_variable(
48 grubroot = os.path.join(config["tftp"]["resource_root"], 'grub')51 CLUSTER_CONFIG.DB_tftp_resource_root), 'grub')
49 destination_path = make_destination(grubroot)52 destination_path = make_destination(grubroot)
50 write_text_file(os.path.join(destination_path, 'grub.cfg'), CONFIG_FILE)53 write_text_file(os.path.join(destination_path, 'grub.cfg'), CONFIG_FILE)
5154
=== modified file 'src/provisioningserver/boot/tests/test_install_grub.py'
--- src/provisioningserver/boot/tests/test_install_grub.py 2014-08-13 21:49:35 +0000
+++ src/provisioningserver/boot/tests/test_install_grub.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -20,7 +20,11 @@
20from maastesting.testcase import MAASTestCase20from maastesting.testcase import MAASTestCase
21import provisioningserver.boot.install_grub21import provisioningserver.boot.install_grub
22from provisioningserver.boot.tftppath import locate_tftp_path22from provisioningserver.boot.tftppath import locate_tftp_path
23from provisioningserver.testing.config import set_tftp_root23from provisioningserver.cluster_config import (
24 CLUSTER_CONFIG,
25 set_config_cluster_variable,
26)
27from provisioningserver.testing.config import ClusterConfigurationFixture
24from provisioningserver.utils.script import MainScript28from provisioningserver.utils.script import MainScript
25from testtools.matchers import FileExists29from testtools.matchers import FileExists
2630
@@ -28,14 +32,17 @@
28class TestInstallGrub(MAASTestCase):32class TestInstallGrub(MAASTestCase):
2933
30 def test_integration(self):34 def test_integration(self):
35 self.useFixture(ClusterConfigurationFixture())
31 tftproot = self.make_dir()36 tftproot = self.make_dir()
32 config_fixture = self.useFixture(set_tftp_root(tftproot))37 set_config_cluster_variable(
38 CLUSTER_CONFIG.DB_tftp_resource_root,
39 tftproot)
3340
34 action = factory.make_name("action")41 action = factory.make_name("action")
35 script = MainScript(action)42 script = MainScript(action)
36 script.register(action, provisioningserver.boot.install_grub)43 script.register(action, provisioningserver.boot.install_grub)
37 script.execute(44 script.execute(
38 ("--config-file", config_fixture.filename, action))45 ("--config-file", "clusterd.conf", action))
3946
40 config_filename = os.path.join('grub', 'grub.cfg')47 config_filename = os.path.join('grub', 'grub.cfg')
41 self.assertThat(48 self.assertThat(
4249
=== modified file 'src/provisioningserver/boot/tests/test_tftppath.py'
--- src/provisioningserver/boot/tests/test_tftppath.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/boot/tests/test_tftppath.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -21,7 +21,6 @@
21from maastesting.matchers import MockCalledOnceWith21from maastesting.matchers import MockCalledOnceWith
22from maastesting.testcase import MAASTestCase22from maastesting.testcase import MAASTestCase
23from mock import Mock23from mock import Mock
24from provisioningserver import config
25from provisioningserver.boot import tftppath24from provisioningserver.boot import tftppath
26from provisioningserver.boot.tftppath import (25from provisioningserver.boot.tftppath import (
27 compose_image_path,26 compose_image_path,
@@ -35,6 +34,10 @@
35 locate_tftp_path,34 locate_tftp_path,
36 maas_meta_last_modified,35 maas_meta_last_modified,
37)36)
37from provisioningserver.cluster_config import (
38 CLUSTER_CONFIG,
39 get_config_cluster_variable,
40)
38from provisioningserver.drivers.osystem import OperatingSystemRegistry41from provisioningserver.drivers.osystem import OperatingSystemRegistry
39from provisioningserver.import_images.boot_image_mapping import (42from provisioningserver.import_images.boot_image_mapping import (
40 BootImageMapping,43 BootImageMapping,
@@ -48,7 +51,10 @@
48 make_boot_image_storage_params,51 make_boot_image_storage_params,
49 make_image,52 make_image,
50)53)
51from provisioningserver.testing.config import set_tftp_root54from provisioningserver.testing.config import (
55 ClusterConfigurationFixture,
56 set_tftp_root,
57)
52from provisioningserver.testing.os import make_osystem58from provisioningserver.testing.os import make_osystem
53from testtools.matchers import (59from testtools.matchers import (
54 Not,60 Not,
@@ -102,12 +108,13 @@
102 self.assertIsNone(observed)108 self.assertIsNone(observed)
103109
104 def test_maas_meta_last_modified_defaults_tftproot(self):110 def test_maas_meta_last_modified_defaults_tftproot(self):
111 self.useFixture(ClusterConfigurationFixture())
105 path = factory.make_file(self.tftproot, name="maas.meta")112 path = factory.make_file(self.tftproot, name="maas.meta")
106 maas_meta_file_path = self.patch(tftppath, 'maas_meta_file_path')113 maas_meta_file_path = self.patch(tftppath, 'maas_meta_file_path')
107 maas_meta_file_path.return_value = path114 maas_meta_file_path.return_value = path
108 maas_meta_last_modified()115 maas_meta_last_modified()
109 expected_path = os.path.join(116 expected_path = get_config_cluster_variable(
110 config.BOOT_RESOURCES_STORAGE, 'current')117 CLUSTER_CONFIG.DB_tftp_resource_root)
111 self.assertThat(maas_meta_file_path, MockCalledOnceWith(expected_path))118 self.assertThat(maas_meta_file_path, MockCalledOnceWith(expected_path))
112119
113 def test_maas_meta_last_modified_reraises_non_ENOENT(self):120 def test_maas_meta_last_modified_reraises_non_ENOENT(self):
@@ -299,7 +306,7 @@
299 resource = dict(306 resource = dict(
300 subarches=factory.make_name("subarch"),307 subarches=factory.make_name("subarch"),
301 other_item=factory.make_name("other"),308 other_item=factory.make_name("other"),
302 )309 )
303 image = make_image_spec()310 image = make_image_spec()
304 mapping = set_resource(image_spec=image, resource=resource)311 mapping = set_resource(image_spec=image, resource=resource)
305 metadata = mapping.dump_json()312 metadata = mapping.dump_json()
@@ -313,7 +320,7 @@
313 "subarchitecture": image.subarch,320 "subarchitecture": image.subarch,
314 "release": image.release,321 "release": image.release,
315 "label": image.label,322 "label": image.label,
316 }323 }
317 extracted_data = extract_metadata(metadata, params)324 extracted_data = extract_metadata(metadata, params)
318325
319 # We only expect the supported_subarches key from the resource data.326 # We only expect the supported_subarches key from the resource data.
@@ -323,7 +330,7 @@
323 def test_extract_metadata_handles_missing_subarch(self):330 def test_extract_metadata_handles_missing_subarch(self):
324 resource = dict(331 resource = dict(
325 other_item=factory.make_name("other"),332 other_item=factory.make_name("other"),
326 )333 )
327 image = make_image_spec()334 image = make_image_spec()
328 mapping = set_resource(image_spec=image, resource=resource)335 mapping = set_resource(image_spec=image, resource=resource)
329 metadata = mapping.dump_json()336 metadata = mapping.dump_json()
@@ -337,7 +344,7 @@
337 "subarchitecture": image.subarch,344 "subarchitecture": image.subarch,
338 "release": image.release,345 "release": image.release,
339 "label": image.label,346 "label": image.label,
340 }347 }
341 self.assertEqual({}, extract_metadata(metadata, params))348 self.assertEqual({}, extract_metadata(metadata, params))
342349
343 def _make_path(self):350 def _make_path(self):
344351
=== modified file 'src/provisioningserver/boot/tftppath.py'
--- src/provisioningserver/boot/tftppath.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/boot/tftppath.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -17,13 +17,16 @@
17 'list_boot_images',17 'list_boot_images',
18 'list_subdirs',18 'list_subdirs',
19 'locate_tftp_path',19 'locate_tftp_path',
20 ]20]
2121
22import errno22import errno
23from itertools import chain23from itertools import chain
24import os.path24import os.path
2525
26from provisioningserver import config26from provisioningserver.cluster_config import (
27 CLUSTER_CONFIG,
28 get_config_cluster_variable,
29)
27from provisioningserver.drivers.osystem import (30from provisioningserver.drivers.osystem import (
28 BOOT_IMAGE_PURPOSE,31 BOOT_IMAGE_PURPOSE,
29 OperatingSystemRegistry,32 OperatingSystemRegistry,
@@ -137,7 +140,7 @@
137 subarch=params["subarchitecture"],140 subarch=params["subarchitecture"],
138 release=params["release"],141 release=params["release"],
139 label=params["label"],142 label=params["label"],
140 )143 )
141 try:144 try:
142 # On upgrade from 1.5 to 1.6, the subarches does not exist in the145 # On upgrade from 1.5 to 1.6, the subarches does not exist in the
143 # maas.meta file . Without this catch boot images will fail to146 # maas.meta file . Without this catch boot images will fail to
@@ -206,10 +209,12 @@
206 or None if the file doesn't exist.209 or None if the file doesn't exist.
207210
208 :param tftproot: Optional tftp root dir, defaults to211 :param tftproot: Optional tftp root dir, defaults to
209 provisioningserver.config.BOOT_RESOURCES_STORAGE212 'tftp-root' in the cluster Config backend. Please refer to the
213 'maas-provision config --tftp-root' command to set this directory
210 """214 """
211 if tftproot is None:215 if tftproot is None:
212 tftproot = os.path.join(config.BOOT_RESOURCES_STORAGE, 'current')216 tftproot = get_config_cluster_variable(
217 CLUSTER_CONFIG.DB_tftp_resource_root)
213 meta_file = maas_meta_file_path(tftproot)218 meta_file = maas_meta_file_path(tftproot)
214 try:219 try:
215 return os.path.getmtime(meta_file)220 return os.path.getmtime(meta_file)
216221
=== modified file 'src/provisioningserver/cluster_config.py'
--- src/provisioningserver/cluster_config.py 2015-04-02 18:44:12 +0000
+++ src/provisioningserver/cluster_config.py 2015-05-04 14:27:25 +0000
@@ -13,13 +13,10 @@
1313
14__metaclass__ = type14__metaclass__ = type
15__all__ = [15__all__ = [
16 'get_cluster_uuid',
17 'get_maas_url',
18 "get_cluster_variable",
19 "get_config_cluster_variable",16 "get_config_cluster_variable",
20 "set_config_cluster_variable", ]17 "get_tftp_generator",
2118 "set_config_cluster_variable",
22from os import environ19 "CLUSTER_CONFIG", ]
2320
24from provisioningserver.config import ClusterConfiguration21from provisioningserver.config import ClusterConfiguration
2522
@@ -34,7 +31,7 @@
34 DB_tftpport = 'tftp_port'31 DB_tftpport = 'tftp_port'
3532
3633
37# New get function for ClusterConfiguration backend34# Get function for ClusterConfiguration backend
38def get_config_cluster_variable(var):35def get_config_cluster_variable(var):
39 """Obtain the given environment variable from clusterd config"""36 """Obtain the given environment variable from clusterd config"""
40 with ClusterConfiguration.open() as config:37 with ClusterConfiguration.open() as config:
@@ -52,37 +49,6 @@
52 """Return the `tftp_generator` setting, which is49 """Return the `tftp_generator` setting, which is
53 <maas url>/api/1.0/pxeconfig/50 <maas url>/api/1.0/pxeconfig/
54 """51 """
55 return '/'.join(get_cluster_variable(CLUSTER_CONFIG.DB_maas_url),52 return '/'.join((
56 'api', '1.0', 'pxeconfig')53 get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url),
5754 'api', '1.0', 'pxeconfig'))
58
59# Old get function for config file (via env variables) backend,
60# to be removed in follow-up branch. This branch is a prerequisite branch for
61# a follow-up branch, where this function will be removed. Both
62# the new and old versions of this function have been included
63# in this intermediate branch at the request of the package
64# maintainers.
65def get_cluster_variable(var):
66 """Obtain the given environment variable from maas_cluster.conf.
67
68 If the variable is not set, it probably means that whatever script
69 started the current process neglected to run maas_cluster.conf.
70 In that case, fail helpfully but utterly.
71 """
72 value = environ.get(var)
73 if value is None:
74 raise AssertionError(
75 "%s is not set. This probably means that the script which "
76 "started this program failed to source maas_cluster.conf."
77 % var)
78 return value
79
80
81def get_cluster_uuid():
82 """Return the `CLUSTER_UUID` setting."""
83 return get_cluster_variable('CLUSTER_UUID')
84
85
86def get_maas_url():
87 """Return the `MAAS_URL` setting."""
88 return get_cluster_variable('MAAS_URL')
8955
=== modified file 'src/provisioningserver/config.py'
--- src/provisioningserver/config.py 2015-04-04 00:40:18 +0000
+++ src/provisioningserver/config.py 2015-05-04 14:27:25 +0000
@@ -52,7 +52,6 @@
5252
53__metaclass__ = type53__metaclass__ = type
54__all__ = [54__all__ = [
55 "BOOT_RESOURCES_STORAGE",
56 "BootSources",55 "BootSources",
57 "Config",56 "Config",
58 "ConfigBase",57 "ConfigBase",
@@ -100,11 +99,6 @@
100)99)
101import yaml100import yaml
102101
103# Path to the directory on the cluster controller where boot resources are
104# stored. This used to be configurable in bootresources.yaml, and may become
105# configurable again in the future.
106BOOT_RESOURCES_STORAGE = '/var/lib/maas/boot-resources/'
107
108# Default result for cluster UUID if not set102# Default result for cluster UUID if not set
109UUID_NOT_SET = '** UUID NOT SET **'103UUID_NOT_SET = '** UUID NOT SET **'
110104
@@ -205,30 +199,6 @@
205 vhost = String(if_missing="/")199 vhost = String(if_missing="/")
206200
207201
208class ConfigTFTP(Schema):
209 """Configuration validator for the TFTP service."""
210
211 if_key_missing = None
212
213 # Obsolete: old TFTP root directory. This is retained for the purpose of
214 # deriving new, Simplestreams-based import configuration from previously
215 # imported boot images.
216 # The last time this is needed is for upgrading an older cluster
217 # controller to the Ubuntu 14.04 version of MAAS. After installation of
218 # the 14.04 version, this setting is never used.
219 root = String(if_missing="/var/lib/maas/tftp")
220
221 # TFTP root directory, managed by the Simplestreams-based import script.
222 # The import script maintains "current" as a symlink pointing to the most
223 # recent images.
224 # XXX jtv 2014-05-22: Redundant with BOOT_RESOURCES_STORAGE.
225 resource_root = String(
226 if_missing=os.path.join(BOOT_RESOURCES_STORAGE, 'current/'))
227
228 port = Int(min=1, max=65535, if_missing=69)
229 generator = String(if_missing=b"http://localhost/MAAS/api/1.0/pxeconfig/")
230
231
232class ConfigLegacyEphemeral(Schema):202class ConfigLegacyEphemeral(Schema):
233 """Legacy `ephemeral` section in `pserv.yaml` prior to MAAS 1.5.203 """Legacy `ephemeral` section in `pserv.yaml` prior to MAAS 1.5.
234204
@@ -415,7 +385,6 @@
415 logfile = String(if_empty=b"pserv.log", if_missing=b"pserv.log")385 logfile = String(if_empty=b"pserv.log", if_missing=b"pserv.log")
416 oops = ConfigOops386 oops = ConfigOops
417 broker = ConfigBroker387 broker = ConfigBroker
418 tftp = ConfigTFTP
419 rpc = ConfigRPC388 rpc = ConfigRPC
420 boot = ConfigLegacyBoot389 boot = ConfigLegacyBoot
421390
422391
=== modified file 'src/provisioningserver/diskless.py'
--- src/provisioningserver/diskless.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/diskless.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -15,17 +15,21 @@
15__all__ = [15__all__ = [
16 'create_diskless_disk',16 'create_diskless_disk',
17 'delete_diskless_disk',17 'delete_diskless_disk',
18 ]18]
1919
20import os20import os
21from textwrap import dedent21from textwrap import dedent
2222
23from provisioningserver import config23from provisioningserver.cluster_config import (
24 CLUSTER_CONFIG,
25 get_config_cluster_variable,
26)
24from provisioningserver.drivers.diskless import DisklessDriverRegistry27from provisioningserver.drivers.diskless import DisklessDriverRegistry
25from provisioningserver.drivers.osystem import (28from provisioningserver.drivers.osystem import (
26 BOOT_IMAGE_PURPOSE,29 BOOT_IMAGE_PURPOSE,
27 OperatingSystemRegistry,30 OperatingSystemRegistry,
28)31)
32from provisioningserver.import_images.boot_resources import two_dir_levels_up
29from provisioningserver.logger import get_maas_logger33from provisioningserver.logger import get_maas_logger
30from provisioningserver.utils.fs import (34from provisioningserver.utils.fs import (
31 atomic_symlink,35 atomic_symlink,
@@ -48,7 +52,8 @@
48 currently in use disk for diskless booting.52 currently in use disk for diskless booting.
49 """53 """
50 return os.path.join(54 return os.path.join(
51 config.BOOT_RESOURCES_STORAGE, 'diskless', 'store')55 two_dir_levels_up(get_config_cluster_variable(
56 CLUSTER_CONFIG.DB_boot_resources_storage)), 'diskless', 'store')
5257
5358
54def compose_diskless_link_path(system_id):59def compose_diskless_link_path(system_id):
@@ -100,7 +105,9 @@
100def get_diskless_tgt_path():105def get_diskless_tgt_path():
101 """Return path to maas-diskless.tgt."""106 """Return path to maas-diskless.tgt."""
102 return os.path.join(107 return os.path.join(
103 config.BOOT_RESOURCES_STORAGE, 'diskless', 'maas-diskless.tgt')108 two_dir_levels_up(get_config_cluster_variable(
109 CLUSTER_CONFIG.DB_boot_resources_storage)),
110 'diskless', 'maas-diskless.tgt')
104111
105112
106def tgt_entry(system_id, image):113def tgt_entry(system_id, image):
@@ -145,7 +152,7 @@
145 '/usr/sbin/tgt-admin',152 '/usr/sbin/tgt-admin',
146 '--conf', get_diskless_tgt_path(),153 '--conf', get_diskless_tgt_path(),
147 '--update', 'ALL',154 '--update', 'ALL',
148 ])155 ])
149156
150157
151def update_diskless_tgt():158def update_diskless_tgt():
@@ -153,7 +160,7 @@
153 symlinks in the diskless store. Reloads the tgt config."""160 symlinks in the diskless store. Reloads the tgt config."""
154 tgt_path = get_diskless_tgt_path()161 tgt_path = get_diskless_tgt_path()
155 tgt_config = compose_diskless_tgt_config()162 tgt_config = compose_diskless_tgt_config()
156 atomic_write(tgt_config, tgt_path, mode=0644)163 atomic_write(tgt_config, tgt_path, mode=0o644)
157 reload_diskless_tgt()164 reload_diskless_tgt()
158165
159166
@@ -184,7 +191,8 @@
184 "OS doesn't support diskless booting: %s" % osystem_name)191 "OS doesn't support diskless booting: %s" % osystem_name)
185 root_path, _ = osystem.get_xinstall_parameters()192 root_path, _ = osystem.get_xinstall_parameters()
186 return os.path.join(193 return os.path.join(
187 config.BOOT_RESOURCES_STORAGE, 'current',194 get_config_cluster_variable(
195 CLUSTER_CONFIG.DB_boot_resources_storage),
188 osystem_name, arch, subarch, release, label, root_path)196 osystem_name, arch, subarch, release, label, root_path)
189197
190198
191199
=== modified file 'src/provisioningserver/drivers/osystem/custom.py'
--- src/provisioningserver/drivers/osystem/custom.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/drivers/osystem/custom.py 2015-05-04 14:27:25 +0000
@@ -7,18 +7,21 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
14__metaclass__ = type14__metaclass__ = type
15__all__ = [15__all__ = [
16 "CustomOS",16 "CustomOS",
17 ]17]
1818
19import os19import os
2020
21from provisioningserver.config import BOOT_RESOURCES_STORAGE21from provisioningserver.cluster_config import (
22 CLUSTER_CONFIG,
23 get_config_cluster_variable,
24)
22from provisioningserver.drivers.osystem import (25from provisioningserver.drivers.osystem import (
23 BOOT_IMAGE_PURPOSE,26 BOOT_IMAGE_PURPOSE,
24 OperatingSystem,27 OperatingSystem,
@@ -55,8 +58,8 @@
5558
56 def get_xinstall_parameters(self, arch, subarch, release, label):59 def get_xinstall_parameters(self, arch, subarch, release, label):
57 """Returns the xinstall image name and type for given image."""60 """Returns the xinstall image name and type for given image."""
58 path = os.path.join(61 path = os.path.join(get_config_cluster_variable(
59 BOOT_RESOURCES_STORAGE, 'current', 'custom',62 CLUSTER_CONFIG.DB_boot_resources_storage), 'custom',
60 arch, subarch, release, label)63 arch, subarch, release, label)
61 if os.path.exists(os.path.join(path, 'root-dd')):64 if os.path.exists(os.path.join(path, 'root-dd')):
62 return "root-dd", "dd-tgz"65 return "root-dd", "dd-tgz"
6366
=== modified file 'src/provisioningserver/drivers/osystem/tests/test_custom.py'
--- src/provisioningserver/drivers/osystem/tests/test_custom.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/drivers/osystem/tests/test_custom.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -19,26 +19,34 @@
1919
20from maastesting.factory import factory20from maastesting.factory import factory
21from maastesting.testcase import MAASTestCase21from maastesting.testcase import MAASTestCase
22from provisioningserver.drivers.osystem import custom22from provisioningserver.cluster_config import (
23 CLUSTER_CONFIG,
24 set_config_cluster_variable,
25)
23from provisioningserver.drivers.osystem.custom import (26from provisioningserver.drivers.osystem.custom import (
24 BOOT_IMAGE_PURPOSE,27 BOOT_IMAGE_PURPOSE,
25 CustomOS,28 CustomOS,
26)29)
30from provisioningserver.testing.config import ClusterConfigurationFixture
2731
2832
29class TestCustomOS(MAASTestCase):33class TestCustomOS(MAASTestCase):
3034
31 def make_resource_path(self, filename):35 def make_resource_path(self, filename):
36 self.useFixture(ClusterConfigurationFixture())
32 tmpdir = self.make_dir()37 tmpdir = self.make_dir()
33 arch = factory.make_name('arch')38 arch = factory.make_name('arch')
34 subarch = factory.make_name('subarch')39 subarch = factory.make_name('subarch')
35 release = factory.make_name('release')40 release = factory.make_name('release')
36 label = factory.make_name('label')41 label = factory.make_name('label')
42 current_dir = os.path.join(tmpdir, 'current') + '/'
37 dirpath = os.path.join(43 dirpath = os.path.join(
38 tmpdir, 'current', 'custom', arch, subarch, release, label)44 current_dir, 'custom', arch, subarch, release, label)
39 os.makedirs(dirpath)45 os.makedirs(dirpath)
40 factory.make_file(dirpath, filename)46 factory.make_file(dirpath, filename)
41 self.patch(custom, 'BOOT_RESOURCES_STORAGE', tmpdir)47 set_config_cluster_variable(
48 CLUSTER_CONFIG.DB_boot_resources_storage,
49 current_dir)
42 return arch, subarch, release, label50 return arch, subarch, release, label
4351
44 def test_get_boot_image_purposes(self):52 def test_get_boot_image_purposes(self):
@@ -54,7 +62,7 @@
54 self.assertIsInstance(expected, list)62 self.assertIsInstance(expected, list)
55 self.assertEqual(expected, [63 self.assertEqual(expected, [
56 BOOT_IMAGE_PURPOSE.XINSTALL,64 BOOT_IMAGE_PURPOSE.XINSTALL,
57 ])65 ])
5866
59 def test_is_release_supported(self):67 def test_is_release_supported(self):
60 osystem = CustomOS()68 osystem = CustomOS()
@@ -62,7 +70,7 @@
62 supported = [70 supported = [
63 osystem.is_release_supported(release)71 osystem.is_release_supported(release)
64 for release in releases72 for release in releases
65 ]73 ]
66 self.assertEqual([True, True, True], supported)74 self.assertEqual([True, True, True], supported)
6775
68 def test_get_default_release(self):76 def test_get_default_release(self):
6977
=== modified file 'src/provisioningserver/import_images/boot_resources.py'
--- src/provisioningserver/import_images/boot_resources.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/import_images/boot_resources.py 2015-05-04 14:27:25 +0000
@@ -5,7 +5,7 @@
5 absolute_import,5 absolute_import,
6 print_function,6 print_function,
7 unicode_literals,7 unicode_literals,
8 )8)
99
10str = None10str = None
1111
@@ -15,16 +15,19 @@
15 'main',15 'main',
16 'main_with_services',16 'main_with_services',
17 'make_arg_parser',17 'make_arg_parser',
18 ]18]
1919
20from argparse import ArgumentParser20from argparse import ArgumentParser
21import errno21import errno
22import os22import os
23from textwrap import dedent23from textwrap import dedent
2424
25import provisioningserver
26from provisioningserver.boot import BootMethodRegistry25from provisioningserver.boot import BootMethodRegistry
27from provisioningserver.boot.tftppath import list_boot_images26from provisioningserver.boot.tftppath import list_boot_images
27from provisioningserver.cluster_config import (
28 CLUSTER_CONFIG,
29 get_config_cluster_variable,
30)
28from provisioningserver.config import BootSources31from provisioningserver.config import BootSources
29from provisioningserver.import_images.cleanup import (32from provisioningserver.import_images.cleanup import (
30 cleanup_snapshots_and_cache,33 cleanup_snapshots_and_cache,
@@ -48,6 +51,16 @@
48from provisioningserver.utils.shell import call_and_check51from provisioningserver.utils.shell import call_and_check
4952
5053
54def two_dir_levels_up(path):
55 # NOTE: Syntax along the lines of:
56 # os.path.normpath(os.path.join(
57 # path, os.path.pardir, os.path.pardir))
58 # will NOT work here, as the classes that use these file paths
59 # to NOT support paths with 'os.path.pardir' segments. Thus
60 # we must manually resolve the path here.
61 return os.path.split(os.path.split(path)[0])[0]
62
63
51class NoConfigFile(Exception):64class NoConfigFile(Exception):
52 """Raised when the config file for the script doesn't exist."""65 """Raised when the config file for the script doesn't exist."""
5366
@@ -81,7 +94,7 @@
81 subarch,94 subarch,
82 release,95 release,
83 label96 label
84 )97 )
85 entry = dedent("""\98 entry = dedent("""\
86 <target {prefix}:{target_name}>99 <target {prefix}:{target_name}>
87 readonly 1100 readonly 1
@@ -191,7 +204,7 @@
191 '/usr/sbin/tgt-admin',204 '/usr/sbin/tgt-admin',
192 '--conf', targets_conf,205 '--conf', targets_conf,
193 '--update', 'ALL',206 '--update', 'ALL',
194 ])207 ])
195208
196209
197def read_sources(sources_yaml):210def read_sources(sources_yaml):
@@ -245,7 +258,8 @@
245 "any boot images available.")258 "any boot images available.")
246 return259 return
247260
248 storage = provisioningserver.config.BOOT_RESOURCES_STORAGE261 storage = two_dir_levels_up(get_config_cluster_variable(
262 CLUSTER_CONFIG.DB_boot_resources_storage))
249 meta_file_content = image_descriptions.dump_json()263 meta_file_content = image_descriptions.dump_json()
250 if meta_contains(storage, meta_file_content):264 if meta_contains(storage, meta_file_content):
251 maaslog.info(265 maaslog.info(
252266
=== modified file 'src/provisioningserver/import_images/tests/test_boot_resources.py'
--- src/provisioningserver/import_images/tests/test_boot_resources.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/import_images/tests/test_boot_resources.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -39,14 +39,20 @@
39import mock39import mock
40from mock import call40from mock import call
41from provisioningserver.boot import BootMethodRegistry41from provisioningserver.boot import BootMethodRegistry
42import provisioningserver.config42from provisioningserver.cluster_config import (
43 CLUSTER_CONFIG,
44 set_config_cluster_variable,
45)
43from provisioningserver.config import BootSources46from provisioningserver.config import BootSources
44from provisioningserver.import_images import boot_resources47from provisioningserver.import_images import boot_resources
45from provisioningserver.import_images.boot_image_mapping import (48from provisioningserver.import_images.boot_image_mapping import (
46 BootImageMapping,49 BootImageMapping,
47)50)
48from provisioningserver.import_images.testing.factory import make_image_spec51from provisioningserver.import_images.testing.factory import make_image_spec
49from provisioningserver.testing.config import BootSourcesFixture52from provisioningserver.testing.config import (
53 BootSourcesFixture,
54 ClusterConfigurationFixture,
55)
50from provisioningserver.utils.fs import write_text_file56from provisioningserver.utils.fs import write_text_file
51from testtools.content import Content57from testtools.content import Content
52from testtools.content_type import UTF8_TEXT58from testtools.content_type import UTF8_TEXT
@@ -195,9 +201,13 @@
195201
196 def setUp(self):202 def setUp(self):
197 super(TestMain, self).setUp()203 super(TestMain, self).setUp()
204 self.useFixture(ClusterConfigurationFixture())
198 self.storage = self.make_dir()205 self.storage = self.make_dir()
199 self.patch(206 current_dir = os.path.join(self.storage, 'current') + os.sep
200 provisioningserver.config, 'BOOT_RESOURCES_STORAGE', self.storage)207 os.makedirs(current_dir)
208 set_config_cluster_variable(CLUSTER_CONFIG.DB_boot_resources_storage,
209 current_dir)
210 os.rmdir(current_dir)
201 # Forcing arch to amd64 causes pxelinux.0 to be installed, giving more211 # Forcing arch to amd64 causes pxelinux.0 to be installed, giving more
202 # test coverage.212 # test coverage.
203 self.image = make_image_spec(arch='amd64')213 self.image = make_image_spec(arch='amd64')
@@ -232,9 +242,9 @@
232 'updated': 'Tue, 25 Mar 2014 16:19:49 +0000',242 'updated': 'Tue, 25 Mar 2014 16:19:49 +0000',
233 'format': 'products:1.0',243 'format': 'products:1.0',
234 'products': [product],244 'products': [product],
235 },
236 },245 },
237 }246 },
247 }
238 write_text_file(index_file, json.dumps(index))248 write_text_file(index_file, json.dumps(index))
239 return index_file249 return index_file
240250
@@ -251,7 +261,7 @@
251 image_spec.release,261 image_spec.release,
252 image_spec.subarch,262 image_spec.subarch,
253 filename,263 filename,
254 ]264 ]
255 native_path = os.path.join(repo, *path)265 native_path = os.path.join(repo, *path)
256 os.makedirs(os.path.dirname(native_path))266 os.makedirs(os.path.dirname(native_path))
257 contents = ("Contents: %s" % filename).encode('utf-8')267 contents = ("Contents: %s" % filename).encode('utf-8')
@@ -318,7 +328,7 @@
318 os_release = '%d.%.2s' % (328 os_release = '%d.%.2s' % (
319 randint(1, 99),329 randint(1, 99),
320 ('04' if randint(0, 1) == 0 else '10'),330 ('04' if randint(0, 1) == 0 else '10'),
321 )331 )
322 repo = self.make_dir()332 repo = self.make_dir()
323 index_dir = os.path.join(repo, 'streams', 'v1')333 index_dir = os.path.join(repo, 'streams', 'v1')
324 os.makedirs(index_dir)334 os.makedirs(index_dir)
@@ -327,7 +337,7 @@
327 os_release,337 os_release,
328 image_spec.arch,338 image_spec.arch,
329 image_spec.subarch,339 image_spec.subarch,
330 )340 )
331 version = '20140317'341 version = '20140317'
332 download_file, sha = self.make_download_file(repo, image_spec, version)342 download_file, sha = self.make_download_file(repo, image_spec, version)
333 self.make_simplestreams_product_index(343 self.make_simplestreams_product_index(
@@ -350,9 +360,9 @@
350 'subarches': [self.subarch],360 'subarches': [self.subarch],
351 'labels': [self.label],361 'labels': [self.label],
352 },362 },
353 ],363 ],
354 },364 },
355 ]365 ]
356 sources_file = self.make_file(366 sources_file = self.make_file(
357 'sources.yaml', contents=yaml.safe_dump(sources))367 'sources.yaml', contents=yaml.safe_dump(sources))
358 return self.make_args(sources_file=sources_file)368 return self.make_args(sources_file=sources_file)
@@ -541,9 +551,9 @@
541 'subarches': [factory.make_name("subarch")],551 'subarches': [factory.make_name("subarch")],
542 'labels': [factory.make_name("label")],552 'labels': [factory.make_name("label")],
543 },553 },
544 ],554 ],
545 },555 },
546 ]556 ]
547 parsed_sources = boot_resources.parse_sources(yaml.safe_dump(sources))557 parsed_sources = boot_resources.parse_sources(yaml.safe_dump(sources))
548 self.assertEqual(sources, parsed_sources)558 self.assertEqual(sources, parsed_sources)
549559
@@ -577,9 +587,9 @@
577 'subarches': [factory.make_name("subarch")],587 'subarches': [factory.make_name("subarch")],
578 'labels': [factory.make_name("label")],588 'labels': [factory.make_name("label")],
579 },589 },
580 ],590 ],
581 },591 },
582 ],592 ],
583 boot_resources.import_images(sources)593 boot_resources.import_images(sources)
584 self.assertThat(594 self.assertThat(
585 fake_write_all_keyrings, MockCalledWith(mock.ANY, sources))595 fake_write_all_keyrings, MockCalledWith(mock.ANY, sources))
586596
=== modified file 'src/provisioningserver/plugin.py'
--- src/provisioningserver/plugin.py 2015-04-29 06:19:04 +0000
+++ src/provisioningserver/plugin.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -17,10 +17,14 @@
17]17]
1818
19from errno import ENOPROTOOPT19from errno import ENOPROTOOPT
20import os
21import socket20import socket
22from socket import error as socket_error21from socket import error as socket_error
2322
23from provisioningserver.cluster_config import (
24 CLUSTER_CONFIG,
25 get_config_cluster_variable,
26 get_tftp_generator,
27)
24from provisioningserver.utils.debug import (28from provisioningserver.utils.debug import (
25 register_sigusr2_thread_dump_handler,29 register_sigusr2_thread_dump_handler,
26)30)
@@ -93,7 +97,7 @@
93 """Command line options for the provisioning server."""97 """Command line options for the provisioning server."""
9498
95 optParameters = [99 optParameters = [
96 ["config-file", "c", "pserv.yaml", "Configuration file to load."],100 ["config-file", "c", "clusterd.conf", "Configuration file to load."],
97 ["introspect", None, None,101 ["introspect", None, None,
98 ("Allow introspection, allowing unhindered access to the internals "102 ("Allow introspection, allowing unhindered access to the internals "
99 "of MAAS. This should probably only be used for debugging. Supply "103 "of MAAS. This should probably only be used for debugging. Supply "
@@ -128,8 +132,6 @@
128 from provisioningserver.pserv_services.image import (132 from provisioningserver.pserv_services.image import (
129 BootImageEndpointService)133 BootImageEndpointService)
130 from twisted.internet.endpoints import AdoptedStreamServerEndpoint134 from twisted.internet.endpoints import AdoptedStreamServerEndpoint
131 from provisioningserver import config
132
133 port = 5248 # config["port"]135 port = 5248 # config["port"]
134 # Make a socket with SO_REUSEPORT set so that we can run multiple we136 # Make a socket with SO_REUSEPORT set so that we can run multiple we
135 # applications. This is easier to do from outside of Twisted as there's137 # applications. This is easier to do from outside of Twisted as there's
@@ -157,59 +159,58 @@
157 site_endpoint.socket = s # Prevent garbage collection.159 site_endpoint.socket = s # Prevent garbage collection.
158160
159 image_service = BootImageEndpointService(161 image_service = BootImageEndpointService(
160 resource_root=os.path.join(162 resource_root=get_config_cluster_variable(
161 config.BOOT_RESOURCES_STORAGE, "current"),163 CLUSTER_CONFIG.DB_boot_resources_storage),
162 endpoint=site_endpoint)164 endpoint=site_endpoint)
163 image_service.setName("image_service")165 image_service.setName("image_service")
164 return image_service166 return image_service
165167
166 def _makeTFTPService(self, tftp_config):168 def _makeTFTPService(self, tftp_root, tftp_port, tftp_generator):
167 """Create the dynamic TFTP service."""169 """Create the dynamic TFTP service."""
168 from provisioningserver.pserv_services.tftp import TFTPService170 from provisioningserver.pserv_services.tftp import TFTPService
169 tftp_service = TFTPService(171 tftp_service = TFTPService(
170 resource_root=tftp_config['resource_root'],172 resource_root=tftp_root, port=tftp_port, generator=tftp_generator)
171 port=tftp_config['port'], generator=tftp_config['generator'])
172 tftp_service.setName("tftp")173 tftp_service.setName("tftp")
173 return tftp_service174 return tftp_service
174175
175 def _makeImageDownloadService(self, rpc_service):176 def _makeImageDownloadService(self, rpc_service):
176 from provisioningserver.cluster_config import get_cluster_uuid
177 from provisioningserver.pserv_services.image_download_service \177 from provisioningserver.pserv_services.image_download_service \
178 import ImageDownloadService178 import ImageDownloadService
179 image_download_service = ImageDownloadService(179 image_download_service = ImageDownloadService(
180 rpc_service, reactor, get_cluster_uuid())180 rpc_service, reactor, get_config_cluster_variable(
181 CLUSTER_CONFIG.DB_cluster_uuid))
181 image_download_service.setName("image_download")182 image_download_service.setName("image_download")
182 return image_download_service183 return image_download_service
183184
184 def _makeLeaseUploadService(self, rpc_service):185 def _makeLeaseUploadService(self, rpc_service):
185 from provisioningserver.cluster_config import get_cluster_uuid
186 from provisioningserver.pserv_services.lease_upload_service \186 from provisioningserver.pserv_services.lease_upload_service \
187 import LeaseUploadService187 import LeaseUploadService
188 lease_upload_service = LeaseUploadService(188 lease_upload_service = LeaseUploadService(
189 rpc_service, reactor, get_cluster_uuid())189 rpc_service, reactor, get_config_cluster_variable(
190 CLUSTER_CONFIG.DB_cluster_uuid))
190 lease_upload_service.setName("lease_upload")191 lease_upload_service.setName("lease_upload")
191 return lease_upload_service192 return lease_upload_service
192193
193 def _makeNodePowerMonitorService(self):194 def _makeNodePowerMonitorService(self):
194 from provisioningserver.cluster_config import get_cluster_uuid
195 from provisioningserver.pserv_services.node_power_monitor_service \195 from provisioningserver.pserv_services.node_power_monitor_service \
196 import NodePowerMonitorService196 import NodePowerMonitorService
197 node_monitor = NodePowerMonitorService(get_cluster_uuid(), reactor)197 node_monitor = NodePowerMonitorService(get_config_cluster_variable(
198 CLUSTER_CONFIG.DB_cluster_uuid), reactor)
198 node_monitor.setName("node_monitor")199 node_monitor.setName("node_monitor")
199 return node_monitor200 return node_monitor
200201
201 def _makeRPCService(self, rpc_config):202 def _makeRPCService(self):
202 from provisioningserver.rpc.clusterservice import ClusterClientService203 from provisioningserver.rpc.clusterservice import ClusterClientService
203 rpc_service = ClusterClientService(reactor)204 rpc_service = ClusterClientService(reactor)
204 rpc_service.setName("rpc")205 rpc_service.setName("rpc")
205 return rpc_service206 return rpc_service
206207
207 def _makeDHCPProbeService(self, rpc_service):208 def _makeDHCPProbeService(self, rpc_service):
208 from provisioningserver.cluster_config import get_cluster_uuid
209 from provisioningserver.pserv_services.dhcp_probe_service \209 from provisioningserver.pserv_services.dhcp_probe_service \
210 import DHCPProbeService210 import DHCPProbeService
211 dhcp_probe_service = DHCPProbeService(211 dhcp_probe_service = DHCPProbeService(
212 rpc_service, reactor, get_cluster_uuid())212 rpc_service, reactor,
213 get_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid))
213 dhcp_probe_service.setName("dhcp_probe")214 dhcp_probe_service.setName("dhcp_probe")
214 return dhcp_probe_service215 return dhcp_probe_service
215216
@@ -226,17 +227,18 @@
226 register_sigusr2_thread_dump_handler()227 register_sigusr2_thread_dump_handler()
227228
228 from provisioningserver import services229 from provisioningserver import services
229 from provisioningserver.config import Config
230
231 config = Config.load(options["config-file"])
232230
233 image_service = self._makeImageService()231 image_service = self._makeImageService()
234 image_service.setServiceParent(services)232 image_service.setServiceParent(services)
235233
236 tftp_service = self._makeTFTPService(config["tftp"])234 tftp_service = self._makeTFTPService(
235 get_config_cluster_variable(CLUSTER_CONFIG.DB_tftp_resource_root),
236 get_config_cluster_variable(CLUSTER_CONFIG.DB_tftpport),
237 get_tftp_generator())
238
237 tftp_service.setServiceParent(services)239 tftp_service.setServiceParent(services)
238240
239 rpc_service = self._makeRPCService(config["rpc"])241 rpc_service = self._makeRPCService()
240 rpc_service.setServiceParent(services)242 rpc_service.setServiceParent(services)
241243
242 node_monitor = self._makeNodePowerMonitorService()244 node_monitor = self._makeNodePowerMonitorService()
243245
=== modified file 'src/provisioningserver/pserv_services/tests/test_tftp.py'
--- src/provisioningserver/pserv_services/tests/test_tftp.py 2015-04-24 20:41:48 +0000
+++ src/provisioningserver/pserv_services/tests/test_tftp.py 2015-05-04 14:27:25 +0000
@@ -30,7 +30,6 @@
30 urlparse,30 urlparse,
31)31)
3232
33from fixtures import EnvironmentVariable
34from maastesting.factory import factory33from maastesting.factory import factory
35from maastesting.matchers import (34from maastesting.matchers import (
36 MockCalledOnceWith,35 MockCalledOnceWith,
@@ -50,6 +49,7 @@
50 IPV4_LINK_LOCAL,49 IPV4_LINK_LOCAL,
51 IPV6_LINK_LOCAL,50 IPV6_LINK_LOCAL,
52)51)
52from provisioningserver import cluster_config
53from provisioningserver.boot import BytesReader53from provisioningserver.boot import BytesReader
54from provisioningserver.boot.pxe import PXEBootMethod54from provisioningserver.boot.pxe import PXEBootMethod
55from provisioningserver.boot.tests.test_pxe import compose_config_path55from provisioningserver.boot.tests.test_pxe import compose_config_path
@@ -63,6 +63,7 @@
63 UDPServer,63 UDPServer,
64)64)
65from provisioningserver.rpc.testing import TwistedLoggerFixture65from provisioningserver.rpc.testing import TwistedLoggerFixture
66from provisioningserver.testing.config import ClusterConfigurationFixture
66from provisioningserver.tests.test_kernel_opts import make_kernel_parameters67from provisioningserver.tests.test_kernel_opts import make_kernel_parameters
67from testtools import ExpectedException68from testtools import ExpectedException
68from testtools.matchers import (69from testtools.matchers import (
@@ -127,6 +128,7 @@
127128
128 def setUp(self):129 def setUp(self):
129 super(TestTFTPBackend, self).setUp()130 super(TestTFTPBackend, self).setUp()
131 self.useFixture(ClusterConfigurationFixture())
130 from provisioningserver import boot132 from provisioningserver import boot
131 self.patch(boot, "find_mac_via_arp")133 self.patch(boot, "find_mac_via_arp")
132 self.patch(tftp_module, 'log_request')134 self.patch(tftp_module, 'log_request')
@@ -219,7 +221,8 @@
219221
220 @inlineCallbacks222 @inlineCallbacks
221 def test_get_reader_converts_404s_to_tftp_error(self):223 def test_get_reader_converts_404s_to_tftp_error(self):
222 self.useFixture(EnvironmentVariable("CLUSTER_UUID", "foobar"))224 cluster_config.set_config_cluster_variable(
225 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, factory.make_UUID())
223226
224 backend = TFTPBackend(self.make_dir(), "http://example.com/")227 backend = TFTPBackend(self.make_dir(), "http://example.com/")
225 get_page = self.patch(backend, 'get_page')228 get_page = self.patch(backend, 'get_page')
@@ -230,7 +233,8 @@
230233
231 @inlineCallbacks234 @inlineCallbacks
232 def test_get_reader_converts_other_exceptions_to_tftp_error(self):235 def test_get_reader_converts_other_exceptions_to_tftp_error(self):
233 self.useFixture(EnvironmentVariable("CLUSTER_UUID", "foobar"))236 cluster_config.set_config_cluster_variable(
237 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, factory.make_UUID())
234238
235 exception_type = factory.make_exception_type()239 exception_type = factory.make_exception_type()
236 exception_message = factory.make_string()240 exception_message = factory.make_string()
@@ -257,8 +261,8 @@
257 # For paths matching PXEBootMethod.match_path, TFTPBackend.get_reader()261 # For paths matching PXEBootMethod.match_path, TFTPBackend.get_reader()
258 # returns a Deferred that will yield a BytesReader.262 # returns a Deferred that will yield a BytesReader.
259 cluster_uuid = factory.make_UUID()263 cluster_uuid = factory.make_UUID()
260 get_cluster_uuid = self.patch(tftp_module, 'get_cluster_uuid')264 cluster_config.set_config_cluster_variable(
261 get_cluster_uuid.return_value = cluster_uuid265 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, cluster_uuid)
262 mac = factory.make_mac_address("-")266 mac = factory.make_mac_address("-")
263 config_path = compose_config_path(mac)267 config_path = compose_config_path(mac)
264 backend = TFTPBackend(self.make_dir(), b"http://example.com/")268 backend = TFTPBackend(self.make_dir(), b"http://example.com/")
@@ -356,8 +360,8 @@
356 # arch field of the parameters (mapping from pxe to maas360 # arch field of the parameters (mapping from pxe to maas
357 # namespace).361 # namespace).
358 cluster_uuid = factory.make_UUID()362 cluster_uuid = factory.make_UUID()
359 get_cluster_uuid = self.patch(tftp_module, 'get_cluster_uuid')363 cluster_config.set_config_cluster_variable(
360 get_cluster_uuid.return_value = cluster_uuid364 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, cluster_uuid)
361 config_path = "pxelinux.cfg/default-arm"365 config_path = "pxelinux.cfg/default-arm"
362 backend = TFTPBackend(self.make_dir(), b"http://example.com/")366 backend = TFTPBackend(self.make_dir(), b"http://example.com/")
363 # python-tx-tftp sets up call context so that backends can discover367 # python-tx-tftp sets up call context so that backends can discover
364368
=== modified file 'src/provisioningserver/pserv_services/tftp.py'
--- src/provisioningserver/pserv_services/tftp.py 2015-04-24 20:39:18 +0000
+++ src/provisioningserver/pserv_services/tftp.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -15,7 +15,7 @@
15__all__ = [15__all__ = [
16 "TFTPBackend",16 "TFTPBackend",
17 "TFTPService",17 "TFTPService",
18 ]18]
1919
20from functools import partial20from functools import partial
21import httplib21import httplib
@@ -35,7 +35,10 @@
35 BootMethodRegistry,35 BootMethodRegistry,
36 get_remote_mac,36 get_remote_mac,
37)37)
38from provisioningserver.cluster_config import get_cluster_uuid38from provisioningserver.cluster_config import (
39 CLUSTER_CONFIG,
40 get_config_cluster_variable,
41)
39from provisioningserver.drivers import ArchitectureRegistry42from provisioningserver.drivers import ArchitectureRegistry
40from provisioningserver.events import (43from provisioningserver.events import (
41 EVENT_TYPES,44 EVENT_TYPES,
@@ -223,7 +226,8 @@
223 params["local"] = local_host226 params["local"] = local_host
224 remote_host, remote_port = tftp.get_remote_address()227 remote_host, remote_port = tftp.get_remote_address()
225 params["remote"] = remote_host228 params["remote"] = remote_host
226 params["cluster_uuid"] = get_cluster_uuid()229 params["cluster_uuid"] = get_config_cluster_variable(
230 CLUSTER_CONFIG.DB_cluster_uuid)
227 d = self.get_boot_method_reader(boot_method, params)231 d = self.get_boot_method_reader(boot_method, params)
228 return d232 return d
229233
230234
=== modified file 'src/provisioningserver/rpc/boot_images.py'
--- src/provisioningserver/rpc/boot_images.py 2015-02-24 13:52:12 +0000
+++ src/provisioningserver/rpc/boot_images.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -16,15 +16,17 @@
16 "import_boot_images",16 "import_boot_images",
17 "list_boot_images",17 "list_boot_images",
18 "is_import_boot_images_running",18 "is_import_boot_images_running",
19 ]19]
2020
21import os
22from urlparse import urlparse21from urlparse import urlparse
2322
24from provisioningserver import concurrency23from provisioningserver import concurrency
25from provisioningserver.auth import get_maas_user_gpghome24from provisioningserver.auth import get_maas_user_gpghome
26from provisioningserver.boot import tftppath25from provisioningserver.boot import tftppath
27from provisioningserver.config import BOOT_RESOURCES_STORAGE26from provisioningserver.cluster_config import (
27 CLUSTER_CONFIG,
28 get_config_cluster_variable,
29)
28from provisioningserver.import_images import boot_resources30from provisioningserver.import_images import boot_resources
29from provisioningserver.utils.env import environment_variables31from provisioningserver.utils.env import environment_variables
30from provisioningserver.utils.twisted import synchronous32from provisioningserver.utils.twisted import synchronous
@@ -41,10 +43,12 @@
41 of IO, as this function is called often. To update the cache call43 of IO, as this function is called often. To update the cache call
42 `reload_boot_images`.44 `reload_boot_images`.
43 """45 """
46
44 global CACHED_BOOT_IMAGES47 global CACHED_BOOT_IMAGES
45 if CACHED_BOOT_IMAGES is None:48 if CACHED_BOOT_IMAGES is None:
46 CACHED_BOOT_IMAGES = tftppath.list_boot_images(49 CACHED_BOOT_IMAGES = tftppath.list_boot_images(
47 os.path.join(BOOT_RESOURCES_STORAGE, 'current'))50 get_config_cluster_variable(
51 CLUSTER_CONFIG.DB_boot_resources_storage))
48 return CACHED_BOOT_IMAGES52 return CACHED_BOOT_IMAGES
4953
5054
@@ -53,7 +57,7 @@
53 most up-to-date boot images list."""57 most up-to-date boot images list."""
54 global CACHED_BOOT_IMAGES58 global CACHED_BOOT_IMAGES
55 CACHED_BOOT_IMAGES = tftppath.list_boot_images(59 CACHED_BOOT_IMAGES = tftppath.list_boot_images(
56 os.path.join(BOOT_RESOURCES_STORAGE, 'current'))60 get_config_cluster_variable(CLUSTER_CONFIG.DB_boot_resources_storage))
5761
5862
59def get_hosts_from_sources(sources):63def get_hosts_from_sources(sources):
@@ -74,7 +78,7 @@
74 """78 """
75 variables = {79 variables = {
76 'GNUPGHOME': get_maas_user_gpghome(),80 'GNUPGHOME': get_maas_user_gpghome(),
77 }81 }
78 if http_proxy is not None:82 if http_proxy is not None:
79 variables['http_proxy'] = http_proxy83 variables['http_proxy'] = http_proxy
80 if https_proxy is not None:84 if https_proxy is not None:
8185
=== modified file 'src/provisioningserver/rpc/clusterservice.py'
--- src/provisioningserver/rpc/clusterservice.py 2015-04-22 16:51:55 +0000
+++ src/provisioningserver/rpc/clusterservice.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -27,8 +27,8 @@
27from apiclient.utils import ascii_url27from apiclient.utils import ascii_url
28from provisioningserver import concurrency28from provisioningserver import concurrency
29from provisioningserver.cluster_config import (29from provisioningserver.cluster_config import (
30 get_cluster_uuid,30 CLUSTER_CONFIG,
31 get_maas_url,31 get_config_cluster_variable,
32)32)
33from provisioningserver.drivers import (33from provisioningserver.drivers import (
34 ArchitectureRegistry,34 ArchitectureRegistry,
@@ -137,7 +137,8 @@
137 Implementation of137 Implementation of
138 :py:class:`~provisioningserver.rpc.cluster.Identify`.138 :py:class:`~provisioningserver.rpc.cluster.Identify`.
139 """139 """
140 return {b"ident": get_cluster_uuid().decode("ascii")}140 return {b"ident": get_config_cluster_variable(
141 CLUSTER_CONFIG.DB_cluster_uuid).decode("ascii")}
141142
142 @cluster.Authenticate.responder143 @cluster.Authenticate.responder
143 def authenticate(self, message):144 def authenticate(self, message):
@@ -194,8 +195,8 @@
194 'architectures': [195 'architectures': [
195 {'name': arch.name, 'description': arch.description}196 {'name': arch.name, 'description': arch.description}
196 for _, arch in ArchitectureRegistry197 for _, arch in ArchitectureRegistry
197 ],198 ],
198 }199 }
199200
200 @cluster.ListOperatingSystems.responder201 @cluster.ListOperatingSystems.responder
201 def list_operating_systems(self):202 def list_operating_systems(self):
@@ -258,7 +259,7 @@
258 osystem, interfaces, auto_interfaces, ips_mapping=ips_mapping,259 osystem, interfaces, auto_interfaces, ips_mapping=ips_mapping,
259 gateways_mapping=gateways_mapping, disable_ipv4=disable_ipv4,260 gateways_mapping=gateways_mapping, disable_ipv4=disable_ipv4,
260 nameservers=nameservers, netmasks=netmasks),261 nameservers=nameservers, netmasks=netmasks),
261 }262 }
262263
263 @cluster.PowerOn.responder264 @cluster.PowerOn.responder
264 def power_on(self, system_id, hostname, power_type, context):265 def power_on(self, system_id, hostname, power_type, context):
@@ -523,9 +524,9 @@
523 returnValue(digest == digest_local)524 returnValue(digest == digest_local)
524525
525 def registerWithRegion(self):526 def registerWithRegion(self):
526 uuid = get_cluster_uuid()527 uuid = get_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid)
527 networks = discover_networks()528 networks = discover_networks()
528 url = get_maas_url()529 url = get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url)
529530
530 def cb_register(_):531 def cb_register(_):
531 log.msg(532 log.msg(
@@ -660,7 +661,7 @@
660 scheme_ports = {661 scheme_ports = {
661 'https': 443,662 'https': 443,
662 'http': 80,663 'http': 80,
663 }664 }
664 defaultPort = scheme_ports.get(scheme, 80)665 defaultPort = scheme_ports.get(scheme, 80)
665666
666 if '[' in netloc:667 if '[' in netloc:
@@ -775,7 +776,7 @@
775 @staticmethod776 @staticmethod
776 def _get_rpc_info_url():777 def _get_rpc_info_url():
777 """Return the URL to the RPC infomation page on the region."""778 """Return the URL to the RPC infomation page on the region."""
778 url = urlparse(get_maas_url())779 url = urlparse(get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url))
779 url = url._replace(path="%s/rpc/" % url.path.rstrip("/"))780 url = url._replace(path="%s/rpc/" % url.path.rstrip("/"))
780 url = url.geturl()781 url = url.geturl()
781 return ascii_url(url)782 return ascii_url(url)
782783
=== modified file 'src/provisioningserver/rpc/tags.py'
--- src/provisioningserver/rpc/tags.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/rpc/tags.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -22,13 +22,26 @@
22 MAASOAuth,22 MAASOAuth,
23)23)
24from provisioningserver.cluster_config import (24from provisioningserver.cluster_config import (
25 get_cluster_uuid,25 CLUSTER_CONFIG,
26 get_maas_url,26 get_config_cluster_variable,
27 set_config_cluster_variable,
27)28)
28from provisioningserver.tags import process_node_tags29from provisioningserver.tags import process_node_tags
29from provisioningserver.utils.twisted import synchronous30from provisioningserver.utils.twisted import synchronous
3031
3132
33def get_maas_url():
34 return get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url)
35
36
37def get_cluster_uuid():
38 return get_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid)
39
40
41def set_maas_url(value):
42 return set_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url, value)
43
44
32@synchronous45@synchronous
33def evaluate_tag(tag_name, tag_definition, tag_nsmap, credentials):46def evaluate_tag(tag_name, tag_definition, tag_nsmap, credentials):
34 """Evaluate `tag_definition` against this cluster's nodes' details.47 """Evaluate `tag_definition` against this cluster's nodes' details.
@@ -40,7 +53,9 @@
40 """53 """
41 client = MAASClient(54 client = MAASClient(
42 auth=MAASOAuth(*credentials), dispatcher=MAASDispatcher(),55 auth=MAASOAuth(*credentials), dispatcher=MAASDispatcher(),
43 base_url=get_maas_url())56 base_url=get_config_cluster_variable(CLUSTER_CONFIG.DB_maas_url))
44 process_node_tags(57 process_node_tags(
45 tag_name=tag_name, tag_definition=tag_definition, tag_nsmap=tag_nsmap,58 tag_name=tag_name, tag_definition=tag_definition, tag_nsmap=tag_nsmap,
46 client=client, nodegroup_uuid=get_cluster_uuid())59 client=client,
60 nodegroup_uuid=get_config_cluster_variable(
61 CLUSTER_CONFIG.DB_cluster_uuid))
4762
=== modified file 'src/provisioningserver/rpc/tests/test_boot_images.py'
--- src/provisioningserver/rpc/tests/test_boot_images.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/rpc/tests/test_boot_images.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -29,7 +29,10 @@
29)29)
30from provisioningserver import concurrency30from provisioningserver import concurrency
31from provisioningserver.boot import tftppath31from provisioningserver.boot import tftppath
32from provisioningserver.config import BOOT_RESOURCES_STORAGE32from provisioningserver.cluster_config import (
33 CLUSTER_CONFIG,
34 get_config_cluster_variable,
35)
33from provisioningserver.import_images import boot_resources36from provisioningserver.import_images import boot_resources
34from provisioningserver.rpc import boot_images37from provisioningserver.rpc import boot_images
35from provisioningserver.rpc.boot_images import (38from provisioningserver.rpc.boot_images import (
@@ -40,7 +43,10 @@
40 list_boot_images,43 list_boot_images,
41 reload_boot_images,44 reload_boot_images,
42)45)
43from provisioningserver.testing.config import BootSourcesFixture46from provisioningserver.testing.config import (
47 BootSourcesFixture,
48 ClusterConfigurationFixture,
49)
44from provisioningserver.testing.testcase import PservTestCase50from provisioningserver.testing.testcase import PservTestCase
45from provisioningserver.utils.twisted import pause51from provisioningserver.utils.twisted import pause
46from testtools.matchers import Equals52from testtools.matchers import Equals
@@ -54,16 +60,20 @@
54 'http://%s:%s/images-stream/streams/v1/index.json' % (60 'http://%s:%s/images-stream/streams/v1/index.json' % (
55 host, randint(1, 1000))61 host, randint(1, 1000))
56 for host in hosts62 for host in hosts
57 ]63 ]
58 sources = [64 sources = [
59 {'url': url, 'selections': []}65 {'url': url, 'selections': []}
60 for url in urls66 for url in urls
61 ]67 ]
62 return sources, hosts68 return sources, hosts
6369
6470
65class TestListBootImages(PservTestCase):71class TestListBootImages(PservTestCase):
6672
73 def setUp(self):
74 super(TestListBootImages, self).setUp()
75 self.useFixture(ClusterConfigurationFixture())
76
67 def test__calls_list_boot_images_with_boot_resource_storage(self):77 def test__calls_list_boot_images_with_boot_resource_storage(self):
68 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)78 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)
69 mock_list_boot_images = self.patch(tftppath, 'list_boot_images')79 mock_list_boot_images = self.patch(tftppath, 'list_boot_images')
@@ -71,7 +81,8 @@
71 self.assertThat(81 self.assertThat(
72 mock_list_boot_images,82 mock_list_boot_images,
73 MockCalledOnceWith(83 MockCalledOnceWith(
74 os.path.join(BOOT_RESOURCES_STORAGE, "current")))84 get_config_cluster_variable(
85 CLUSTER_CONFIG.DB_boot_resources_storage)))
7586
76 def test__calls_list_boot_images_when_cache_is_None(self):87 def test__calls_list_boot_images_when_cache_is_None(self):
77 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)88 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)
7889
=== modified file 'src/provisioningserver/rpc/tests/test_clusterservice.py'
--- src/provisioningserver/rpc/tests/test_clusterservice.py 2015-04-22 16:51:55 +0000
+++ src/provisioningserver/rpc/tests/test_clusterservice.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -49,13 +49,12 @@
49 Mock,49 Mock,
50 sentinel,50 sentinel,
51)51)
52from provisioningserver import concurrency52from provisioningserver import (
53 cluster_config,
54 concurrency,
55)
53from provisioningserver.boot import tftppath56from provisioningserver.boot import tftppath
54from provisioningserver.boot.tests.test_tftppath import make_osystem57from provisioningserver.boot.tests.test_tftppath import make_osystem
55from provisioningserver.cluster_config import (
56 get_cluster_uuid,
57 get_maas_url,
58)
59from provisioningserver.dhcp.testing.config import make_subnet_config58from provisioningserver.dhcp.testing.config import make_subnet_config
60from provisioningserver.drivers.osystem import (59from provisioningserver.drivers.osystem import (
61 OperatingSystem,60 OperatingSystem,
@@ -106,6 +105,7 @@
106 StubOS,105 StubOS,
107)106)
108from provisioningserver.security import set_shared_secret_on_filesystem107from provisioningserver.security import set_shared_secret_on_filesystem
108from provisioningserver.testing.config import ClusterConfigurationFixture
109from testtools import ExpectedException109from testtools import ExpectedException
110from testtools.deferredruntest import extract_result110from testtools.deferredruntest import extract_result
111from testtools.matchers import (111from testtools.matchers import (
@@ -150,10 +150,11 @@
150 self.assertIsNotNone(responder)150 self.assertIsNotNone(responder)
151151
152 def test_identify_reports_cluster_uuid(self):152 def test_identify_reports_cluster_uuid(self):
153 self.useFixture(ClusterConfigurationFixture())
153 example_uuid = factory.make_UUID()154 example_uuid = factory.make_UUID()
154155
155 get_cluster_uuid = self.patch(clusterservice, "get_cluster_uuid")156 cluster_config.set_config_cluster_variable(
156 get_cluster_uuid.return_value = example_uuid157 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid, example_uuid)
157158
158 d = call_responder(Cluster(), cluster.Identify, {})159 d = call_responder(Cluster(), cluster.Identify, {})
159160
@@ -239,6 +240,7 @@
239240
240 @inlineCallbacks241 @inlineCallbacks
241 def test_list_boot_images_with_things_to_report(self):242 def test_list_boot_images_with_things_to_report(self):
243 self.useFixture(ClusterConfigurationFixture())
242 # tftppath.list_boot_images()'s return value matches the244 # tftppath.list_boot_images()'s return value matches the
243 # response schema that ListBootImages declares, and is245 # response schema that ListBootImages declares, and is
244 # serialised correctly.246 # serialised correctly.
@@ -258,7 +260,11 @@
258 for options in product(osystems, archs, subarchs, releases, labels):260 for options in product(osystems, archs, subarchs, releases, labels):
259 os.makedirs(os.path.join(current_dir, *options))261 os.makedirs(os.path.join(current_dir, *options))
260 make_osystem(self, options[0], purposes)262 make_osystem(self, options[0], purposes)
261 self.patch(boot_images, 'BOOT_RESOURCES_STORAGE', tftpdir)263
264 cluster_config.set_config_cluster_variable(
265 cluster_config.CLUSTER_CONFIG.DB_tftp_resource_root,
266 os.path.join(tftpdir, 'current/'))
267
262 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)268 self.patch(boot_images, 'CACHED_BOOT_IMAGES', None)
263269
264 expected_images = [270 expected_images = [
@@ -272,7 +278,7 @@
272 }278 }
273 for osystem, arch, subarch, release, label, purpose in product(279 for osystem, arch, subarch, release, label, purpose in product(
274 osystems, archs, subarchs, releases, labels, purposes)280 osystems, archs, subarchs, releases, labels, purposes)
275 ]281 ]
276 for expected_image in expected_images:282 for expected_image in expected_images:
277 if expected_image['purpose'] == 'xinstall':283 if expected_image['purpose'] == 'xinstall':
278 expected_image['xinstall_path'] = 'root-tgz'284 expected_image['xinstall_path'] = 'root-tgz'
@@ -343,7 +349,7 @@
343 'sources': [],349 'sources': [],
344 'http_proxy': parsed_proxy,350 'http_proxy': parsed_proxy,
345 'https_proxy': parsed_proxy,351 'https_proxy': parsed_proxy,
346 })352 })
347353
348 self.assertThat(354 self.assertThat(
349 import_boot_images,355 import_boot_images,
@@ -465,9 +471,13 @@
465 self.assertThat(service.clock, Is(sentinel.reactor))471 self.assertThat(service.clock, Is(sentinel.reactor))
466472
467 def test__get_rpc_info_url(self):473 def test__get_rpc_info_url(self):
474 self.useFixture(ClusterConfigurationFixture())
475
468 maas_url = "http://%s/%s/" % (476 maas_url = "http://%s/%s/" % (
469 factory.make_hostname(), factory.make_name("path"))477 factory.make_hostname(), factory.make_name("path"))
470 self.useFixture(EnvironmentVariable("MAAS_URL", maas_url))478 cluster_config.set_config_cluster_variable(
479 cluster_config.CLUSTER_CONFIG.DB_maas_url,
480 maas_url)
471 expected_rpc_info_url = maas_url + "rpc/"481 expected_rpc_info_url = maas_url + "rpc/"
472 observed_rpc_info_url = ClusterClientService._get_rpc_info_url()482 observed_rpc_info_url = ClusterClientService._get_rpc_info_url()
473 self.assertThat(observed_rpc_info_url, Equals(expected_rpc_info_url))483 self.assertThat(observed_rpc_info_url, Equals(expected_rpc_info_url))
@@ -1199,15 +1209,18 @@
11991209
1200 @inlineCallbacks1210 @inlineCallbacks
1201 def test_registerWithRegion_end_to_end(self):1211 def test_registerWithRegion_end_to_end(self):
1212 self.useFixture(ClusterConfigurationFixture())
1202 fixture = self.useFixture(MockLiveClusterToRegionRPCFixture())1213 fixture = self.useFixture(MockLiveClusterToRegionRPCFixture())
1203 protocol, connecting = fixture.makeEventLoop()1214 protocol, connecting = fixture.makeEventLoop()
1204 self.addCleanup((yield connecting))1215 self.addCleanup((yield connecting))
1205 yield getRegionClient()1216 yield getRegionClient()
1206 self.assertThat(1217 self.assertThat(
1207 protocol.Register, MockCalledOnceWith(1218 protocol.Register, MockCalledOnceWith(
1208 protocol, uuid=get_cluster_uuid(),1219 protocol, uuid=cluster_config.get_config_cluster_variable(
1220 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid),
1209 networks=discover_networks(),1221 networks=discover_networks(),
1210 url=urlparse(get_maas_url())))1222 url=urlparse(cluster_config.get_config_cluster_variable(
1223 cluster_config.CLUSTER_CONFIG.DB_maas_url))))
12111224
12121225
1213class TestClusterProtocol_ListSupportedArchitectures(MAASTestCase):1226class TestClusterProtocol_ListSupportedArchitectures(MAASTestCase):
@@ -1438,9 +1451,9 @@
1438 'ips_mapping': {mac: [factory.make_ipv4_address()]},1451 'ips_mapping': {mac: [factory.make_ipv4_address()]},
1439 'gateways_mapping': {mac: [factory.make_ipv4_address()]},1452 'gateways_mapping': {mac: [factory.make_ipv4_address()]},
1440 'nameservers': [],1453 'nameservers': [],
1441 },1454 },
1442 'disable_ipv4': factory.pick_bool(),1455 'disable_ipv4': factory.pick_bool(),
1443 }1456 }
14441457
1445 def test__is_registered(self):1458 def test__is_registered(self):
1446 protocol = Cluster()1459 protocol = Cluster()
@@ -1654,7 +1667,7 @@
1654 yield call_responder(Cluster(), self.command, {1667 yield call_responder(Cluster(), self.command, {
1655 'omapi_key': omapi_key,1668 'omapi_key': omapi_key,
1656 'subnet_configs': subnet_configs,1669 'subnet_configs': subnet_configs,
1657 })1670 })
16581671
1659 self.assertThat(DHCPServer, MockCalledOnceWith(omapi_key))1672 self.assertThat(DHCPServer, MockCalledOnceWith(omapi_key))
1660 self.assertThat(configure, MockCalledOnceWith(1673 self.assertThat(configure, MockCalledOnceWith(
@@ -1675,7 +1688,7 @@
1675 yield call_responder(Cluster(), self.command, {1688 yield call_responder(Cluster(), self.command, {
1676 'omapi_key': factory.make_name('key'),1689 'omapi_key': factory.make_name('key'),
1677 'subnet_configs': [],1690 'subnet_configs': [],
1678 })1691 })
1679 self.assertFalse(concurrency.dhcp.locked)1692 self.assertFalse(concurrency.dhcp.locked)
16801693
1681 @inlineCallbacks1694 @inlineCallbacks
@@ -1692,7 +1705,7 @@
1692 yield call_responder(Cluster(), self.command, {1705 yield call_responder(Cluster(), self.command, {
1693 'omapi_key': omapi_key,1706 'omapi_key': omapi_key,
1694 'subnet_configs': subnet_configs,1707 'subnet_configs': subnet_configs,
1695 })1708 })
16961709
16971710
1698class TestClusterProtocol_CreateHostMaps(MAASTestCase):1711class TestClusterProtocol_CreateHostMaps(MAASTestCase):
@@ -1905,7 +1918,7 @@
1905 "password": password,1918 "password": password,
1906 "prefix_filter": prefix_filter,1919 "prefix_filter": prefix_filter,
1907 "accept_all": True,1920 "accept_all": True,
1908 })1921 })
1909 self.assertThat(1922 self.assertThat(
1910 mock_deferToThread, MockCalledOnceWith(1923 mock_deferToThread, MockCalledOnceWith(
1911 clusterservice.probe_virsh_and_enlist,1924 clusterservice.probe_virsh_and_enlist,
@@ -1923,7 +1936,7 @@
1923 "password": None,1936 "password": None,
1924 "prefix_filter": prefix_filter,1937 "prefix_filter": prefix_filter,
1925 "accept_all": True,1938 "accept_all": True,
1926 })1939 })
1927 self.assertThat(1940 self.assertThat(
1928 mock_deferToThread, MockCalledOnceWith(1941 mock_deferToThread, MockCalledOnceWith(
1929 clusterservice.probe_virsh_and_enlist,1942 clusterservice.probe_virsh_and_enlist,
@@ -1940,7 +1953,7 @@
1940 "poweraddr": poweraddr,1953 "poweraddr": poweraddr,
1941 "prefix_filter": prefix_filter,1954 "prefix_filter": prefix_filter,
1942 "accept_all": True,1955 "accept_all": True,
1943 })1956 })
1944 self.assertThat(1957 self.assertThat(
1945 mock_deferToThread, MockCalledOnceWith(1958 mock_deferToThread, MockCalledOnceWith(
1946 clusterservice.probe_virsh_and_enlist,1959 clusterservice.probe_virsh_and_enlist,
@@ -1962,7 +1975,7 @@
1962 "password": password,1975 "password": password,
1963 "prefix_filter": prefix_filter,1976 "prefix_filter": prefix_filter,
1964 "accept_all": True,1977 "accept_all": True,
1965 })1978 })
1966 self.assertThat(1979 self.assertThat(
1967 clusterservice.maaslog.error,1980 clusterservice.maaslog.error,
1968 MockAnyCall(1981 MockAnyCall(
@@ -1998,7 +2011,7 @@
1998 "protocol": protocol,2011 "protocol": protocol,
1999 "prefix_filter": prefix_filter,2012 "prefix_filter": prefix_filter,
2000 "accept_all": True,2013 "accept_all": True,
2001 })2014 })
2002 self.assertThat(2015 self.assertThat(
2003 mock_deferToThread, MockCalledOnceWith(2016 mock_deferToThread, MockCalledOnceWith(
2004 clusterservice.probe_vsphere_and_enlist,2017 clusterservice.probe_vsphere_and_enlist,
@@ -2024,7 +2037,7 @@
2024 "protocol": None,2037 "protocol": None,
2025 "prefix_filter": prefix_filter,2038 "prefix_filter": prefix_filter,
2026 "accept_all": True,2039 "accept_all": True,
2027 })2040 })
2028 self.assertThat(2041 self.assertThat(
2029 mock_deferToThread, MockCalledOnceWith(2042 mock_deferToThread, MockCalledOnceWith(
2030 clusterservice.probe_vsphere_and_enlist,2043 clusterservice.probe_vsphere_and_enlist,
@@ -2049,7 +2062,7 @@
2049 "password": password,2062 "password": password,
2050 "prefix_filter": prefix_filter,2063 "prefix_filter": prefix_filter,
2051 "accept_all": True,2064 "accept_all": True,
2052 })2065 })
2053 self.assertThat(2066 self.assertThat(
2054 mock_deferToThread, MockCalledOnceWith(2067 mock_deferToThread, MockCalledOnceWith(
2055 clusterservice.probe_vsphere_and_enlist,2068 clusterservice.probe_vsphere_and_enlist,
@@ -2076,7 +2089,7 @@
2076 "password": password,2089 "password": password,
2077 "prefix_filter": prefix_filter,2090 "prefix_filter": prefix_filter,
2078 "accept_all": True,2091 "accept_all": True,
2079 })2092 })
20802093
2081 self.assertThat(2094 self.assertThat(
2082 clusterservice.maaslog.error,2095 clusterservice.maaslog.error,
@@ -2108,7 +2121,7 @@
2108 "password": password,2121 "password": password,
2109 "prefix_filter": prefix_filter,2122 "prefix_filter": prefix_filter,
2110 "accept_all": True,2123 "accept_all": True,
2111 })2124 })
2112 self.assertThat(2125 self.assertThat(
2113 mock_deferToThread, MockCalledOnceWith(2126 mock_deferToThread, MockCalledOnceWith(
2114 clusterservice.probe_esxi_and_enlist,2127 clusterservice.probe_esxi_and_enlist,
@@ -2133,7 +2146,7 @@
2133 "password": password,2146 "password": password,
2134 "prefix_filter": prefix_filter,2147 "prefix_filter": prefix_filter,
2135 "accept_all": True,2148 "accept_all": True,
2136 })2149 })
2137 self.assertThat(2150 self.assertThat(
2138 clusterservice.maaslog.error,2151 clusterservice.maaslog.error,
2139 MockAnyCall(2152 MockAnyCall(
@@ -2169,7 +2182,7 @@
2169 "password": password,2182 "password": password,
2170 "power_control": power_control,2183 "power_control": power_control,
2171 "accept_all": True,2184 "accept_all": True,
2172 })2185 })
21732186
2174 self.assertThat(2187 self.assertThat(
2175 find_ip_via_arp, MockCalledOnceWith(mac))2188 find_ip_via_arp, MockCalledOnceWith(mac))
@@ -2195,7 +2208,7 @@
2195 "password": password,2208 "password": password,
2196 "power_control": power_control,2209 "power_control": power_control,
2197 "accept_all": True,2210 "accept_all": True,
2198 })2211 })
21992212
2200 self.assertThat(2213 self.assertThat(
2201 maaslog.warning,2214 maaslog.warning,
@@ -2221,7 +2234,7 @@
2221 "password": password,2234 "password": password,
2222 "power_control": power_control,2235 "power_control": power_control,
2223 "accept_all": True,2236 "accept_all": True,
2224 })2237 })
22252238
2226 self.assertThat(2239 self.assertThat(
2227 mock_deferToThread, MockCalledOnceWith(2240 mock_deferToThread, MockCalledOnceWith(
@@ -2251,7 +2264,7 @@
2251 "password": password,2264 "password": password,
2252 "power_control": power_control,2265 "power_control": power_control,
2253 "accept_all": True,2266 "accept_all": True,
2254 })2267 })
2255 self.assertThat(2268 self.assertThat(
2256 clusterservice.maaslog.error,2269 clusterservice.maaslog.error,
2257 MockAnyCall(2270 MockAnyCall(
22582271
=== modified file 'src/provisioningserver/rpc/tests/test_tags.py'
--- src/provisioningserver/rpc/tests/test_tags.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/rpc/tests/test_tags.py 2015-05-04 14:27:25 +0000
@@ -7,13 +7,14 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
14__metaclass__ = type14__metaclass__ = type
15__all__ = []15__all__ = []
1616
17
17from apiclient.maas_client import (18from apiclient.maas_client import (
18 MAASClient,19 MAASClient,
19 MAASDispatcher,20 MAASDispatcher,
@@ -26,17 +27,25 @@
26 ANY,27 ANY,
27 sentinel,28 sentinel,
28)29)
30from provisioningserver import cluster_config
29from provisioningserver.rpc import tags31from provisioningserver.rpc import tags
32from provisioningserver.testing.config import ClusterConfigurationFixture
3033
3134
32class TestEvaluateTag(MAASTestCase):35class TestEvaluateTag(MAASTestCase):
3336
34 def setUp(self):37 def setUp(self):
35 super(TestEvaluateTag, self).setUp()38 super(TestEvaluateTag, self).setUp()
36 get_maas_url = self.patch_autospec(tags, "get_maas_url")39 self.useFixture(ClusterConfigurationFixture())
37 get_maas_url.return_value = sentinel.maas_url40
38 get_cluster_uuid = self.patch_autospec(tags, "get_cluster_uuid")41 self.mock_cluster_uuid = factory.make_UUID()
39 get_cluster_uuid.return_value = sentinel.cluster_uuid42 self.mock_url = factory.make_simple_http_url()
43
44 cluster_config.set_config_cluster_variable(
45 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid,
46 self.mock_cluster_uuid)
47 cluster_config.set_config_cluster_variable(
48 cluster_config.CLUSTER_CONFIG.DB_maas_url, self.mock_url)
4049
41 def test__calls_process_node_tags(self):50 def test__calls_process_node_tags(self):
42 credentials = "aaa", "bbb", "ccc"51 credentials = "aaa", "bbb", "ccc"
@@ -49,7 +58,7 @@
49 tag_name=sentinel.tag_name,58 tag_name=sentinel.tag_name,
50 tag_definition=sentinel.tag_definition,59 tag_definition=sentinel.tag_definition,
51 tag_nsmap=sentinel.tag_nsmap, client=ANY,60 tag_nsmap=sentinel.tag_nsmap, client=ANY,
52 nodegroup_uuid=sentinel.cluster_uuid))61 nodegroup_uuid=self.mock_cluster_uuid))
5362
54 def test__constructs_client_with_credentials(self):63 def test__constructs_client_with_credentials(self):
55 consumer_key = factory.make_name("ckey")64 consumer_key = factory.make_name("ckey")
@@ -66,7 +75,7 @@
6675
67 client = tags.process_node_tags.call_args[1]["client"]76 client = tags.process_node_tags.call_args[1]["client"]
68 self.assertIsInstance(client, MAASClient)77 self.assertIsInstance(client, MAASClient)
69 self.assertEqual(sentinel.maas_url, client.url)78 self.assertEqual(self.mock_url, client.url)
70 self.assertIsInstance(client.dispatcher, MAASDispatcher)79 self.assertIsInstance(client.dispatcher, MAASDispatcher)
71 self.assertIsInstance(client.auth, MAASOAuth)80 self.assertIsInstance(client.auth, MAASOAuth)
72 self.assertThat(tags.MAASOAuth, MockCalledOnceWith(81 self.assertThat(tags.MAASOAuth, MockCalledOnceWith(
7382
=== modified file 'src/provisioningserver/tests/test_cluster_config.py'
--- src/provisioningserver/tests/test_cluster_config.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/tests/test_cluster_config.py 2015-05-04 14:27:25 +0000
@@ -7,42 +7,83 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
14__metaclass__ = type14__metaclass__ = type
15__all__ = []15__all__ = []
1616
17from fixtures import EnvironmentVariableFixture17import os
18
18from maastesting.factory import factory19from maastesting.factory import factory
19from maastesting.testcase import MAASTestCase20from maastesting.testcase import MAASTestCase
20from provisioningserver.cluster_config import (21from provisioningserver import cluster_config
21 get_cluster_uuid,22from provisioningserver.config import UUID_NOT_SET
22 get_cluster_variable,23from provisioningserver.testing.config import ClusterConfigurationFixture
23 get_maas_url,24
24)25
2526class TestClusterConfigTFTPGenerator(MAASTestCase):
2627 """Tests for the get_tftp_generator() function."""
27class TestClusterConfig(MAASTestCase):28
2829 def test_get_tftp_generator(self):
29 def test_get_cluster_variable_reads_env(self):30 self.useFixture(ClusterConfigurationFixture())
30 var = factory.make_name('variable')31 random_path = factory.make_simple_http_url()
31 value = factory.make_name('value')32 cluster_config.set_config_cluster_variable(
32 self.useFixture(EnvironmentVariableFixture(var, value))33 cluster_config.CLUSTER_CONFIG.DB_maas_url, random_path)
33 self.assertEqual(value, get_cluster_variable(var))34
3435 observed = cluster_config.get_tftp_generator()
35 def test_get_cluster_variable_fails_if_not_set(self):36 expected = os.path.join(random_path, 'api', '1.0', 'pxeconfig')
36 self.assertRaises(37 self.assertEqual(observed, expected)
37 AssertionError,38
38 get_cluster_variable, factory.make_name('nonexistent-variable'))39
3940class TestClusterConfigDatabaseOptions(MAASTestCase):
40 def test_get_cluster_uuid_reads_CLUSTER_UUID(self):41 """Tests for the database options in `cluster_config`."""
41 uuid = factory.make_name('uuid')42
42 self.useFixture(EnvironmentVariableFixture('CLUSTER_UUID', uuid))43 def setUp(self):
43 self.assertEqual(uuid, get_cluster_uuid())44 super(TestClusterConfigDatabaseOptions, self).setUp()
4445 self.useFixture(ClusterConfigurationFixture())
45 def test_get_maas_url_reads_MAAS_URL(self):46
46 maas_url = factory.make_name('maas_url')47 options_and_defaults = {
47 self.useFixture(EnvironmentVariableFixture('MAAS_URL', maas_url))48 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid: UUID_NOT_SET,
48 self.assertEqual(maas_url, get_maas_url())49 cluster_config.CLUSTER_CONFIG.DB_maas_url:
50 "http://localhost:5240/MAAS",
51 cluster_config.CLUSTER_CONFIG.DB_tftp_resource_root:
52 "/var/lib/maas/boot-resources/current/",
53 cluster_config.CLUSTER_CONFIG.DB_boot_resources_storage:
54 "/var/lib/maas/boot-resources/current/",
55 cluster_config.CLUSTER_CONFIG.DB_tftpport: 69,
56 }
57
58 scenarios = tuple(
59 (name, {"option": name, "default": default})
60 for name, default in options_and_defaults.viewitems()
61 )
62
63 def test__default(self):
64 self.assertEqual(
65 self.default,
66 cluster_config.get_config_cluster_variable(self.option))
67
68 def test__set_and_get(self):
69 # NOTE: test_values cannot be a class attribute factory
70 # since make_dir() requires a reference to 'self' for the
71 # TempDirectory fixture.
72 test_values = {
73 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid: factory.make_UUID(),
74 cluster_config.CLUSTER_CONFIG.DB_maas_url:
75 factory.make_simple_http_url(),
76 cluster_config.CLUSTER_CONFIG.DB_tftp_resource_root:
77 self.make_dir(),
78 cluster_config.CLUSTER_CONFIG.DB_boot_resources_storage:
79 self.make_dir(),
80 cluster_config.CLUSTER_CONFIG.DB_tftpport: factory.pick_port(),
81 }
82
83 example_value = test_values[self.option]
84
85 cluster_config.set_config_cluster_variable(self.option, example_value)
86
87 self.assertEqual(example_value,
88 cluster_config.get_config_cluster_variable(
89 self.option))
4990
=== modified file 'src/provisioningserver/tests/test_config.py'
--- src/provisioningserver/tests/test_config.py 2015-05-04 14:27:25 +0000
+++ src/provisioningserver/tests/test_config.py 2015-05-04 14:27:25 +0000
@@ -15,24 +15,17 @@
15__all__ = []15__all__ = []
1616
17import contextlib17import contextlib
18from copy import deepcopy
19import errno
20from functools import partial
21from getpass import getuser
22from io import BytesIO
23from operator import methodcaller18from operator import methodcaller
24import os.path19import os.path
25import random20import random
26import re21import re
27import sqlite322import sqlite3
28from textwrap import dedent
29from uuid import uuid423from uuid import uuid4
3024
31from fixtures import EnvironmentVariableFixture25from fixtures import EnvironmentVariableFixture
32import formencode26import formencode
33import formencode.validators27import formencode.validators
34from formencode.validators import Invalid28from formencode.validators import Invalid
35from maastesting import root
36from maastesting.factory import factory29from maastesting.factory import factory
37from maastesting.matchers import (30from maastesting.matchers import (
38 MockCalledOnceWith,31 MockCalledOnceWith,
@@ -41,11 +34,7 @@
41from maastesting.testcase import MAASTestCase34from maastesting.testcase import MAASTestCase
42from mock import sentinel35from mock import sentinel
43from provisioningserver.config import (36from provisioningserver.config import (
44 BootSources,
45 ClusterConfiguration,37 ClusterConfiguration,
46 Config,
47 ConfigBase,
48 ConfigMeta,
49 Configuration,38 Configuration,
50 ConfigurationDatabase,39 ConfigurationDatabase,
51 ConfigurationFile,40 ConfigurationFile,
@@ -56,17 +45,13 @@
56 UUID,45 UUID,
57)46)
58from provisioningserver.path import get_path47from provisioningserver.path import get_path
59from provisioningserver.testing.config import ConfigFixtureBase
60from provisioningserver.utils.fs import FileLockProxy48from provisioningserver.utils.fs import FileLockProxy
61from testtools import ExpectedException49from testtools import ExpectedException
62from testtools.matchers import (50from testtools.matchers import (
63 DirExists,
64 FileContains,51 FileContains,
65 FileExists,52 FileExists,
66 Is,53 Is,
67 MatchesException,
68 MatchesStructure,54 MatchesStructure,
69 Raises,
70)55)
71from twisted.python.filepath import FilePath56from twisted.python.filepath import FilePath
72import yaml57import yaml
@@ -224,444 +209,6 @@
224 "url: %s" % url)209 "url: %s" % url)
225210
226211
227class ExampleConfig(ConfigBase, formencode.Schema):
228 """An example configuration schema.
229
230 It derives from :class:`ConfigBase` and has a metaclass derived from
231 :class:`ConfigMeta`, just as a "real" schema must.
232 """
233
234 class __metaclass__(ConfigMeta):
235 envvar = "MAAS_TESTING_SETTINGS"
236 default = "example.yaml"
237
238 something = formencode.validators.String(if_missing="*missing*")
239
240
241class ExampleConfigFixture(ConfigFixtureBase):
242 """A fixture to help with testing :class:`ExampleConfig`."""
243
244 schema = ExampleConfig
245
246
247class TestConfigFixtureBase(MAASTestCase):
248 """Tests for `ConfigFixtureBase`."""
249
250 def exercise_fixture(self, fixture):
251 # ConfigFixtureBase arranges a minimal configuration on disk,
252 # and exports the configuration filename to the environment so
253 # that subprocesses can find it.
254 with fixture:
255 self.assertThat(fixture.dir, DirExists())
256 self.assertThat(fixture.filename, FileExists())
257 self.assertEqual(
258 {fixture.schema.envvar: fixture.filename},
259 fixture.environ)
260 self.assertEqual(
261 fixture.filename, os.environ[fixture.schema.envvar])
262 with open(fixture.filename, "rb") as stream:
263 self.assertEqual(fixture.config, yaml.safe_load(stream))
264
265 def test_use_minimal(self):
266 # With no arguments, ConfigFixtureBase arranges a minimal
267 # configuration.
268 fixture = ExampleConfigFixture()
269 self.exercise_fixture(fixture)
270
271 def test_use_with_config(self):
272 # Given a configuration, ConfigFixtureBase can arrange a minimal
273 # global configuration with the additional options merged in.
274 something = self.getUniqueString("something")
275 fixture = ExampleConfigFixture({"something": something})
276 self.assertEqual(something, fixture.config["something"])
277 self.exercise_fixture(fixture)
278
279
280class TestConfigMeta_DEFAULT_FILENAME(MAASTestCase):
281 """Tests for `provisioningserver.config.ConfigBase.DEFAULT_FILENAME`."""
282
283 def set_envvar(self, filepath=None):
284 """Continue this test with a given environment variable."""
285 self.useFixture(EnvironmentVariableFixture(
286 ExampleConfig.envvar, filepath))
287
288 def set_MAAS_CONFIG_DIR(self, dirpath=None):
289 """Continue this test with a given `MAAS_CONFIG_DIR`."""
290 self.useFixture(EnvironmentVariableFixture("MAAS_CONFIG_DIR", dirpath))
291
292 def make_config(self):
293 """Create a config file in a directory of its own."""
294 return self.make_file(name=ExampleConfig.default)
295
296 def test_gets_filename_from_MAAS_PROVISIONING_SETTNGS(self):
297 dummy_filename = factory.make_name("config")
298 self.set_MAAS_CONFIG_DIR(None)
299 self.set_envvar(dummy_filename)
300 self.assertEqual(dummy_filename, ExampleConfig.DEFAULT_FILENAME)
301
302 def test_falls_back_to_MAAS_CONFIG_DIR(self):
303 config_file = self.make_config()
304 self.set_MAAS_CONFIG_DIR(os.path.dirname(config_file))
305 self.set_envvar(None)
306 self.assertEqual(config_file, ExampleConfig.DEFAULT_FILENAME)
307
308 def test_MAAS_PROVISIONING_SETTINGS_trumps_MAAS_CONFIG_DIR(self):
309 provisioning_settings = factory.make_name("config")
310 self.set_MAAS_CONFIG_DIR(os.path.dirname(self.make_config()))
311 self.set_envvar(provisioning_settings)
312 self.assertEqual(
313 provisioning_settings,
314 ExampleConfig.DEFAULT_FILENAME)
315
316 def test_defaults_to_global_config(self):
317 self.set_MAAS_CONFIG_DIR(None)
318 self.set_envvar(None)
319 self.assertEqual(
320 '/etc/maas/%s' % ExampleConfig.default,
321 ExampleConfig.DEFAULT_FILENAME)
322
323 def test_set(self):
324 dummy_filename = factory.make_name("config")
325 ExampleConfig.DEFAULT_FILENAME = dummy_filename
326 self.assertEqual(dummy_filename, ExampleConfig.DEFAULT_FILENAME)
327
328 def test_delete(self):
329 self.set_MAAS_CONFIG_DIR(None)
330 self.set_envvar(None)
331 ExampleConfig.DEFAULT_FILENAME = factory.make_name("config")
332 del ExampleConfig.DEFAULT_FILENAME
333 # The filename reverts; see test_get_with_environment_empty.
334 self.assertEqual(
335 "/etc/maas/%s" % ExampleConfig.default,
336 ExampleConfig.DEFAULT_FILENAME)
337 # The delete does not fail when called multiple times.
338 del ExampleConfig.DEFAULT_FILENAME
339
340
341class TestConfigBase(MAASTestCase):
342 """Tests for `provisioningserver.config.ConfigBase`."""
343
344 def make_config_data(self):
345 """Return random config data for `ExampleConfig`."""
346 return {'something': factory.make_name('value')}
347
348 def make_config_file(self, name=None, data=None):
349 """Write a YAML config file, and return its path."""
350 if name is None:
351 name = factory.make_name('config') + '.yaml'
352 if data is None:
353 data = self.make_config_data()
354 return self.make_file(name=name, contents=yaml.safe_dump(data))
355
356 def test_get_defaults_returns_default_config(self):
357 # The default configuration is production-ready.
358 observed = ExampleConfig.get_defaults()
359 self.assertEqual({"something": "*missing*"}, observed)
360
361 def test_get_defaults_ignores_settings(self):
362 self.useFixture(ExampleConfigFixture(self.make_config_data()))
363 observed = ExampleConfig.get_defaults()
364 self.assertEqual({"something": "*missing*"}, observed)
365
366 def test_parse(self):
367 # Configuration can be parsed from a snippet of YAML.
368 observed = ExampleConfig.parse(b'something: "important"\n')
369 self.assertEqual("important", observed["something"])
370
371 def test_load(self):
372 # Configuration can be loaded and parsed from a file.
373 config = dedent("""
374 something: "important"
375 """)
376 filename = self.make_file(contents=config)
377 observed = ExampleConfig.load(filename)
378 self.assertEqual({"something": "important"}, observed)
379
380 def test_load_defaults_to_default_filename(self):
381 data = self.make_config_data()
382 filename = self.make_config_file(name='config.yaml', data=data)
383 self.patch(ExampleConfig, 'DEFAULT_FILENAME', filename)
384 self.assertEqual(data, ExampleConfig.load())
385
386 def test_load_from_cache_loads_config(self):
387 data = self.make_config_data()
388 filename = self.make_config_file(data=data)
389 self.assertEqual(data, ExampleConfig.load_from_cache(filename))
390
391 def test_load_from_cache_uses_defaults(self):
392 filename = self.make_file(contents='')
393 self.assertEqual(
394 ExampleConfig.get_defaults(),
395 ExampleConfig.load_from_cache(filename))
396
397 def test_load_from_cache_caches_each_file_separately(self):
398 config1 = self.make_file(contents=yaml.safe_dump({'something': "1"}))
399 config2 = self.make_file(contents=yaml.safe_dump({'something': "2"}))
400
401 self.assertEqual(
402 {"something": "1"},
403 ExampleConfig.load_from_cache(config1))
404 self.assertEqual(
405 {"something": "2"},
406 ExampleConfig.load_from_cache(config2))
407
408 def test_load_from_cache_reloads_from_cache_not_from_file(self):
409 # A config loaded by Config.load_from_cache() is never reloaded.
410 filename = self.make_config_file()
411 config_before = ExampleConfig.load_from_cache(filename)
412 os.unlink(filename)
413 config_after = ExampleConfig.load_from_cache(filename)
414 self.assertEqual(config_before, config_after)
415
416 def test_load_from_cache_caches_immutable_copy(self):
417 filename = self.make_config_file()
418
419 first_load = ExampleConfig.load_from_cache(filename)
420 second_load = ExampleConfig.load_from_cache(filename)
421
422 self.assertEqual(first_load, second_load)
423 self.assertIsNot(first_load, second_load)
424 first_load['something'] = factory.make_name('newthing')
425 self.assertNotEqual(first_load['something'], second_load['something'])
426
427 def test_flush_cache_without_filename_empties_cache(self):
428 filename = self.make_config_file()
429 ExampleConfig.load_from_cache(filename)
430 os.unlink(filename)
431 ExampleConfig.flush_cache()
432 error = self.assertRaises(
433 IOError,
434 ExampleConfig.load_from_cache, filename)
435 self.assertEqual(errno.ENOENT, error.errno)
436
437 def test_flush_cache_flushes_specific_file(self):
438 filename = self.make_config_file()
439 ExampleConfig.load_from_cache(filename)
440 os.unlink(filename)
441 ExampleConfig.flush_cache(filename)
442 error = self.assertRaises(
443 IOError,
444 ExampleConfig.load_from_cache, filename)
445 self.assertEqual(errno.ENOENT, error.errno)
446
447 def test_flush_cache_retains_other_files(self):
448 flushed_file = self.make_config_file()
449 cached_file = self.make_config_file()
450 ExampleConfig.load_from_cache(flushed_file)
451 cached_config = ExampleConfig.load_from_cache(cached_file)
452 os.unlink(cached_file)
453 ExampleConfig.flush_cache(flushed_file)
454 self.assertEqual(
455 cached_config,
456 ExampleConfig.load_from_cache(cached_file))
457
458 def test_flush_cache_ignores_uncached_files(self):
459 data = self.make_config_data()
460 filename = self.make_config_file(data=data)
461 ExampleConfig.flush_cache(filename)
462 self.assertEqual(data, ExampleConfig.load_from_cache(filename))
463
464 def test_field(self):
465 self.assertIs(ExampleConfig, ExampleConfig.field())
466 self.assertIs(
467 ExampleConfig.fields["something"],
468 ExampleConfig.field("something"))
469
470 def test_save_and_load_interoperate(self):
471 something = self.getUniqueString()
472 saved_file = self.make_file()
473
474 ExampleConfig.save({'something': something}, saved_file)
475 loaded_config = ExampleConfig.load(saved_file)
476 self.assertEqual(something, loaded_config['something'])
477
478 def test_save_saves_yaml_file(self):
479 config = {'something': self.getUniqueString()}
480 saved_file = self.make_file()
481
482 ExampleConfig.save(config, saved_file)
483
484 with open(saved_file, 'rb') as written_file:
485 loaded_config = yaml.safe_load(written_file)
486 self.assertEqual(config, loaded_config)
487
488 def test_save_defaults_to_default_filename(self):
489 something = self.getUniqueString()
490 filename = self.make_file(name="config.yaml")
491 self.patch(ExampleConfig, 'DEFAULT_FILENAME', filename)
492
493 ExampleConfig.save({'something': something})
494
495 self.assertEqual(
496 {'something': something},
497 ExampleConfig.load(filename))
498
499 def test_create_backup_creates_backup(self):
500 something = self.getUniqueString()
501 filename = self.make_file(name="config.yaml")
502 config = {'something': something}
503 yaml_config = yaml.safe_dump(config)
504 self.patch(ExampleConfig, 'DEFAULT_FILENAME', filename)
505 ExampleConfig.save(config)
506
507 ExampleConfig.create_backup('test')
508
509 backup_name = "%s.%s.bak" % (filename, 'test')
510 self.assertThat(backup_name, FileContains(yaml_config))
511
512
513class TestConfig(MAASTestCase):
514 """Tests for `provisioningserver.config.Config`."""
515
516 default_production_config = {
517 'broker': {
518 'host': 'localhost',
519 'port': 5673,
520 'username': getuser(),
521 'password': 'test',
522 'vhost': '/',
523 },
524 'logfile': 'pserv.log',
525 'oops': {
526 'directory': '',
527 'reporter': '',
528 },
529 'rpc': {},
530 'tftp': {
531 'generator': 'http://localhost/MAAS/api/1.0/pxeconfig/',
532 'port': 69,
533 # The "root" setting is obsolete; resource_root replaces it.
534 'root': "/var/lib/maas/tftp",
535 'resource_root': "/var/lib/maas/boot-resources/current/",
536 },
537 # Legacy section. Became unused in MAAS 1.5.
538 'boot': {
539 'architectures': None,
540 'ephemeral': {
541 'images_directory': None,
542 'releases': None,
543 },
544 },
545 }
546
547 default_development_config = deepcopy(default_production_config)
548 default_development_config.update(logfile="/dev/null")
549 default_development_config["tftp"].update(
550 port=5244, generator="http://localhost:5240/MAAS/api/1.0/pxeconfig/")
551
552 def test_get_defaults_returns_default_config(self):
553 # The default configuration is production-ready.
554 observed = Config.get_defaults()
555 self.assertEqual(self.default_production_config, observed)
556
557 def test_load_example(self):
558 # The example configuration is designed for development.
559 filename = os.path.join(root, "etc", "maas", "pserv.yaml")
560 self.assertEqual(
561 self.default_development_config,
562 Config.load(filename))
563
564 def test_oops_directory_without_reporter(self):
565 # It is an error to omit the OOPS reporter if directory is specified.
566 config = (
567 'oops:\n'
568 ' directory: /tmp/oops\n'
569 )
570 expected = MatchesException(
571 formencode.Invalid, "oops: You must give a value for reporter")
572 self.assertThat(
573 partial(Config.parse, config),
574 Raises(expected))
575
576 def test_accepts_1_4_config_file(self):
577 # A config file that was valid with MAAS 1.4 still loads, even though
578 # its "boot" section is no longer used.
579 broker_password = factory.make_name('pass')
580 config = Config.parse(dedent("""\
581 logfile: "/dev/null"
582 oops:
583 directory: "logs/oops"
584 reporter: "maas-pserv"
585 broker:
586 host: "localhost"
587 port: 5673
588 username: brokeruser
589 password: "%s"
590 vhost: "/"
591 tftp:
592 root: /var/lib/maas/tftp
593 port: 5244
594 generator: http://localhost:5240/api/1.0/pxeconfig/
595 boot:
596 architectures: ['i386', 'armhf']
597 ephemeral:
598 images_directory: /var/lib/maas/ephemeral
599 releases: ['precise', 'saucy']
600 """) % broker_password)
601 # This does not fail.
602 self.assertEqual(broker_password, config['broker']['password'])
603
604
605class TestBootSources(MAASTestCase):
606 """Tests for `provisioningserver.config.BootSources`."""
607
608 default_source = {
609 'url': (
610 'http://maas.ubuntu.com/images/ephemeral-v2/releases/'
611 ),
612 'keyring': (
613 '/usr/share/keyrings/ubuntu-cloudimage-keyring.gpg'),
614 'keyring_data': None,
615 'selections': [
616 {
617 'os': '*',
618 'release': '*',
619 'labels': ['*'],
620 'arches': ['*'],
621 'subarches': ['*'],
622 },
623 ],
624 }
625
626 def make_source(self):
627 """Create a dict defining an arbitrary `BootSource`."""
628 return {
629 'url': 'http://example.com/' + factory.make_name('path'),
630 'keyring': factory.make_name('keyring'),
631 'keyring_data': factory.make_string(),
632 'selections': [{
633 'os': factory.make_name('os'),
634 'release': factory.make_name('release'),
635 'labels': [factory.make_name('label')],
636 'arches': [factory.make_name('arch')],
637 'subarches': [factory.make_name('sub') for _ in range(3)],
638 }],
639 }
640
641 def test_parse_parses_source(self):
642 sources = [self.make_source()]
643 self.assertEqual(
644 sources,
645 BootSources.parse(BytesIO(yaml.safe_dump(sources))))
646
647 def test_parse_parses_multiple_sources(self):
648 sources = [self.make_source() for _ in range(2)]
649 self.assertEqual(
650 sources,
651 BootSources.parse(BytesIO(yaml.safe_dump(sources))))
652
653 def test_parse_uses_defaults(self):
654 self.assertEqual(
655 [self.default_source],
656 BootSources.parse(BytesIO(b'[{}]')))
657
658 def test_load_parses_file(self):
659 sources = [self.make_source()]
660 self.assertEqual(
661 sources,
662 BootSources.load(self.make_file(contents=yaml.safe_dump(sources))))
663
664
665###############################################################################212###############################################################################
666# New configuration API follows.213# New configuration API follows.
667###############################################################################214###############################################################################
668215
=== modified file 'src/provisioningserver/tests/test_diskless.py'
--- src/provisioningserver/tests/test_diskless.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/tests/test_diskless.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -24,9 +24,11 @@
24)24)
25from maastesting.testcase import MAASTestCase25from maastesting.testcase import MAASTestCase
26from mock import sentinel26from mock import sentinel
27from provisioningserver import (27from provisioningserver import diskless
28 config,28from provisioningserver.cluster_config import (
29 diskless,29 CLUSTER_CONFIG,
30 get_config_cluster_variable,
31 set_config_cluster_variable,
30)32)
31from provisioningserver.diskless import (33from provisioningserver.diskless import (
32 compose_diskless_link_path,34 compose_diskless_link_path,
@@ -54,6 +56,7 @@
54 BOOT_IMAGE_PURPOSE,56 BOOT_IMAGE_PURPOSE,
55 OperatingSystemRegistry,57 OperatingSystemRegistry,
56)58)
59from provisioningserver.testing.config import ClusterConfigurationFixture
57from provisioningserver.testing.os import FakeOS60from provisioningserver.testing.os import FakeOS
58from provisioningserver.utils.testing import RegistryFixture61from provisioningserver.utils.testing import RegistryFixture
59from testtools.matchers import (62from testtools.matchers import (
@@ -71,13 +74,18 @@
7174
72 def setUp(self):75 def setUp(self):
73 super(DisklessTestMixin, self).setUp()76 super(DisklessTestMixin, self).setUp()
77 self.useFixture(ClusterConfigurationFixture())
74 # Ensure the global registry is empty for each test run.78 # Ensure the global registry is empty for each test run.
75 self.useFixture(RegistryFixture())79 self.useFixture(RegistryFixture())
7680
77 def configure_resource_storage(self):81 def configure_resource_storage(self):
78 resource_dir = self.make_dir()82 resource_dir = self.make_dir()
79 os.mkdir(os.path.join(resource_dir, 'diskless'))83 os.mkdir(os.path.join(resource_dir, 'diskless'))
80 self.patch(config, 'BOOT_RESOURCES_STORAGE', resource_dir)84 current_dir = os.path.join(resource_dir, 'current') + '/'
85 os.mkdir(current_dir)
86 set_config_cluster_variable(
87 CLUSTER_CONFIG.DB_boot_resources_storage,
88 current_dir)
81 return resource_dir89 return resource_dir
8290
83 def configure_diskless_storage(self):91 def configure_diskless_storage(self):
@@ -116,8 +124,12 @@
116class TestHelpers(MAASTestCase, DisklessTestMixin):124class TestHelpers(MAASTestCase, DisklessTestMixin):
117125
118 def test_get_diskless_store(self):126 def test_get_diskless_store(self):
119 storage_dir = factory.make_name('storage')127 storage_dir = self.make_dir()
120 self.patch(config, 'BOOT_RESOURCES_STORAGE', storage_dir)128 current_dir = os.path.join(storage_dir, 'current') + '/'
129 os.mkdir(current_dir)
130 set_config_cluster_variable(
131 CLUSTER_CONFIG.DB_boot_resources_storage,
132 current_dir)
121 self.assertEqual(133 self.assertEqual(
122 os.path.join(storage_dir, 'diskless', 'store'),134 os.path.join(storage_dir, 'diskless', 'store'),
123 get_diskless_store())135 get_diskless_store())
@@ -241,7 +253,7 @@
241 '%s</target>\n' % entry253 '%s</target>\n' % entry
242 for entry in tgt_output.split('</target>\n')254 for entry in tgt_output.split('</target>\n')
243 if entry != ""255 if entry != ""
244 ])256 ])
245257
246 def test_reload_diskless_tgt(self):258 def test_reload_diskless_tgt(self):
247 tgt_path = factory.make_name('tgt_path')259 tgt_path = factory.make_name('tgt_path')
@@ -255,7 +267,7 @@
255 '/usr/sbin/tgt-admin',267 '/usr/sbin/tgt-admin',
256 '--conf', tgt_path,268 '--conf', tgt_path,
257 '--update', 'ALL',269 '--update', 'ALL',
258 ]))270 ]))
259271
260 def test_update_diskless_tgt_calls_atomic_write(self):272 def test_update_diskless_tgt_calls_atomic_write(self):
261 tgt_path = factory.make_name('tgt_path')273 tgt_path = factory.make_name('tgt_path')
@@ -269,7 +281,7 @@
269 update_diskless_tgt()281 update_diskless_tgt()
270 self.assertThat(282 self.assertThat(
271 mock_write,283 mock_write,
272 MockCalledOnceWith(tgt_config, tgt_path, mode=0644))284 MockCalledOnceWith(tgt_config, tgt_path, mode=0o644))
273285
274286
275class TestComposeSourcePath(MAASTestCase, DisklessTestMixin):287class TestComposeSourcePath(MAASTestCase, DisklessTestMixin):
@@ -299,7 +311,8 @@
299 mock_xi_params.return_value = (root_path, 'tgz')311 mock_xi_params.return_value = (root_path, 'tgz')
300 self.assertEqual(312 self.assertEqual(
301 os.path.join(313 os.path.join(
302 config.BOOT_RESOURCES_STORAGE, 'current', os_name,314 get_config_cluster_variable(
315 CLUSTER_CONFIG.DB_boot_resources_storage), os_name,
303 arch, subarch, release, label, root_path),316 arch, subarch, release, label, root_path),
304 compose_source_path(os_name, arch, subarch, release, label))317 compose_source_path(os_name, arch, subarch, release, label))
305318
@@ -337,7 +350,7 @@
337 driver_options = {350 driver_options = {
338 factory.make_name('arg'): factory.make_name('value')351 factory.make_name('arg'): factory.make_name('value')
339 for _ in range(3)352 for _ in range(3)
340 }353 }
341 create_diskless_disk(354 create_diskless_disk(
342 driver.name, driver_options,355 driver.name, driver_options,
343 system_id, sentinel.osystem, sentinel.arch,356 system_id, sentinel.osystem, sentinel.arch,
@@ -451,7 +464,7 @@
451 driver_options = {464 driver_options = {
452 factory.make_name('arg'): factory.make_name('value')465 factory.make_name('arg'): factory.make_name('value')
453 for _ in range(3)466 for _ in range(3)
454 }467 }
455 delete_diskless_disk(driver.name, driver_options, system_id)468 delete_diskless_disk(driver.name, driver_options, system_id)
456 self.assertThat(469 self.assertThat(
457 mock_delete,470 mock_delete,
458471
=== modified file 'src/provisioningserver/tests/test_plugin.py'
--- src/provisioningserver/tests/test_plugin.py 2015-04-29 06:19:04 +0000
+++ src/provisioningserver/tests/test_plugin.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -16,13 +16,16 @@
1616
17import os17import os
1818
19from fixtures import EnvironmentVariableFixture
20from maastesting.factory import factory
21from maastesting.testcase import (19from maastesting.testcase import (
22 MAASTestCase,20 MAASTestCase,
23 MAASTwistedRunTest,21 MAASTwistedRunTest,
24)22)
25import provisioningserver23import provisioningserver
24from provisioningserver.cluster_config import (
25 CLUSTER_CONFIG,
26 get_config_cluster_variable,
27 get_tftp_generator,
28)
26from provisioningserver.plugin import (29from provisioningserver.plugin import (
27 Options,30 Options,
28 ProvisioningRealm,31 ProvisioningRealm,
@@ -43,6 +46,7 @@
43 TFTPBackend,46 TFTPBackend,
44 TFTPService,47 TFTPService,
45)48)
49from provisioningserver.testing.config import ClusterConfigurationFixture
46from testtools.deferredruntest import assert_fails_with50from testtools.deferredruntest import assert_fails_with
47from testtools.matchers import (51from testtools.matchers import (
48 AfterPreprocessing,52 AfterPreprocessing,
@@ -56,7 +60,6 @@
56from twisted.cred.error import UnauthorizedLogin60from twisted.cred.error import UnauthorizedLogin
57from twisted.internet.defer import inlineCallbacks61from twisted.internet.defer import inlineCallbacks
58from twisted.web.resource import IResource62from twisted.web.resource import IResource
59import yaml
6063
6164
62class TestOptions(MAASTestCase):65class TestOptions(MAASTestCase):
@@ -64,7 +67,7 @@
6467
65 def test_defaults(self):68 def test_defaults(self):
66 options = Options()69 options = Options()
67 expected = {"config-file": "pserv.yaml", "introspect": None}70 expected = {"config-file": "clusterd.conf", "introspect": None}
68 self.assertEqual(expected, options.defaults)71 self.assertEqual(expected, options.defaults)
6972
70 def test_parse_minimal_options(self):73 def test_parse_minimal_options(self):
@@ -81,17 +84,9 @@
8184
82 def setUp(self):85 def setUp(self):
83 super(TestProvisioningServiceMaker, self).setUp()86 super(TestProvisioningServiceMaker, self).setUp()
87 self.useFixture(ClusterConfigurationFixture())
84 self.patch(provisioningserver, "services", MultiService())88 self.patch(provisioningserver, "services", MultiService())
85 self.tempdir = self.make_dir()89 self.tempdir = self.make_dir()
86 self.useFixture(
87 EnvironmentVariableFixture(
88 "CLUSTER_UUID", factory.make_UUID()))
89
90 def write_config(self, config):
91 config_filename = os.path.join(self.tempdir, "config.yaml")
92 with open(config_filename, "wb") as stream:
93 yaml.safe_dump(config, stream)
94 return config_filename
9590
96 def test_init(self):91 def test_init(self):
97 service_maker = ProvisioningServiceMaker("Harry", "Hill")92 service_maker = ProvisioningServiceMaker("Harry", "Hill")
@@ -103,14 +98,13 @@
103 Only the site service is created when no options are given.98 Only the site service is created when no options are given.
104 """99 """
105 options = Options()100 options = Options()
106 options["config-file"] = self.write_config({})
107 service_maker = ProvisioningServiceMaker("Harry", "Hill")101 service_maker = ProvisioningServiceMaker("Harry", "Hill")
108 service = service_maker.makeService(options)102 service = service_maker.makeService(options)
109 self.assertIsInstance(service, MultiService)103 self.assertIsInstance(service, MultiService)
110 expected_services = [104 expected_services = [
111 "dhcp_probe", "image_download", "lease_upload",105 "dhcp_probe", "image_download", "lease_upload",
112 "node_monitor", "rpc", "tftp", "image_service"106 "node_monitor", "rpc", "tftp", "image_service"
113 ]107 ]
114 self.assertItemsEqual(expected_services, service.namedServices)108 self.assertItemsEqual(expected_services, service.namedServices)
115 self.assertEqual(109 self.assertEqual(
116 len(service.namedServices), len(service.services),110 len(service.namedServices), len(service.services),
@@ -119,7 +113,6 @@
119113
120 def test_image_download_service(self):114 def test_image_download_service(self):
121 options = Options()115 options = Options()
122 options["config-file"] = self.write_config({})
123 service_maker = ProvisioningServiceMaker("Harry", "Hill")116 service_maker = ProvisioningServiceMaker("Harry", "Hill")
124 service = service_maker.makeService(options)117 service = service_maker.makeService(options)
125 image_service = service.getServiceNamed("image_download")118 image_service = service.getServiceNamed("image_download")
@@ -127,7 +120,6 @@
127120
128 def test_node_monitor_service(self):121 def test_node_monitor_service(self):
129 options = Options()122 options = Options()
130 options["config-file"] = self.write_config({})
131 service_maker = ProvisioningServiceMaker("Harry", "Hill")123 service_maker = ProvisioningServiceMaker("Harry", "Hill")
132 service = service_maker.makeService(options)124 service = service_maker.makeService(options)
133 node_monitor = service.getServiceNamed("node_monitor")125 node_monitor = service.getServiceNamed("node_monitor")
@@ -135,7 +127,6 @@
135127
136 def test_dhcp_probe_service(self):128 def test_dhcp_probe_service(self):
137 options = Options()129 options = Options()
138 options["config-file"] = self.write_config({})
139 service_maker = ProvisioningServiceMaker("Spike", "Milligan")130 service_maker = ProvisioningServiceMaker("Spike", "Milligan")
140 service = service_maker.makeService(options)131 service = service_maker.makeService(options)
141 dhcp_probe = service.getServiceNamed("dhcp_probe")132 dhcp_probe = service.getServiceNamed("dhcp_probe")
@@ -143,15 +134,7 @@
143134
144 def test_tftp_service(self):135 def test_tftp_service(self):
145 # A TFTP service is configured and added to the top-level service.136 # A TFTP service is configured and added to the top-level service.
146 config = {
147 "tftp": {
148 "generator": "http://candlemass/solitude",
149 "resource_root": self.tempdir,
150 "port": factory.pick_port(),
151 },
152 }
153 options = Options()137 options = Options()
154 options["config-file"] = self.write_config(config)
155 service_maker = ProvisioningServiceMaker("Harry", "Hill")138 service_maker = ProvisioningServiceMaker("Harry", "Hill")
156 service = service_maker.makeService(options)139 service = service_maker.makeService(options)
157 tftp_service = service.getServiceNamed("tftp")140 tftp_service = service.getServiceNamed("tftp")
@@ -161,24 +144,25 @@
161 IsInstance(TFTPBackend),144 IsInstance(TFTPBackend),
162 AfterPreprocessing(145 AfterPreprocessing(
163 lambda backend: backend.base.path,146 lambda backend: backend.base.path,
164 Equals(config["tftp"]["resource_root"])),147 Equals(os.path.split(
148 get_config_cluster_variable(
149 CLUSTER_CONFIG.DB_tftp_resource_root))[0])),
165 AfterPreprocessing(150 AfterPreprocessing(
166 lambda backend: backend.generator_url.geturl(),151 lambda backend: backend.generator_url.geturl(),
167 Equals(config["tftp"]["generator"])))152 Equals(get_tftp_generator())))
168153
169 self.assertThat(154 self.assertThat(
170 tftp_service, MatchesStructure(155 tftp_service, MatchesStructure(
171 backend=expected_backend,156 backend=expected_backend,
172 port=Equals(config["tftp"]["port"]),157 port=Equals(get_config_cluster_variable(
158 CLUSTER_CONFIG.DB_tftpport)),
173 ))159 ))
174160
175 def test_image_service(self):161 def test_image_service(self):
176 from provisioningserver import config
177 from twisted.web.server import Site162 from twisted.web.server import Site
178 from twisted.python.filepath import FilePath163 from twisted.python.filepath import FilePath
179164
180 options = Options()165 options = Options()
181 options["config-file"] = self.write_config({})
182 service_maker = ProvisioningServiceMaker("Harry", "Hill")166 service_maker = ProvisioningServiceMaker("Harry", "Hill")
183 service = service_maker.makeService(options)167 service = service_maker.makeService(options)
184 image_service = service.getServiceNamed("image_service")168 image_service = service.getServiceNamed("image_service")
@@ -189,8 +173,9 @@
189 "images", request=None)173 "images", request=None)
190 self.assertThat(root, IsInstance(FilePath))174 self.assertThat(root, IsInstance(FilePath))
191175
192 resource_root = os.path.join(176 resource_root = os.path.split(
193 config.BOOT_RESOURCES_STORAGE, "current")177 get_config_cluster_variable(
178 CLUSTER_CONFIG.DB_tftp_resource_root))[0]
194179
195 self.assertEqual(resource_root, root.path)180 self.assertEqual(resource_root, root.path)
196181
197182
=== modified file 'src/provisioningserver/tests/test_upgrade_cluster.py'
--- src/provisioningserver/tests/test_upgrade_cluster.py 2015-03-25 15:33:23 +0000
+++ src/provisioningserver/tests/test_upgrade_cluster.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -27,11 +27,13 @@
27from maastesting.testcase import MAASTestCase27from maastesting.testcase import MAASTestCase
28from maastesting.utils import sample_binary_data28from maastesting.utils import sample_binary_data
29from mock import Mock29from mock import Mock
30from provisioningserver import (30from provisioningserver import upgrade_cluster
31 config,
32 upgrade_cluster,
33)
34from provisioningserver.boot.tftppath import list_subdirs31from provisioningserver.boot.tftppath import list_subdirs
32from provisioningserver.cluster_config import (
33 CLUSTER_CONFIG,
34 set_config_cluster_variable,
35)
36from provisioningserver.testing.config import ClusterConfigurationFixture
35from provisioningserver.utils.fs import read_text_file37from provisioningserver.utils.fs import read_text_file
36from testtools.matchers import (38from testtools.matchers import (
37 DirExists,39 DirExists,
@@ -86,9 +88,14 @@
86class TestMakeMAASOwnBootResources(MAASTestCase):88class TestMakeMAASOwnBootResources(MAASTestCase):
87 """Tests for the `make_maas_own_boot_resources` upgrade."""89 """Tests for the `make_maas_own_boot_resources` upgrade."""
8890
91 def setUp(self):
92 super(TestMakeMAASOwnBootResources, self).setUp()
93 self.useFixture(ClusterConfigurationFixture())
94
89 def configure_storage(self, storage_dir):95 def configure_storage(self, storage_dir):
90 """Create a storage config."""96 """Create a storage config."""
91 self.patch(config, 'BOOT_RESOURCES_STORAGE', storage_dir)97 set_config_cluster_variable(
98 CLUSTER_CONFIG.DB_boot_resources_storage, storage_dir)
9299
93 def test__calls_chown_if_boot_resources_dir_exists(self):100 def test__calls_chown_if_boot_resources_dir_exists(self):
94 self.patch(upgrade_cluster, 'check_call')101 self.patch(upgrade_cluster, 'check_call')
@@ -102,7 +109,9 @@
102 def test__skips_chown_if_boot_resources_dir_does_not_exist(self):109 def test__skips_chown_if_boot_resources_dir_does_not_exist(self):
103 self.patch(upgrade_cluster, 'check_call')110 self.patch(upgrade_cluster, 'check_call')
104 storage_dir = os.path.join(self.make_dir(), factory.make_name('none'))111 storage_dir = os.path.join(self.make_dir(), factory.make_name('none'))
112 os.mkdir(storage_dir)
105 self.configure_storage(storage_dir)113 self.configure_storage(storage_dir)
114 os.rmdir(storage_dir)
106 upgrade_cluster.make_maas_own_boot_resources()115 upgrade_cluster.make_maas_own_boot_resources()
107 self.assertThat(upgrade_cluster.check_call, MockNotCalled())116 self.assertThat(upgrade_cluster.check_call, MockNotCalled())
108117
@@ -203,12 +212,18 @@
203class TestMigrateArchitecturesIntoUbuntuDirectory(MAASTestCase):212class TestMigrateArchitecturesIntoUbuntuDirectory(MAASTestCase):
204 """Tests for the `migrate_architectures_into_ubuntu_directory` upgrade."""213 """Tests for the `migrate_architectures_into_ubuntu_directory` upgrade."""
205214
215 def setUp(self):
216 super(TestMigrateArchitecturesIntoUbuntuDirectory, self).setUp()
217 self.useFixture(ClusterConfigurationFixture())
218
206 def configure_storage(self, storage_dir, make_current_dir=True):219 def configure_storage(self, storage_dir, make_current_dir=True):
207 """Create a storage config."""220 """Create a storage config."""
208 if make_current_dir:221 current_dir = os.path.join(storage_dir, "current")
209 current_dir = os.path.join(storage_dir, "current")222 os.makedirs(current_dir)
210 os.mkdir(current_dir)223 set_config_cluster_variable(
211 self.patch(config, 'BOOT_RESOURCES_STORAGE', storage_dir)224 CLUSTER_CONFIG.DB_boot_resources_storage, current_dir)
225 if not make_current_dir:
226 os.rmdir(current_dir)
212227
213 def test__list_subdirs_under_current_directory(self):228 def test__list_subdirs_under_current_directory(self):
214 self.patch(upgrade_cluster, 'list_subdirs').return_value = ['ubuntu']229 self.patch(upgrade_cluster, 'list_subdirs').return_value = ['ubuntu']
215230
=== modified file 'src/provisioningserver/upgrade_cluster.py'
--- src/provisioningserver/upgrade_cluster.py 2015-03-26 00:12:12 +0000
+++ src/provisioningserver/upgrade_cluster.py 2015-05-04 14:27:25 +0000
@@ -22,7 +22,7 @@
22 absolute_import,22 absolute_import,
23 print_function,23 print_function,
24 unicode_literals,24 unicode_literals,
25 )25)
2626
27str = None27str = None
2828
@@ -30,7 +30,7 @@
30__all__ = [30__all__ = [
31 'add_arguments',31 'add_arguments',
32 'run',32 'run',
33 ]33]
3434
35import os35import os
36from os import makedirs36from os import makedirs
@@ -38,12 +38,15 @@
38from subprocess import check_call38from subprocess import check_call
39from textwrap import dedent39from textwrap import dedent
4040
41from provisioningserver import config
42from provisioningserver.auth import get_maas_user_gpghome41from provisioningserver.auth import get_maas_user_gpghome
43from provisioningserver.boot.tftppath import (42from provisioningserver.boot.tftppath import (
44 drill_down,43 drill_down,
45 list_subdirs,44 list_subdirs,
46)45)
46from provisioningserver.cluster_config import (
47 CLUSTER_CONFIG,
48 get_config_cluster_variable,
49)
47from provisioningserver.import_images.boot_resources import (50from provisioningserver.import_images.boot_resources import (
48 update_targets_conf,51 update_targets_conf,
49 write_targets_conf,52 write_targets_conf,
@@ -57,8 +60,10 @@
57def make_maas_own_boot_resources():60def make_maas_own_boot_resources():
58 """Upgrade hook: make the `maas` user the owner of the boot resources."""61 """Upgrade hook: make the `maas` user the owner of the boot resources."""
59 # This reduces the privileges required for importing and managing images.62 # This reduces the privileges required for importing and managing images.
60 if os.path.isdir(config.BOOT_RESOURCES_STORAGE):63 boot_resources_storage = get_config_cluster_variable(
61 check_call(['chown', '-R', 'maas', config.BOOT_RESOURCES_STORAGE])64 CLUSTER_CONFIG.DB_boot_resources_storage)
65 if os.path.isdir(boot_resources_storage):
66 check_call(['chown', '-R', 'maas', boot_resources_storage])
6267
6368
64def create_gnupg_home():69def create_gnupg_home():
@@ -146,8 +151,8 @@
146 """Remove paths that contain directories with more levels. We don't want151 """Remove paths that contain directories with more levels. We don't want
147 to move other operating systems under the ubuntu directory."""152 to move other operating systems under the ubuntu directory."""
148 for arch, subarch, release, label in paths:153 for arch, subarch, release, label in paths:
149 path = os.path.join(154 path = os.path.join(get_config_cluster_variable(
150 config.BOOT_RESOURCES_STORAGE, 'current',155 CLUSTER_CONFIG.DB_boot_resources_storage),
151 arch, subarch, release, label)156 arch, subarch, release, label)
152 if len(list_subdirs(path)) == 0:157 if len(list_subdirs(path)) == 0:
153 yield (arch, subarch, release, label)158 yield (arch, subarch, release, label)
@@ -165,7 +170,8 @@
165 folders have structure arch/subarch/release/label and move them into170 folders have structure arch/subarch/release/label and move them into
166 ubuntu folder. Making the final path ubuntu/arch/subarch/release/label.171 ubuntu folder. Making the final path ubuntu/arch/subarch/release/label.
167 """172 """
168 current_dir = os.path.join(config.BOOT_RESOURCES_STORAGE, "current")173 current_dir = get_config_cluster_variable(
174 CLUSTER_CONFIG.DB_boot_resources_storage)
169 if not os.path.isdir(current_dir):175 if not os.path.isdir(current_dir):
170 return176 return
171 # If ubuntu folder already exists, then no reason to continue177 # If ubuntu folder already exists, then no reason to continue
@@ -213,7 +219,7 @@
213 create_gnupg_home,219 create_gnupg_home,
214 retire_bootresources_yaml,220 retire_bootresources_yaml,
215 migrate_architectures_into_ubuntu_directory,221 migrate_architectures_into_ubuntu_directory,
216 ]222]
217223
218224
219def add_arguments(parser):225def add_arguments(parser):
220226
=== modified file 'src/provisioningserver/utils/__init__.py'
--- src/provisioningserver/utils/__init__.py 2015-03-30 18:05:57 +0000
+++ src/provisioningserver/utils/__init__.py 2015-05-04 14:27:25 +0000
@@ -97,7 +97,7 @@
97 """97 """
98 # Avoid circular dependencies.98 # Avoid circular dependencies.
99 from provisioningserver.rpc.region import CreateNode99 from provisioningserver.rpc.region import CreateNode
100 from provisioningserver.cluster_config import get_cluster_uuid100 from provisioningserver import cluster_config
101101
102 for elapsed, remaining, wait in retries(15, 5, reactor):102 for elapsed, remaining, wait in retries(15, 5, reactor):
103 try:103 try:
@@ -116,7 +116,8 @@
116 try:116 try:
117 response = yield client(117 response = yield client(
118 CreateNode,118 CreateNode,
119 cluster_uuid=get_cluster_uuid(),119 cluster_uuid=cluster_config.get_config_cluster_variable(
120 cluster_config.CLUSTER_CONFIG.DB_cluster_uuid),
120 architecture=arch,121 architecture=arch,
121 power_type=power_type,122 power_type=power_type,
122 power_parameters=json.dumps(power_parameters),123 power_parameters=json.dumps(power_parameters),
123124
=== modified file 'src/provisioningserver/utils/script.py'
--- src/provisioningserver/utils/script.py 2015-02-24 13:52:12 +0000
+++ src/provisioningserver/utils/script.py 2015-05-04 14:27:25 +0000
@@ -7,7 +7,7 @@
7 absolute_import,7 absolute_import,
8 print_function,8 print_function,
9 unicode_literals,9 unicode_literals,
10 )10)
1111
12str = None12str = None
1313
@@ -16,7 +16,7 @@
16 'ActionScript',16 'ActionScript',
17 'AtomicWriteScript',17 'AtomicWriteScript',
18 'MainScript',18 'MainScript',
19 ]19]
2020
21from argparse import ArgumentParser21from argparse import ArgumentParser
22from os import fdopen22from os import fdopen
@@ -24,6 +24,7 @@
24from subprocess import CalledProcessError24from subprocess import CalledProcessError
25import sys25import sys
2626
27from provisioningserver.config import ClusterConfiguration
27from provisioningserver.utils.fs import atomic_write28from provisioningserver.utils.fs import atomic_write
2829
2930
@@ -92,20 +93,18 @@
9293
93 The `--config-file` option defaults to the value of94 The `--config-file` option defaults to the value of
94 `MAAS_PROVISIONING_SETTINGS` in the process's environment, or absent95 `MAAS_PROVISIONING_SETTINGS` in the process's environment, or absent
95 that, `$MAAS_CONFIG_DIR/pserv.yaml` (normally /etc/maas/pserv.yaml for96 that, or when running from branch, the equivalent
96 packaged installations, or when running from branch, the equivalent
97 inside that branch).97 inside that branch).
98 """98 """
9999
100 def __init__(self, description):100 def __init__(self, description):
101 # Avoid circular imports.101 # Avoid circular imports.
102 from provisioningserver.config import Config
103102
104 super(MainScript, self).__init__(description)103 super(MainScript, self).__init__(description)
105 self.parser.add_argument(104 self.parser.add_argument(
106 "-c", "--config-file", metavar="FILENAME",105 "-c", "--config-file", metavar="FILENAME",
107 help="Configuration file to load [%(default)s].",106 help="Configuration file to load [%(default)s].",
108 default=Config.DEFAULT_FILENAME)107 default=ClusterConfiguration.default)
109108
110109
111class AtomicWriteScript:110class AtomicWriteScript:
@@ -141,7 +140,7 @@
141 if args.mode is not None:140 if args.mode is not None:
142 mode = int(args.mode, 8)141 mode = int(args.mode, 8)
143 else:142 else:
144 mode = 0600143 mode = 0o600
145 atomic_write(144 atomic_write(
146 content, args.filename, overwrite=not args.no_overwrite,145 content, args.filename, overwrite=not args.no_overwrite,
147 mode=mode)146 mode=mode)
148147
=== modified file 'src/provisioningserver/utils/tests/test_utils.py'
--- src/provisioningserver/utils/tests/test_utils.py 2015-03-30 18:05:57 +0000
+++ src/provisioningserver/utils/tests/test_utils.py 2015-05-04 14:27:25 +0000
@@ -34,12 +34,17 @@
34 sentinel,34 sentinel,
35)35)
36import provisioningserver36import provisioningserver
37from provisioningserver.cluster_config import (
38 CLUSTER_CONFIG,
39 set_config_cluster_variable,
40)
37from provisioningserver.rpc import region41from provisioningserver.rpc import region
38from provisioningserver.rpc.exceptions import (42from provisioningserver.rpc.exceptions import (
39 CommissionNodeFailed,43 CommissionNodeFailed,
40 NodeAlreadyExists,44 NodeAlreadyExists,
41)45)
42from provisioningserver.rpc.testing import MockLiveClusterToRegionRPCFixture46from provisioningserver.rpc.testing import MockLiveClusterToRegionRPCFixture
47from provisioningserver.testing.config import ClusterConfigurationFixture
43from provisioningserver.testing.testcase import PservTestCase48from provisioningserver.testing.testcase import PservTestCase
44import provisioningserver.utils49import provisioningserver.utils
45from provisioningserver.utils import (50from provisioningserver.utils import (
@@ -411,6 +416,10 @@
411416
412class TestCreateNode(PservTestCase):417class TestCreateNode(PservTestCase):
413418
419 def setUp(self):
420 super(TestCreateNode, self).setUp()
421 self.useFixture(ClusterConfigurationFixture())
422
414 run_tests_with = MAASTwistedRunTest.make_factory(timeout=5)423 run_tests_with = MAASTwistedRunTest.make_factory(timeout=5)
415424
416 def prepare_region_rpc(self):425 def prepare_region_rpc(self):
@@ -438,14 +447,14 @@
438 'power_control': None,447 'power_control': None,
439 'system_id': uuid448 'system_id': uuid
440 }449 }
441 get_cluster_uuid = self.patch(450 test_uuid = factory.make_UUID()
442 provisioningserver.cluster_config, 'get_cluster_uuid')451 set_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid, test_uuid)
443 get_cluster_uuid.return_value = 'cluster-' + factory.make_UUID()452
444 yield create_node(453 yield create_node(
445 macs, arch, power_type, power_parameters, hostname=hostname)454 macs, arch, power_type, power_parameters, hostname=hostname)
446 self.assertThat(455 self.assertThat(
447 protocol.CreateNode, MockCalledOnceWith(456 protocol.CreateNode, MockCalledOnceWith(
448 protocol, cluster_uuid=get_cluster_uuid.return_value,457 protocol, cluster_uuid=test_uuid,
449 architecture=arch, power_type=power_type,458 architecture=arch, power_type=power_type,
450 power_parameters=json.dumps(power_parameters),459 power_parameters=json.dumps(power_parameters),
451 mac_addresses=macs, hostname=hostname))460 mac_addresses=macs, hostname=hostname))
@@ -483,9 +492,9 @@
483 system_id = factory.make_name("system-id")492 system_id = factory.make_name("system-id")
484 protocol.CreateNode.return_value = defer.succeed(493 protocol.CreateNode.return_value = defer.succeed(
485 {"system_id": system_id})494 {"system_id": system_id})
486 get_cluster_uuid = self.patch(495
487 provisioningserver.cluster_config, 'get_cluster_uuid')496 test_uuid = factory.make_UUID()
488 get_cluster_uuid.return_value = 'cluster-' + factory.make_UUID()497 set_config_cluster_variable(CLUSTER_CONFIG.DB_cluster_uuid, test_uuid)
489498
490 uuid = 'node-' + factory.make_UUID()499 uuid = 'node-' + factory.make_UUID()
491 arch = factory.make_name('architecture')500 arch = factory.make_name('architecture')
@@ -506,7 +515,7 @@
506 macs_with_duplicate, arch, power_type, power_parameters)515 macs_with_duplicate, arch, power_type, power_parameters)
507 self.assertThat(516 self.assertThat(
508 protocol.CreateNode, MockCalledOnceWith(517 protocol.CreateNode, MockCalledOnceWith(
509 protocol, cluster_uuid=get_cluster_uuid.return_value,518 protocol, cluster_uuid=test_uuid,
510 architecture=arch, power_type=power_type,519 architecture=arch, power_type=power_type,
511 power_parameters=json.dumps(power_parameters),520 power_parameters=json.dumps(power_parameters),
512 mac_addresses=macs, hostname=None))521 mac_addresses=macs, hostname=None))
@@ -517,9 +526,6 @@
517 self.addCleanup((yield connecting))526 self.addCleanup((yield connecting))
518 system_id = factory.make_name("system-id")527 system_id = factory.make_name("system-id")
519 maaslog = self.patch(provisioningserver.utils, 'maaslog')528 maaslog = self.patch(provisioningserver.utils, 'maaslog')
520 get_cluster_uuid = self.patch(
521 provisioningserver.utils, 'get_cluster_uuid')
522 get_cluster_uuid.return_value = 'cluster-' + factory.make_UUID()
523529
524 uuid = 'node-' + factory.make_UUID()530 uuid = 'node-' + factory.make_UUID()
525 macs = sorted(factory.make_mac_address() for _ in range(3))531 macs = sorted(factory.make_mac_address() for _ in range(3))