Merge lp:~fwereade/pyjuju/provider-base-launch-machine into lp:~fwereade/pyjuju/provider-base

Proposed by William Reade
Status: Merged
Merged at revision: 325
Proposed branch: lp:~fwereade/pyjuju/provider-base-launch-machine
Merge into: lp:~fwereade/pyjuju/provider-base
Diff against target: 386 lines (+68/-84)
8 files modified
ensemble/providers/common/base.py (+13/-12)
ensemble/providers/common/bootstrap.py (+4/-5)
ensemble/providers/common/launch.py (+13/-10)
ensemble/providers/common/tests/test_base.py (+4/-42)
ensemble/providers/common/tests/test_launch.py (+9/-8)
ensemble/providers/dummy.py (+1/-1)
ensemble/providers/ec2/__init__.py (+12/-2)
ensemble/providers/orchestra/__init__.py (+12/-4)
To merge this branch: bzr merge lp:~fwereade/pyjuju/provider-base-launch-machine
Reviewer Review Type Date Requested Status
Gustavo Niemeyer (community) Approve
Review via email: mp+71850@code.launchpad.net

Description of the change

Does this cover what you need from https://code.launchpad.net/~fwereade/ensemble/provider-base/+merge/71272 point [1]?

I'm not totally sold on the bootstrap argument to start_machine, but it does simplify the code, and I think it's a good candidate for inclusion in the forthcoming-as-soon-as-I-get-around-to-it fix for lp:820892. That is to say: the act of starting a machine isn't really connected to the concept of bootstrapping, it's just that when we *are* bootstrapping we want the incidentally-started machine to play a couple of extra roles, which would go nicely in whatever we end up replacing machine_data with.

To post a comment you must log in.
Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

Please just rename the bootstrap=True parameter on start_machine to
master=True, and +1. Thanks for separating it out.

review: Approve
326. By William Reade

