Merge lp:~rvb/maas/option-to-disable-image-update into lp:~maas-committers/maas/trunk

Proposed by Raphaël Badin
Status: Merged
Approved by: Raphaël Badin
Approved revision: no longer in the source branch.
Merged at revision: 3887
Proposed branch: lp:~rvb/maas/option-to-disable-image-update
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 267 lines (+100/-14)
6 files modified
src/maasserver/bootresources.py (+23/-4)
src/maasserver/forms.py (+22/-6)
src/maasserver/forms_settings.py (+12/-0)
src/maasserver/models/config.py (+2/-0)
src/maasserver/tests/test_bootresources.py (+21/-1)
src/maasserver/tests/test_forms_config.py (+20/-3)
To merge this branch: bzr merge lp:~rvb/maas/option-to-disable-image-update
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+259010@code.launchpad.net

Commit message

Add option to disable the auto import of images.

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

Looks good.

review: Approve
Revision history for this message
Raphaël Badin (rvb) wrote :

All fixed, thanks for the review Gavin!

Revision history for this message
Raphaël Badin (rvb) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/bootresources.py'
2--- src/maasserver/bootresources.py 2015-05-07 18:14:38 +0000
3+++ src/maasserver/bootresources.py 2015-05-13 16:38:46 +0000
4@@ -13,10 +13,11 @@
5
6 __metaclass__ = type
7 __all__ = [
8- "ImportResourcesProgressService",
9 "ensure_boot_source_definition",
10 "get_simplestream_endpoint",
11+ "ImportResourcesProgressService",
12 "ImportResourcesService",
13+ "IMPORT_RESOURCES_SERVICE_PERIOD",
14 "is_import_resources_running",
15 "simplestreams_file_handler",
16 "simplestreams_stream_handler",
17@@ -59,6 +60,7 @@
18 BootResource,
19 BootResourceFile,
20 BootResourceSet,
21+ Config,
22 LargeFile,
23 NodeGroup,
24 )
25@@ -994,16 +996,33 @@
26 return locks.import_images.is_locked()
27
28
29+def import_resources_periodically():
30+ """Import boot resources.
31+
32+ This is called by the ImportResourcesService to import the boot resources
33+ periodically. It will simply call _import_resources_in_thread unless
34+ the periodic image import mechanism has been disabled.
35+ """
36+ if Config.objects.get_config('boot_images_auto_import'):
37+ return _import_resources_in_thread()
38+ else:
39+ maaslog.debug(
40+ "Skipping periodic import of boot resources as it is disabled.")
41+
42+
43+# How often the import service runs.
44+IMPORT_RESOURCES_SERVICE_PERIOD = timedelta(hours=1)
45+
46+
47 class ImportResourcesService(TimerService, object):
48 """Service to periodically import boot resources.
49
50 This will run immediately when it's started, then once again every hour,
51 though the interval can be overridden by passing it to the constructor.
52 """
53-
54- def __init__(self, interval=timedelta(hours=1)):
55+ def __init__(self, interval=IMPORT_RESOURCES_SERVICE_PERIOD):
56 super(ImportResourcesService, self).__init__(
57- interval.total_seconds(), _import_resources_in_thread)
58+ interval.total_seconds(), import_resources_periodically)
59
60
61 class ImportResourcesProgressService(TimerService, object):
62
63=== modified file 'src/maasserver/forms.py'
64--- src/maasserver/forms.py 2015-05-11 18:57:33 +0000
65+++ src/maasserver/forms.py 2015-05-13 16:38:46 +0000
66@@ -1264,6 +1264,9 @@
67 """A base class for forms that save the content of their fields into
68 Config objects.
69 """
70+ # List of fields that should be considered configuration fields.
71+ # Consider all the fields as configuration fields if this is None.
72+ config_fields = None
73
74 def __init__(self, *args, **kwargs):
75 super(ConfigForm, self).__init__(*args, **kwargs)
76@@ -1280,9 +1283,14 @@
77 def clean(self):
78 cleaned_data = super(Form, self).clean()
79 for config_name in cleaned_data.keys():
80- if config_name not in CONFIG_ITEMS_KEYS:
81- self._errors[config_name] = self.error_class([
82- INVALID_SETTING_MSG_TEMPLATE % config_name])
83+ consider_field = (
84+ self.config_fields is None or
85+ config_name in self.config_fields
86+ )
87+ if consider_field:
88+ if config_name not in CONFIG_ITEMS_KEYS:
89+ self._errors[config_name] = self.error_class([
90+ INVALID_SETTING_MSG_TEMPLATE % config_name])
91 return cleaned_data
92
93 def save(self):
94@@ -1299,7 +1307,12 @@
95 return False
96 else:
97 for name, value in self.cleaned_data.items():
98- Config.objects.set_config(name, value)
99+ consider_field = (
100+ self.config_fields is None or
101+ name in self.config_fields
102+ )
103+ if consider_field:
104+ Config.objects.set_config(name, value)
105 return True
106
107
108@@ -1379,8 +1392,11 @@
109 kernel_opts = get_config_field('kernel_opts')
110
111
112-class BootSourceSettingsForm(Form):
113+class BootSourceSettingsForm(ConfigForm):
114 """Settings page, Boot Images section."""
115+ config_fields = ['boot_images_auto_import']
116+
117+ boot_images_auto_import = get_config_field('boot_images_auto_import')
118 boot_source_url = forms.CharField(
119 label="Sync URL", required=True,
120 help_text=(
121@@ -1420,7 +1436,7 @@
122 sucessfully saved into the detabase.
123 :rtype: boolean
124 """
125- self.full_clean()
126+ super(BootSourceSettingsForm, self).save()
127 if self._errors:
128 return False
129 boot_source = BootSource.objects.first()
130
131=== modified file 'src/maasserver/forms_settings.py'
132--- src/maasserver/forms_settings.py 2015-05-07 18:14:38 +0000
133+++ src/maasserver/forms_settings.py 2015-05-13 16:38:46 +0000
134@@ -25,6 +25,7 @@
135
136 from django import forms
137 from django.core.exceptions import ValidationError
138+from maasserver.bootresources import IMPORT_RESOURCES_SERVICE_PERIOD
139 from maasserver.models.config import (
140 Config,
141 DEFAULT_OS,
142@@ -293,6 +294,17 @@
143 "Erase nodes' disks prior to releasing.")
144 }
145 },
146+ 'boot_images_auto_import': {
147+ 'default': True,
148+ 'form': forms.BooleanField,
149+ 'form_kwargs': {
150+ 'required': False,
151+ 'label': (
152+ "Automatically import/refresh the boot images "
153+ "every %d minutes" %
154+ (IMPORT_RESOURCES_SERVICE_PERIOD.total_seconds() / 60.0))
155+ }
156+ },
157 }
158
159
160
161=== modified file 'src/maasserver/models/config.py'
162--- src/maasserver/models/config.py 2015-05-07 18:14:38 +0000
163+++ src/maasserver/models/config.py 2015-05-13 16:38:46 +0000
164@@ -63,6 +63,8 @@
165 # RPC configuration.
166 'rpc_region_certificate': None,
167 'rpc_shared_secret': None,
168+ # Images.
169+ 'boot_images_auto_import': True,
170 # Third Party
171 'enable_third_party_drivers': True,
172 'enable_disk_erasing_on_release': False,
173
174=== modified file 'src/maasserver/tests/test_bootresources.py'
175--- src/maasserver/tests/test_bootresources.py 2015-05-07 18:14:38 +0000
176+++ src/maasserver/tests/test_bootresources.py 2015-05-13 16:38:46 +0000
177@@ -1240,10 +1240,30 @@
178 def test__calls__import_resources_in_thread(self):
179 service = bootresources.ImportResourcesService()
180 self.assertEqual(
181- (bootresources._import_resources_in_thread, (), {}),
182+ (bootresources.import_resources_periodically, (), {}),
183 service.call)
184
185
186+class TestImportResourcesPeriodically(MAASTestCase):
187+ """Tests for `import_resources_periodically`."""
188+
189+ def test__calls__import_resources_in_thread_if_auto(self):
190+ Config.objects.set_config('boot_images_auto_import', True)
191+ mock__import_resources_in_thread = self.patch(
192+ bootresources, '_import_resources_in_thread')
193+ bootresources.import_resources_periodically()
194+ self.assertThat(
195+ mock__import_resources_in_thread, MockCalledOnceWith())
196+
197+ def test__doesnt_call__import_resources_in_thread_if_no_auto(self):
198+ Config.objects.set_config('boot_images_auto_import', False)
199+ mock__import_resources_in_thread = self.patch(
200+ bootresources, '_import_resources_in_thread')
201+ bootresources.import_resources_periodically()
202+ self.assertThat(
203+ mock__import_resources_in_thread, MockNotCalled())
204+
205+
206 class TestImportResourcesProgressService(MAASServerTestCase):
207 """Tests for `ImportResourcesProgressService`."""
208
209
210=== modified file 'src/maasserver/tests/test_forms_config.py'
211--- src/maasserver/tests/test_forms_config.py 2014-08-26 03:50:06 +0000
212+++ src/maasserver/tests/test_forms_config.py 2015-05-13 16:38:46 +0000
213@@ -31,6 +31,13 @@
214 maas_name = forms.CharField(label="Field 1", max_length=10)
215
216
217+class TestCompositeForm(ConfigForm):
218+ config_fields = ['maas_name']
219+
220+ maas_name = forms.CharField(label="Field 1", max_length=10)
221+ non_config_field = forms.CharField(label="Field 2", max_length=10)
222+
223+
224 class ConfigFormTest(MAASServerTestCase):
225
226 def test_form_valid_saves_into_db(self):
227@@ -38,7 +45,7 @@
228 form = TestValidOptionForm({'maas_name': value})
229 result = form.save()
230
231- self.assertTrue(result)
232+ self.assertTrue(result, form._errors)
233 self.assertEqual(value, Config.objects.get_config('maas_name'))
234
235 def test_form_rejects_unknown_settings(self):
236@@ -47,7 +54,7 @@
237 form = TestOptionForm({'field1': value, 'field2': value2})
238 valid = form.is_valid()
239
240- self.assertFalse(valid)
241+ self.assertFalse(valid, form._errors)
242 self.assertIn('field1', form._errors)
243 self.assertIn('field2', form._errors)
244
245@@ -56,7 +63,7 @@
246 form = TestOptionForm({'field1': value_too_long, 'field2': False})
247 result = form.save()
248
249- self.assertFalse(result)
250+ self.assertFalse(result, form._errors)
251 self.assertIn('field1', form._errors)
252 self.assertIsNone(Config.objects.get_config('field1'))
253 self.assertIsNone(Config.objects.get_config('field2'))
254@@ -76,3 +83,13 @@
255
256 self.assertItemsEqual(['field1'], form.initial)
257 self.assertEqual(value, form.initial['field1'])
258+
259+ def test_validates_composite_form(self):
260+ value1 = factory.make_string(5)
261+ value2 = factory.make_string(5)
262+ form = TestCompositeForm(
263+ {'maas_name': value1, 'non_config_field': value2})
264+ result = form.save()
265+
266+ self.assertTrue(result, form._errors)
267+ self.assertEqual(value1, Config.objects.get_config('maas_name'))