Merge lp:~hazmat/pyjuju/unit-with-addresses into lp:pyjuju
- unit-with-addresses
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Gustavo Niemeyer | ||||
Approved revision: | 400 | ||||
Merged at revision: | 373 | ||||
Proposed branch: | lp:~hazmat/pyjuju/unit-with-addresses | ||||
Merge into: | lp:pyjuju | ||||
Prerequisite: | lp:~bcsaller/pyjuju/lxc-omega | ||||
Diff against target: |
482 lines (+333/-7) 9 files modified
juju/agents/tests/test_unit.py (+17/-0) juju/agents/unit.py (+8/-0) juju/environment/config.py (+1/-0) juju/providers/lxc/__init__.py (+7/-0) juju/providers/lxc/tests/test_provider.py (+5/-5) juju/state/service.py (+60/-1) juju/state/tests/test_service.py (+23/-1) juju/unit/address.py (+86/-0) juju/unit/tests/test_address.py (+126/-0) |
||||
To merge this branch: | bzr merge lp:~hazmat/pyjuju/unit-with-addresses | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gustavo Niemeyer | Approve | ||
Review via email: mp+76917@code.launchpad.net |
Commit message
Description of the change
Service units should know their public and private addresses.
This adds a two additional accessor/mutators to units for public/private
addresses, respectively. As well as provider specific implementation of address
detection, and unit agent initialization of those addresses on the unit state.
Kapil Thangavelu (hazmat) wrote : | # |
Excerpts from Gustavo Niemeyer's message of Mon Sep 26 13:15:39 UTC 2011:
> Review: Approve
>
> This looks very nice too, thanks!
>
> Just a couple of details:
>
>
> [1]
>
> + elif provider_type == "lxc":
>
> Please do not forget to rename the provider type to "local"
> before making this public.
sounds good, i'll put another branch in for the rename.
>
> [2]
>
> + output = subprocess.
>
> Why is this different for orchestra? Won't this fail if thethe release.
> machine doesn't have a properly assigned domain name? I suspect
> it will, and suggest using the same implementation of the local
> case there as well.
>
orchestra asserts that hostname is a valid fqdn. after long discussion on irc,
it seems that this is the most appropriate thing, and helps us get the
equivalent lines out of charms.
cheers,
Kapil
- 401. By Kapil Thangavelu
-
remove stray pdb
- 402. By Kapil Thangavelu
-
Merged lxc-omega-merge into unit-with-
addresses. - 403. By Kapil Thangavelu
-
Merged lxc-omega-merge into unit-with-
addresses. - 404. By Kapil Thangavelu
-
merge trunk and resolve conflict
Preview Diff
1 | === modified file 'juju/agents/tests/test_unit.py' | |||
2 | --- juju/agents/tests/test_unit.py 2011-09-29 00:33:59 +0000 | |||
3 | +++ juju/agents/tests/test_unit.py 2011-09-30 02:57:25 +0000 | |||
4 | @@ -11,6 +11,7 @@ | |||
5 | 11 | from juju.charm import get_charm_from_path | 11 | from juju.charm import get_charm_from_path |
6 | 12 | from juju.charm.url import CharmURL | 12 | from juju.charm.url import CharmURL |
7 | 13 | from juju.errors import JujuError | 13 | from juju.errors import JujuError |
8 | 14 | from juju.state.environment import GlobalSettingsStateManager | ||
9 | 14 | from juju.state.errors import ServiceStateNotFound | 15 | from juju.state.errors import ServiceStateNotFound |
10 | 15 | from juju.state.service import NO_HOOKS, RETRY_HOOKS | 16 | from juju.state.service import NO_HOOKS, RETRY_HOOKS |
11 | 16 | 17 | ||
12 | @@ -29,6 +30,8 @@ | |||
13 | 29 | @inlineCallbacks | 30 | @inlineCallbacks |
14 | 30 | def setUp(self): | 31 | def setUp(self): |
15 | 31 | yield super(UnitAgentTestBase, self).setUp() | 32 | yield super(UnitAgentTestBase, self).setUp() |
16 | 33 | settings = GlobalSettingsStateManager(self.client) | ||
17 | 34 | yield settings.set_provider_type("dummy") | ||
18 | 32 | self.change_environment( | 35 | self.change_environment( |
19 | 33 | PATH=get_cli_environ_path(), | 36 | PATH=get_cli_environ_path(), |
20 | 34 | JUJU_UNIT_NAME="mysql/0") | 37 | JUJU_UNIT_NAME="mysql/0") |
21 | @@ -148,6 +151,18 @@ | |||
22 | 148 | return self.assertFailure(agent.startService(), ServiceStateNotFound) | 151 | return self.assertFailure(agent.startService(), ServiceStateNotFound) |
23 | 149 | 152 | ||
24 | 150 | @inlineCallbacks | 153 | @inlineCallbacks |
25 | 154 | def test_agent_records_address_on_startup(self): | ||
26 | 155 | """On startup the agent will record the unit's addresses. | ||
27 | 156 | """ | ||
28 | 157 | yield self.agent.startService() | ||
29 | 158 | self.assertEqual( | ||
30 | 159 | (yield self.agent.unit_state.get_public_address()), | ||
31 | 160 | "localhost") | ||
32 | 161 | self.assertEqual( | ||
33 | 162 | (yield self.agent.unit_state.get_private_address()), | ||
34 | 163 | "localhost") | ||
35 | 164 | |||
36 | 165 | @inlineCallbacks | ||
37 | 151 | def test_agent_agent_executes_install_and_start_hooks_on_startup(self): | 166 | def test_agent_agent_executes_install_and_start_hooks_on_startup(self): |
38 | 152 | """On initial startup, the unit agent executes install and start hooks. | 167 | """On initial startup, the unit agent executes install and start hooks. |
39 | 153 | """ | 168 | """ |
40 | @@ -497,6 +512,8 @@ | |||
41 | 497 | @inlineCallbacks | 512 | @inlineCallbacks |
42 | 498 | def setUp(self): | 513 | def setUp(self): |
43 | 499 | yield super(UnitAgentTestBase, self).setUp() | 514 | yield super(UnitAgentTestBase, self).setUp() |
44 | 515 | settings = GlobalSettingsStateManager(self.client) | ||
45 | 516 | yield settings.set_provider_type("dummy") | ||
46 | 500 | self.makeDir(path=os.path.join(self.juju_directory, "charms")) | 517 | self.makeDir(path=os.path.join(self.juju_directory, "charms")) |
47 | 501 | 518 | ||
48 | 502 | @inlineCallbacks | 519 | @inlineCallbacks |
49 | 503 | 520 | ||
50 | === modified file 'juju/agents/unit.py' | |||
51 | --- juju/agents/unit.py 2011-09-27 19:18:08 +0000 | |||
52 | +++ juju/agents/unit.py 2011-09-30 02:57:25 +0000 | |||
53 | @@ -10,6 +10,7 @@ | |||
54 | 10 | from juju.hooks.protocol import UnitSettingsFactory | 10 | from juju.hooks.protocol import UnitSettingsFactory |
55 | 11 | from juju.hooks.executor import HookExecutor | 11 | from juju.hooks.executor import HookExecutor |
56 | 12 | 12 | ||
57 | 13 | from juju.unit.address import get_unit_address | ||
58 | 13 | from juju.unit.lifecycle import UnitLifecycle, HOOK_SOCKET_FILE | 14 | from juju.unit.lifecycle import UnitLifecycle, HOOK_SOCKET_FILE |
59 | 14 | from juju.unit.workflow import UnitWorkflowState | 15 | from juju.unit.workflow import UnitWorkflowState |
60 | 15 | 16 | ||
61 | @@ -84,6 +85,13 @@ | |||
62 | 84 | os.path.join(self.unit_directory, HOOK_SOCKET_FILE), | 85 | os.path.join(self.unit_directory, HOOK_SOCKET_FILE), |
63 | 85 | self.api_factory) | 86 | self.api_factory) |
64 | 86 | 87 | ||
65 | 88 | # Setup the unit state's address | ||
66 | 89 | address = yield get_unit_address(self.client) | ||
67 | 90 | yield self.unit_state.set_public_address( | ||
68 | 91 | (yield address.get_public_address())) | ||
69 | 92 | yield self.unit_state.set_private_address( | ||
70 | 93 | (yield address.get_private_address())) | ||
71 | 94 | |||
72 | 87 | # Inform the system, we're alive. | 95 | # Inform the system, we're alive. |
73 | 88 | yield self.unit_state.connect_agent() | 96 | yield self.unit_state.connect_agent() |
74 | 89 | 97 | ||
75 | 90 | 98 | ||
76 | === modified file 'juju/environment/config.py' | |||
77 | --- juju/environment/config.py 2011-09-27 04:29:30 +0000 | |||
78 | +++ juju/environment/config.py 2011-09-30 02:57:25 +0000 | |||
79 | @@ -57,6 +57,7 @@ | |||
80 | 57 | "default-series": String()}, | 57 | "default-series": String()}, |
81 | 58 | optional=["storage-url", "placement", | 58 | optional=["storage-url", "placement", |
82 | 59 | "default-series"]), | 59 | "default-series"]), |
83 | 60 | "dummy": KeyDict({}), | ||
84 | 60 | "lxc": KeyDict({"admin-secret": String(), | 61 | "lxc": KeyDict({"admin-secret": String(), |
85 | 61 | "data-dir": String(), | 62 | "data-dir": String(), |
86 | 62 | "placement": Constant("local"), | 63 | "placement": Constant("local"), |
87 | 63 | 64 | ||
88 | === modified file 'juju/providers/lxc/__init__.py' | |||
89 | --- juju/providers/lxc/__init__.py 2011-09-27 04:29:30 +0000 | |||
90 | +++ juju/providers/lxc/__init__.py 2011-09-30 02:57:25 +0000 | |||
91 | @@ -46,6 +46,13 @@ | |||
92 | 46 | "Unsupported placement policy for local provider") | 46 | "Unsupported placement policy for local provider") |
93 | 47 | return LOCAL_POLICY | 47 | return LOCAL_POLICY |
94 | 48 | 48 | ||
95 | 49 | def get_placement_policy(self): | ||
96 | 50 | """Local dev supports only one unit placement policy.""" | ||
97 | 51 | if self.config.get("placement", LOCAL_POLICY) != LOCAL_POLICY: | ||
98 | 52 | raise ProviderError( | ||
99 | 53 | "Unsupported placement policy for local provider") | ||
100 | 54 | return LOCAL_POLICY | ||
101 | 55 | |||
102 | 49 | @property | 56 | @property |
103 | 50 | def provider_type(self): | 57 | def provider_type(self): |
104 | 51 | return "lxc" | 58 | return "lxc" |
105 | 52 | 59 | ||
106 | === modified file 'juju/providers/lxc/tests/test_provider.py' | |||
107 | --- juju/providers/lxc/tests/test_provider.py 2011-09-27 04:29:30 +0000 | |||
108 | +++ juju/providers/lxc/tests/test_provider.py 2011-09-30 02:57:25 +0000 | |||
109 | @@ -1,7 +1,6 @@ | |||
110 | 1 | import logging | 1 | import logging |
111 | 2 | import os | 2 | import os |
112 | 3 | import pwd | 3 | import pwd |
113 | 4 | import subprocess | ||
114 | 5 | from StringIO import StringIO | 4 | from StringIO import StringIO |
115 | 6 | import zookeeper | 5 | import zookeeper |
116 | 7 | 6 | ||
117 | @@ -124,10 +123,11 @@ | |||
118 | 124 | lxc_ls_mock = self.mocker.mock() | 123 | lxc_ls_mock = self.mocker.mock() |
119 | 125 | self.patch(lxc_lib, "_cmd", lxc_ls_mock) | 124 | self.patch(lxc_lib, "_cmd", lxc_ls_mock) |
120 | 126 | lxc_ls_mock(["lxc-ls"]) | 125 | lxc_ls_mock(["lxc-ls"]) |
125 | 127 | self.mocker.result((0, | 126 | self.mocker.result( |
126 | 128 | "%(name)s-local-test-unit-1\n%(name)s-local-test-unit-2\n" | 127 | (0, |
127 | 129 | "%(name)s-local-test-unit-3\n%(name)s-local-test-unit-1\n" | 128 | "%(name)s-local-test-unit-1\n%(name)s-local-test-unit-2\n" |
128 | 130 | "%(name)s-local-test-unit-2\n" % dict(name=user_name))) | 129 | "%(name)s-local-test-unit-3\n%(name)s-local-test-unit-1\n" |
129 | 130 | "%(name)s-local-test-unit-2\n" % dict(name=user_name))) | ||
130 | 131 | 131 | ||
131 | 132 | mock_container = self.mocker.patch(LXCContainer) | 132 | mock_container = self.mocker.patch(LXCContainer) |
132 | 133 | mock_container.stop() | 133 | mock_container.stop() |
133 | 134 | 134 | ||
134 | === modified file 'juju/state/service.py' | |||
135 | --- juju/state/service.py 2011-09-28 23:54:04 +0000 | |||
136 | +++ juju/state/service.py 2011-09-30 02:57:25 +0000 | |||
137 | @@ -15,7 +15,7 @@ | |||
138 | 15 | ServiceUnitStateMachineAlreadyAssigned, ServiceStateNameInUse, | 15 | ServiceUnitStateMachineAlreadyAssigned, ServiceStateNameInUse, |
139 | 16 | BadDescriptor, BadServiceStateName, NoUnusedMachines, | 16 | BadDescriptor, BadServiceStateName, NoUnusedMachines, |
140 | 17 | ServiceUnitDebugAlreadyEnabled, ServiceUnitResolvedAlreadyEnabled, | 17 | ServiceUnitDebugAlreadyEnabled, ServiceUnitResolvedAlreadyEnabled, |
142 | 18 | ServiceUnitRelationResolvedAlreadyEnabled, StopWatcher) | 18 | ServiceUnitRelationResolvedAlreadyEnabled, StopWatcher, StateError) |
143 | 19 | from juju.state.charm import CharmStateManager | 19 | from juju.state.charm import CharmStateManager |
144 | 20 | from juju.state.relation import ServiceRelationState, RelationStateManager | 20 | from juju.state.relation import ServiceRelationState, RelationStateManager |
145 | 21 | from juju.state.machine import _public_machine_id, MachineState | 21 | from juju.state.machine import _public_machine_id, MachineState |
146 | @@ -708,6 +708,64 @@ | |||
147 | 708 | return "/units/%s/agent" % self._internal_id | 708 | return "/units/%s/agent" % self._internal_id |
148 | 709 | 709 | ||
149 | 710 | @inlineCallbacks | 710 | @inlineCallbacks |
150 | 711 | def get_public_address(self): | ||
151 | 712 | """Get the public address of the unit. | ||
152 | 713 | |||
153 | 714 | If the unit is unassigned, or its unit agent hasn't started this | ||
154 | 715 | value maybe None. | ||
155 | 716 | """ | ||
156 | 717 | unit_data, stat = yield self._client.get( | ||
157 | 718 | "/units/%s" % self.internal_id) | ||
158 | 719 | data = yaml.load(unit_data) | ||
159 | 720 | returnValue(data.get("public-address")) | ||
160 | 721 | |||
161 | 722 | @inlineCallbacks | ||
162 | 723 | def set_public_address(self, public_address): | ||
163 | 724 | """A unit's public address can be utilized to access the service. | ||
164 | 725 | |||
165 | 726 | The service must have been exposed for the service to be reachable | ||
166 | 727 | outside of the environment. | ||
167 | 728 | """ | ||
168 | 729 | def update_private_address(content, stat): | ||
169 | 730 | data = yaml.load(content) | ||
170 | 731 | data["public-address"] = public_address | ||
171 | 732 | return yaml.safe_dump(data) | ||
172 | 733 | |||
173 | 734 | yield retry_change( | ||
174 | 735 | self._client, | ||
175 | 736 | "/units/%s" % self.internal_id, | ||
176 | 737 | update_private_address) | ||
177 | 738 | |||
178 | 739 | @inlineCallbacks | ||
179 | 740 | def get_private_address(self): | ||
180 | 741 | """Get the private address of the unit. | ||
181 | 742 | |||
182 | 743 | If the unit is unassigned, or its unit agent hasn't started this | ||
183 | 744 | value maybe None. | ||
184 | 745 | """ | ||
185 | 746 | unit_data, stat = yield self._client.get( | ||
186 | 747 | "/units/%s" % self.internal_id) | ||
187 | 748 | data = yaml.load(unit_data) | ||
188 | 749 | returnValue(data.get("private-address")) | ||
189 | 750 | |||
190 | 751 | @inlineCallbacks | ||
191 | 752 | def set_private_address(self, private_address): | ||
192 | 753 | """A unit's address private to the environment. | ||
193 | 754 | |||
194 | 755 | Other service will see and utilize this address for relations. | ||
195 | 756 | """ | ||
196 | 757 | |||
197 | 758 | def update_private_address(content, stat): | ||
198 | 759 | data = yaml.load(content) | ||
199 | 760 | data["private-address"] = private_address | ||
200 | 761 | return yaml.safe_dump(data) | ||
201 | 762 | |||
202 | 763 | yield retry_change( | ||
203 | 764 | self._client, | ||
204 | 765 | "/units/%s" % self.internal_id, | ||
205 | 766 | update_private_address) | ||
206 | 767 | |||
207 | 768 | @inlineCallbacks | ||
208 | 711 | def get_charm_id(self): | 769 | def get_charm_id(self): |
209 | 712 | """Get the charm identifier that the unit is currently running.""" | 770 | """Get the charm identifier that the unit is currently running.""" |
210 | 713 | unit_data, stat = yield self._client.get( | 771 | unit_data, stat = yield self._client.get( |
211 | @@ -1331,6 +1389,7 @@ | |||
212 | 1331 | sequence = int(sequence) | 1389 | sequence = int(sequence) |
213 | 1332 | return service_name, sequence | 1390 | return service_name, sequence |
214 | 1333 | 1391 | ||
215 | 1392 | |||
216 | 1334 | def parse_service_name(unit_name): | 1393 | def parse_service_name(unit_name): |
217 | 1335 | """Return the service name from a given unit name.""" | 1394 | """Return the service name from a given unit name.""" |
218 | 1336 | try: | 1395 | try: |
219 | 1337 | 1396 | ||
220 | === modified file 'juju/state/tests/test_service.py' | |||
221 | --- juju/state/tests/test_service.py 2011-09-28 22:42:59 +0000 | |||
222 | +++ juju/state/tests/test_service.py 2011-09-30 02:57:25 +0000 | |||
223 | @@ -20,7 +20,7 @@ | |||
224 | 20 | ServiceUnitStateMachineAlreadyAssigned, ServiceStateNameInUse, | 20 | ServiceUnitStateMachineAlreadyAssigned, ServiceStateNameInUse, |
225 | 21 | BadDescriptor, BadServiceStateName, ServiceUnitDebugAlreadyEnabled, | 21 | BadDescriptor, BadServiceStateName, ServiceUnitDebugAlreadyEnabled, |
226 | 22 | MachineStateNotFound, NoUnusedMachines, ServiceUnitResolvedAlreadyEnabled, | 22 | MachineStateNotFound, NoUnusedMachines, ServiceUnitResolvedAlreadyEnabled, |
228 | 23 | ServiceUnitRelationResolvedAlreadyEnabled, StopWatcher) | 23 | ServiceUnitRelationResolvedAlreadyEnabled, StopWatcher, StateError) |
229 | 24 | 24 | ||
230 | 25 | 25 | ||
231 | 26 | from juju.state.tests.common import StateTestBase | 26 | from juju.state.tests.common import StateTestBase |
232 | @@ -532,6 +532,28 @@ | |||
233 | 532 | self.fail("Error not raised") | 532 | self.fail("Error not raised") |
234 | 533 | 533 | ||
235 | 534 | @inlineCallbacks | 534 | @inlineCallbacks |
236 | 535 | def test_get_set_public_address(self): | ||
237 | 536 | service_state = yield self.service_state_manager.add_service_state( | ||
238 | 537 | "wordpress", self.charm_state) | ||
239 | 538 | unit_state = yield service_state.add_unit_state() | ||
240 | 539 | self.assertEqual((yield unit_state.get_public_address()), None) | ||
241 | 540 | yield unit_state.set_public_address("example.foobar.com") | ||
242 | 541 | yield self.assertEqual( | ||
243 | 542 | (yield unit_state.get_public_address()), | ||
244 | 543 | "example.foobar.com") | ||
245 | 544 | |||
246 | 545 | @inlineCallbacks | ||
247 | 546 | def test_get_set_private_address(self): | ||
248 | 547 | service_state = yield self.service_state_manager.add_service_state( | ||
249 | 548 | "wordpress", self.charm_state) | ||
250 | 549 | unit_state = yield service_state.add_unit_state() | ||
251 | 550 | self.assertEqual((yield unit_state.get_private_address()), None) | ||
252 | 551 | yield unit_state.set_private_address("example.local") | ||
253 | 552 | yield self.assertEqual( | ||
254 | 553 | (yield unit_state.get_private_address()), | ||
255 | 554 | "example.local") | ||
256 | 555 | |||
257 | 556 | @inlineCallbacks | ||
258 | 535 | def test_get_service_unit_with_changing_state(self): | 557 | def test_get_service_unit_with_changing_state(self): |
259 | 536 | """ | 558 | """ |
260 | 537 | If a service is removed during operation, get_service_unit() | 559 | If a service is removed during operation, get_service_unit() |
261 | 538 | 560 | ||
262 | === added file 'juju/unit/address.py' | |||
263 | --- juju/unit/address.py 1970-01-01 00:00:00 +0000 | |||
264 | +++ juju/unit/address.py 2011-09-30 02:57:25 +0000 | |||
265 | @@ -0,0 +1,86 @@ | |||
266 | 1 | """Service units have both a public and private address. | ||
267 | 2 | """ | ||
268 | 3 | import subprocess | ||
269 | 4 | |||
270 | 5 | from twisted.internet.defer import inlineCallbacks, returnValue, succeed | ||
271 | 6 | from twisted.internet.threads import deferToThread | ||
272 | 7 | from twisted.web import client | ||
273 | 8 | |||
274 | 9 | from juju.errors import JujuError | ||
275 | 10 | from juju.state.environment import GlobalSettingsStateManager | ||
276 | 11 | |||
277 | 12 | |||
278 | 13 | @inlineCallbacks | ||
279 | 14 | def get_unit_address(client): | ||
280 | 15 | settings = GlobalSettingsStateManager(client) | ||
281 | 16 | provider_type = yield settings.get_provider_type() | ||
282 | 17 | if provider_type == "ec2": | ||
283 | 18 | returnValue(EC2UnitAddress()) | ||
284 | 19 | elif provider_type == "lxc": | ||
285 | 20 | returnValue(LocalUnitAddress()) | ||
286 | 21 | elif provider_type == "orchestra": | ||
287 | 22 | returnValue(OrchestraUnitAddress()) | ||
288 | 23 | elif provider_type == "dummy": | ||
289 | 24 | returnValue(DummyUnitAddress()) | ||
290 | 25 | |||
291 | 26 | raise JujuError( | ||
292 | 27 | "Unknown provider type: %r, unit addresses unknown." % provider_type) | ||
293 | 28 | |||
294 | 29 | |||
295 | 30 | class UnitAddress(object): | ||
296 | 31 | |||
297 | 32 | def get_private_address(self): | ||
298 | 33 | raise NotImplemented() | ||
299 | 34 | |||
300 | 35 | def get_public_address(self): | ||
301 | 36 | raise NotImplemented() | ||
302 | 37 | |||
303 | 38 | |||
304 | 39 | class DummyUnitAddress(UnitAddress): | ||
305 | 40 | |||
306 | 41 | def get_private_address(self): | ||
307 | 42 | return succeed("localhost") | ||
308 | 43 | |||
309 | 44 | def get_public_address(self): | ||
310 | 45 | return succeed("localhost") | ||
311 | 46 | |||
312 | 47 | |||
313 | 48 | class EC2UnitAddress(UnitAddress): | ||
314 | 49 | |||
315 | 50 | @inlineCallbacks | ||
316 | 51 | def get_private_address(self): | ||
317 | 52 | content = yield client.getPage( | ||
318 | 53 | "http://169.254.169.254/latest/meta-data/local-hostname") | ||
319 | 54 | returnValue(content.strip()) | ||
320 | 55 | |||
321 | 56 | @inlineCallbacks | ||
322 | 57 | def get_public_address(self): | ||
323 | 58 | content = yield client.getPage( | ||
324 | 59 | "http://169.254.169.254/latest/meta-data/public-hostname") | ||
325 | 60 | returnValue(content.strip()) | ||
326 | 61 | |||
327 | 62 | |||
328 | 63 | class LocalUnitAddress(UnitAddress): | ||
329 | 64 | |||
330 | 65 | def get_private_address(self): | ||
331 | 66 | return deferToThread(self._get_address) | ||
332 | 67 | |||
333 | 68 | def get_public_address(self): | ||
334 | 69 | return deferToThread(self._get_address) | ||
335 | 70 | |||
336 | 71 | def _get_address(self): | ||
337 | 72 | output = subprocess.check_output(["hostname", "-I"]) | ||
338 | 73 | return output.strip().split()[0] | ||
339 | 74 | |||
340 | 75 | |||
341 | 76 | class OrchestraUnitAddress(UnitAddress): | ||
342 | 77 | |||
343 | 78 | def get_private_address(self): | ||
344 | 79 | return deferToThread(self._get_address) | ||
345 | 80 | |||
346 | 81 | def get_public_address(self): | ||
347 | 82 | return deferToThread(self._get_address) | ||
348 | 83 | |||
349 | 84 | def _get_address(self): | ||
350 | 85 | output = subprocess.check_output(["hostname", "-f"]) | ||
351 | 86 | return output.strip() | ||
352 | 0 | 87 | ||
353 | === added file 'juju/unit/tests/test_address.py' | |||
354 | --- juju/unit/tests/test_address.py 1970-01-01 00:00:00 +0000 | |||
355 | +++ juju/unit/tests/test_address.py 2011-09-30 02:57:25 +0000 | |||
356 | @@ -0,0 +1,126 @@ | |||
357 | 1 | import subprocess | ||
358 | 2 | import zookeeper | ||
359 | 3 | |||
360 | 4 | from twisted.internet.defer import inlineCallbacks, succeed, returnValue | ||
361 | 5 | from twisted.web import client | ||
362 | 6 | |||
363 | 7 | from juju.errors import JujuError | ||
364 | 8 | from juju.lib.testing import TestCase | ||
365 | 9 | from juju.unit.address import ( | ||
366 | 10 | EC2UnitAddress, LocalUnitAddress, OrchestraUnitAddress, DummyUnitAddress, | ||
367 | 11 | get_unit_address) | ||
368 | 12 | from juju.state.environment import GlobalSettingsStateManager | ||
369 | 13 | |||
370 | 14 | |||
371 | 15 | class AddressTest(TestCase): | ||
372 | 16 | |||
373 | 17 | def setUp(self): | ||
374 | 18 | zookeeper.set_debug_level(0) | ||
375 | 19 | self.client = self.get_zookeeper_client() | ||
376 | 20 | return self.client.connect() | ||
377 | 21 | |||
378 | 22 | @inlineCallbacks | ||
379 | 23 | def get_address_for(self, provider_type): | ||
380 | 24 | settings = GlobalSettingsStateManager(self.client) | ||
381 | 25 | yield settings.set_provider_type(provider_type) | ||
382 | 26 | address = yield get_unit_address(self.client) | ||
383 | 27 | returnValue(address) | ||
384 | 28 | |||
385 | 29 | @inlineCallbacks | ||
386 | 30 | def test_get_ec2_address(self): | ||
387 | 31 | address = yield self.get_address_for("ec2") | ||
388 | 32 | self.assertTrue(isinstance(address, EC2UnitAddress)) | ||
389 | 33 | |||
390 | 34 | @inlineCallbacks | ||
391 | 35 | def test_get_local_address(self): | ||
392 | 36 | address = yield self.get_address_for("lxc") | ||
393 | 37 | self.assertTrue(isinstance(address, LocalUnitAddress)) | ||
394 | 38 | |||
395 | 39 | @inlineCallbacks | ||
396 | 40 | def test_get_orchestra_address(self): | ||
397 | 41 | address = yield self.get_address_for("orchestra") | ||
398 | 42 | self.assertTrue(isinstance(address, OrchestraUnitAddress)) | ||
399 | 43 | |||
400 | 44 | @inlineCallbacks | ||
401 | 45 | def test_get_dummy_address(self): | ||
402 | 46 | address = yield self.get_address_for("dummy") | ||
403 | 47 | self.assertTrue(isinstance(address, DummyUnitAddress)) | ||
404 | 48 | |||
405 | 49 | def test_get_unknown_address(self): | ||
406 | 50 | return self.assertFailure(self.get_address_for("foobar"), JujuError) | ||
407 | 51 | |||
408 | 52 | |||
409 | 53 | class DummyAddressTest(TestCase): | ||
410 | 54 | |||
411 | 55 | def setUp(self): | ||
412 | 56 | self.address = DummyUnitAddress() | ||
413 | 57 | |||
414 | 58 | def test_get_address(self): | ||
415 | 59 | |||
416 | 60 | self.assertEqual( | ||
417 | 61 | (yield self.address.get_public_address()), | ||
418 | 62 | "localhost") | ||
419 | 63 | |||
420 | 64 | self.assertEqual( | ||
421 | 65 | (yield self.address.get_private_address()), | ||
422 | 66 | "localhost") | ||
423 | 67 | |||
424 | 68 | |||
425 | 69 | class EC2AddressTest(TestCase): | ||
426 | 70 | |||
427 | 71 | def setUp(self): | ||
428 | 72 | self.address = EC2UnitAddress() | ||
429 | 73 | |||
430 | 74 | @inlineCallbacks | ||
431 | 75 | def test_get_address(self): | ||
432 | 76 | urls = [ | ||
433 | 77 | "http://169.254.169.254/latest/meta-data/local-hostname", | ||
434 | 78 | "http://169.254.169.254/latest/meta-data/public-hostname"] | ||
435 | 79 | |||
436 | 80 | def verify_args(url): | ||
437 | 81 | self.assertEqual(urls.pop(0), url) | ||
438 | 82 | return succeed("foobar\n") | ||
439 | 83 | |||
440 | 84 | self.patch(client, "getPage", verify_args) | ||
441 | 85 | self.assertEqual( | ||
442 | 86 | (yield self.address.get_private_address()), "foobar") | ||
443 | 87 | self.assertEqual( | ||
444 | 88 | (yield self.address.get_public_address()), "foobar") | ||
445 | 89 | |||
446 | 90 | |||
447 | 91 | class LocalAddressTest(TestCase): | ||
448 | 92 | |||
449 | 93 | def setUp(self): | ||
450 | 94 | self.address = LocalUnitAddress() | ||
451 | 95 | |||
452 | 96 | @inlineCallbacks | ||
453 | 97 | def test_get_address(self): | ||
454 | 98 | self.patch( | ||
455 | 99 | subprocess, "check_output", | ||
456 | 100 | lambda args: "192.168.1.122 127.0.0.1\n") | ||
457 | 101 | self.assertEqual( | ||
458 | 102 | (yield self.address.get_public_address()), | ||
459 | 103 | "192.168.1.122") | ||
460 | 104 | self.assertEqual( | ||
461 | 105 | (yield self.address.get_private_address()), | ||
462 | 106 | "192.168.1.122") | ||
463 | 107 | |||
464 | 108 | |||
465 | 109 | class OrchestraAddressTest(TestCase): | ||
466 | 110 | |||
467 | 111 | def setUp(self): | ||
468 | 112 | self.address = OrchestraUnitAddress() | ||
469 | 113 | |||
470 | 114 | @inlineCallbacks | ||
471 | 115 | def test_get_address(self): | ||
472 | 116 | self.patch( | ||
473 | 117 | subprocess, "check_output", | ||
474 | 118 | lambda args: "slice.foobar.domain.net\n") | ||
475 | 119 | |||
476 | 120 | self.assertEqual( | ||
477 | 121 | (yield self.address.get_public_address()), | ||
478 | 122 | "slice.foobar.domain.net") | ||
479 | 123 | |||
480 | 124 | self.assertEqual( | ||
481 | 125 | (yield self.address.get_private_address()), | ||
482 | 126 | "slice.foobar.domain.net") |
This looks very nice too, thanks!
Just a couple of details:
[1]
+ elif provider_type == "lxc":
Please do not forget to rename the provider type to "local"
before making this public.
[2]
+ output = subprocess. check_output( ["hostname" , "-f"])
Why is this different for orchestra? Won't this fail if thethe release.
machine doesn't have a properly assigned domain name? I suspect
it will, and suggest using the same implementation of the local
case there as well.