Merge lp:~trapnine/maas/fix-1562214 into lp:~maas-committers/maas/trunk

Proposed by Jeffrey C Jones
Status: Merged
Approved by: Jeffrey C Jones
Approved revision: no longer in the source branch.
Merged at revision: 4856
Proposed branch: lp:~trapnine/maas/fix-1562214
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 305 lines (+106/-31)
7 files modified
src/maasserver/enum.py (+2/-0)
src/maasserver/service_monitor.py (+19/-3)
src/maasserver/tests/test_service_monitor.py (+48/-1)
src/provisioningserver/service_monitor.py (+1/-1)
src/provisioningserver/tests/test_service_monitor.py (+2/-2)
src/provisioningserver/utils/service_monitor.py (+20/-22)
src/provisioningserver/utils/tests/test_service_monitor.py (+14/-2)
To merge this branch: bzr merge lp:~trapnine/maas/fix-1562214
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+290594@code.launchpad.net

Commit message

The proxy service status will not be failed when the internal proxy server has been disabled in MAAS Settings.

Description of the change

The proxy service status will not be failed when the internal proxy server has been disabled in MAAS Settings.

When this is the case, the proxy status_info will read 'disabled, alternate proxy is configured in settings' so the user knows why proxy is off, and where to change it.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks really good. Just one comment that needs to be fixed before landing.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/enum.py'
2--- src/maasserver/enum.py 2016-03-26 00:36:43 +0000
3+++ src/maasserver/enum.py 2016-03-31 16:08:17 +0000
4@@ -609,6 +609,8 @@
5 DEAD = 'dead'
6 #: Service is off. (Should be off and is off).
7 OFF = 'off'
8+ #: Service is on.
9+ ON = 'on'
10
11
12 SERVICE_STATUS_CHOICES = (
13
14=== modified file 'src/maasserver/service_monitor.py'
15--- src/maasserver/service_monitor.py 2016-03-11 02:42:18 +0000
16+++ src/maasserver/service_monitor.py 2016-03-31 16:08:17 +0000
17@@ -8,14 +8,17 @@
18
19 from datetime import timedelta
20
21+from maasserver.enum import SERVICE_STATUS
22+from maasserver.models.config import Config
23 from maasserver.models.regioncontrollerprocess import RegionControllerProcess
24-from maasserver.models.service import Service
25+from maasserver.models.service import Service as ServiceModel
26 from maasserver.utils.orm import transactional
27 from maasserver.utils.threads import deferToDatabase
28 from provisioningserver.config import is_dev_environment
29 from provisioningserver.logger import get_maas_logger
30 from provisioningserver.utils.service_monitor import (
31 AlwaysOnService,
32+ Service,
33 ServiceMonitor,
34 )
35 from twisted.application.internet import TimerService
36@@ -34,12 +37,25 @@
37 service_name = "bind9"
38
39
40-class ProxyService(AlwaysOnService):
41+class ProxyService(Service):
42 """Monitored proxy service."""
43
44 name = "proxy"
45 service_name = "maas-proxy"
46
47+ def get_expected_state(self):
48+
49+ @transactional
50+ def db_get_expected_state():
51+ if (Config.objects.get_config("enable_http_proxy") and
52+ Config.objects.get_config("http_proxy")):
53+ return (SERVICE_STATUS.OFF,
54+ "disabled, alternate proxy is configured in settings.")
55+ else:
56+ return (SERVICE_STATUS.ON, None)
57+
58+ return deferToDatabase(db_get_expected_state)
59+
60
61 # Global service monitor for regiond.
62 service_monitor = ServiceMonitor(
63@@ -88,7 +104,7 @@
64 """
65 process = RegionControllerProcess.objects.get(id=processId)
66 for service in services:
67- Service.objects.update_service_for(
68+ ServiceModel.objects.update_service_for(
69 process.region, service["name"],
70 service["status"], service["status_info"])
71
72
73=== modified file 'src/maasserver/tests/test_service_monitor.py'
74--- src/maasserver/tests/test_service_monitor.py 2016-03-08 21:35:13 +0000
75+++ src/maasserver/tests/test_service_monitor.py 2016-03-31 16:08:17 +0000
76@@ -10,8 +10,10 @@
77 from crochet import wait_for
78 from maasserver import service_monitor as service_monitor_module
79 from maasserver.enum import SERVICE_STATUS
80+from maasserver.models.config import Config
81 from maasserver.models.service import Service
82 from maasserver.service_monitor import (
83+ ProxyService,
84 service_monitor,
85 ServiceMonitorService,
86 )
87@@ -38,6 +40,7 @@
88 from twisted.internet.defer import (
89 fail,
90 inlineCallbacks,
91+ maybeDeferred,
92 succeed,
93 )
94 from twisted.internet.task import Clock
95@@ -157,4 +160,48 @@
96 "status": "running",
97 "status_info": "",
98 }]
99- self.assertEquals(expected_services, observed_services)
100+ self.assertEqual(expected_services, observed_services)
101+
102+
103+class TestProxyService(MAASTransactionServerTestCase):
104+
105+ def make_proxy_service(self):
106+ class FakeProxyService(ProxyService):
107+ name = factory.make_name("name")
108+ service_name = factory.make_name("service")
109+ return FakeProxyService()
110+
111+ @inlineCallbacks
112+ def test_get_expected_state_returns_on_for_proxy_off_and_unset(self):
113+ service = self.make_proxy_service()
114+ Config.objects.set_config("enable_http_proxy", False)
115+ Config.objects.set_config("http_proxy", "")
116+ expected_state = yield maybeDeferred(service.get_expected_state)
117+ self.assertEqual((SERVICE_STATUS.ON, None), expected_state)
118+
119+ @inlineCallbacks
120+ def test_get_expected_state_returns_on_for_proxy_off_and_set(self):
121+ service = self.make_proxy_service()
122+ Config.objects.set_config("enable_http_proxy", False)
123+ Config.objects.set_config("http_proxy", factory.make_url())
124+ expected_state = yield maybeDeferred(service.get_expected_state)
125+ self.assertEqual((SERVICE_STATUS.ON, None), expected_state)
126+
127+ @inlineCallbacks
128+ def test_get_expected_state_returns_on_for_proxy_on_but_unset(self):
129+ service = self.make_proxy_service()
130+ Config.objects.set_config("enable_http_proxy", True)
131+ Config.objects.set_config("http_proxy", "")
132+ expected_state = yield maybeDeferred(service.get_expected_state)
133+ self.assertEqual((SERVICE_STATUS.ON, None), expected_state)
134+
135+ @inlineCallbacks
136+ def test_get_expected_state_returns_off_for_proxy_on_and_set(self):
137+ service = self.make_proxy_service()
138+ Config.objects.set_config("enable_http_proxy", True)
139+ Config.objects.set_config("http_proxy", factory.make_url())
140+ expected_state = yield maybeDeferred(service.get_expected_state)
141+ self.assertEqual(
142+ (SERVICE_STATUS.OFF,
143+ 'disabled, alternate proxy is configured in settings.'),
144+ expected_state)
145
146=== modified file 'src/provisioningserver/service_monitor.py'
147--- src/provisioningserver/service_monitor.py 2016-03-25 14:52:23 +0000
148+++ src/provisioningserver/service_monitor.py 2016-03-31 16:08:17 +0000
149@@ -27,7 +27,7 @@
150 The dhcp service always starts as off. Once the rackd starts dhcp
151 `expected_state` will be set to ON.
152 """
153- return self.expected_state
154+ return (self.expected_state, None)
155
156 def is_on(self):
157 """Return true if the service should be on."""
158
159=== modified file 'src/provisioningserver/tests/test_service_monitor.py'
160--- src/provisioningserver/tests/test_service_monitor.py 2016-03-25 14:52:23 +0000
161+++ src/provisioningserver/tests/test_service_monitor.py 2016-03-31 16:08:17 +0000
162@@ -36,7 +36,7 @@
163 def test_get_expected_state_returns_from_expected_state(self):
164 service = self.make_dhcp_service()
165 service.expected_state = sentinel.state
166- self.assertEqual(sentinel.state, service.get_expected_state())
167+ self.assertEqual((sentinel.state, None), service.get_expected_state())
168
169 def test_is_on_returns_True_when_expected_state_on(self):
170 service = self.make_dhcp_service()
171@@ -95,7 +95,7 @@
172
173 def test_get_expected_state(self):
174 tgt = TGTService()
175- self.assertEqual(SERVICE_STATE.ON, tgt.get_expected_state())
176+ self.assertEqual((SERVICE_STATE.ON, None), tgt.get_expected_state())
177
178
179 class TestGlobalServiceMonitor(MAASTestCase):
180
181=== modified file 'src/provisioningserver/utils/service_monitor.py'
182--- src/provisioningserver/utils/service_monitor.py 2016-03-25 14:52:23 +0000
183+++ src/provisioningserver/utils/service_monitor.py 2016-03-31 16:08:17 +0000
184@@ -71,28 +71,26 @@
185 @inlineCallbacks
186 def get_status_and_status_info_for(self, service):
187 """Return the status and status_info for the state of `service`."""
188+ status = "off"
189+ status_info = ""
190+ expected_state, service_status_info = yield maybeDeferred(
191+ service.get_expected_state)
192 if self.active_state == SERVICE_STATE.UNKNOWN:
193 status = "unknown"
194- status_info = ""
195 elif self.active_state == SERVICE_STATE.ON:
196 status = "running"
197- status_info = ""
198- else:
199- expected_state = yield maybeDeferred(
200- service.get_expected_state)
201- if expected_state == SERVICE_STATE.ON:
202- status = "dead"
203- if self.active_state == SERVICE_STATE.OFF:
204- status_info = "%s is currently stopped." % (
205- service.service_name)
206- else:
207- status_info = (
208- "%s failed to start, process result: (%s)" % (
209- service.service_name, self.process_state))
210+ elif expected_state == SERVICE_STATE.ON:
211+ status = "dead"
212+ if self.active_state == SERVICE_STATE.OFF:
213+ status_info = "%s is currently stopped." % (
214+ service.service_name)
215 else:
216- status = "off"
217- status_info = ""
218- returnValue((status, status_info))
219+ status_info = (
220+ "%s failed to start, process result: (%s)" % (
221+ service.service_name, self.process_state))
222+ returnValue((
223+ status,
224+ service_status_info if service_status_info else status_info))
225
226
227 class Service(metaclass=ABCMeta):
228@@ -108,15 +106,15 @@
229
230 @abstractmethod
231 def get_expected_state(self):
232- """Return a the expected state for the service."""
233+ """Returns (expected state, status_info) for the service."""
234
235
236 class AlwaysOnService(Service):
237 """Service that should always be on."""
238
239 def get_expected_state(self):
240- """Service is should always on."""
241- return SERVICE_STATE.ON
242+ """AlwaysOnService should always be on."""
243+ return (SERVICE_STATE.ON, None)
244
245
246 class ServiceUnknownError(Exception):
247@@ -252,7 +250,7 @@
248 services expected state is not ON.
249 """
250 service = self.getServiceByName(name)
251- expected_state = yield maybeDeferred(service.get_expected_state)
252+ expected_state, _ = yield maybeDeferred(service.get_expected_state)
253 if expected_state != SERVICE_STATE.ON:
254 raise ServiceNotOnError(
255 "Service '%s' is not expected to be on, unable to restart." % (
256@@ -374,7 +372,7 @@
257 reach its expected process state based on the service's current
258 active state.
259 """
260- expected_state = yield maybeDeferred(service.get_expected_state)
261+ expected_state, _ = yield maybeDeferred(service.get_expected_state)
262 state = yield self.getServiceState(service.name, now=True)
263 if state.active_state == expected_state:
264 expected_process_state = (
265
266=== modified file 'src/provisioningserver/utils/tests/test_service_monitor.py'
267--- src/provisioningserver/utils/tests/test_service_monitor.py 2016-03-25 14:52:23 +0000
268+++ src/provisioningserver/utils/tests/test_service_monitor.py 2016-03-31 16:08:17 +0000
269@@ -46,7 +46,7 @@
270 from twisted.internet.threads import deferToThread
271
272
273-def make_fake_service(expected_state=None):
274+def make_fake_service(expected_state=None, status_info=None):
275 fake_name = factory.make_name("name")
276 fake_service_name = factory.make_name("service")
277 if expected_state is None:
278@@ -60,7 +60,7 @@
279 service_name = fake_service_name
280
281 def get_expected_state(self):
282- return succeed(expected_state)
283+ return succeed((expected_state, status_info))
284
285 return FakeService()
286
287@@ -117,6 +117,18 @@
288 self.assertEquals(
289 ("off", ""), observed_status)
290
291+ @inlineCallbacks
292+ def test_get_status_and_status_info_for_returns_service_service_info(self):
293+ # Make sure any service_info given by a service gets passed through.
294+ status_info = factory.make_string(60, True)
295+ active_state = factory.pick_enum(SERVICE_STATE)
296+ service = make_fake_service(active_state, status_info)
297+ state = ServiceState(active_state, None)
298+ observed_status = yield state.get_status_and_status_info_for(
299+ service)
300+ # Only check status_info - tests above have tested state.
301+ self.assertEquals(status_info, observed_status[1])
302+
303
304 class TestServiceMonitor(MAASTestCase):
305 """Tests for `ServiceMonitor`."""