Merge lp:~jimbaker/pyjuju/env-origin into lp:pyjuju

Proposed by Jim Baker
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
Reviewer Review Type Date Requested Status
Gustavo Niemeyer Approve
William Reade (community) Approve
Review via email: mp+75823@code.launchpad.net

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.

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

[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
214 + if origin is None:
215 + self._origin_type = _DISTRO
216 + elif (origin.startswith("deb ") or \
217 + origin.startswith("ppa:") or \
218 + origin.startswith("http:") or \
219 + origin.startswith("https:")):
220 + self._origin_type = _DEBIAN
221 + elif origin.startswith("lp:"):
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.

review: Needs Fixing
Revision history for this message
William Reade (fwereade) wrote :

[0]

+ :type branch: str or None

two of these, should be "origin" and "version" instead of "branch"

[1]

+ version=str(config.get("juju-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.

review: Approve
Revision history for this message
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_origin(self):
(...)

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_origin(data) or similar,
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://us.archive.ubuntu.com/ubuntu/ natty/main amd64 Packages
+ 100 /var/lib/dpkg/status
+EOF

This is testing the idempotent parse_juju_origin(data) function. Put the
data inside the test file, and test the function trivially:

    def test_foo(self):
        origin, source = parse_juju_policy(data)
 self.assertEquals(origin, "whatever")
 self.assertEquals(source, "whatever else")

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.startswith("ppa:"):
+ cloud_init.set_juju_source(ppa=True)

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 OriginPolicyTestMixin(object):
+
+ def setup_origin_policy(self, name, is_branch=False):
(...)
+class EC2MachineLaunchTest(EC2TestMixin, EC2MachineLaunchMixin,
+ OriginPolicyTestMixin, TestCase):

Ouch!

Please drop the mixin.. this is a single simple function,
so let's handle it as such.

[12]

--- juju/providers/ec2/tests/data/launch_cloud_init_branch 1970-01-01 00:00:00 +0000

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.

review: Needs Fixing
Revision history for this message
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.net/juju/pkgs", return "ppa"
<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_not_installed(self):
+ data = (
+ "juju:\n"
+ " Installed: (none)\n"
+ " Candidate: good-magic-1.0\n"

Much better, thank you.

review: Needs Fixing
Revision history for this message
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://wtf.labix.org/. I will certainly
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.net/juju/pkgs", return "ppa"
> <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_not_installed(self):
> + data = (
> + "juju:\n"
> + " Installed: (none)\n"
> + " Candidate: good-magic-1.0\n"
>
> Much better, thank you.
>
>
Thanks!

Revision history for this message
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

review: Needs Fixing
Revision history for this message
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.

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

[18]

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/ "

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.

review: Approve
Revision history for this message
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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'}

Subscribers

People subscribed via source and target branches

to status/vote changes: