Merge lp:~hazmat/pyjuju/sans-ami into lp:pyjuju

Proposed by Kapil Thangavelu
Status: Merged
Approved by: Kapil Thangavelu
Approved revision: 269
Merged at revision: 266
Proposed branch: lp:~hazmat/pyjuju/sans-ami
Merge into: lp:pyjuju
Diff against target: 286 lines (+131/-35)
5 files modified
ensemble/providers/ec2/launch.py (+29/-13)
ensemble/providers/ec2/tests/data/natty.txt (+21/-0)
ensemble/providers/ec2/tests/test_launch.py (+1/-1)
ensemble/providers/ec2/tests/test_utils.py (+54/-13)
ensemble/providers/ec2/utils.py (+26/-8)
To merge this branch: bzr merge lp:~hazmat/pyjuju/sans-ami
Reviewer Review Type Date Requested Status
Benjamin Saller (community) Approve
Gustavo Niemeyer Approve
Review via email: mp+66203@code.launchpad.net

Description of the change

This branch (re) enables usage of standard ubuntu amis for ensemble machines, utilizing the ensemble ppa as the default mechanism for installing ensemble, as an added bonus this removes the extraneous zk instances on service unit machines. It also preserves the ability to install ensemble from a public lp branch

To post a comment you must log in.
Revision history for this message
Benjamin Saller (bcsaller) wrote :

Overall, fine, I think point 0 is important and where we want to be in terms of installing ensemble on top of 'clean' APIs. I think the point I'm trying to make in [3] about configuration is also important. The rest is kinda nitpicky.

[0]

I think in general we need to support 3 options for the ensemble code.
    a. distro's packages (which will be the 11.10 default)
    b. a ppa's packages (tip will be be the default for most of our initial consumers)
    c. a lp branch (the developers common case)

I think its a minor refactoring to support all 3 and will be well worth while to get this right.

47 + # These should be in the deb
48 + launch_scripts.extend([
49 + "sudo mkdir -p /var/lib/ensemble",
50 + "sudo mkdir -p /var/log/ensemble"])
51 +

[1] This _should_ be in the deb.

123 class EC2UtilsTest(TestCase):
124 @@ -28,7 +28,7 @@
125 a LookupError is raised.
126 """
127 page = self.mocker.replace("twisted.web.client.getPage")
128 - page(SAMPLE_URI)
129 + page(IMAGE_URI_TEMPLATE % "lucid")
130 self.mocker.result(succeed(""))
131 self.mocker.replay()
132 d = get_current_ami(ubuntu_release_name="lucid")

[2] Our consumers are already plotting about 11.10. Even in our test cases we might benefit from removing release names to avoid feeling of bit rot as things move forward. Every 6 months these references look older and older. release-1, release-2 etc might make as much sense. I think we should also remove actual release names from the codebase like get_current_ami.

[3] related to the last note but I think ensemble.providers.ec2.utils.get_current_ami should be renamed and retargeted based on a default from the environment file and remove the default disto assumption from here. This is something that will have to generally be in sync with what happens on orchestra and lxc providers in the future (even if they don't actually use an AMI). When someone is ready to transition their dev or production deployment environment to a new Ubuntu rev series it should default to a single decision they have to take.

review: Needs Fixing
Revision history for this message
Kapil Thangavelu (hazmat) wrote :

[0]. I think we're a little early to support static packages atm, we're not upstream on any release we're actually using atm, so its a dead option, and we're iterating on features way to fast to let people use a static version.

[1]. Its still needed for (c) a source install case.

[3] allow a distro spec from the environment yaml file sounds good

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

This looks good, thanks for sorting this out so quickly. +1, assuming
both deployment scenarios were tested.

[0]

Ben's [0] is a very good point, but I agree we can sort it out in a
follow up. We have to deal with picking the proper package until the
sprint in Austin. We really can't let it go through without it, or
we'll be in trouble soon.

[1]

def get_machine_options(config, authorized_keys, packages=None,
                        repositories=None, scripts=None, **kw):
(...)
                params[p_name] = kw[a_name]
                del kw[a_name]
        params["region"] = region
(...)
        data=kw)

The way we have a blob of data spreading through to various locations
which poke at it and pick what they need isn't entirely comforting.
I guess it's fine since it's fairly well contained ATM, but we should
look at opportunities to refactor that into a more understandable
flow if we continue growing into this direction.

[2]

+ # XXX ideally should come from latest available or client release name.

We really have to sort out the situation of the way Ubuntu releases
are selected, and take into account the formula preference. We'll
necessarily have to solve that up to the sprint in Austin, otherwise
we risk going out with an unmanaged situation which will bite us
heavily later.

review: Approve
Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

Moved back to WIP until Ben's points are sorted.

Revision history for this message
Kapil Thangavelu (hazmat) wrote :

Excerpts from Benjamin Saller's message of Fri Jul 01 15:12:53 UTC 2011:

0 and 1 in the works.
>
> [1] This _should_ be in the deb.
>
> 123 class EC2UtilsTest(TestCase):
> 124 @@ -28,7 +28,7 @@
> 125 a LookupError is raised.
> 126 """
> 127 page = self.mocker.replace("twisted.web.client.getPage")
> 128 - page(SAMPLE_URI)
> 129 + page(IMAGE_URI_TEMPLATE % "lucid")
> 130 self.mocker.result(succeed(""))
> 131 self.mocker.replay()
> 132 d = get_current_ami(ubuntu_release_name="lucid")
>
> [2] Our consumers are already plotting about 11.10. Even in our test cases we might benefit from removing release names to avoid feeling of bit rot as things move forward. Every 6 months these references look older and older. release-1, release-2 etc might make as much sense. I think we should also remove actual release names from the codebase like get_current_ami.