renamed start_machine bootstrap kwarg (and LaunchMachine.__init__ bootstrap kwarg, and LaunchMachine._bootstrap) to master

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ensemble/providers/common/base.py'
2--- ensemble/providers/common/base.py 2011-08-11 22:04:38 +0000
3+++ ensemble/providers/common/base.py 2011-08-17 12:06:25 +0000
4@@ -16,6 +16,7 @@
5
6 * connect
7 * get_file_storage
8+ * start_machine
9 * get_machines
10 * shutdown_machines
11 * open_port
12@@ -32,7 +33,7 @@
13 You probably shouldn't override anything else.
14 """
15
16- def __init__(self, environment_name, config, launch_machine_class):
17+ def __init__(self, environment_name, config):
18 if ("authorized-keys-path" in config and
19 "authorized-keys" in config):
20 raise EnvironmentsConfigError(
21@@ -41,7 +42,6 @@
22
23 self.environment_name = environment_name
24 self.config = config
25- self.launch_machine_class = launch_machine_class
26
27 def get_serialization_data(self):
28 """Get provider configuration suitable for serialization."""
29@@ -70,6 +70,17 @@
30 """Retrieve the provider C{FileStorage} abstraction."""
31 raise NotImplementedError()
32
33+ def start_machine(self, machine_data, master=False):
34+ """Start a machine in the provider.
35+
36+ @param machine_data: a dictionary of data to pass along to the newly
37+ launched machine.
38+
39+ @param master: if True, machine will initialize the ensemble admin
40+ and run a provisioning agent.
41+ """
42+ raise NotImplementedError()
43+
44 def get_machines(self, instance_ids=()):
45 """List machines running in the provider.
46
47@@ -119,16 +130,6 @@
48 """Bootstrap an ensemble server in the provider."""
49 return Bootstrap(self).run()
50
51- def start_machine(self, machine_data):
52- """Start a machine in the provider.
53-
54- @param machine_data: a dictionary of data to pass along to the newly
55- launched machine.
56- """
57- # XXX something's a bit inelegant here; also see Bootstrap operation
58- launch = self.launch_machine_class(self)
59- return launch.run(machine_data=machine_data)
60-
61 def get_machine(self, instance_id):
62 """Retrieve a provider machine by instance id.
63
64
65=== modified file 'ensemble/providers/common/bootstrap.py'
66--- ensemble/providers/common/bootstrap.py 2011-08-04 09:50:57 +0000
67+++ ensemble/providers/common/bootstrap.py 2011-08-17 12:06:25 +0000
68@@ -41,11 +41,10 @@
69 return storage.put(_VERIFY_PATH, StringIO("storage is writable"))
70
71 def _cannot_write(self, failure):
72- raise ProviderError("Bootstrap aborted: file storage not writable (%s)"
73- % str(failure.value))
74+ raise ProviderError(
75+ "Bootstrap aborted because file storage is not writable: %s"
76+ % str(failure.value))
77
78 def _launch_machine(self, unused):
79 log.debug("Launching Ensemble bootstrap instance.")
80- launch_class = self._provider.launch_machine_class
81- launch = launch_class(self._provider, bootstrap=True)
82- return launch.run({"machine-id": "0"})
83+ return self._provider.start_machine({"machine-id": "0"}, master=True)
84
85=== modified file 'ensemble/providers/common/launch.py'
86--- ensemble/providers/common/launch.py 2011-08-10 18:12:47 +0000
87+++ ensemble/providers/common/launch.py 2011-08-17 12:06:25 +0000
88@@ -55,7 +55,7 @@
89 class LaunchMachine(object):
90 """Abstract class with generic instance-launching logic.
91
92- Constructing with bootstrap=True will cause the run method to
93+ Constructing with master=True will cause the run method to
94 construct a machine which is also running a zookeeper for the
95 cluster, and a provisioning agent, as well as the usual machine
96 agent.
97@@ -65,9 +65,9 @@
98 convenient to override C{get_machine_variables} as well.
99 """
100
101- def __init__(self, provider, bootstrap=False):
102+ def __init__(self, provider, master=False):
103 self._provider = provider
104- self._bootstrap = bootstrap
105+ self._master = master
106
107 @inlineCallbacks
108 def run(self, machine_data):
109@@ -85,8 +85,8 @@
110 machine_variables = yield self.get_machine_variables(machine_data)
111 provider_machines = yield self.start_machine(
112 machine_variables, machine_data["machine-id"])
113- if self._bootstrap:
114- yield self._on_bootstrap_launched(provider_machines)
115+ if self._master:
116+ yield self._on_master_launched(provider_machines)
117 returnValue(provider_machines)
118
119 def start_machine(self, machine_variables, machine_id):
120@@ -127,7 +127,7 @@
121
122 @inlineCallbacks
123 def _get_zookeeper_hosts(self):
124- if self._bootstrap:
125+ if self._master:
126 returnValue("localhost:2181")
127 machines = yield self._provider.get_zookeeper_machines()
128 hosts = [m.private_dns_name for m in machines]
129@@ -136,7 +136,7 @@
130
131 def _get_packages(self):
132 result = list(DEFAULT_PACKAGES)
133- if self._bootstrap:
134+ if self._master:
135 result.extend(BOOTSTRAP_PACKAGES)
136 return result
137
138@@ -149,7 +149,7 @@
139 "sudo mkdir -p /var/lib/ensemble",
140 "sudo mkdir -p /var/log/ensemble"])
141
142- if self._bootstrap:
143+ if self._master:
144 launch_scripts.append(self._get_initialize_script())
145
146 # Every machine has its own agent.
147@@ -161,7 +161,7 @@
148 "--pidfile=/var/run/ensemble/machine-agent.pid")
149 launch_scripts.append(machine_agent_script_template % machine_data)
150
151- if self._bootstrap:
152+ if self._master:
153 launch_scripts.append(_get_provision_agent_script(machine_data))
154
155 return launch_scripts
156@@ -184,7 +184,10 @@
157 return _get_initialize_script(
158 self.get_instance_id_command(), admin_secret)
159
160- def _on_bootstrap_launched(self, machines):
161+ def _on_master_launched(self, machines):
162+ # TODO this should be part of Bootstrap (and should really extend,
163+ # rather than effectively replace, the result of
164+ # self._provider.get_zookeeper_machines)
165 instance_ids = [m.instance_id for m in machines]
166 d = self._provider.save_state({"zookeeper-instances": instance_ids})
167 d.addCallback(lambda _: machines)
168
169=== modified file 'ensemble/providers/common/tests/test_base.py'
170--- ensemble/providers/common/tests/test_base.py 2011-08-11 22:04:38 +0000
171+++ ensemble/providers/common/tests/test_base.py 2011-08-17 12:06:25 +0000
172@@ -12,8 +12,8 @@
173
174 class DummyLaunchMachine(object):
175
176- def __init__(self, bootstrap=False):
177- self._bootstrap = bootstrap
178+ def __init__(self, master=False):
179+ self._master = master
180
181 def run(self, machine_data):
182 return succeed([ProviderMachine(machine_data["machine-id"])])
183@@ -21,11 +21,8 @@
184
185 class DummyProvider(MachineProviderBase):
186
187- def __init__(self, config=None, launch_machine_class=None):
188- if launch_machine_class is None:
189- launch_machine_class = DummyLaunchMachine
190- super(DummyProvider, self).__init__(
191- "venus", config or {}, launch_machine_class)
192+ def __init__(self, config=None):
193+ super(DummyProvider, self).__init__("venus", config or {})
194
195
196 class MachineProviderBaseTest(TestCase):
197@@ -34,7 +31,6 @@
198 provider = DummyProvider({"some": "config"})
199 self.assertEquals(provider.environment_name, "venus")
200 self.assertEquals(provider.config, {"some": "config"})
201- self.assertEquals(provider.launch_machine_class, DummyLaunchMachine)
202
203 def test_bad_config(self):
204 try:
205@@ -137,37 +133,3 @@
206 self.assertEquals(result, machines)
207 d.addCallback(verify)
208 return d
209-
210- def test_start_machine_error(self):
211- LaunchMachine = self.mocker.mock()
212- provider = DummyProvider(launch_machine_class=LaunchMachine)
213- LaunchMachine(provider)
214- launchmachine = self.mocker.mock()
215- self.mocker.result(launchmachine)
216- machine_data = object()
217- launchmachine.run(machine_data=machine_data)
218- self.mocker.result(fail(SomeError()))
219- self.mocker.replay()
220-
221- d = provider.start_machine(machine_data)
222- self.assertFailure(d, SomeError)
223- return d
224-
225- def test_start_machine_success(self):
226- LaunchMachine = self.mocker.mock()
227- provider = DummyProvider(launch_machine_class=LaunchMachine)
228- LaunchMachine(provider)
229- launchmachine = self.mocker.mock()
230- self.mocker.result(launchmachine)
231- machine_data = object()
232- launchmachine.run(machine_data=machine_data)
233- machine = object()
234- self.mocker.result(succeed([machine]))
235- self.mocker.replay()
236-
237- d = provider.start_machine(machine_data)
238-
239- def verify(result):
240- self.assertEquals(result, [machine])
241- d.addCallback(verify)
242- return d
243
244=== modified file 'ensemble/providers/common/tests/test_launch.py'
245--- ensemble/providers/common/tests/test_launch.py 2011-08-11 22:04:38 +0000
246+++ ensemble/providers/common/tests/test_launch.py 2011-08-17 12:06:25 +0000
247@@ -18,7 +18,7 @@
248 class DummyLaunchMachine(LaunchMachine):
249
250 def start_machine(self, variables, data):
251- if self._bootstrap:
252+ if self._master:
253 name = "bootstrapped-instance-id"
254 else:
255 name = "some-instance-id"
256@@ -46,8 +46,7 @@
257 class DummyProvider(MachineProviderBase):
258
259 def __init__(self, config):
260- super(DummyProvider, self).__init__(
261- "venus", config, launch_class)
262+ super(DummyProvider, self).__init__("venus", config)
263 self._file_storage = file_storage_class()
264
265 def get_zookeeper_machines(self):
266@@ -61,6 +60,9 @@
267 def get_file_storage(self):
268 return self._file_storage
269
270+ def start_machine(self, machine_data, master=False):
271+ return launch_class(self, master).run(machine_data)
272+
273 create_config = {"authorized-keys": "abc"}
274 if config is not None:
275 create_config.update(config)
276@@ -68,9 +70,9 @@
277
278
279 def get_launch(launch_class=DummyLaunchMachine, config=None,
280- zookeeper=True, bootstrap=False):
281+ zookeeper=True, master=False):
282 provider = get_provider(launch_class, config, zookeeper)
283- return launch_class(provider, bootstrap=bootstrap)
284+ return launch_class(provider, master=master)
285
286
287 class LaunchMachineTest(TestCase):
288@@ -95,7 +97,7 @@
289 @inlineCallbacks
290 def test_bootstrap_run(self):
291 provider = get_provider(config={"admin-secret": "whatever"})
292- launch = DummyLaunchMachine(provider, bootstrap=True)
293+ launch = DummyLaunchMachine(provider, master=True)
294 yield launch.run({"machine-id": "machine-32767"})
295 saved_state = yield provider.load_state()
296 self.assertEquals(
297@@ -151,8 +153,7 @@
298 return d
299
300 def test_get_machine_variables_bootstrap(self):
301- launch = get_launch(config={"admin-secret": "SEEKRIT"},
302- bootstrap=True)
303+ launch = get_launch(config={"admin-secret": "SEEKRIT"}, master=True)
304 d = launch.get_machine_variables({"machine-id": "machine-757"})
305
306 def verify_vars(vars):
307
308=== modified file 'ensemble/providers/dummy.py'
309--- ensemble/providers/dummy.py 2011-08-12 21:00:41 +0000
310+++ ensemble/providers/dummy.py 2011-08-17 12:06:25 +0000
311@@ -58,7 +58,7 @@
312 return fail(MachinesNotFound(missing_instance_ids))
313 return succeed(machines)
314
315- def start_machine(self, machine_data):
316+ def start_machine(self, machine_data, master=False):
317 """Start a machine in the provider."""
318 if not "machine-id" in machine_data:
319 return fail(ProviderError(
320
321=== modified file 'ensemble/providers/ec2/__init__.py'
322--- ensemble/providers/ec2/__init__.py 2011-08-17 09:42:00 +0000
323+++ ensemble/providers/ec2/__init__.py 2011-08-17 12:06:25 +0000
324@@ -23,8 +23,7 @@
325 class MachineProvider(MachineProviderBase):
326
327 def __init__(self, environment_name, config):
328- super(MachineProvider, self).__init__(
329- environment_name, config, EC2LaunchMachine)
330+ super(MachineProvider, self).__init__(environment_name, config)
331
332 if not config.get("ec2-uri"):
333 ec2_uri = get_region_uri(config.get("region", "us-east-1"))
334@@ -70,6 +69,17 @@
335 """Retrieve an S3-backed C{FileStorage}."""
336 return FileStorage(self.s3, self.config["control-bucket"])
337
338+ def start_machine(self, machine_data, master=False):
339+ """Start a machine in the provider.
340+
341+ @param machine_data: a dictionary of data to pass along to the newly
342+ launched machine.
343+
344+ @param master: if True, machine will initialize the ensemble admin
345+ and run a provisioning agent.
346+ """
347+ return EC2LaunchMachine(self, master).run(machine_data)
348+
349 @inlineCallbacks
350 def get_machines(self, instance_ids=()):
351 """List machines running in the provider.
352
353=== modified file 'ensemble/providers/orchestra/__init__.py'
354--- ensemble/providers/orchestra/__init__.py 2011-08-12 21:00:41 +0000
355+++ ensemble/providers/orchestra/__init__.py 2011-08-17 12:06:25 +0000
356@@ -10,11 +10,8 @@
357
358 class MachineProvider(MachineProviderBase):
359
360- launch_machine_class = OrchestraLaunchMachine
361-
362 def __init__(self, environment_name, config):
363- super(MachineProvider, self).__init__(
364- environment_name, config, OrchestraLaunchMachine)
365+ super(MachineProvider, self).__init__(environment_name, config)
366 self.cobbler = CobblerClient(config)
367
368 def get_file_storage(self):
369@@ -24,6 +21,17 @@
370 "http://%(orchestra-server)s/webdav" % self.config)
371 return FileStorage(self.config["storage-url"])
372
373+ def start_machine(self, machine_data, master=False):
374+ """Start a machine in the provider.
375+
376+ @param machine_data: a dictionary of data to pass along to the newly
377+ launched machine.
378+
379+ @param master: if True, machine will initialize the ensemble admin
380+ and run a provisioning agent.
381+ """
382+ return OrchestraLaunchMachine(self, master).run(machine_data)
383+
384 @inlineCallbacks
385 def get_machines(self, instance_ids=()):
386 """List machines running in the provider.

Subscribers

People subscribed via source and target branches

to all changes: