Merge lp:~jimbaker/pyjuju/env-origin into lp:pyjuju
- env-origin
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Gustavo Niemeyer |
Approved revision: | 380 |
Merged at revision: | 382 |
Proposed branch: | lp:~jimbaker/pyjuju/env-origin |
Merge into: | lp:pyjuju |
Diff against target: |
608 lines (+337/-27) 19 files modified
docs/source/provider-configuration-ec2.rst (+9/-3) juju/providers/common/cloudinit.py (+78/-2) juju/providers/common/launch.py (+9/-2) juju/providers/common/tests/data/cloud_init_bootstrap (+0/-2) juju/providers/common/tests/data/cloud_init_bootstrap_zookeepers (+0/-2) juju/providers/common/tests/data/cloud_init_branch_trunk (+17/-0) juju/providers/common/tests/data/cloud_init_normal (+0/-2) juju/providers/common/tests/data/cloud_init_ppa (+15/-0) juju/providers/common/tests/test_cloudinit.py (+109/-3) juju/providers/ec2/tests/common.py (+1/-0) juju/providers/ec2/tests/data/bootstrap_cloud_init (+0/-2) juju/providers/ec2/tests/data/launch_cloud_init (+0/-2) juju/providers/ec2/tests/data/launch_cloud_init_branch (+20/-0) juju/providers/ec2/tests/data/launch_cloud_init_ppa (+15/-0) juju/providers/ec2/tests/test_bootstrap.py (+1/-0) juju/providers/ec2/tests/test_launch.py (+60/-2) juju/providers/orchestra/tests/common.py (+3/-1) juju/providers/orchestra/tests/data/bootstrap_user_data (+0/-2) juju/providers/orchestra/tests/data/launch_user_data (+0/-2) |
To merge this branch: | bzr merge lp:~jimbaker/pyjuju/env-origin |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gustavo Niemeyer | Approve | ||
William Reade (community) | Approve | ||
Review via email: mp+75823@code.launchpad.net |
Commit message
Description of the change
Implements optional environment settings juju-origin (which replaces juju-branch).
Does not implement juju-version or support for deb repositories, per attached bug.
Functionally tested for not setting juju-origin, setting it to the standard PPA (the only one supported now), and LP branches.
William Reade (fwereade) wrote : | # |
[0]
+ :type branch: str or None
two of these, should be "origin" and "version" instead of "branch"
[1]
+ version=
Won't that lead to version being "None" rather than None? If so, maybe add a test for that path.
Otherwise looks very nice, +1.
Gustavo Niemeyer (niemeyer) wrote : | # |
[6]
+ PPA (use a `ppa:` prefix, eg `ppa:juju/pkgs`). Otherwise, the
+ utilized source will be based on the machine running the
+ bootstrap command (distribution, PPA, or branch).
s/eg/e.g./
In the following sentence, please use this wording:
Otherwise, juju will attempt to detect the correct origin based on
its run location and the installed juju package.
Also this should be fixed according to the rest of this review.
[7]
+ def _parse_policy(self, output):
(...)
+ def get_default_
(...)
Neither of these methods seem to need any information from "self",
which means they are actually independent functions rather than
methods.
[8]
+ if k != "juju":
+ # Sanity check: no record at all, the only possibility is that
+ # this being run as a branch
+ return "lp:juju"
+ for k, v in parse:
+ if k == "Installed" and v == "(none)":
+ return _PPA
+ if k == "Version table":
+ break
+ for _, version_info in parse:
+ if "ppa.launchpad.net" in version_info:
+ return _PPA
As we talked yesterday online, all of this logic is idempotent, and should
be part of a single function, called parse_juju_
and not part of the same function that interacts with the system (calling
"apt-cache policy juju").
[9]
+cat <<EOF
+juju:
+ Installed: (none)
+ Candidate: good-magic-1.0
+ Version table:
+ *** good-magic-1.0
+ 500 http://
+ 100 /var/lib/
+EOF
This is testing the idempotent parse_juju_
data inside the test file, and test the function trivially:
def test_foo(self):
origin, source = parse_juju_
self.assertEqu
self.assertEqu
It's really that simple! :-)
Kill most of these apt-cache dummies, please. You only need one test
of these, to ensure that the system interaction is really working as
it should. All the variations should be tested in the above fashion.
[10]
+ elif origin.
+ cloud_init.
This is bogus. This should be `if origin == "ppa":`, otherwise you're
promising something and delivering something else. Please fix the
branch and documentation.
[11]
+class OriginPolicyTes
+
+ def setup_origin_
(...)
+class EC2MachineLaunc
+ OriginPolicyTes
Ouch!
Please drop the mixin.. this is a single simple function,
so let's handle it as such.
[12]
--- juju/providers/
The number of these files and the way we copy them blindly on every
minor detail we want to test is pretty sad. That's fine for this
branch, but it'd be awesome to figure a better way to test this in
the future.
Gustavo Niemeyer (niemeyer) wrote : | # |
[13]
+ juju-origin:
+ The origin of juju deployed to machines within an environment
+ is set by this option. This option can be set to a bzr branch
+ pushed to Launchpad (use a `lp:` prefix, e.g., `lp:juju`); to
+ the PPA by using `ppa`; or to the juju distribution by using
+ `distro`. If this option cannot be parsed, the distribution is
+ used.
This sentence is not reading correctly in a few ways (e.g. the
juju _origin_ is not really deployed, and there's no such thing
as a juju distribution.. it's the Ubuntu distribution).
Please use this:
juju-origin:
Defines where juju should be obtained for installing in
machines. Can be set to a "lp..." branch url, to "ppa" for
getting packages from the official juju PPA, or to "distro"
for using packages from the official Ubuntu repositories.
[14]
Jim, please read this excerpt from our conversation again, *carefully*:
<niemeyer> 1) Grab the installed version from the "Installed:" line
<niemeyer> 2) If this is "(none)" return "branch"
<niemeyer> 3) Otherwise, store the version in a variable, and keep parsing
<niemeyer> 4) Find the version table, and find the installed version
<niemeyer> 5) For each line in the given version, if it contains "ppa.launchpad.
<niemeyer> 6) If you reach the end of the installed version, return "distro"
Compare to what is in the branch right now.
[15]
+ if k == "Installed" and v == "(none)":
+ return "ppa", None
Compare with the summary above.
If there's no juju package installed in the system, it means the
user is not using the ppa.
[16]
+ for _, version_info in parse:
+ if "ppa.launchpad.net" in version_info:
+ return "ppa", None
Compare with the summary above.
Which version is this? The existence of _any_ version that comes from
a PPA in the apt cache is not an indication that the _installed_
version comes from a PPA. The indication that it comes from _a_ ppa
is not an indication that it comes from _our_ ppa either.
[17]
+ def test_distro_
+ data = (
+ "juju:\n"
+ " Installed: (none)\n"
+ " Candidate: good-magic-1.0\n"
Much better, thank you.
Jim Baker (jimbaker) wrote : | # |
I do not see my reply that I emailed to the lp gateway last night, so I'm reposting:
I have made the desired changes, merged trunk, and retested against EC2 for
the various combinations (other than distro, of course).
Please note that some of the branches that were recently merged into trunk
have broken it, as indicated here: http://
remerge trunk as soon as that's fixed.
- Jim
On Wed, Sep 28, 2011 at 7:18 PM, Gustavo Niemeyer <email address hidden>wrote:
> Review: Needs Fixing
>
> [13]
>
> + juju-origin:
> + The origin of juju deployed to machines within an environment
> + is set by this option. This option can be set to a bzr branch
> + pushed to Launchpad (use a `lp:` prefix, e.g., `lp:juju`); to
> + the PPA by using `ppa`; or to the juju distribution by using
> + `distro`. If this option cannot be parsed, the distribution is
> + used.
>
> This sentence is not reading correctly in a few ways (e.g. the
> juju _origin_ is not really deployed, and there's no such thing
> as a juju distribution.. it's the Ubuntu distribution).
>
> Please use this:
>
> juju-origin:
> Defines where juju should be obtained for installing in
> machines. Can be set to a "lp..." branch url, to "ppa" for
> getting packages from the official juju PPA, or to "distro"
> for using packages from the official Ubuntu repositories.
>
>
Used this text as suggested.
>
> [14]
>
> Jim, please read this excerpt from our conversation again, *carefully*:
>
> <niemeyer> 1) Grab the installed version from the "Installed:" line
> <niemeyer> 2) If this is "(none)" return "branch"
> <niemeyer> 3) Otherwise, store the version in a variable, and keep parsing
> <niemeyer> 4) Find the version table, and find the installed version
> <niemeyer> 5) For each line in the given version, if it contains "
> ppa.launchpad.
> <niemeyer> 6) If you reach the end of the installed version, return
> "distro"
>
> Compare to what is in the branch right now.
>
>
> [15]
>
> + if k == "Installed" and v == "(none)":
> + return "ppa", None
>
> Compare with the summary above.
>
> If there's no juju package installed in the system, it means the
> user is not using the ppa.
>
Changed the logic above and the impacted test
>
>
> [16]
>
> + for _, version_info in parse:
> + if "ppa.launchpad.net" in version_info:
> + return "ppa", None
>
> Compare with the summary above.
>
> Which version is this? The existence of _any_ version that comes from
> a PPA in the apt cache is not an indication that the _installed_
> version comes from a PPA. The indication that it comes from _a_ ppa
> is not an indication that it comes from _our_ ppa either.
>
>
Got it. It's now using the precise test as you specified earlier. Sorry
about that.
>
> [17]
>
> + def test_distro_
> + data = (
> + "juju:\n"
> + " Installed: (none)\n"
> + " Candidate: good-magic-1.0\n"
>
> Much better, thank you.
>
>
Thanks!
Gustavo Niemeyer (niemeyer) wrote : | # |
<jimbaker> niemeyer, hi
<niemeyer> jimbaker: Hi
<niemeyer> jimbaker: Please re-read points 3, 4 and 5
<niemeyer> jimbaker: and compare to the implementation
<jimbaker> niemeyer, ok
<niemeyer> jimbaker: Is there anything missing there?
<niemeyer> jimbaker: Maybe I'm just missing.. where's that: 3) Otherwise, store the version in a variable, and keep parsing
<jimbaker> niemeyer, #3 - python-txzookeeper dependency is no longer relevant; #4, it uses the original implementation; #5, there is no attempt to test deb repositories, since they are no longer supported
<niemeyer> jimbaker: 4) Find the version table, and find the installed version
<niemeyer> ?
* ejat has quit (Remote host closed the connection)
<jimbaker> niemeyer, ok, i'm referring to the review points. you are referring to a list from irc
<niemeyer> jimbaker: yeah
<jimbaker> looking at that now
<jimbaker> niemeyer, ok, i believe what you are saying here is that 6) refers to the installed version, which was stored earlier in 3), is that correct?
<niemeyer> 1) Grab the installed version from the "Installed:" line
<niemeyer> 2) If this is "(none)" return "branch"
<niemeyer> 3) Otherwise, store the version in a variable, and keep parsing
<niemeyer> 4) Find the version table, and find the installed version
<niemeyer> jimbaker: Is there any ambiguity here?
<jimbaker> niemeyer, correct, there is no ambiguity. the version table has more information than i have assumed, and this parse needs to take it in account
Jim Baker (jimbaker) wrote : | # |
> <niemeyer> 1) Grab the installed version from the "Installed:" line
> <niemeyer> 2) If this is "(none)" return "branch"
> <niemeyer> 3) Otherwise, store the version in a variable, and keep parsing
> <niemeyer> 4) Find the version table, and find the installed version
> <niemeyer> jimbaker: Is there any ambiguity here?
> <jimbaker> niemeyer, correct, there is no ambiguity. the version table has
> more information than i have assumed, and this parse needs to take it in
> account
The algorithm in parse_juju_origin, and its helper function, has been reworked as described.
Gustavo Niemeyer (niemeyer) wrote : | # |
[18]
345 + " *** 0.5+bzr366-
346 + " 500 http://
347 + "natty/main amd64 Packages\n"
348 + " *** 0.5+bzr356-
349 + " 500 http://
Your multiple versions test has the PPA both in the installed and in the
non-installed version, so it's not really verifying the bug that you have
just fixed.
Change the URL in the non-installed version in this test so it doesn't come
from the PPA so that we ensure that it's really testing the installed version.
Also add a non-installed version that comes from the ppa in the distro test,
to ensure it's not being considered.
Please ensure tests pass with this and that a real interaction passes as well
before merging.
Gustavo Niemeyer (niemeyer) wrote : | # |
I'm taking this over after a conversation on IRC.
Pushed the following changes onto lp:~niemeyer/juju/env-origin, reviewed by Kapil:
- Implementation redone completely.
- Do not crash on missing apt-cache.
- Exported and tested get_default_origin.
- Tests tweaked to explore edge cases.
Preview Diff
1 | === modified file 'docs/source/provider-configuration-ec2.rst' |
2 | --- docs/source/provider-configuration-ec2.rst 2011-09-15 17:41:55 +0000 |
3 | +++ docs/source/provider-configuration-ec2.rst 2011-09-29 23:50:28 +0000 |
4 | @@ -24,9 +24,15 @@ |
5 | An S3 bucket unique to the environment, where some runtime metadata and |
6 | charms are stored. |
7 | |
8 | - juju-branch: |
9 | - Allow a juju bzr branch to be utilized for all machines within an |
10 | - environment. |
11 | + juju-origin: |
12 | + Defines where juju should be obtained for installing in |
13 | + machines. Can be set to a "lp:..." branch url, to "ppa" for |
14 | + getting packages from the official juju PPA, or to "distro" |
15 | + for using packages from the official Ubuntu repositories. |
16 | + |
17 | + If this option is not set, juju will attempt to detect the |
18 | + correct origin based on its run location and the installed |
19 | + juju package. |
20 | |
21 | default-instance-type: |
22 | The instance type to be used for machines launched within the juju |
23 | |
24 | === modified file 'juju/providers/common/cloudinit.py' |
25 | --- juju/providers/common/cloudinit.py 2011-09-23 20:35:02 +0000 |
26 | +++ juju/providers/common/cloudinit.py 2011-09-29 23:50:28 +0000 |
27 | @@ -1,3 +1,5 @@ |
28 | +from subprocess import Popen, PIPE |
29 | + |
30 | from juju.errors import CloudInitError |
31 | from juju.providers.common.utils import format_cloud_init |
32 | from juju.state.auth import make_identity |
33 | @@ -54,6 +56,80 @@ |
34 | % zookeeper_hosts] |
35 | |
36 | |
37 | +def _get_apt_cache_policy(): |
38 | + return Popen(["apt-cache", "policy", "juju"], stdout=PIPE).\ |
39 | + communicate()[0] |
40 | + |
41 | + |
42 | +def _parse_apt_cache_policy(data): |
43 | + """Flatten apt-cache policy output to generate (key, value) pairs.""" |
44 | + |
45 | + # Need to parse in two different phases, so set up iterator now |
46 | + data = iter(data.split("\n")) |
47 | + |
48 | + # Parse preamble |
49 | + for row in data: |
50 | + split = row.split(":", 1) |
51 | + if len(split) != 2: |
52 | + yield None, None |
53 | + k, v = split[0].strip(), split[1].strip() |
54 | + yield k, v |
55 | + if k == "Version table": |
56 | + break |
57 | + |
58 | + # Parse version table into tag, priorities |
59 | + tag = None |
60 | + for row in data: |
61 | + row = row.strip() |
62 | + if row.startswith("***"): |
63 | + tag = row |
64 | + elif tag: |
65 | + yield tag, row |
66 | + |
67 | + |
68 | +def parse_juju_origin(data): |
69 | + """Parse output of apt-cache to determine how juju was installed.""" |
70 | + parse = _parse_apt_cache_policy(data) |
71 | + k, _ = parse.next() |
72 | + if k != "juju": |
73 | + # Sanity check: no record at all, the only possibility is that |
74 | + # this being run as a branch |
75 | + return "branch", "lp:juju" |
76 | + |
77 | + version = None |
78 | + for k, v in parse: |
79 | + if k == "Installed": |
80 | + if v == "(none)": |
81 | + return "branch", "lp:juju" |
82 | + version = v |
83 | + if k == "Version table": |
84 | + break |
85 | + |
86 | + for tag, priority in parse: |
87 | + if (version in tag and |
88 | + "http://ppa.launchpad.net/juju/pkgs/" in priority): |
89 | + return "ppa", None |
90 | + |
91 | + return "distro", None |
92 | + |
93 | + |
94 | +def _get_default_origin(): |
95 | + """Select the best fit for running juju on cloudinit. |
96 | + |
97 | + Used if not otherwise specified by juju-origin. |
98 | + """ |
99 | + import juju |
100 | + if not juju.__file__.startswith("/usr/"): |
101 | + return "lp:juju" |
102 | + origin, source = parse_juju_origin(_get_apt_cache_policy()) |
103 | + if origin == "branch": |
104 | + return source |
105 | + elif origin == "ppa": |
106 | + return _PPA |
107 | + else: |
108 | + return _DISTRO |
109 | + |
110 | + |
111 | class CloudInit(object): |
112 | """Encapsulates juju-specific machine initialisation. |
113 | |
114 | @@ -65,7 +141,7 @@ |
115 | self._machine_id = None |
116 | self._instance_id = None |
117 | self._provider_type = None |
118 | - self._source = _PPA |
119 | + self._source = _get_default_origin() |
120 | self._ssh_keys = [] |
121 | self._provision = False |
122 | self._zookeeper = False |
123 | @@ -103,7 +179,7 @@ |
124 | or fewer than one options, are specified. |
125 | |
126 | Note that you don't need to call this method; the juju source |
127 | - defaults to the juju PPA. |
128 | + defaults to what is returned by `get_default_origin`. |
129 | """ |
130 | if len(filter(None, (branch, ppa, distro))) != 1: |
131 | raise CloudInitError("Please specify one source") |
132 | |
133 | === modified file 'juju/providers/common/launch.py' |
134 | --- juju/providers/common/launch.py 2011-09-22 13:23:00 +0000 |
135 | +++ juju/providers/common/launch.py 2011-09-29 23:50:28 +0000 |
136 | @@ -76,8 +76,15 @@ |
137 | cloud_init.add_ssh_key(get_user_authorized_keys(config)) |
138 | cloud_init.set_machine_id(machine_id) |
139 | cloud_init.set_zookeeper_machines(zookeepers) |
140 | - if config.get("juju-branch"): |
141 | - cloud_init.set_juju_source(config["juju-branch"]) |
142 | + origin = config.get("juju-origin") |
143 | + if origin: |
144 | + if origin.startswith("lp:"): |
145 | + cloud_init.set_juju_source(branch=origin) |
146 | + elif origin == "ppa": |
147 | + cloud_init.set_juju_source(ppa=True) |
148 | + else: |
149 | + # Ignore other values, just use the distro for sanity |
150 | + cloud_init.set_juju_source(distro=True) |
151 | if self._master: |
152 | cloud_init.enable_bootstrap() |
153 | cloud_init.set_zookeeper_secret(config["admin-secret"]) |
154 | |
155 | === modified file 'juju/providers/common/tests/data/cloud_init_bootstrap' |
156 | --- juju/providers/common/tests/data/cloud_init_bootstrap 2011-09-23 20:35:02 +0000 |
157 | +++ juju/providers/common/tests/data/cloud_init_bootstrap 2011-09-29 23:50:28 +0000 |
158 | @@ -1,8 +1,6 @@ |
159 | #cloud-config |
160 | apt-update: true |
161 | apt-upgrade: true |
162 | -apt_sources: |
163 | -- {source: 'ppa:juju/pkgs'} |
164 | machine-data: {juju-provider-type: dummy, juju-zookeeper-hosts: 'localhost:2181', |
165 | machine-id: passport} |
166 | output: {all: '| tee -a /var/log/cloud-init-output.log'} |
167 | |
168 | === modified file 'juju/providers/common/tests/data/cloud_init_bootstrap_zookeepers' |
169 | --- juju/providers/common/tests/data/cloud_init_bootstrap_zookeepers 2011-09-23 20:35:02 +0000 |
170 | +++ juju/providers/common/tests/data/cloud_init_bootstrap_zookeepers 2011-09-29 23:50:28 +0000 |
171 | @@ -1,8 +1,6 @@ |
172 | #cloud-config |
173 | apt-update: true |
174 | apt-upgrade: true |
175 | -apt_sources: |
176 | -- {source: 'ppa:juju/pkgs'} |
177 | machine-data: {juju-provider-type: dummy, juju-zookeeper-hosts: 'cotswold:2181,longleat:2181,localhost:2181', |
178 | machine-id: passport} |
179 | output: {all: '| tee -a /var/log/cloud-init-output.log'} |
180 | |
181 | === added file 'juju/providers/common/tests/data/cloud_init_branch_trunk' |
182 | --- juju/providers/common/tests/data/cloud_init_branch_trunk 1970-01-01 00:00:00 +0000 |
183 | +++ juju/providers/common/tests/data/cloud_init_branch_trunk 2011-09-29 23:50:28 +0000 |
184 | @@ -0,0 +1,17 @@ |
185 | +#cloud-config |
186 | +apt-update: true |
187 | +apt-upgrade: true |
188 | +apt_sources: |
189 | +- {source: 'ppa:juju/pkgs'} |
190 | +machine-data: {juju-provider-type: dummy, juju-zookeeper-hosts: 'cotswold:2181,longleat:2181', |
191 | + machine-id: passport} |
192 | +output: {all: '| tee -a /var/log/cloud-init-output.log'} |
193 | +packages: [bzr, byobu, tmux, python-setuptools, python-twisted, python-argparse, python-txaws, |
194 | + python-zookeeper] |
195 | +runcmd: [sudo apt-get install -y python-txzookeeper, sudo mkdir -p /usr/lib/juju, |
196 | + 'cd /usr/lib/juju && sudo /usr/bin/bzr co lp:juju juju', |
197 | + cd /usr/lib/juju/juju && sudo python setup.py develop, sudo mkdir -p /var/lib/juju, |
198 | + sudo mkdir -p /var/log/juju, 'JUJU_MACHINE_ID=passport JUJU_ZOOKEEPER=cotswold:2181,longleat:2181 |
199 | + python -m juju.agents.machine -n --logfile=/var/log/juju/machine-agent.log |
200 | + --pidfile=/var/run/juju/machine-agent.pid'] |
201 | +ssh_authorized_keys: [chubb] |
202 | |
203 | === modified file 'juju/providers/common/tests/data/cloud_init_normal' |
204 | --- juju/providers/common/tests/data/cloud_init_normal 2011-09-15 19:29:57 +0000 |
205 | +++ juju/providers/common/tests/data/cloud_init_normal 2011-09-29 23:50:28 +0000 |
206 | @@ -1,8 +1,6 @@ |
207 | #cloud-config |
208 | apt-update: true |
209 | apt-upgrade: true |
210 | -apt_sources: |
211 | -- {source: 'ppa:juju/pkgs'} |
212 | machine-data: {juju-provider-type: dummy, juju-zookeeper-hosts: 'cotswold:2181,longleat:2181', |
213 | machine-id: passport} |
214 | output: {all: '| tee -a /var/log/cloud-init-output.log'} |
215 | |
216 | === added file 'juju/providers/common/tests/data/cloud_init_ppa' |
217 | --- juju/providers/common/tests/data/cloud_init_ppa 1970-01-01 00:00:00 +0000 |
218 | +++ juju/providers/common/tests/data/cloud_init_ppa 2011-09-29 23:50:28 +0000 |
219 | @@ -0,0 +1,15 @@ |
220 | +#cloud-config |
221 | +apt-update: true |
222 | +apt-upgrade: true |
223 | +apt_sources: |
224 | +- {'source': 'ppa:juju/pkgs'} |
225 | +machine-data: {juju-provider-type: dummy, juju-zookeeper-hosts: 'cotswold:2181,longleat:2181', |
226 | + machine-id: passport} |
227 | +output: {all: '| tee -a /var/log/cloud-init-output.log'} |
228 | +packages: [bzr, byobu, tmux, python-setuptools, python-twisted, python-argparse, python-txaws, |
229 | + python-zookeeper] |
230 | +runcmd: [sudo apt-get -y install juju, sudo mkdir -p /var/lib/juju, sudo mkdir |
231 | + -p /var/log/juju, 'JUJU_MACHINE_ID=passport JUJU_ZOOKEEPER=cotswold:2181,longleat:2181 |
232 | + python -m juju.agents.machine -n --logfile=/var/log/juju/machine-agent.log |
233 | + --pidfile=/var/run/juju/machine-agent.pid'] |
234 | +ssh_authorized_keys: [chubb] |
235 | |
236 | === modified file 'juju/providers/common/tests/test_cloudinit.py' |
237 | --- juju/providers/common/tests/test_cloudinit.py 2011-09-22 13:23:00 +0000 |
238 | +++ juju/providers/common/tests/test_cloudinit.py 2011-09-29 23:50:28 +0000 |
239 | @@ -1,12 +1,14 @@ |
240 | import os |
241 | +import stat |
242 | |
243 | import yaml |
244 | |
245 | from juju.errors import CloudInitError |
246 | from juju.lib.testing import TestCase |
247 | -from juju.providers.common.cloudinit import CloudInit |
248 | +from juju.providers.common.cloudinit import CloudInit, parse_juju_origin |
249 | from juju.providers.dummy import DummyMachine |
250 | |
251 | + |
252 | DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "data") |
253 | |
254 | |
255 | @@ -30,6 +32,7 @@ |
256 | cloud_init.set_provider_type("dummy") |
257 | cloud_init.set_instance_id_accessor("token") |
258 | cloud_init.set_zookeeper_secret("seekrit") |
259 | + cloud_init.set_juju_source(distro=True) |
260 | if with_zookeepers: |
261 | cloud_init.set_zookeeper_machines([ |
262 | DummyMachine("blah", "blah", "cotswold"), |
263 | @@ -74,12 +77,34 @@ |
264 | self.assertEquals(str(error), "Please specify one source") |
265 | |
266 | def test_render_normal(self): |
267 | - self.assert_render(self.construct_normal(), "cloud_init_normal") |
268 | + path = os.environ.get("PATH", "") |
269 | + alt_apt_cache_path = self.makeDir() |
270 | + filename = os.path.join(alt_apt_cache_path, "apt-cache") |
271 | + with open(filename, "w") as f: |
272 | + f.write( |
273 | + "#!/bin/bash\n" |
274 | + "cat <<EOF\n" |
275 | + "juju:\n" |
276 | + " Installed: good-magic-1.0\n" |
277 | + " Candidate: good-magic-1.0\n" |
278 | + " Version table:\n" |
279 | + " *** good-magic-1.0\n" |
280 | + " 500 http://us.archive.ubuntu.com/ubuntu/ " |
281 | + "natty/main amd64 Packages\n" |
282 | + " 100 /var/lib/dpkg/status\n" |
283 | + "EOF\n") |
284 | + os.chmod(filename, stat.S_IEXEC | stat.S_IREAD) |
285 | + updated_path = alt_apt_cache_path + ":" + path |
286 | + self.change_environment(PATH=updated_path) |
287 | + import juju |
288 | + self.patch(juju, "__file__", |
289 | + "/usr/lib/pymodules/python2.7/juju/__init__.pyc") |
290 | + self.assert_render(self.construct_normal(), "cloud_init_distro") |
291 | |
292 | def test_render_ppa_source(self): |
293 | cloud_init = self.construct_normal() |
294 | cloud_init.set_juju_source(ppa=True) |
295 | - self.assert_render(cloud_init, "cloud_init_normal") |
296 | + self.assert_render(cloud_init, "cloud_init_ppa") |
297 | |
298 | def test_render_distro_source(self): |
299 | cloud_init = self.construct_normal() |
300 | @@ -91,9 +116,90 @@ |
301 | cloud_init.set_juju_source(branch="lp:blah/juju/blah-blah") |
302 | self.assert_render(cloud_init, "cloud_init_branch") |
303 | |
304 | + def test_render_branch_source_if_not_installed(self): |
305 | + import juju |
306 | + self.patch(juju, "__file__", "/not/installed/under/usr") |
307 | + cloud_init = self.construct_normal() |
308 | + self.assert_render(cloud_init, "cloud_init_branch_trunk") |
309 | + |
310 | def test_render_bootstrap(self): |
311 | self.assert_render(self.construct_bootstrap(), "cloud_init_bootstrap") |
312 | |
313 | def test_render_bootstrap_with_zookeepers(self): |
314 | self.assert_render( |
315 | self.construct_bootstrap(True), "cloud_init_bootstrap_zookeepers") |
316 | + |
317 | + |
318 | +class ParseJujuOriginTest(TestCase): |
319 | + |
320 | + def test_distro_installed(self): |
321 | + data = ( |
322 | + "juju:\n" |
323 | + " Installed: good-magic-1.0\n" |
324 | + " Candidate: good-magic-1.0\n" |
325 | + " Version table:\n" |
326 | + " *** good-magic-1.0 0\n" |
327 | + " 500 http://us.archive.ubuntu.com/ubuntu/ " |
328 | + "natty/main amd64 Packages\n" |
329 | + " 100 /var/lib/dpkg/status\n") |
330 | + |
331 | + origin, source = parse_juju_origin(data) |
332 | + self.assertEqual(origin, "distro") |
333 | + self.assertEqual(source, None) |
334 | + |
335 | + def test_multiple_versions_available(self): |
336 | + data = ( |
337 | + "juju:\n" |
338 | + " Installed: 0.5+bzr366-1juju1~natty1\n" |
339 | + " Candidate: 0.5+bzr366-1juju1~natty1\n" |
340 | + " Version table:\n" |
341 | + " *** bad-magic-0.5 0\n" |
342 | + " 500 http://us.archive.ubuntu.com/ubuntu/ " |
343 | + "natty/main amd64 Packages\n" |
344 | + " 100 /var/lib/dpkg/status\n" |
345 | + " *** 0.5+bzr366-1juju1~natty1 0\n" |
346 | + " 500 http://ppa.launchpad.net/juju/pkgs/ubuntu/ " |
347 | + "natty/main amd64 Packages\n" |
348 | + " *** 0.5+bzr356-1juju1~natty1 0\n" |
349 | + " 500 http://ppa.launchpad.net/juju/pkgs/ubuntu/ " |
350 | + "natty/main amd64 Packages\n") |
351 | + |
352 | + origin, source = parse_juju_origin(data) |
353 | + self.assertEqual(origin, "ppa") |
354 | + self.assertEqual(source, None) |
355 | + |
356 | + def test_distro_not_installed(self): |
357 | + data = ( |
358 | + "juju:\n" |
359 | + " Installed: (none)\n" |
360 | + " Candidate: good-magic-1.0\n" |
361 | + " Version table:\n" |
362 | + " *** good-magic-1.0 0\n" |
363 | + " 500 http://us.archive.ubuntu.com/ubuntu/ " |
364 | + "natty/main amd64 Packages\n" |
365 | + " 100 /var/lib/dpkg/status\n") |
366 | + |
367 | + origin, source = parse_juju_origin(data) |
368 | + self.assertEqual(origin, "branch") |
369 | + self.assertEqual(source, "lp:juju") |
370 | + |
371 | + def test_ppa_installed(self): |
372 | + data = ( |
373 | + "juju:\n" |
374 | + " Installed: 0.5+bzr356-1juju1~natty1\n" |
375 | + " Candidate: 0.5+bzr356-1juju1~natty1\n" |
376 | + " Version table:\n" |
377 | + " *** 0.5+bzr356-1juju1~natty1 0\n" |
378 | + " 500 http://ppa.launchpad.net/juju/pkgs/ubuntu/ " |
379 | + "natty/main amd64 Packages\n" |
380 | + " 100 /var/lib/dpkg/status\n") |
381 | + |
382 | + origin, source = parse_juju_origin(data) |
383 | + self.assertEqual(origin, "ppa") |
384 | + self.assertEqual(source, None) |
385 | + |
386 | + def test_juju_package_is_unknown(self): |
387 | + data = "N: Unable to locate package juju" |
388 | + origin, source = parse_juju_origin(data) |
389 | + self.assertEqual(origin, "branch") |
390 | + self.assertEqual(source, "lp:juju") |
391 | |
392 | === modified file 'juju/providers/ec2/tests/common.py' |
393 | --- juju/providers/ec2/tests/common.py 2011-09-22 13:23:00 +0000 |
394 | +++ juju/providers/ec2/tests/common.py 2011-09-29 23:50:28 +0000 |
395 | @@ -22,6 +22,7 @@ |
396 | |
397 | def get_config(self): |
398 | return {"type": "ec2", |
399 | + "juju-origin": "distro", |
400 | "admin-secret": "magic-beans", |
401 | "access-key": "0f62e973d5f8", |
402 | "secret-key": "3e5a7c653f59", |
403 | |
404 | === modified file 'juju/providers/ec2/tests/data/bootstrap_cloud_init' |
405 | --- juju/providers/ec2/tests/data/bootstrap_cloud_init 2011-09-23 20:35:02 +0000 |
406 | +++ juju/providers/ec2/tests/data/bootstrap_cloud_init 2011-09-29 23:50:28 +0000 |
407 | @@ -1,8 +1,6 @@ |
408 | #cloud-config |
409 | apt-update: true |
410 | apt-upgrade: true |
411 | -apt_sources: |
412 | -- {source: 'ppa:juju/pkgs'} |
413 | machine-data: {juju-provider-type: ec2, juju-zookeeper-hosts: 'localhost:2181', |
414 | machine-id: '0'} |
415 | output: {all: '| tee -a /var/log/cloud-init-output.log'} |
416 | |
417 | === modified file 'juju/providers/ec2/tests/data/launch_cloud_init' |
418 | --- juju/providers/ec2/tests/data/launch_cloud_init 2011-09-15 19:29:57 +0000 |
419 | +++ juju/providers/ec2/tests/data/launch_cloud_init 2011-09-29 23:50:28 +0000 |
420 | @@ -1,8 +1,6 @@ |
421 | #cloud-config |
422 | apt-update: true |
423 | apt-upgrade: true |
424 | -apt_sources: |
425 | -- {source: 'ppa:juju/pkgs'} |
426 | machine-data: {juju-provider-type: ec2, juju-zookeeper-hosts: 'es.example.internal:2181', |
427 | machine-id: '1'} |
428 | output: {all: '| tee -a /var/log/cloud-init-output.log'} |
429 | |
430 | === added file 'juju/providers/ec2/tests/data/launch_cloud_init_branch' |
431 | --- juju/providers/ec2/tests/data/launch_cloud_init_branch 1970-01-01 00:00:00 +0000 |
432 | +++ juju/providers/ec2/tests/data/launch_cloud_init_branch 2011-09-29 23:50:28 +0000 |
433 | @@ -0,0 +1,20 @@ |
434 | +#cloud-config |
435 | +apt-update: true |
436 | +apt-upgrade: true |
437 | +apt_sources: |
438 | +- {source: 'ppa:juju/pkgs'} |
439 | +machine-data: {juju-provider-type: ec2, juju-zookeeper-hosts: 'es.example.internal:2181', |
440 | + machine-id: '1'} |
441 | +output: {all: '| tee -a /var/log/cloud-init-output.log'} |
442 | +packages: [bzr, byobu, tmux, python-setuptools, python-twisted, python-argparse, python-txaws, |
443 | + python-zookeeper] |
444 | +runcmd: [sudo apt-get install -y python-txzookeeper, |
445 | + sudo mkdir -p /usr/lib/juju, |
446 | + 'cd /usr/lib/juju && sudo /usr/bin/bzr co lp:~wizard/juju-juicebar juju', |
447 | + cd /usr/lib/juju/juju && sudo python setup.py develop, |
448 | + sudo mkdir -p /var/lib/juju, |
449 | + sudo mkdir -p /var/log/juju, |
450 | + 'JUJU_MACHINE_ID=1 JUJU_ZOOKEEPER=es.example.internal:2181 |
451 | + python -m juju.agents.machine -n --logfile=/var/log/juju/machine-agent.log |
452 | + --pidfile=/var/run/juju/machine-agent.pid'] |
453 | +ssh_authorized_keys: [zebra] |
454 | |
455 | === added file 'juju/providers/ec2/tests/data/launch_cloud_init_ppa' |
456 | --- juju/providers/ec2/tests/data/launch_cloud_init_ppa 1970-01-01 00:00:00 +0000 |
457 | +++ juju/providers/ec2/tests/data/launch_cloud_init_ppa 2011-09-29 23:50:28 +0000 |
458 | @@ -0,0 +1,15 @@ |
459 | +#cloud-config |
460 | +apt-update: true |
461 | +apt-upgrade: true |
462 | +apt_sources: |
463 | +- {source: 'ppa:juju/pkgs'} |
464 | +machine-data: {juju-provider-type: ec2, juju-zookeeper-hosts: 'es.example.internal:2181', |
465 | + machine-id: '1'} |
466 | +output: {all: '| tee -a /var/log/cloud-init-output.log'} |
467 | +packages: [bzr, byobu, tmux, python-setuptools, python-twisted, python-argparse, python-txaws, |
468 | + python-zookeeper] |
469 | +runcmd: [sudo apt-get -y install juju, sudo mkdir -p /var/lib/juju, sudo mkdir |
470 | + -p /var/log/juju, 'JUJU_MACHINE_ID=1 JUJU_ZOOKEEPER=es.example.internal:2181 |
471 | + python -m juju.agents.machine -n --logfile=/var/log/juju/machine-agent.log |
472 | + --pidfile=/var/run/juju/machine-agent.pid'] |
473 | +ssh_authorized_keys: [zebra] |
474 | |
475 | === modified file 'juju/providers/ec2/tests/test_bootstrap.py' |
476 | --- juju/providers/ec2/tests/test_bootstrap.py 2011-09-22 13:23:00 +0000 |
477 | +++ juju/providers/ec2/tests/test_bootstrap.py 2011-09-29 23:50:28 +0000 |
478 | @@ -13,6 +13,7 @@ |
479 | |
480 | from .common import EC2TestMixin, EC2MachineLaunchMixin |
481 | |
482 | + |
483 | DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "data") |
484 | |
485 | |
486 | |
487 | === modified file 'juju/providers/ec2/tests/test_launch.py' |
488 | --- juju/providers/ec2/tests/test_launch.py 2011-09-16 00:36:31 +0000 |
489 | +++ juju/providers/ec2/tests/test_launch.py 2011-09-29 23:50:28 +0000 |
490 | @@ -21,10 +21,11 @@ |
491 | class EC2MachineLaunchTest(EC2TestMixin, EC2MachineLaunchMixin, TestCase): |
492 | |
493 | def _mock_launch(self, instance, expect_ami="ami-default", |
494 | - expect_instance_type="m1.small"): |
495 | + expect_instance_type="m1.small", |
496 | + cloud_init="launch_cloud_init"): |
497 | |
498 | def verify_user_data(data): |
499 | - expect_path = os.path.join(DATA_DIR, "launch_cloud_init") |
500 | + expect_path = os.path.join(DATA_DIR, cloud_init) |
501 | with open(expect_path) as f: |
502 | expect_cloud_init = yaml.load(f.read()) |
503 | self.assertEquals(yaml.load(data), expect_cloud_init) |
504 | @@ -75,6 +76,63 @@ |
505 | return d |
506 | |
507 | @inlineCallbacks |
508 | + def test_provider_launch_using_branch(self): |
509 | + """Can use a juju branch to launch a machine""" |
510 | + self.ec2.describe_security_groups() |
511 | + self.mocker.result(succeed([])) |
512 | + self._mock_create_group() |
513 | + self._mock_create_machine_group("1") |
514 | + self._mock_launch_utils(region="us-east-1") |
515 | + self._mock_get_zookeeper_hosts() |
516 | + self._mock_launch( |
517 | + self.get_instance("i-foobar"), |
518 | + cloud_init="launch_cloud_init_branch") |
519 | + self.mocker.replay() |
520 | + |
521 | + provider = self.get_provider() |
522 | + provider.config["juju-origin"] = "lp:~wizard/juju-juicebar" |
523 | + machines = yield provider.start_machine({"machine-id": "1"}) |
524 | + self.assert_machine(machines[0], "i-foobar", "") |
525 | + |
526 | + @inlineCallbacks |
527 | + def test_provider_launch_using_ppa(self): |
528 | + """Can use the juju ppa to launch a machine""" |
529 | + self.ec2.describe_security_groups() |
530 | + self.mocker.result(succeed([])) |
531 | + self._mock_create_group() |
532 | + self._mock_create_machine_group("1") |
533 | + self._mock_launch_utils(region="us-east-1") |
534 | + self._mock_get_zookeeper_hosts() |
535 | + self._mock_launch( |
536 | + self.get_instance("i-foobar"), |
537 | + cloud_init="launch_cloud_init_ppa") |
538 | + self.mocker.replay() |
539 | + |
540 | + provider = self.get_provider() |
541 | + provider.config["juju-origin"] = "ppa" |
542 | + machines = yield provider.start_machine({"machine-id": "1"}) |
543 | + self.assert_machine(machines[0], "i-foobar", "") |
544 | + |
545 | + @inlineCallbacks |
546 | + def test_provider_launch_using_explicit_distro(self): |
547 | + """Can set juju-origin explicitly to `distro`""" |
548 | + self.ec2.describe_security_groups() |
549 | + self.mocker.result(succeed([])) |
550 | + self._mock_create_group() |
551 | + self._mock_create_machine_group("1") |
552 | + self._mock_launch_utils(region="us-east-1") |
553 | + self._mock_get_zookeeper_hosts() |
554 | + self._mock_launch( |
555 | + self.get_instance("i-foobar"), |
556 | + cloud_init="launch_cloud_init") |
557 | + self.mocker.replay() |
558 | + |
559 | + provider = self.get_provider() |
560 | + provider.config["juju-origin"] = "distro" |
561 | + machines = yield provider.start_machine({"machine-id": "1"}) |
562 | + self.assert_machine(machines[0], "i-foobar", "") |
563 | + |
564 | + @inlineCallbacks |
565 | def test_provider_launch_existing_security_group(self): |
566 | """Verify that the launch works if the env security group exists""" |
567 | instance = Instance("i-foobar", "running", dns_name="x1.example.com") |
568 | |
569 | === modified file 'juju/providers/orchestra/tests/common.py' |
570 | --- juju/providers/orchestra/tests/common.py 2011-09-22 13:23:00 +0000 |
571 | +++ juju/providers/orchestra/tests/common.py 2011-09-29 23:50:28 +0000 |
572 | @@ -13,7 +13,9 @@ |
573 | |
574 | DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "data") |
575 | |
576 | -CONFIG = {"orchestra-server": "somewhe.re", |
577 | +CONFIG = {"type": "orchestra", |
578 | + "juju-origin": "distro", |
579 | + "orchestra-server": "somewhe.re", |
580 | "orchestra-user": "user", |
581 | "orchestra-pass": "pass", |
582 | "acquired-mgmt-class": "acquired", |
583 | |
584 | === modified file 'juju/providers/orchestra/tests/data/bootstrap_user_data' |
585 | --- juju/providers/orchestra/tests/data/bootstrap_user_data 2011-09-23 20:35:02 +0000 |
586 | +++ juju/providers/orchestra/tests/data/bootstrap_user_data 2011-09-29 23:50:28 +0000 |
587 | @@ -1,8 +1,6 @@ |
588 | #cloud-config |
589 | apt-update: true |
590 | apt-upgrade: true |
591 | -apt_sources: |
592 | -- {source: 'ppa:juju/pkgs'} |
593 | machine-data: {juju-provider-type: orchestra, juju-zookeeper-hosts: 'localhost:2181', |
594 | machine-id: '0'} |
595 | output: {all: '| tee -a /var/log/cloud-init-output.log'} |
596 | |
597 | === modified file 'juju/providers/orchestra/tests/data/launch_user_data' |
598 | --- juju/providers/orchestra/tests/data/launch_user_data 2011-09-16 14:07:03 +0000 |
599 | +++ juju/providers/orchestra/tests/data/launch_user_data 2011-09-29 23:50:28 +0000 |
600 | @@ -1,8 +1,6 @@ |
601 | #cloud-config |
602 | apt-update: true |
603 | apt-upgrade: true |
604 | -apt_sources: |
605 | -- {source: 'ppa:juju/pkgs'} |
606 | machine-data: {juju-provider-type: orchestra, juju-zookeeper-hosts: 'jennifer:2181', |
607 | machine-id: '42'} |
608 | output: {all: '| tee -a /var/log/cloud-init-output.log'} |
[1]
The documentation must be changed accordingly.
[2]
Please drop the version support. Without pinning, this doesn't guarantee that
the version will stay as suggested, and we shouldn't be looking into pinning
right now.
[3]
238 + # XXX needed for python-txzookeeper dependency
239 return ["ppa:juju/pkgs"]
That's a *major* one. Why? Please synchronize with SpamapS and ensure that's not
needed anymore.
[4]
213 + # Classify origins so the proper install script is later selected startswith( "deb ") or \ startswith( "ppa:") or \ startswith( "http:" ) or \ startswith( "https: ")): startswith( "lp:"):
214 + if origin is None:
215 + self._origin_type = _DISTRO
216 + elif (origin.
217 + origin.
218 + origin.
219 + origin.
220 + self._origin_type = _DEBIAN
221 + elif origin.
222 + self._origin_type = _BRANCH
Why is this changing? The original version of this logic was significantly
simpler and cleaner, and seems to support all the cases we're trying to
support right now.
[5]
I'm _very_ concerned about your summary. The support for other package sources
besides branches is precisely what this branch is introducing, and you seem to
claim this wasn't tested at all.
Please do make sure this stuff is tested.