I think this is just testing against a known data set, the notion of bitrot here seems limited, its a test verifying a parsing process with a known input and output.

> [3] related to the last note but I think ensemble.providers.ec2.utils.get_current_ami should be renamed and retargeted based on a default from the environment file and remove the default disto assumption from here. This is something that will have to generally be in sync with what happens on orchestra and lxc providers in the future (even if they don't actually use an AMI). When someone is ready to transition their dev or production deployment environment to a new Ubuntu rev series it should default to a single decision they have to take.
>

This is a little unclear to me, an ensemble environment might have multiple distributions within it. Its an easy option to add, i'm just unclear for both this and instance-type if we really want to be spec'ing this at the environment level. For a default distro if not spec'd in the environment, i'd assume the distro release name of the machine that the admin tools are running from.

Its unclear how this should react with nightlies, but perhaps that notion is more ec2 image centric.

Revision history for this message
Benjamin Saller (bcsaller) wrote :

We've agreed that the changes mentioned in [0] can come in a later branch. There is pressing need for a solution now, so +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ensemble/providers/ec2/launch.py'
2--- ensemble/providers/ec2/launch.py 2011-06-02 17:50:24 +0000
3+++ ensemble/providers/ec2/launch.py 2011-06-28 20:16:40 +0000
4@@ -128,22 +128,39 @@
5 return group_created.addCallback(lambda x: groups)
6 return groups
7
8+ def _get_branch_install_scripts(self, branch):
9+ """Returns the commands to install ensemble from a bzr branch.
10+
11+ The branch identifier must be a valid publicly accessible bzr
12+ url that can be used by bzr to checkout the branch. The install
13+ commands will setup local directories and installation of the branch.
14+ """
15+ ensemble_vcs = ("cd /usr/lib/ensemble "
16+ "&& sudo /usr/bin/bzr co %s ensemble" % branch)
17+ ensemble_install = [
18+ "sudo apt-get install -y python-txzookeeper",
19+ "sudo mkdir -p /usr/lib/ensemble",
20+ ensemble_vcs,
21+ "cd /usr/lib/ensemble/ensemble && sudo python setup.py develop"]
22+
23+ return ensemble_install
24+
25 def get_launch_scripts(self, machine_data):
26 """Get the scripts that will execute after the machine has launched."""
27
28+ launch_scripts = ["sudo apt-get -y install ensemble"]
29+
30+ # Support installation of ensemble directly from an LP hosted branch.
31 if machine_data.get("ensemble-branch"):
32- ensemble_vcs = ENSEMBLE_UPDATE_TEMPLATE % (
33- "switch %s" % machine_data["ensemble-branch"])
34- else:
35- ensemble_vcs = ENSEMBLE_UPDATE
36-
37- launch_scripts = [
38- "sudo mkdir -p /usr/lib/ensemble",
39- ensemble_vcs,
40- "cd /usr/lib/ensemble/ensemble && sudo python setup.py develop",
41- "cd /usr/lib/ensemble/txzookeeper && sudo /usr/bin/bzr up",
42- "cd /usr/lib/ensemble/txzookeeper && sudo python setup.py develop"]
43-
44+ launch_scripts = self._get_branch_install_scripts(
45+ machine_data["ensemble-branch"])
46+
47+ # These should be in the deb
48+ launch_scripts.extend([
49+ "sudo mkdir -p /var/lib/ensemble",
50+ "sudo mkdir -p /var/log/ensemble"])
51+
52+ # Every machine has its own agent.
53 machine_agent_script = (
54 "ENSEMBLE_MACHINE_ID=%(machine-id)s "
55 "ENSEMBLE_ZOOKEEPER=%(ensemble-zookeeper-hosts)s "
56@@ -151,7 +168,6 @@
57 "--logfile=/var/log/ensemble/machine-agent.log "
58 "--pidfile=/var/run/ensemble/machine-agent.pid")
59 launch_scripts.append(machine_agent_script % machine_data)
60-
61 return launch_scripts
62
63 def get_machine_variables(self, machine_data):
64
65=== renamed file 'ensemble/providers/ec2/tests/data/lucid-release.txt' => 'ensemble/providers/ec2/tests/data/lucid.txt'
66=== added file 'ensemble/providers/ec2/tests/data/natty.txt'
67--- ensemble/providers/ec2/tests/data/natty.txt 1970-01-01 00:00:00 +0000
68+++ ensemble/providers/ec2/tests/data/natty.txt 2011-06-28 20:16:40 +0000
69@@ -0,0 +1,21 @@
70+natty server release 20110426 ebs amd64 ap-northeast-1 ami-dab812db aki-d409a2d5 paravirtual
71+natty server release 20110426 ebs i386 ap-northeast-1 ami-d8b812d9 aki-d209a2d3 paravirtual
72+natty server release 20110426 instance-store amd64 ap-northeast-1 ami-a4b812a5 aki-d409a2d5 paravirtual
73+natty server release 20110426 instance-store i386 ap-northeast-1 ami-46b81247 aki-d209a2d3 paravirtual
74+natty server release 20110426 ebs amd64 ap-southeast-1 ami-60582132 aki-11d5aa43 paravirtual
75+natty server release 20110426 ebs i386 ap-southeast-1 ami-62582130 aki-13d5aa41 paravirtual
76+natty server release 20110426 instance-store amd64 ap-southeast-1 ami-aa5920f8 aki-11d5aa43 paravirtual
77+natty server release 20110426 instance-store i386 ap-southeast-1 ami-c0592092 aki-13d5aa41 paravirtual
78+natty server release 20110426 ebs amd64 eu-west-1 ami-379ea943 aki-4feec43b paravirtual
79+natty server release 20110426 ebs i386 eu-west-1 ami-359ea941 aki-4deec439 paravirtual
80+natty server release 20110426 instance-store amd64 eu-west-1 ami-619ea915 aki-4feec43b paravirtual
81+natty server release 20110426 instance-store i386 eu-west-1 ami-1b9fa86f aki-4deec439 paravirtual
82+natty server release 20110426 ebs amd64 us-east-1 ami-1cad5275 hvm
83+natty server release 20110426 ebs amd64 us-east-1 ami-1aad5273 aki-427d952b paravirtual
84+natty server release 20110426 ebs i386 us-east-1 ami-06ad526f aki-407d9529 paravirtual
85+natty server release 20110426 instance-store amd64 us-east-1 ami-68ad5201 aki-427d952b paravirtual
86+natty server release 20110426 instance-store i386 us-east-1 ami-e2af508b aki-407d9529 paravirtual
87+natty server release 20110426 ebs amd64 us-west-1 ami-136f3c56 aki-9ba0f1de paravirtual
88+natty server release 20110426 ebs i386 us-west-1 ami-116f3c54 aki-99a0f1dc paravirtual
89+natty server release 20110426 instance-store amd64 us-west-1 ami-0b6f3c4e aki-9ba0f1de paravirtual
90+natty server release 20110426 instance-store i386 us-west-1 ami-596f3c1c aki-99a0f1dc paravirtual
91
92=== modified file 'ensemble/providers/ec2/tests/test_launch.py'
93--- ensemble/providers/ec2/tests/test_launch.py 2011-06-03 18:11:39 +0000
94+++ ensemble/providers/ec2/tests/test_launch.py 2011-06-28 20:16:40 +0000
95@@ -200,7 +200,7 @@
96 machine_data={
97 "machine-id": "machine-2",
98 "ensemble-zookeeper-hosts": get_test_zookeeper_address()})
99- cmd = "cd /usr/lib/ensemble/ensemble && sudo /usr/bin/bzr switch %s"%(
100+ cmd = "cd /usr/lib/ensemble && sudo /usr/bin/bzr co %s" % (
101 custom_branch)
102 self.failUnlessIn(cmd, variables["scripts"])
103 self.assertEqual(variables["ensemble-branch"], custom_branch)
104
105=== modified file 'ensemble/providers/ec2/tests/test_utils.py'
106--- ensemble/providers/ec2/tests/test_utils.py 2011-06-03 18:11:39 +0000
107+++ ensemble/providers/ec2/tests/test_utils.py 2011-06-28 20:16:40 +0000
108@@ -13,11 +13,11 @@
109
110 from ensemble.lib.testing import TestCase
111
112-SAMPLE_URI = "\
113-http://uec-images.ubuntu.com/query/lucid/server/released.current.txt"
114+IMAGE_URI_TEMPLATE = "\
115+http://uec-images.ubuntu.com/query/%s/server/released.current.txt"
116
117-SAMPLE_FILE = os.path.join(os.path.dirname(inspect.getabsfile(ec2)),
118- "tests", "data", "lucid-release.txt")
119+IMAGE_DATA_DIR = os.path.join(
120+ os.path.dirname(inspect.getabsfile(ec2)), "tests", "data")
121
122
123 class EC2UtilsTest(TestCase):
124@@ -28,7 +28,7 @@
125 a LookupError is raised.
126 """
127 page = self.mocker.replace("twisted.web.client.getPage")
128- page(SAMPLE_URI)
129+ page(IMAGE_URI_TEMPLATE % "lucid")
130 self.mocker.result(succeed(""))
131 self.mocker.replay()
132 d = get_current_ami(ubuntu_release_name="lucid")
133@@ -38,8 +38,10 @@
134 def test_current_ami(self):
135 """The current server machine image can be retrieved."""
136 page = self.mocker.replace("twisted.web.client.getPage")
137- page(SAMPLE_URI)
138- self.mocker.result(succeed(open(SAMPLE_FILE).read()))
139+ page(IMAGE_URI_TEMPLATE % "lucid")
140+ self.mocker.result(succeed(
141+ open(os.path.join(IMAGE_DATA_DIR, "lucid.txt")).read()))
142+
143 self.mocker.replay()
144 d = get_current_ami(ubuntu_release_name="lucid")
145
146@@ -52,8 +54,10 @@
147 def test_current_ami_by_region(self):
148 """The current server machine image can be retrieved by region."""
149 page = self.mocker.replace("twisted.web.client.getPage")
150- page(SAMPLE_URI)
151- self.mocker.result(succeed(open(SAMPLE_FILE).read()))
152+ page(IMAGE_URI_TEMPLATE % "lucid")
153+ self.mocker.result(
154+ succeed(open(
155+ os.path.join(IMAGE_DATA_DIR, "lucid.txt")).read()))
156 self.mocker.replay()
157 d = get_current_ami(ubuntu_release_name="lucid", region="us-west-1")
158
159@@ -69,8 +73,9 @@
160 to guide image selection.
161 """
162 page = self.mocker.replace("twisted.web.client.getPage")
163- page(SAMPLE_URI)
164- self.mocker.result(succeed(open(SAMPLE_FILE).read()))
165+ page(IMAGE_URI_TEMPLATE % "lucid")
166+ self.mocker.result(succeed(
167+ open(os.path.join(IMAGE_DATA_DIR, "lucid.txt")).read()))
168 self.mocker.replay()
169 d = get_current_ami(ubuntu_release_name="lucid", ebs=False)
170
171@@ -173,18 +178,54 @@
172 the ec2 client's run instance method. A known set of default
173 is utilized.
174 """
175+
176+ page = self.mocker.replace("twisted.web.client.getPage")
177+ page(IMAGE_URI_TEMPLATE % "natty")
178+ self.mocker.result(
179+ succeed(open(
180+ os.path.join(IMAGE_DATA_DIR, "natty.txt")).read()))
181+ self.mocker.replay()
182+
183 config = {}
184-
185 d = get_machine_options(config, "zebra")
186
187 def verify_result(result):
188 self.assertTrue(isinstance(result, dict))
189- self.assertEqual(result["image_id"], "ami-d2ba45bb")
190+ self.assertEqual(result["image_id"], "ami-06ad526f")
191 self.assertEqual(result["instance_type"], "m1.small")
192
193 d.addCallback(verify_result)
194 return d
195
196+ def test_get_machine_options_with_params(self):
197+ """
198+ Image parameters can be specified to determine which ami is to
199+ be launched. Image paramters specified are not passed to the
200+ instance via user data.
201+ """
202+ page = self.mocker.replace("twisted.web.client.getPage")
203+ page(IMAGE_URI_TEMPLATE % "natty")
204+ self.mocker.result(
205+ succeed(open(
206+ os.path.join(IMAGE_DATA_DIR, "natty.txt")).read()))
207+ self.mocker.replay()
208+
209+ d = get_machine_options(
210+ {"default-instance-type": "m1.large"},
211+ "zebra", image_arch="amd64", image_ebs=False)
212+
213+ def verify_result(result):
214+ self.assertTrue(isinstance(result, dict))
215+ self.assertEqual(result["image_id"], "ami-68ad5201")
216+ self.assertEqual(result["instance_type"], "m1.large")
217+ self.assertNotIn(
218+ "arch", result["user_data"])
219+ self.assertNotIn(
220+ "ebs", result["user_data"])
221+
222+ d.addCallback(verify_result)
223+ return d
224+
225 def test_configured_default_image_has_precedence_over_region(self):
226 """If the server machine image is specified it takes precendence over
227 region."""
228
229=== modified file 'ensemble/providers/ec2/utils.py'
230--- ensemble/providers/ec2/utils.py 2011-06-03 18:11:39 +0000
231+++ ensemble/providers/ec2/utils.py 2011-06-28 20:16:40 +0000
232@@ -27,7 +27,7 @@
233 return "https://ec2.%s.amazonaws.com" % region
234
235
236-def get_current_ami(ubuntu_release_name="lucid", arch="i386", ebs=True,
237+def get_current_ami(ubuntu_release_name="natty", arch="i386", ebs=True,
238 region="us-east-1", daily=False, desktop=False,
239 url_fetch=None):
240 """Get the latest ami for the last release of ubuntu."""
241@@ -143,6 +143,31 @@
242 Given an ensemble environment configuration, extract the proper machine
243 information to be used for launching the machine via the ec2 api.
244 """
245+
246+ instance_type = config.get("default-instance-type", "m1.small")
247+
248+ # XXX ideally should come from latest available or client release name.
249+ region = config.get("region", "us-east-1")
250+ image_id = config.get("default-image-id", None)
251+
252+ # Lookup a standard ami by region, if none is specified, use any
253+ # specified image specification to locate an image, and remove the
254+ # image specification so it doesn't propogate to user data.
255+ if not image_id:
256+ params = {}
257+ for a_name, p_name in (
258+ ("image_release_name", "ubuntu_release_name"),
259+ ("image_arch", "arch"),
260+ ("image_ebs", "ebs"),
261+ ("image_daily", "daily")):
262+ if a_name in kw:
263+ params[p_name] = kw[a_name]
264+ del kw[a_name]
265+ params["region"] = region
266+ d = get_current_ami(**params)
267+ else:
268+ d = succeed(image_id)
269+
270 user_data = format_cloud_ini(
271 authorized_keys=authorized_keys,
272 packages=packages,
273@@ -150,13 +175,6 @@
274 scripts=scripts,
275 data=kw)
276
277- instance_type = config.get("default-instance-type", "m1.small")
278- # XXX ideally should come from latest available or client release name,
279- # for now to speed bootstrap, we use a prepopulated image by region.
280- region = config.get("region", "us-east-1")
281- image_id = config.get("default-image-id", AMI_REGION_MAP[region])
282- d = succeed(image_id)
283-
284 def on_machine_image(current_image_id):
285 return {"image_id": current_image_id,
286 "min_count": 1,

Subscribers

People subscribed via source and target branches

to status/vote changes: