Merge lp:~dimitern/juju-core/330-general-improvements into lp:~go-bot/juju-core/trunk
- 330-general-improvements
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Dimiter Naydenov |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2409 |
Proposed branch: | lp:~dimitern/juju-core/330-general-improvements |
Merge into: | lp:~go-bot/juju-core/trunk |
Diff against target: |
1961 lines (+551/-446) 35 files modified
cmd/juju/destroyenvironment.go (+1/-1) cmd/juju/destroyenvironment_test.go (+2/-2) cmd/juju/help_topics.go (+31/-25) environs/boilerplate_config.go (+20/-8) environs/bootstrap/bootstrap.go (+3/-2) environs/bootstrap/state.go (+2/-0) environs/cloudinit/cloudinit.go (+2/-2) environs/cloudinit/cloudinit_test.go (+4/-4) environs/httpstorage/storage.go (+7/-0) environs/jujutest/livetests.go (+2/-3) environs/jujutest/tests.go (+5/-6) environs/manual/bootstrap_test.go (+17/-16) environs/manual/export_test.go (+7/-0) environs/manual/fakessh.go (+0/-87) environs/manual/fakessh_test.go (+156/-0) environs/manual/init.go (+9/-7) environs/manual/init_test.go (+26/-26) environs/manual/provisioner_test.go (+10/-9) environs/open.go (+22/-14) environs/sshstorage/storage.go (+6/-0) environs/testing/storage.go (+0/-17) environs/utils.go (+22/-0) juju/conn_test.go (+3/-3) provider/azure/config.go (+19/-11) provider/common/bootstrap.go (+0/-15) provider/ec2/ec2.go (+16/-9) provider/joyent/config.go (+40/-19) provider/local/environprovider.go (+15/-9) provider/maas/environprovider.go (+4/-2) provider/manual/environ.go (+1/-0) provider/openstack/provider.go (+89/-59) state/apiserver/charms.go (+3/-3) state/apiserver/charms_test.go (+3/-3) state/apiserver/client/client_test.go (+4/-4) utils/ssh/testing/fakessh.go (+0/-80) |
To merge this branch: | bzr merge lp:~dimitern/juju-core/330-general-improvements |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+210108@code.launchpad.net |
Commit message
various: production code and logging improvements
Fixed 4 slightly annoying, unrelated minor issues:
1. Refactored production code not to depend on
gocheck (manual provider and apiserver/charms).
As a drive-by fix, I refactored environs/manual
tests to be proper black-box unit tests, rather
than white-box tests in the manual package.
2. Fixed and improved tools download output via
curl and better handling of errors.
3. Added debug logging to environs sshstorage and
httpstorage, and the manual provider.
4. Reformatted and unified generated boilerplate
config across all providers, fixing bug #1221134 in
the process (-e env not properly explained).
Changes tested live with a manual and local environs
with added manually provisioned machines.
While testing I found out and filed this bug #1291292
(basically manual bootstrap is broken with ssl-hostname-
verification set to false, but this is due to a deeper
issue).
I tried to unify and fix when all commands report
"environment not bootstrapped", consistently across
providers, but it turned out like more work than I
originally thought, so I'll do a follow-up on that
(which will entail dropping support for 1.14 environments
without a .jenv file).
https:/
R=jameinel, rogpeppe
Description of the change
various: production code and logging improvements
Fixed 4 slightly annoying, unrelated minor issues:
1. Refactored production code not to depend on
gocheck (manual provider and apiserver/charms).
As a drive-by fix, I refactored environs/manual
tests to be proper black-box unit tests, rather
than white-box tests in the manual package.
2. Fixed and improved tools download output via
curl and better handling of errors.
3. Added debug logging to environs sshstorage and
httpstorage, and the manual provider.
4. Reformatted and unified generated boilerplate
config across all providers, fixing bug #1221134 in
the process (-e env not properly explained).
Changes tested live with a manual and local environs
with added manually provisioned machines.
While testing I found out and filed this bug #1291292
(basically manual bootstrap is broken with ssl-hostname-
verification set to false, but this is due to a deeper
issue).
I tried to unify and fix when all commands report
"environment not bootstrapped", consistently across
providers, but it turned out like more work than I
originally thought, so I'll do a follow-up on that
(which will entail dropping support for 1.14 environments
without a .jenv file).
Dimiter Naydenov (dimitern) wrote : | # |
Andrew Wilkins (axwalk) wrote : | # |
https:/
File environs/
https:/
environs/
strings.
utils/ssh is for *general ssh* things. These scripts do not belong
there. I see the case for exposing them, for the test code, but please
keep them out of utils/ssh.
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
https:/
File environs/
https:/
environs/
strings.
On 2014/03/10 01:08:52, axw wrote:
> utils/ssh is for *general ssh* things. These scripts do not belong
there. I see
> the case for exposing them, for the test code, but please keep them
out of
> utils/ssh.
Thanks for the explanation! As discussed on IRC, moved fakessh to
environs/
Andrew Wilkins (axwalk) wrote : | # |
Thanks for the changes, and cleaning the code up. Looks much better now
:)
Just a few little things...
https:/
File environs/
https:/
environs/
storage %#v", StateFile, storage)
s/boostrap/
https:/
File environs/
https:/
environs/
disk-based environment config storage
returns true iff?
https:/
File environs/open.go (right):
https:/
environs/
Is this right? You're changing behaviour here; the old code only updated
the error if the existing error was non-nil.
John A Meinel (jameinel) wrote : | # |
overall LGTM, though I did have some comments.
https:/
File environs/open.go (right):
https:/
environs/
On 2014/03/11 04:43:22, axw wrote:
> Is this right? You're changing behaviour here; the old code only
updated the
> error if the existing error was non-nil.
So I think this means that if an environ was bootstrapped with 1.14 then
you wouldn't have the .jenv. However, we don't need to preserve compat
with 1.14 if it makes things cleaner.
1.16+ should have always created a .jenv when it bootstrapped.
https:/
File errors/errors.go (right):
https:/
errors/errors.go:6: import "fmt"
I actually prefer the other form.
Because as soon as we need 2 imports, we want to do it anyway, and that
avoids having the noise of what actually changed confused with the extra
lines.
Certainly not worth going around again, just wanted to give my feeling
that multiline imports are still reasonable to use when you only have
one.
https:/
File juju/api.go (right):
https:/
juju/api.go:107: }
I didn't see a change in apiconn_test.go that would actually exercise
this. Can you add one so we don't break it by accident?
Roger Peppe (rogpeppe) wrote : | # |
review so far.
https:/
File environs/
https:/
environs/
storage %#v", StateFile, storage)
I'd be tempted lose this line entirely - it would be nicer to have
better debugging on the storage put methods. But if we keep it, I'd lose
the %#v - it could be very noisy. %T might be better.
https:/
File environs/
https:/
environs/
disk-based environment config storage
On 2014/03/11 04:43:22, axw wrote:
> returns true iff?
The canonical form is:
// Exists reports whether ...
I'm having difficulty understanding why this function exists though.
For a start, the name "Exists" doesn't imply in which configstore
implementation the environment info exists.
The only place that it's used in the production code, it seems that it
could be trivially replaced with a call to ReadInfo.
It's easy to "mock" the existence of the environ info without resorting
to replacing this function - just create the info. That way our tests
don't become unnecessarily dependent on internal details of the code.
I suggest removing this functon.
Roger Peppe (rogpeppe) wrote : | # |
A few more suggestions. It's great that we've lost the testing
dependencies from the code, but there are a few pieces I'm concerned
about.
https:/
File environs/
https:/
environs/
I don't quite see why this and CheckProvisione
exported.
The only reason that I can see is that manual/testing is a separate
package. Given that it's only imported from environs/manual, I don't see
what value that adds. I'd prefer to avoid unnecessary twisty
dependencies.
https:/
File environs/open.go (right):
https:/
environs/
I think andrew has a point here - if ConfigForName returns a useful
error message, it will be lost.
If we're going to deprecate reading config from environments.yaml,
that deserves its own CL, as there is a substantial amount
of cleanup that can and should happen then.
https:/
File errors/errors.go (right):
https:/
errors/errors.go:6: import "fmt"
On 2014/03/11 10:06:33, jameinel wrote:
> I actually prefer the other form.
> Because as soon as we need 2 imports, we want to do it anyway, and
that avoids
> having the noise of what actually changed confused with the extra
lines.
> Certainly not worth going around again, just wanted to give my feeling
that
> multiline imports are still reasonable to use when you only have one.
I think we shouldn't care too much. If goimports inserts a single
import, it does so without the ( ), and that's a useful enough tool that
I think it's reasonable to allow its default output through.
https:/
File juju/api.go (right):
https:/
juju/api.go:104: if !configstore.
As I mentioned in earlier comments, I don't think this is right.
If we want to make it so that we can't open the API without a .jenv
file, that should be a deeper change in this file - there is a fair
amount of logic that can be simplified here.
https:/
File juju/apiconn_
https:/
juju/apiconn_
coretesting.
This is changed only because of the unnecessary Exists patching AFAICS.
https:/
File juju/conn_test.go (right):
https:/
juju/conn_
string) bool {
This seems wrong, as I've mentioned earlier.
It is not at all clear how patching this value will
affect any of the lines of code below - it's truly
action-
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
https:/
File environs/
https:/
environs/
storage %#v", StateFile, storage)
On 2014/03/11 04:43:22, axw wrote:
> s/boostrap/
Done.
https:/
environs/
storage %#v", StateFile, storage)
On 2014/03/11 11:57:46, rog wrote:
> I'd be tempted lose this line entirely - it would be nicer to have
better
> debugging on the storage put methods. But if we keep it, I'd lose the
%#v - it
> could be very noisy. %T might be better.
Changed to %T as suggested.
https:/
File environs/
https:/
environs/
disk-based environment config storage
On 2014/03/11 04:43:22, axw wrote:
> returns true iff?
I dropped this entirely.
https:/
environs/
disk-based environment config storage
On 2014/03/11 11:57:46, rog wrote:
> On 2014/03/11 04:43:22, axw wrote:
> > returns true iff?
> The canonical form is:
> // Exists reports whether ...
> I'm having difficulty understanding why this function exists though.
> For a start, the name "Exists" doesn't imply in which configstore
implementation
> the environment info exists.
> The only place that it's used in the production code, it seems that it
could be
> trivially replaced with a call to ReadInfo.
> It's easy to "mock" the existence of the environ info without
resorting to
> replacing this function - just create the info. That way our tests
don't become
> unnecessarily dependent on internal details of the code.
> I suggest removing this functon.
I dropped this entirely.
https:/
File environs/
https:/
environs/
On 2014/03/11 12:59:34, rog wrote:
> I don't quite see why this and CheckProvisione
exported.
> The only reason that I can see is that manual/testing is a separate
package.
> Given that it's only imported from environs/manual, I don't see what
value that
> adds. I'd prefer to avoid unnecessary twisty dependencies.
DetectionScript and CheckProvisioned scripts need to be exported,
because they are used by both production code and tests.
https:/
File environs/open.go (right):
https:/
environs/
On 2014/03/11 10:06:33, jameinel wrote:
> On 2014/03/11 04:43:22, axw wrote:...
John A Meinel (jameinel) wrote : | # |
LGTM, though you should probably wait for Roger since he had the most
comments on it.
Roger Peppe (rogpeppe) wrote : | # |
On 2014/03/12 12:13:00, jameinel wrote:
> LGTM, though you should probably wait for Roger since he had the most
comments
> on it.
LGTM, thanks!
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
Preview Diff
1 | === modified file 'cmd/juju/destroyenvironment.go' |
2 | --- cmd/juju/destroyenvironment.go 2014-02-11 01:35:20 +0000 |
3 | +++ cmd/juju/destroyenvironment.go 2014-03-12 12:33:26 +0000 |
4 | @@ -67,7 +67,7 @@ |
5 | } |
6 | answer := strings.ToLower(scanner.Text()) |
7 | if answer != "y" && answer != "yes" { |
8 | - return errors.New("Environment destruction aborted") |
9 | + return errors.New("environment destruction aborted") |
10 | } |
11 | } |
12 | // If --force is supplied, then don't attempt to use the API. |
13 | |
14 | === modified file 'cmd/juju/destroyenvironment_test.go' |
15 | --- cmd/juju/destroyenvironment_test.go 2014-02-13 02:46:58 +0000 |
16 | +++ cmd/juju/destroyenvironment_test.go 2014-03-12 12:33:26 +0000 |
17 | @@ -130,7 +130,7 @@ |
18 | // Ensure confirmation is requested if "-y" is not specified. |
19 | stdin.WriteString("n") |
20 | opc, errc := runCommand(ctx, new(DestroyEnvironmentCommand), "dummyenv") |
21 | - c.Check(<-errc, gc.ErrorMatches, "Environment destruction aborted") |
22 | + c.Check(<-errc, gc.ErrorMatches, "environment destruction aborted") |
23 | c.Check(<-opc, gc.IsNil) |
24 | c.Check(stdout.String(), gc.Matches, "WARNING!.*dummyenv.*\\(type: dummy\\)(.|\n)*") |
25 | assertEnvironNotDestroyed(c, env, s.ConfigStore) |
26 | @@ -140,7 +140,7 @@ |
27 | stdout.Reset() |
28 | opc, errc = runCommand(ctx, new(DestroyEnvironmentCommand), "dummyenv") |
29 | c.Check(<-opc, gc.IsNil) |
30 | - c.Check(<-errc, gc.ErrorMatches, "Environment destruction aborted") |
31 | + c.Check(<-errc, gc.ErrorMatches, "environment destruction aborted") |
32 | assertEnvironNotDestroyed(c, env, s.ConfigStore) |
33 | |
34 | // "--yes" passed: no confirmation request. |
35 | |
36 | === modified file 'cmd/juju/help_topics.go' |
37 | --- cmd/juju/help_topics.go 2014-03-04 14:33:43 +0000 |
38 | +++ cmd/juju/help_topics.go 2014-03-12 12:33:26 +0000 |
39 | @@ -47,8 +47,8 @@ |
40 | |
41 | ` |
42 | |
43 | -const helpLocalProvider = ` |
44 | -The local provider is a linux-only Juju environment that uses LXC containers as |
45 | +const helpLocalProvider = ` |
46 | +The local provider is a Linux-only Juju environment that uses LXC containers as |
47 | a virtual cloud on the local machine. Because of this, lxc and mongodb are |
48 | required for the local provider to work. If you don't already have lxc and |
49 | mongodb installed, run the following commands: |
50 | @@ -64,14 +64,14 @@ |
51 | Now you need to tell Juju to use the local provider and then bootstrap: |
52 | |
53 | juju switch local |
54 | - sudo juju bootstrap |
55 | + juju bootstrap |
56 | |
57 | The first time this runs it might take a bit, as it's doing a netinstall for |
58 | the container, it's around a 300 megabyte download. Subsequent bootstraps |
59 | -should be much quicker. 'sudo' is needed because only root can create LXC |
60 | -containers. After the initial bootstrap, you do not need 'sudo' anymore, |
61 | -except to 'sudo juju destroy-environment' when you want to tear everything |
62 | -down. |
63 | +should be much quicker. You'll be asked for your 'sudo' password, which is |
64 | +needed because only root can create LXC containers. When you need to destroy |
65 | +the environment, do 'juju destroy-environment local' and you could be asked |
66 | +for your 'sudo' password again. |
67 | |
68 | You deploy charms from the charm store using the following commands: |
69 | |
70 | @@ -90,31 +90,35 @@ |
71 | |
72 | sample_openstack: |
73 | type: openstack |
74 | + |
75 | # Specifies whether the use of a floating IP address is required to |
76 | # give the nodes a public IP address. Some installations assign public |
77 | # IP addresses by default without requiring a floating IP address. |
78 | # use-floating-ip: false |
79 | + |
80 | # Specifies whether new machine instances should have the "default" |
81 | # Openstack security group assigned. |
82 | # use-default-secgroup: false |
83 | - admin-secret: 13850d1b9786065cadd0f477e8c97cd3 |
84 | - # Globally unique swift bucket name |
85 | - control-bucket: juju-fd6ab8d02393af742bfbe8b9629707ee |
86 | + |
87 | # Usually set via the env variable OS_AUTH_URL, but can be specified here |
88 | # auth-url: https://yourkeystoneurl:443/v2.0/ |
89 | - # override if your workstation is running a different series to which |
90 | - # you are deploying |
91 | + |
92 | # The following are used for userpass authentication (the default) |
93 | - auth-mode: userpass |
94 | + # auth-mode: userpass |
95 | + |
96 | # Usually set via the env variable OS_USERNAME, but can be specified here |
97 | # username: <your username> |
98 | + |
99 | # Usually set via the env variable OS_PASSWORD, but can be specified here |
100 | # password: <secret> |
101 | + |
102 | # Usually set via the env variable OS_TENANT_NAME, but can be specified here |
103 | # tenant-name: <your tenant name> |
104 | + |
105 | # Usually set via the env variable OS_REGION_NAME, but can be specified here |
106 | # region: <your region> |
107 | |
108 | +If you have set the described OS_* environment variables, you only need "type:". |
109 | References: |
110 | |
111 | http://juju.ubuntu.com/docs/provider-configuration-openstack.html |
112 | @@ -125,7 +129,7 @@ |
113 | This answer is for generic OpenStack support, if you're using an OpenStack-based |
114 | provider check these questions out for provider-specific information: |
115 | |
116 | - https://juju.ubuntu.com/docs/config-hpcloud.html |
117 | + https://juju.ubuntu.com/docs/config-hpcloud.html |
118 | |
119 | ` |
120 | |
121 | @@ -141,11 +145,8 @@ |
122 | type: ec2 |
123 | # access-key: YOUR-ACCESS-KEY-GOES-HERE |
124 | # secret-key: YOUR-SECRET-KEY-GOES-HERE |
125 | - control-bucket: juju-faefb490d69a41f0a3616a4808e0766b |
126 | - admin-secret: 81a1e7429e6847c4941fda7591246594 |
127 | |
128 | -See the EC2 provider documentation[2] for more options. The S3 bucket does not |
129 | -need to exist already. |
130 | +See the EC2 provider documentation[2] for more options. |
131 | |
132 | Note If you already have an AWS account, you can determine your access key by |
133 | visiting your account page[3], clicking "Security Credentials" and then clicking |
134 | @@ -183,7 +184,7 @@ |
135 | |
136 | See the online help for more information: |
137 | |
138 | - https://juju.ubuntu.com/docs/config-hpcloud.html |
139 | + https://juju.ubuntu.com/docs/config-hpcloud.html |
140 | ` |
141 | |
142 | const helpAzureProvider = ` |
143 | @@ -191,17 +192,22 @@ |
144 | |
145 | sample_azure: |
146 | type: azure |
147 | + |
148 | # Location for instances, e.g. West US, North Europe. |
149 | location: West US |
150 | + |
151 | # http://msdn.microsoft.com/en-us/library/windowsazure |
152 | # Windows Azure Management info. |
153 | management-subscription-id: 886413e1-3b8a-5382-9b90-0c9aee199e5d |
154 | management-certificate-path: /home/me/azure.pem |
155 | + |
156 | # Windows Azure Storage info. |
157 | storage-account-name: juju0useast0 |
158 | + |
159 | # Override OS image selection with a fixed image for all deployments. |
160 | # Most useful for developers. |
161 | # force-image-name: b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-13_10-amd64-server-DEVELOPMENT-20130713-Juju_ALPHA-en-us-30GB |
162 | + |
163 | # Pick a simplestreams stream to select OS images from: daily or released |
164 | # images, or any other stream available on simplestreams. Leave blank for |
165 | # released images. |
166 | @@ -219,7 +225,7 @@ |
167 | https://juju.ubuntu.com/docs/config-azure.html |
168 | ` |
169 | |
170 | -const helpConstraints = ` |
171 | +const helpConstraints = ` |
172 | Constraints constrain the possible instances that may be started by juju |
173 | commands. They are usually passed as a flag to commands that provision a new |
174 | machine (such as bootstrap, deploy, and add-machine). |
175 | @@ -272,7 +278,7 @@ |
176 | T terabytes (1024 gigabytes) |
177 | P petabytes (1024 terabytes) |
178 | |
179 | -root-disk |
180 | +root-disk |
181 | Root-Disk is a float that defines the amount of space in megabytes that must |
182 | be available in the machine's root partition. For providers that have |
183 | configurable root disk sizes (such as EC2) an instance with the specified |
184 | @@ -280,8 +286,8 @@ |
185 | defaults to megabytes and may be specified in the same manner as the mem |
186 | constraint. |
187 | |
188 | -container |
189 | - Container defines that the machine must be a container of the specified type. |
190 | +container |
191 | + Container defines that the machine must be a container of the specified type. |
192 | A container of that type may be created by juju to fulfill the request. |
193 | Currently supported containers: |
194 | none - (default) no container |
195 | @@ -294,7 +300,7 @@ |
196 | roughly, a single 2007-era Xeon). Cpu-power is currently only supported by |
197 | the Amazon EC2 environment. |
198 | |
199 | -tags |
200 | +tags |
201 | Tags defines the list of tags that the machine must have applied to it. |
202 | Multiple tags must be delimited by a comma. Tags are currently only supported |
203 | by the MaaS environment. |
204 | @@ -374,7 +380,7 @@ |
205 | other, and the way in which the topology of Services is assembled. The Charm |
206 | defines which Relations a given Service may establish, and what kind of |
207 | interface these Relations require. |
208 | - |
209 | + |
210 | In many cases, the establishment of a Relation will result into an actual TCP |
211 | connection being created between the Service Units, but that's not necessarily |
212 | the case. Relations may also be established to inform Services of |
213 | |
214 | === modified file 'environs/boilerplate_config.go' |
215 | --- environs/boilerplate_config.go 2013-10-11 14:05:04 +0000 |
216 | +++ environs/boilerplate_config.go 2014-03-12 12:33:26 +0000 |
217 | @@ -12,24 +12,36 @@ |
218 | ) |
219 | |
220 | var configHeader = ` |
221 | -# This is the Juju config file, which you can use to specify multiple environments in which to deploy. |
222 | -# By default Juju ships AWS (default), HP Cloud, OpenStack. |
223 | -# See https://juju.ubuntu.com/docs for more information |
224 | +# This is the Juju config file, which you can use to specify multiple |
225 | +# environments in which to deploy. By default Juju ships with AWS |
226 | +# (default), HP Cloud, OpenStack, Azure, MaaS, Local and Manual |
227 | +# providers. See https://juju.ubuntu.com/docs for more information |
228 | |
229 | -# An environment configuration must always specify at least the following information: |
230 | -# |
231 | +# An environment configuration must always specify at least the |
232 | +# following information: |
233 | # - name (to identify the environment) |
234 | # - type (to specify the provider) |
235 | +# In the following example the name is "myenv" and type is "ec2". |
236 | +# myenv: |
237 | +# type: ec2 |
238 | |
239 | # Values in <brackets> below need to be filled in by the user. |
240 | # Optional attributes are shown commented out, with |
241 | # a sample value or a value in <brackets>. |
242 | |
243 | +# There are several settings supported by all environments, all of which |
244 | +# are optional and have specified default values. For more info, see the |
245 | +# Juju documentation. |
246 | + |
247 | # The default environment is chosen when an environment is not |
248 | # specified using any of the following, in descending order of precedence: |
249 | -# -e or --environment command line parameter. |
250 | -# JUJU_ENV environment variable. |
251 | -# the juju switch command. |
252 | +# 1. -e or --environment command line parameter, passed after the command, e.g. |
253 | +# $ juju add-unit -e myenv myservice |
254 | +# 2. By setting JUJU_ENV environment variable. |
255 | +# 3. Using the juju switch command like this: |
256 | +# $ juju switch myenv |
257 | +# |
258 | + |
259 | default: amazon |
260 | |
261 | environments: |
262 | |
263 | === modified file 'environs/bootstrap/bootstrap.go' |
264 | --- environs/bootstrap/bootstrap.go 2014-03-05 19:41:34 +0000 |
265 | +++ environs/bootstrap/bootstrap.go 2014-03-12 12:33:26 +0000 |
266 | @@ -71,8 +71,9 @@ |
267 | return toolsList, nil |
268 | } |
269 | |
270 | -// EnsureNotBootstrapped returns null if the environment is not bootstrapped, |
271 | -// and an error if it is or if the function was not able to tell. |
272 | +// EnsureNotBootstrapped returns nil if the environment is not |
273 | +// bootstrapped, and an error if it is or if the function was not able |
274 | +// to tell. |
275 | func EnsureNotBootstrapped(env environs.Environ) error { |
276 | _, err := LoadState(env.Storage()) |
277 | // If there is no error loading the bootstrap state, then we are |
278 | |
279 | === modified file 'environs/bootstrap/state.go' |
280 | --- environs/bootstrap/state.go 2014-02-25 22:19:30 +0000 |
281 | +++ environs/bootstrap/state.go 2014-03-12 12:33:26 +0000 |
282 | @@ -40,6 +40,7 @@ |
283 | // putState writes the given data to the state file on the given storage. |
284 | // The file's name is as defined in StateFile. |
285 | func putState(storage storage.StorageWriter, data []byte) error { |
286 | + logger.Debugf("putting %q to bootstrap storage %T", StateFile, storage) |
287 | return storage.Put(StateFile, bytes.NewBuffer(data), int64(len(data))) |
288 | } |
289 | |
290 | @@ -69,6 +70,7 @@ |
291 | |
292 | // LoadStateFromURL reads state from the given URL. |
293 | func LoadStateFromURL(url string, disableSSLHostnameVerification bool) (*BootstrapState, error) { |
294 | + logger.Debugf("loading %q from %q", StateFile, url) |
295 | client := http.DefaultClient |
296 | if disableSSLHostnameVerification { |
297 | logger.Infof("hostname SSL verification disabled") |
298 | |
299 | === modified file 'environs/cloudinit/cloudinit.go' |
300 | --- environs/cloudinit/cloudinit.go 2014-03-11 18:33:39 +0000 |
301 | +++ environs/cloudinit/cloudinit.go 2014-03-12 12:33:26 +0000 |
302 | @@ -299,9 +299,9 @@ |
303 | if strings.HasPrefix(cfg.Tools.URL, fileSchemePrefix) { |
304 | copyCmd = fmt.Sprintf("cp %s $bin/tools.tar.gz", shquote(cfg.Tools.URL[len(fileSchemePrefix):])) |
305 | } else { |
306 | - curlCommand := "curl" |
307 | + curlCommand := "curl -sSfw 'tools from %{url_effective} downloaded: HTTP %{http_code}; time %{time_total}s; size %{size_download} bytes; speed %{speed_download} bytes/s '" |
308 | if cfg.DisableSSLHostnameVerification { |
309 | - curlCommand = "curl --insecure" |
310 | + curlCommand += " --insecure" |
311 | } |
312 | copyCmd = fmt.Sprintf("%s -o $bin/tools.tar.gz %s", curlCommand, shquote(cfg.Tools.URL)) |
313 | c.AddRunCmd(cloudinit.LogProgressCmd("Fetching tools: %s", copyCmd)) |
314 | |
315 | === modified file 'environs/cloudinit/cloudinit_test.go' |
316 | --- environs/cloudinit/cloudinit_test.go 2014-03-11 18:33:39 +0000 |
317 | +++ environs/cloudinit/cloudinit_test.go 2014-03-12 12:33:26 +0000 |
318 | @@ -124,7 +124,7 @@ |
319 | echo 'Fetching tools.* |
320 | bin='/var/lib/juju/tools/1\.2\.3-precise-amd64' |
321 | mkdir -p \$bin |
322 | -curl -o \$bin/tools\.tar\.gz 'http://foo\.com/tools/releases/juju1\.2\.3-precise-amd64\.tgz' |
323 | +curl -sSfw 'tools from %{url_effective} downloaded: HTTP %{http_code}; time %{time_total}s; size %{size_download} bytes; speed %{speed_download} bytes/s ' -o \$bin/tools\.tar\.gz 'http://foo\.com/tools/releases/juju1\.2\.3-precise-amd64\.tgz' |
324 | sha256sum \$bin/tools\.tar\.gz > \$bin/juju1\.2\.3-precise-amd64\.sha256 |
325 | grep '1234' \$bin/juju1\.2\.3-precise-amd64.sha256 \|\| \(echo "Tools checksum mismatch"; exit 1\) |
326 | tar zxf \$bin/tools.tar.gz -C \$bin |
327 | @@ -195,7 +195,7 @@ |
328 | inexactMatch: true, |
329 | expectScripts: ` |
330 | bin='/var/lib/juju/tools/1\.2\.3-raring-amd64' |
331 | -curl -o \$bin/tools\.tar\.gz 'http://foo\.com/tools/releases/juju1\.2\.3-raring-amd64\.tgz' |
332 | +curl -sSfw 'tools from %{url_effective} downloaded: HTTP %{http_code}; time %{time_total}s; size %{size_download} bytes; speed %{speed_download} bytes/s ' -o \$bin/tools\.tar\.gz 'http://foo\.com/tools/releases/juju1\.2\.3-raring-amd64\.tgz' |
333 | sha256sum \$bin/tools\.tar\.gz > \$bin/juju1\.2\.3-raring-amd64\.sha256 |
334 | grep '1234' \$bin/juju1\.2\.3-raring-amd64.sha256 \|\| \(echo "Tools checksum mismatch"; exit 1\) |
335 | rm \$bin/tools\.tar\.gz && rm \$bin/juju1\.2\.3-raring-amd64\.sha256 |
336 | @@ -243,7 +243,7 @@ |
337 | echo 'Fetching tools.* |
338 | bin='/var/lib/juju/tools/1\.2\.3-linux-amd64' |
339 | mkdir -p \$bin |
340 | -curl -o \$bin/tools\.tar\.gz 'http://foo\.com/tools/releases/juju1\.2\.3-linux-amd64\.tgz' |
341 | +curl -sSfw 'tools from %{url_effective} downloaded: HTTP %{http_code}; time %{time_total}s; size %{size_download} bytes; speed %{speed_download} bytes/s ' -o \$bin/tools\.tar\.gz 'http://foo\.com/tools/releases/juju1\.2\.3-linux-amd64\.tgz' |
342 | sha256sum \$bin/tools\.tar\.gz > \$bin/juju1\.2\.3-linux-amd64\.sha256 |
343 | grep '1234' \$bin/juju1\.2\.3-linux-amd64.sha256 \|\| \(echo "Tools checksum mismatch"; exit 1\) |
344 | tar zxf \$bin/tools.tar.gz -C \$bin |
345 | @@ -324,7 +324,7 @@ |
346 | }, |
347 | inexactMatch: true, |
348 | expectScripts: ` |
349 | -curl --insecure -o \$bin/tools\.tar\.gz 'http://foo\.com/tools/releases/juju1\.2\.3-linux-amd64\.tgz' |
350 | +curl -sSfw 'tools from %{url_effective} downloaded: HTTP %{http_code}; time %{time_total}s; size %{size_download} bytes; speed %{speed_download} bytes/s ' --insecure -o \$bin/tools\.tar\.gz 'http://foo\.com/tools/releases/juju1\.2\.3-linux-amd64\.tgz' |
351 | `, |
352 | }, { |
353 | // empty contraints. |
354 | |
355 | === modified file 'environs/httpstorage/storage.go' |
356 | --- environs/httpstorage/storage.go 2014-02-25 22:19:30 +0000 |
357 | +++ environs/httpstorage/storage.go 2014-03-12 12:33:26 +0000 |
358 | @@ -16,11 +16,15 @@ |
359 | "strings" |
360 | "sync" |
361 | |
362 | + "github.com/juju/loggo" |
363 | + |
364 | "launchpad.net/juju-core/environs/storage" |
365 | coreerrors "launchpad.net/juju-core/errors" |
366 | "launchpad.net/juju-core/utils" |
367 | ) |
368 | |
369 | +var logger = loggo.GetLogger("juju.environs.httpstorage") |
370 | + |
371 | // storage implements the storage.Storage interface. |
372 | type localStorage struct { |
373 | addr string |
374 | @@ -46,6 +50,7 @@ |
375 | // using TLS. The client is given an authentication key, |
376 | // which the server will verify for Put and Remove* operations. |
377 | func ClientTLS(addr string, caCertPEM []byte, authkey string) (storage.Storage, error) { |
378 | + logger.Debugf("using https storage at %q", addr) |
379 | caCerts := x509.NewCertPool() |
380 | if caCertPEM != nil { |
381 | if !caCerts.AppendCertsFromPEM(caCertPEM) { |
382 | @@ -83,6 +88,7 @@ |
383 | // responsibility to close it after use. If the name does not |
384 | // exist, it should return a *NotFoundError. |
385 | func (s *localStorage) Get(name string) (io.ReadCloser, error) { |
386 | + logger.Debugf("getting %q from storage", name) |
387 | url, err := s.URL(name) |
388 | if err != nil { |
389 | return nil, err |
390 | @@ -167,6 +173,7 @@ |
391 | // Put reads from r and writes to the given storage file. |
392 | // The length must be set to the total length of the file. |
393 | func (s *localStorage) Put(name string, r io.Reader, length int64) error { |
394 | + logger.Debugf("putting %q (len %d) to storage", name, length) |
395 | url, err := s.modURL(name) |
396 | if err != nil { |
397 | return err |
398 | |
399 | === modified file 'environs/jujutest/livetests.go' |
400 | --- environs/jujutest/livetests.go 2014-02-20 08:23:40 +0000 |
401 | +++ environs/jujutest/livetests.go 2014-03-12 12:33:26 +0000 |
402 | @@ -27,7 +27,6 @@ |
403 | "launchpad.net/juju-core/instance" |
404 | "launchpad.net/juju-core/juju" |
405 | "launchpad.net/juju-core/juju/testing" |
406 | - "launchpad.net/juju-core/provider/common" |
407 | "launchpad.net/juju-core/provider/dummy" |
408 | "launchpad.net/juju-core/state" |
409 | "launchpad.net/juju-core/state/api" |
410 | @@ -138,7 +137,7 @@ |
411 | c.Assert(err, gc.IsNil) |
412 | } |
413 | envtesting.UploadFakeTools(c, t.Env.Storage()) |
414 | - err := common.EnsureNotBootstrapped(t.Env) |
415 | + err := bootstrap.EnsureNotBootstrapped(t.Env) |
416 | c.Assert(err, gc.IsNil) |
417 | err = bootstrap.Bootstrap(coretesting.Context(c), t.Env, cons) |
418 | c.Assert(err, gc.IsNil) |
419 | @@ -382,7 +381,7 @@ |
420 | // already up, this has been moved into the bootstrap command. |
421 | t.BootstrapOnce(c) |
422 | |
423 | - err := common.EnsureNotBootstrapped(t.Env) |
424 | + err := bootstrap.EnsureNotBootstrapped(t.Env) |
425 | c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped") |
426 | |
427 | c.Logf("destroy env") |
428 | |
429 | === modified file 'environs/jujutest/tests.go' |
430 | --- environs/jujutest/tests.go 2014-02-13 02:46:58 +0000 |
431 | +++ environs/jujutest/tests.go 2014-03-12 12:33:26 +0000 |
432 | @@ -21,7 +21,6 @@ |
433 | "launchpad.net/juju-core/errors" |
434 | "launchpad.net/juju-core/instance" |
435 | "launchpad.net/juju-core/juju/testing" |
436 | - "launchpad.net/juju-core/provider/common" |
437 | coretesting "launchpad.net/juju-core/testing" |
438 | jc "launchpad.net/juju-core/testing/checkers" |
439 | "launchpad.net/juju-core/testing/testbase" |
440 | @@ -132,7 +131,7 @@ |
441 | func (t *Tests) TestBootstrap(c *gc.C) { |
442 | e := t.Prepare(c) |
443 | envtesting.UploadFakeTools(c, e.Storage()) |
444 | - err := common.EnsureNotBootstrapped(e) |
445 | + err := bootstrap.EnsureNotBootstrapped(e) |
446 | c.Assert(err, gc.IsNil) |
447 | err = bootstrap.Bootstrap(coretesting.Context(c), e, constraints.Value{}) |
448 | c.Assert(err, gc.IsNil) |
449 | @@ -141,12 +140,12 @@ |
450 | c.Check(info.Addrs, gc.Not(gc.HasLen), 0) |
451 | c.Check(apiInfo.Addrs, gc.Not(gc.HasLen), 0) |
452 | |
453 | - err = common.EnsureNotBootstrapped(e) |
454 | + err = bootstrap.EnsureNotBootstrapped(e) |
455 | c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped") |
456 | |
457 | e2 := t.Open(c) |
458 | envtesting.UploadFakeTools(c, e2.Storage()) |
459 | - err = common.EnsureNotBootstrapped(e2) |
460 | + err = bootstrap.EnsureNotBootstrapped(e2) |
461 | c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped") |
462 | |
463 | info2, apiInfo2, err := e2.StateInfo() |
464 | @@ -160,12 +159,12 @@ |
465 | e3 := t.Prepare(c) |
466 | envtesting.UploadFakeTools(c, e3.Storage()) |
467 | |
468 | - err = common.EnsureNotBootstrapped(e3) |
469 | + err = bootstrap.EnsureNotBootstrapped(e3) |
470 | c.Assert(err, gc.IsNil) |
471 | err = bootstrap.Bootstrap(coretesting.Context(c), e3, constraints.Value{}) |
472 | c.Assert(err, gc.IsNil) |
473 | |
474 | - err = common.EnsureNotBootstrapped(e3) |
475 | + err = bootstrap.EnsureNotBootstrapped(e3) |
476 | c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped") |
477 | } |
478 | |
479 | |
480 | === modified file 'environs/manual/bootstrap_test.go' |
481 | --- environs/manual/bootstrap_test.go 2014-03-04 16:55:38 +0000 |
482 | +++ environs/manual/bootstrap_test.go 2014-03-12 12:33:26 +0000 |
483 | @@ -1,7 +1,7 @@ |
484 | // Copyright 2013 Canonical Ltd. |
485 | // Licensed under the AGPLv3, see LICENCE file for details. |
486 | |
487 | -package manual |
488 | +package manual_test |
489 | |
490 | import ( |
491 | "fmt" |
492 | @@ -14,6 +14,7 @@ |
493 | "launchpad.net/juju-core/environs/bootstrap" |
494 | "launchpad.net/juju-core/environs/cloudinit" |
495 | "launchpad.net/juju-core/environs/filestorage" |
496 | + "launchpad.net/juju-core/environs/manual" |
497 | "launchpad.net/juju-core/environs/storage" |
498 | "launchpad.net/juju-core/environs/tools" |
499 | "launchpad.net/juju-core/instance" |
500 | @@ -59,13 +60,13 @@ |
501 | s.env.storage = storage |
502 | } |
503 | |
504 | -func (s *bootstrapSuite) getArgs(c *gc.C) BootstrapArgs { |
505 | +func (s *bootstrapSuite) getArgs(c *gc.C) manual.BootstrapArgs { |
506 | hostname, err := os.Hostname() |
507 | c.Assert(err, gc.IsNil) |
508 | toolsList, err := tools.FindBootstrapTools(s.Conn.Environ, tools.BootstrapToolsParams{}) |
509 | c.Assert(err, gc.IsNil) |
510 | arch := "amd64" |
511 | - return BootstrapArgs{ |
512 | + return manual.BootstrapArgs{ |
513 | Host: hostname, |
514 | DataDir: "/var/lib/juju", |
515 | Environ: s.env, |
516 | @@ -83,7 +84,7 @@ |
517 | args.Host = "ubuntu@" + args.Host |
518 | |
519 | defer fakeSSH{SkipDetection: true}.install(c).Restore() |
520 | - err := Bootstrap(args) |
521 | + err := manual.Bootstrap(args) |
522 | c.Assert(err, gc.IsNil) |
523 | |
524 | bootstrapState, err := bootstrap.LoadState(s.env.Storage()) |
525 | @@ -91,14 +92,14 @@ |
526 | c.Assert( |
527 | bootstrapState.StateInstances, |
528 | gc.DeepEquals, |
529 | - []instance.Id{BootstrapInstanceId}, |
530 | + []instance.Id{manual.BootstrapInstanceId}, |
531 | ) |
532 | |
533 | // Do it all again; this should work, despite the fact that |
534 | // there's a bootstrap state file. Existence for that is |
535 | // checked in general bootstrap code (environs/bootstrap). |
536 | defer fakeSSH{SkipDetection: true}.install(c).Restore() |
537 | - err = Bootstrap(args) |
538 | + err = manual.Bootstrap(args) |
539 | c.Assert(err, gc.IsNil) |
540 | |
541 | // We *do* check that the machine has no juju* upstart jobs, though. |
542 | @@ -107,15 +108,15 @@ |
543 | SkipDetection: true, |
544 | SkipProvisionAgent: true, |
545 | }.install(c).Restore() |
546 | - err = Bootstrap(args) |
547 | - c.Assert(err, gc.Equals, ErrProvisioned) |
548 | + err = manual.Bootstrap(args) |
549 | + c.Assert(err, gc.Equals, manual.ErrProvisioned) |
550 | } |
551 | |
552 | func (s *bootstrapSuite) TestBootstrapScriptFailure(c *gc.C) { |
553 | args := s.getArgs(c) |
554 | args.Host = "ubuntu@" + args.Host |
555 | defer fakeSSH{SkipDetection: true, ProvisionAgentExitCode: 1}.install(c).Restore() |
556 | - err := Bootstrap(args) |
557 | + err := manual.Bootstrap(args) |
558 | c.Assert(err, gc.NotNil) |
559 | |
560 | // Since the script failed, the state file should have been |
561 | @@ -127,19 +128,19 @@ |
562 | func (s *bootstrapSuite) TestBootstrapEmptyDataDir(c *gc.C) { |
563 | args := s.getArgs(c) |
564 | args.DataDir = "" |
565 | - c.Assert(Bootstrap(args), gc.ErrorMatches, "data-dir argument is empty") |
566 | + c.Assert(manual.Bootstrap(args), gc.ErrorMatches, "data-dir argument is empty") |
567 | } |
568 | |
569 | func (s *bootstrapSuite) TestBootstrapEmptyHost(c *gc.C) { |
570 | args := s.getArgs(c) |
571 | args.Host = "" |
572 | - c.Assert(Bootstrap(args), gc.ErrorMatches, "host argument is empty") |
573 | + c.Assert(manual.Bootstrap(args), gc.ErrorMatches, "host argument is empty") |
574 | } |
575 | |
576 | func (s *bootstrapSuite) TestBootstrapNilEnviron(c *gc.C) { |
577 | args := s.getArgs(c) |
578 | args.Environ = nil |
579 | - c.Assert(Bootstrap(args), gc.ErrorMatches, "environ argument is nil") |
580 | + c.Assert(manual.Bootstrap(args), gc.ErrorMatches, "environ argument is nil") |
581 | } |
582 | |
583 | func (s *bootstrapSuite) TestBootstrapNoMatchingTools(c *gc.C) { |
584 | @@ -147,13 +148,13 @@ |
585 | args := s.getArgs(c) |
586 | args.PossibleTools = nil |
587 | defer fakeSSH{SkipDetection: true, SkipProvisionAgent: true}.install(c).Restore() |
588 | - c.Assert(Bootstrap(args), gc.ErrorMatches, "possible tools is empty") |
589 | + c.Assert(manual.Bootstrap(args), gc.ErrorMatches, "possible tools is empty") |
590 | |
591 | // Non-empty list, but none that match the series/arch. |
592 | args = s.getArgs(c) |
593 | args.Series = "edgy" |
594 | defer fakeSSH{SkipDetection: true, SkipProvisionAgent: true}.install(c).Restore() |
595 | - c.Assert(Bootstrap(args), gc.ErrorMatches, "no matching tools available") |
596 | + c.Assert(manual.Bootstrap(args), gc.ErrorMatches, "no matching tools available") |
597 | } |
598 | |
599 | func (s *bootstrapSuite) TestBootstrapToolsFileURL(c *gc.C) { |
600 | @@ -170,13 +171,13 @@ |
601 | } |
602 | |
603 | func (s *bootstrapSuite) testBootstrapToolsURL(c *gc.C, toolsURL, expectedURL string) { |
604 | - s.PatchValue(&provisionMachineAgent, func(host string, mcfg *cloudinit.MachineConfig, w io.Writer) error { |
605 | + s.PatchValue(manual.ProvisionMachineAgent, func(host string, mcfg *cloudinit.MachineConfig, w io.Writer) error { |
606 | c.Assert(mcfg.Tools.URL, gc.Equals, expectedURL) |
607 | return nil |
608 | }) |
609 | args := s.getArgs(c) |
610 | args.PossibleTools[0].URL = toolsURL |
611 | defer fakeSSH{SkipDetection: true}.install(c).Restore() |
612 | - err := Bootstrap(args) |
613 | + err := manual.Bootstrap(args) |
614 | c.Assert(err, gc.IsNil) |
615 | } |
616 | |
617 | === modified file 'environs/manual/export_test.go' |
618 | --- environs/manual/export_test.go 2014-01-30 03:18:20 +0000 |
619 | +++ environs/manual/export_test.go 2014-03-12 12:33:26 +0000 |
620 | @@ -5,4 +5,11 @@ |
621 | |
622 | var ( |
623 | InstanceHostAddresses = &instanceHostAddresses |
624 | + ProvisionMachineAgent = &provisionMachineAgent |
625 | + CheckProvisioned = checkProvisioned |
626 | +) |
627 | + |
628 | +const ( |
629 | + DetectionScript = detectionScript |
630 | + CheckProvisionedScript = checkProvisionedScript |
631 | ) |
632 | |
633 | === removed file 'environs/manual/fakessh.go' |
634 | --- environs/manual/fakessh.go 2014-01-13 06:25:28 +0000 |
635 | +++ environs/manual/fakessh.go 1970-01-01 00:00:00 +0000 |
636 | @@ -1,87 +0,0 @@ |
637 | -// Copyright 2013 Canonical Ltd. |
638 | -// Licensed under the AGPLv3, see LICENCE file for details. |
639 | - |
640 | -package manual |
641 | - |
642 | -import ( |
643 | - "strings" |
644 | - |
645 | - gc "launchpad.net/gocheck" |
646 | - |
647 | - "launchpad.net/juju-core/testing/testbase" |
648 | - sshtesting "launchpad.net/juju-core/utils/ssh/testing" |
649 | -) |
650 | - |
651 | -// installDetectionFakeSSH installs a fake SSH command, which will respond |
652 | -// to the series/hardware detection script with the specified |
653 | -// series/arch. |
654 | -func installDetectionFakeSSH(c *gc.C, series, arch string) testbase.Restorer { |
655 | - if series == "" { |
656 | - series = "precise" |
657 | - } |
658 | - if arch == "" { |
659 | - arch = "amd64" |
660 | - } |
661 | - detectionoutput := strings.Join([]string{ |
662 | - series, |
663 | - arch, |
664 | - "MemTotal: 4096 kB", |
665 | - "processor: 0", |
666 | - }, "\n") |
667 | - return sshtesting.InstallFakeSSH(c, detectionScript, detectionoutput, 0) |
668 | -} |
669 | - |
670 | -// FakeSSH wraps the invocation of InstallFakeSSH based on the parameters. |
671 | -type fakeSSH struct { |
672 | - Series string |
673 | - Arch string |
674 | - |
675 | - // Provisioned should be set to true if the fakeSSH script |
676 | - // should respond to checkProvisioned with a non-empty result. |
677 | - Provisioned bool |
678 | - |
679 | - // exit code for the checkProvisioned script. |
680 | - CheckProvisionedExitCode int |
681 | - |
682 | - // exit code for the machine agent provisioning script. |
683 | - ProvisionAgentExitCode int |
684 | - |
685 | - // InitUbuntuUser should be set to true if the fakeSSH script |
686 | - // should respond to an attempt to initialise the ubuntu user. |
687 | - InitUbuntuUser bool |
688 | - |
689 | - // there are conditions other than error in the above |
690 | - // that might cause provisioning to not go ahead, such |
691 | - // as tools being missing. |
692 | - SkipProvisionAgent bool |
693 | - |
694 | - // detection will be skipped if the series/hardware were |
695 | - // detected ahead of time. This should always be set to |
696 | - // true when testing Bootstrap. |
697 | - SkipDetection bool |
698 | -} |
699 | - |
700 | -// install installs fake SSH commands, which will respond to |
701 | -// manual provisioning/bootstrapping commands with the specified |
702 | -// output and exit codes. |
703 | -func (r fakeSSH) install(c *gc.C) testbase.Restorer { |
704 | - var restore testbase.Restorer |
705 | - add := func(input, output interface{}, rc int) { |
706 | - restore = restore.Add(sshtesting.InstallFakeSSH(c, input, output, rc)) |
707 | - } |
708 | - if !r.SkipProvisionAgent { |
709 | - add(nil, nil, r.ProvisionAgentExitCode) |
710 | - } |
711 | - if !r.SkipDetection { |
712 | - restore.Add(installDetectionFakeSSH(c, r.Series, r.Arch)) |
713 | - } |
714 | - var checkProvisionedOutput interface{} |
715 | - if r.Provisioned { |
716 | - checkProvisionedOutput = "/etc/init/jujud-machine-0.conf" |
717 | - } |
718 | - add(checkProvisionedScript, checkProvisionedOutput, r.CheckProvisionedExitCode) |
719 | - if r.InitUbuntuUser { |
720 | - add("", nil, 0) |
721 | - } |
722 | - return restore |
723 | -} |
724 | |
725 | === added file 'environs/manual/fakessh_test.go' |
726 | --- environs/manual/fakessh_test.go 1970-01-01 00:00:00 +0000 |
727 | +++ environs/manual/fakessh_test.go 2014-03-12 12:33:26 +0000 |
728 | @@ -0,0 +1,156 @@ |
729 | +// Copyright 2013 Canonical Ltd. |
730 | +// Licensed under the AGPLv3, see LICENCE file for details. |
731 | + |
732 | +package manual_test |
733 | + |
734 | +import ( |
735 | + "fmt" |
736 | + "io/ioutil" |
737 | + "path/filepath" |
738 | + "strings" |
739 | + |
740 | + gc "launchpad.net/gocheck" |
741 | + |
742 | + "launchpad.net/juju-core/environs/manual" |
743 | + "launchpad.net/juju-core/testing/testbase" |
744 | +) |
745 | + |
746 | +// sshscript should only print the result on the first execution, |
747 | +// to handle the case where it's called multiple times. On |
748 | +// subsequent executions, it should find the next 'ssh' in $PATH |
749 | +// and exec that. |
750 | +var sshscript = `#!/bin/bash --norc |
751 | +if [ ! -e "$0.run" ]; then |
752 | + touch "$0.run" |
753 | + if [ -e "$0.expected-input" ]; then |
754 | + diff "$0.expected-input" - |
755 | + exitcode=$? |
756 | + if [ $exitcode -ne 0 ]; then |
757 | + echo "ERROR: did not match expected input" >&2 |
758 | + exit $exitcode |
759 | + fi |
760 | + else |
761 | + head >/dev/null |
762 | + fi |
763 | + # stdout |
764 | + %s |
765 | + # stderr |
766 | + %s |
767 | + exit %d |
768 | +else |
769 | + export PATH=${PATH#*:} |
770 | + exec ssh $* |
771 | +fi` |
772 | + |
773 | +// installFakeSSH creates a fake "ssh" command in a new $PATH, |
774 | +// updates $PATH, and returns a function to reset $PATH to its |
775 | +// original value when called. |
776 | +// |
777 | +// input may be: |
778 | +// - nil (ignore input) |
779 | +// - a string (match input exactly) |
780 | +// output may be: |
781 | +// - nil (no output) |
782 | +// - a string (stdout) |
783 | +// - a slice of strings, of length two (stdout, stderr) |
784 | +func installFakeSSH(c *gc.C, input, output interface{}, rc int) testbase.Restorer { |
785 | + fakebin := c.MkDir() |
786 | + ssh := filepath.Join(fakebin, "ssh") |
787 | + switch input := input.(type) { |
788 | + case nil: |
789 | + case string: |
790 | + sshexpectedinput := ssh + ".expected-input" |
791 | + err := ioutil.WriteFile(sshexpectedinput, []byte(input), 0644) |
792 | + c.Assert(err, gc.IsNil) |
793 | + default: |
794 | + c.Errorf("input has invalid type: %T", input) |
795 | + } |
796 | + var stdout, stderr string |
797 | + switch output := output.(type) { |
798 | + case nil: |
799 | + case string: |
800 | + stdout = fmt.Sprintf("cat<<EOF\n%s\nEOF", output) |
801 | + case []string: |
802 | + c.Assert(output, gc.HasLen, 2) |
803 | + stdout = fmt.Sprintf("cat<<EOF\n%s\nEOF", output[0]) |
804 | + stderr = fmt.Sprintf("cat>&2<<EOF\n%s\nEOF", output[1]) |
805 | + } |
806 | + script := fmt.Sprintf(sshscript, stdout, stderr, rc) |
807 | + err := ioutil.WriteFile(ssh, []byte(script), 0777) |
808 | + c.Assert(err, gc.IsNil) |
809 | + return testbase.PatchEnvPathPrepend(fakebin) |
810 | +} |
811 | + |
812 | +// installDetectionFakeSSH installs a fake SSH command, which will respond |
813 | +// to the series/hardware detection script with the specified |
814 | +// series/arch. |
815 | +func installDetectionFakeSSH(c *gc.C, series, arch string) testbase.Restorer { |
816 | + if series == "" { |
817 | + series = "precise" |
818 | + } |
819 | + if arch == "" { |
820 | + arch = "amd64" |
821 | + } |
822 | + detectionoutput := strings.Join([]string{ |
823 | + series, |
824 | + arch, |
825 | + "MemTotal: 4096 kB", |
826 | + "processor: 0", |
827 | + }, "\n") |
828 | + return installFakeSSH(c, manual.DetectionScript, detectionoutput, 0) |
829 | +} |
830 | + |
831 | +// fakeSSH wraps the invocation of InstallFakeSSH based on the parameters. |
832 | +type fakeSSH struct { |
833 | + Series string |
834 | + Arch string |
835 | + |
836 | + // Provisioned should be set to true if the fakeSSH script |
837 | + // should respond to checkProvisioned with a non-empty result. |
838 | + Provisioned bool |
839 | + |
840 | + // exit code for the checkProvisioned script. |
841 | + CheckProvisionedExitCode int |
842 | + |
843 | + // exit code for the machine agent provisioning script. |
844 | + ProvisionAgentExitCode int |
845 | + |
846 | + // InitUbuntuUser should be set to true if the fakeSSH script |
847 | + // should respond to an attempt to initialise the ubuntu user. |
848 | + InitUbuntuUser bool |
849 | + |
850 | + // there are conditions other than error in the above |
851 | + // that might cause provisioning to not go ahead, such |
852 | + // as tools being missing. |
853 | + SkipProvisionAgent bool |
854 | + |
855 | + // detection will be skipped if the series/hardware were |
856 | + // detected ahead of time. This should always be set to |
857 | + // true when testing Bootstrap. |
858 | + SkipDetection bool |
859 | +} |
860 | + |
861 | +// install installs fake SSH commands, which will respond to |
862 | +// manual provisioning/bootstrapping commands with the specified |
863 | +// output and exit codes. |
864 | +func (r fakeSSH) install(c *gc.C) testbase.Restorer { |
865 | + var restore testbase.Restorer |
866 | + add := func(input, output interface{}, rc int) { |
867 | + restore = restore.Add(installFakeSSH(c, input, output, rc)) |
868 | + } |
869 | + if !r.SkipProvisionAgent { |
870 | + add(nil, nil, r.ProvisionAgentExitCode) |
871 | + } |
872 | + if !r.SkipDetection { |
873 | + restore.Add(installDetectionFakeSSH(c, r.Series, r.Arch)) |
874 | + } |
875 | + var checkProvisionedOutput interface{} |
876 | + if r.Provisioned { |
877 | + checkProvisionedOutput = "/etc/init/jujud-machine-0.conf" |
878 | + } |
879 | + add(manual.CheckProvisionedScript, checkProvisionedOutput, r.CheckProvisionedExitCode) |
880 | + if r.InitUbuntuUser { |
881 | + add("", nil, 0) |
882 | + } |
883 | + return restore |
884 | +} |
885 | |
886 | === modified file 'environs/manual/init.go' |
887 | --- environs/manual/init.go 2014-03-11 05:55:35 +0000 |
888 | +++ environs/manual/init.go 2014-03-12 12:33:26 +0000 |
889 | @@ -16,6 +16,15 @@ |
890 | "launchpad.net/juju-core/utils/ssh" |
891 | ) |
892 | |
893 | +// detectionScript is the script to run on the remote machine to |
894 | +// detect the OS series and hardware characteristics. |
895 | +const detectionScript = `#!/bin/bash |
896 | +set -e |
897 | +lsb_release -cs |
898 | +uname -m |
899 | +grep MemTotal /proc/meminfo |
900 | +cat /proc/cpuinfo` |
901 | + |
902 | // checkProvisionedScript is the script to run on the remote machine |
903 | // to check if a machine has already been provisioned. |
904 | // |
905 | @@ -132,13 +141,6 @@ |
906 | {regexp.MustCompile("ppc64el|ppc64le"), "ppc64"}, |
907 | } |
908 | |
909 | -const detectionScript = `#!/bin/bash |
910 | -set -e |
911 | -lsb_release -cs |
912 | -uname -m |
913 | -grep MemTotal /proc/meminfo |
914 | -cat /proc/cpuinfo` |
915 | - |
916 | // InitUbuntuUser adds the ubuntu user if it doesn't |
917 | // already exist, updates its ~/.ssh/authorized_keys, |
918 | // and enables passwordless sudo for it. |
919 | |
920 | === modified file 'environs/manual/init_test.go' |
921 | --- environs/manual/init_test.go 2014-02-07 13:58:06 +0000 |
922 | +++ environs/manual/init_test.go 2014-03-12 12:33:26 +0000 |
923 | @@ -1,16 +1,16 @@ |
924 | // Copyright 2013 Canonical Ltd. |
925 | // Licensed under the AGPLv3, see LICENCE file for details. |
926 | |
927 | -package manual |
928 | +package manual_test |
929 | |
930 | import ( |
931 | "strings" |
932 | |
933 | gc "launchpad.net/gocheck" |
934 | |
935 | + "launchpad.net/juju-core/environs/manual" |
936 | jc "launchpad.net/juju-core/testing/checkers" |
937 | "launchpad.net/juju-core/testing/testbase" |
938 | - sshtesting "launchpad.net/juju-core/utils/ssh/testing" |
939 | ) |
940 | |
941 | type initialisationSuite struct { |
942 | @@ -26,8 +26,8 @@ |
943 | "MemTotal: 4096 kB", |
944 | "processor: 0", |
945 | }, "\n") |
946 | - defer sshtesting.InstallFakeSSH(c, detectionScript, response, 0)() |
947 | - _, series, err := DetectSeriesAndHardwareCharacteristics("whatever") |
948 | + defer installFakeSSH(c, manual.DetectionScript, response, 0)() |
949 | + _, series, err := manual.DetectSeriesAndHardwareCharacteristics("whatever") |
950 | c.Assert(err, gc.IsNil) |
951 | c.Assert(series, gc.Equals, "edgy") |
952 | } |
953 | @@ -41,12 +41,12 @@ |
954 | }, "\n") |
955 | // if the script fails for whatever reason, then checkProvisioned |
956 | // will return an error. stderr will be included in the error message. |
957 | - defer sshtesting.InstallFakeSSH(c, detectionScript, []string{scriptResponse, "oh noes"}, 33)() |
958 | - hc, _, err := DetectSeriesAndHardwareCharacteristics("hostname") |
959 | + defer installFakeSSH(c, manual.DetectionScript, []string{scriptResponse, "oh noes"}, 33)() |
960 | + hc, _, err := manual.DetectSeriesAndHardwareCharacteristics("hostname") |
961 | c.Assert(err, gc.ErrorMatches, "rc: 33 \\(oh noes\\)") |
962 | // if the script doesn't fail, stderr is simply ignored. |
963 | - defer sshtesting.InstallFakeSSH(c, detectionScript, []string{scriptResponse, "non-empty-stderr"}, 0)() |
964 | - hc, _, err = DetectSeriesAndHardwareCharacteristics("hostname") |
965 | + defer installFakeSSH(c, manual.DetectionScript, []string{scriptResponse, "non-empty-stderr"}, 0)() |
966 | + hc, _, err = manual.DetectSeriesAndHardwareCharacteristics("hostname") |
967 | c.Assert(err, gc.IsNil) |
968 | c.Assert(hc.String(), gc.Equals, "arch=arm cpu-cores=1 mem=4M") |
969 | } |
970 | @@ -106,52 +106,52 @@ |
971 | for i, test := range tests { |
972 | c.Logf("test %d: %s", i, test.summary) |
973 | scriptResponse := strings.Join(test.scriptResponse, "\n") |
974 | - defer sshtesting.InstallFakeSSH(c, detectionScript, scriptResponse, 0)() |
975 | - hc, _, err := DetectSeriesAndHardwareCharacteristics("hostname") |
976 | + defer installFakeSSH(c, manual.DetectionScript, scriptResponse, 0)() |
977 | + hc, _, err := manual.DetectSeriesAndHardwareCharacteristics("hostname") |
978 | c.Assert(err, gc.IsNil) |
979 | c.Assert(hc.String(), gc.Equals, test.expectedHc) |
980 | } |
981 | } |
982 | |
983 | func (s *initialisationSuite) TestCheckProvisioned(c *gc.C) { |
984 | - defer sshtesting.InstallFakeSSH(c, checkProvisionedScript, "", 0)() |
985 | - provisioned, err := checkProvisioned("example.com") |
986 | + defer installFakeSSH(c, manual.CheckProvisionedScript, "", 0)() |
987 | + provisioned, err := manual.CheckProvisioned("example.com") |
988 | c.Assert(err, gc.IsNil) |
989 | c.Assert(provisioned, jc.IsFalse) |
990 | |
991 | - defer sshtesting.InstallFakeSSH(c, checkProvisionedScript, "non-empty", 0)() |
992 | - provisioned, err = checkProvisioned("example.com") |
993 | + defer installFakeSSH(c, manual.CheckProvisionedScript, "non-empty", 0)() |
994 | + provisioned, err = manual.CheckProvisioned("example.com") |
995 | c.Assert(err, gc.IsNil) |
996 | c.Assert(provisioned, jc.IsTrue) |
997 | |
998 | // stderr should not affect result. |
999 | - defer sshtesting.InstallFakeSSH(c, checkProvisionedScript, []string{"", "non-empty-stderr"}, 0)() |
1000 | - provisioned, err = checkProvisioned("example.com") |
1001 | + defer installFakeSSH(c, manual.CheckProvisionedScript, []string{"", "non-empty-stderr"}, 0)() |
1002 | + provisioned, err = manual.CheckProvisioned("example.com") |
1003 | c.Assert(err, gc.IsNil) |
1004 | c.Assert(provisioned, jc.IsFalse) |
1005 | |
1006 | // if the script fails for whatever reason, then checkProvisioned |
1007 | // will return an error. stderr will be included in the error message. |
1008 | - defer sshtesting.InstallFakeSSH(c, checkProvisionedScript, []string{"non-empty-stdout", "non-empty-stderr"}, 255)() |
1009 | - _, err = checkProvisioned("example.com") |
1010 | + defer installFakeSSH(c, manual.CheckProvisionedScript, []string{"non-empty-stdout", "non-empty-stderr"}, 255)() |
1011 | + _, err = manual.CheckProvisioned("example.com") |
1012 | c.Assert(err, gc.ErrorMatches, "rc: 255 \\(non-empty-stderr\\)") |
1013 | } |
1014 | |
1015 | func (s *initialisationSuite) TestInitUbuntuUserNonExisting(c *gc.C) { |
1016 | - defer sshtesting.InstallFakeSSH(c, "", "", 0)() // successful creation of ubuntu user |
1017 | - defer sshtesting.InstallFakeSSH(c, "", "", 1)() // simulate failure of ubuntu@ login |
1018 | - err := InitUbuntuUser("testhost", "testuser", "", nil, nil) |
1019 | + defer installFakeSSH(c, "", "", 0)() // successful creation of ubuntu user |
1020 | + defer installFakeSSH(c, "", "", 1)() // simulate failure of ubuntu@ login |
1021 | + err := manual.InitUbuntuUser("testhost", "testuser", "", nil, nil) |
1022 | c.Assert(err, gc.IsNil) |
1023 | } |
1024 | |
1025 | func (s *initialisationSuite) TestInitUbuntuUserExisting(c *gc.C) { |
1026 | - defer sshtesting.InstallFakeSSH(c, "", nil, 0)() |
1027 | - InitUbuntuUser("testhost", "testuser", "", nil, nil) |
1028 | + defer installFakeSSH(c, "", nil, 0)() |
1029 | + manual.InitUbuntuUser("testhost", "testuser", "", nil, nil) |
1030 | } |
1031 | |
1032 | func (s *initialisationSuite) TestInitUbuntuUserError(c *gc.C) { |
1033 | - defer sshtesting.InstallFakeSSH(c, "", []string{"", "failed to create ubuntu user"}, 123)() |
1034 | - defer sshtesting.InstallFakeSSH(c, "", "", 1)() // simulate failure of ubuntu@ login |
1035 | - err := InitUbuntuUser("testhost", "testuser", "", nil, nil) |
1036 | + defer installFakeSSH(c, "", []string{"", "failed to create ubuntu user"}, 123)() |
1037 | + defer installFakeSSH(c, "", "", 1)() // simulate failure of ubuntu@ login |
1038 | + err := manual.InitUbuntuUser("testhost", "testuser", "", nil, nil) |
1039 | c.Assert(err, gc.ErrorMatches, "rc: 123 \\(failed to create ubuntu user\\)") |
1040 | } |
1041 | |
1042 | === modified file 'environs/manual/provisioner_test.go' |
1043 | --- environs/manual/provisioner_test.go 2014-02-07 13:58:06 +0000 |
1044 | +++ environs/manual/provisioner_test.go 2014-03-12 12:33:26 +0000 |
1045 | @@ -1,7 +1,7 @@ |
1046 | // Copyright 2013 Canonical Ltd. |
1047 | // Licensed under the AGPLv3, see LICENCE file for details. |
1048 | |
1049 | -package manual |
1050 | +package manual_test |
1051 | |
1052 | import ( |
1053 | "fmt" |
1054 | @@ -9,6 +9,7 @@ |
1055 | |
1056 | gc "launchpad.net/gocheck" |
1057 | |
1058 | + "launchpad.net/juju-core/environs/manual" |
1059 | envtesting "launchpad.net/juju-core/environs/testing" |
1060 | "launchpad.net/juju-core/instance" |
1061 | "launchpad.net/juju-core/juju/testing" |
1062 | @@ -25,10 +26,10 @@ |
1063 | |
1064 | var _ = gc.Suite(&provisionerSuite{}) |
1065 | |
1066 | -func (s *provisionerSuite) getArgs(c *gc.C) ProvisionMachineArgs { |
1067 | +func (s *provisionerSuite) getArgs(c *gc.C) manual.ProvisionMachineArgs { |
1068 | hostname, err := os.Hostname() |
1069 | c.Assert(err, gc.IsNil) |
1070 | - return ProvisionMachineArgs{ |
1071 | + return manual.ProvisionMachineArgs{ |
1072 | Host: hostname, |
1073 | EnvName: "dummyenv", |
1074 | } |
1075 | @@ -50,7 +51,7 @@ |
1076 | SkipProvisionAgent: true, |
1077 | }.install(c).Restore() |
1078 | // Attempt to provision a machine with no tools available, expect it to fail. |
1079 | - machineId, err := ProvisionMachine(args) |
1080 | + machineId, err := manual.ProvisionMachine(args) |
1081 | c.Assert(err, jc.Satisfies, params.IsCodeNotFound) |
1082 | c.Assert(machineId, gc.Equals, "") |
1083 | |
1084 | @@ -68,7 +69,7 @@ |
1085 | InitUbuntuUser: true, |
1086 | ProvisionAgentExitCode: errorCode, |
1087 | }.install(c).Restore() |
1088 | - machineId, err = ProvisionMachine(args) |
1089 | + machineId, err = manual.ProvisionMachine(args) |
1090 | if errorCode != 0 { |
1091 | c.Assert(err, gc.ErrorMatches, fmt.Sprintf("rc: %d", errorCode)) |
1092 | c.Assert(machineId, gc.Equals, "") |
1093 | @@ -94,8 +95,8 @@ |
1094 | SkipDetection: true, |
1095 | SkipProvisionAgent: true, |
1096 | }.install(c).Restore() |
1097 | - _, err = ProvisionMachine(args) |
1098 | - c.Assert(err, gc.Equals, ErrProvisioned) |
1099 | + _, err = manual.ProvisionMachine(args) |
1100 | + c.Assert(err, gc.Equals, manual.ErrProvisioned) |
1101 | defer fakeSSH{ |
1102 | Provisioned: true, |
1103 | CheckProvisionedExitCode: 255, |
1104 | @@ -103,7 +104,7 @@ |
1105 | SkipDetection: true, |
1106 | SkipProvisionAgent: true, |
1107 | }.install(c).Restore() |
1108 | - _, err = ProvisionMachine(args) |
1109 | + _, err = manual.ProvisionMachine(args) |
1110 | c.Assert(err, gc.ErrorMatches, "error checking if provisioned: rc: 255") |
1111 | } |
1112 | |
1113 | @@ -115,7 +116,7 @@ |
1114 | Arch: arch, |
1115 | InitUbuntuUser: true, |
1116 | }.install(c).Restore() |
1117 | - machineId, err := ProvisionMachine(s.getArgs(c)) |
1118 | + machineId, err := manual.ProvisionMachine(s.getArgs(c)) |
1119 | c.Assert(err, gc.IsNil) |
1120 | |
1121 | // Now check what we would've configured it with. |
1122 | |
1123 | === added directory 'environs/manual/testing' |
1124 | === modified file 'environs/open.go' |
1125 | --- environs/open.go 2014-02-18 01:29:47 +0000 |
1126 | +++ environs/open.go 2014-03-12 12:33:26 +0000 |
1127 | @@ -46,16 +46,14 @@ |
1128 | ConfigFromEnvirons |
1129 | ) |
1130 | |
1131 | -// ConfigForName returns the configuration for the environment with the |
1132 | -// given name from the default environments file. If the name is blank, |
1133 | -// the default environment will be used. If the configuration is not |
1134 | -// found, an errors.NotFoundError is returned. |
1135 | -// If the given store contains an entry for the environment |
1136 | -// and it has associated bootstrap config, that configuration |
1137 | -// will be returned. |
1138 | -// ConfigForName also returns where the configuration |
1139 | -// was sourced from (this is also valid even when there |
1140 | -// is an error. |
1141 | +// ConfigForName returns the configuration for the environment with |
1142 | +// the given name from the default environments file. If the name is |
1143 | +// blank, the default environment will be used. If the configuration |
1144 | +// is not found, an errors.NotFoundError is returned. If the given |
1145 | +// store contains an entry for the environment and it has associated |
1146 | +// bootstrap config, that configuration will be returned. |
1147 | +// ConfigForName also returns where the configuration was sourced from |
1148 | +// (this is also valid even when there is an error. |
1149 | func ConfigForName(name string, store configstore.Storage) (*config.Config, ConfigSource, error) { |
1150 | envs, err := ReadEnvirons("") |
1151 | if err != nil { |
1152 | @@ -86,6 +84,16 @@ |
1153 | return cfg, ConfigFromEnvirons, err |
1154 | } |
1155 | |
1156 | +// maybeNotBootstrapped takes an error and source, returned by |
1157 | +// ConfigForName and returns ErrNotBootstrapped if it looks like the |
1158 | +// environment is not bootstrapped, or err as-is otherwise. |
1159 | +func maybeNotBootstrapped(err error, source ConfigSource) error { |
1160 | + if err != nil && source == ConfigFromEnvirons { |
1161 | + return ErrNotBootstrapped |
1162 | + } |
1163 | + return err |
1164 | +} |
1165 | + |
1166 | // NewFromName opens the environment with the given |
1167 | // name from the default environments file. If the |
1168 | // name is blank, the default environment will be used. |
1169 | @@ -99,16 +107,16 @@ |
1170 | // configuration attributes don't exist which |
1171 | // will be filled in by Prepare. |
1172 | cfg, source, err := ConfigForName(name, store) |
1173 | - if err != nil && source == ConfigFromEnvirons { |
1174 | - err = ErrNotBootstrapped |
1175 | + if err := maybeNotBootstrapped(err, source); err != nil { |
1176 | + return nil, err |
1177 | } |
1178 | if err != nil { |
1179 | return nil, err |
1180 | } |
1181 | |
1182 | env, err := New(cfg) |
1183 | - if err != nil && source == ConfigFromEnvirons { |
1184 | - err = ErrNotBootstrapped |
1185 | + if err := maybeNotBootstrapped(err, source); err != nil { |
1186 | + return nil, err |
1187 | } |
1188 | return env, err |
1189 | } |
1190 | |
1191 | === modified file 'environs/sshstorage/storage.go' |
1192 | --- environs/sshstorage/storage.go 2014-01-13 06:25:28 +0000 |
1193 | +++ environs/sshstorage/storage.go 2014-03-12 12:33:26 +0000 |
1194 | @@ -16,11 +16,15 @@ |
1195 | "strconv" |
1196 | "strings" |
1197 | |
1198 | + "github.com/juju/loggo" |
1199 | + |
1200 | coreerrors "launchpad.net/juju-core/errors" |
1201 | "launchpad.net/juju-core/utils" |
1202 | "launchpad.net/juju-core/utils/ssh" |
1203 | ) |
1204 | |
1205 | +var logger = loggo.GetLogger("juju.environs.sshstorage") |
1206 | + |
1207 | // base64LineLength is the default line length for wrapping |
1208 | // output generated by the base64 command line utility. |
1209 | const base64LineLength = 76 |
1210 | @@ -240,6 +244,7 @@ |
1211 | |
1212 | // Get implements storage.StorageReader.Get. |
1213 | func (s *SSHStorage) Get(name string) (io.ReadCloser, error) { |
1214 | + logger.Debugf("getting %q from storage", name) |
1215 | path, err := s.path(name) |
1216 | if err != nil { |
1217 | return nil, err |
1218 | @@ -305,6 +310,7 @@ |
1219 | |
1220 | // Put implements storage.StorageWriter.Put |
1221 | func (s *SSHStorage) Put(name string, r io.Reader, length int64) error { |
1222 | + logger.Debugf("putting %q (len %d) to storage", name, length) |
1223 | path, err := s.path(name) |
1224 | if err != nil { |
1225 | return err |
1226 | |
1227 | === modified file 'environs/testing/storage.go' |
1228 | --- environs/testing/storage.go 2014-03-04 16:55:38 +0000 |
1229 | +++ environs/testing/storage.go 2014-03-12 12:33:26 +0000 |
1230 | @@ -4,16 +4,13 @@ |
1231 | package testing |
1232 | |
1233 | import ( |
1234 | - "fmt" |
1235 | "io" |
1236 | |
1237 | gc "launchpad.net/gocheck" |
1238 | |
1239 | - "launchpad.net/juju-core/environs" |
1240 | "launchpad.net/juju-core/environs/filestorage" |
1241 | "launchpad.net/juju-core/environs/httpstorage" |
1242 | "launchpad.net/juju-core/environs/storage" |
1243 | - "launchpad.net/juju-core/state" |
1244 | ) |
1245 | |
1246 | // CreateLocalTestStorage returns the listener, which needs to be closed, and |
1247 | @@ -29,17 +26,3 @@ |
1248 | closer = listener |
1249 | return |
1250 | } |
1251 | - |
1252 | -// GetEnvironStorage creates an Environ from the config in state and |
1253 | -// returns its storage interface. |
1254 | -func GetEnvironStorage(st *state.State) (storage.Storage, error) { |
1255 | - envConfig, err := st.EnvironConfig() |
1256 | - if err != nil { |
1257 | - return nil, fmt.Errorf("cannot get environment config: %v", err) |
1258 | - } |
1259 | - env, err := environs.New(envConfig) |
1260 | - if err != nil { |
1261 | - return nil, fmt.Errorf("cannot access environment: %v", err) |
1262 | - } |
1263 | - return env.Storage(), nil |
1264 | -} |
1265 | |
1266 | === added file 'environs/utils.go' |
1267 | --- environs/utils.go 1970-01-01 00:00:00 +0000 |
1268 | +++ environs/utils.go 2014-03-12 12:33:26 +0000 |
1269 | @@ -0,0 +1,22 @@ |
1270 | +package environs |
1271 | + |
1272 | +import ( |
1273 | + "fmt" |
1274 | + |
1275 | + "launchpad.net/juju-core/environs/storage" |
1276 | + "launchpad.net/juju-core/state" |
1277 | +) |
1278 | + |
1279 | +// GetStorage creates an Environ from the config in state and returns |
1280 | +// its storage interface. |
1281 | +func GetStorage(st *state.State) (storage.Storage, error) { |
1282 | + envConfig, err := st.EnvironConfig() |
1283 | + if err != nil { |
1284 | + return nil, fmt.Errorf("cannot get environment config: %v", err) |
1285 | + } |
1286 | + env, err := New(envConfig) |
1287 | + if err != nil { |
1288 | + return nil, fmt.Errorf("cannot access environment: %v", err) |
1289 | + } |
1290 | + return env.Storage(), nil |
1291 | +} |
1292 | |
1293 | === modified file 'juju/conn_test.go' |
1294 | --- juju/conn_test.go 2014-03-07 14:15:28 +0000 |
1295 | +++ juju/conn_test.go 2014-03-12 12:33:26 +0000 |
1296 | @@ -124,7 +124,7 @@ |
1297 | c.Assert(conn.Environ.Name(), gc.Equals, envName) |
1298 | } |
1299 | |
1300 | -func (cs *NewConnSuite) TestConnStateSecretsSideEffect(c *gc.C) { |
1301 | +func (*NewConnSuite) TestConnStateSecretsSideEffect(c *gc.C) { |
1302 | attrs := dummy.SampleConfig().Merge(coretesting.Attrs{ |
1303 | "admin-secret": "side-effect secret", |
1304 | "secret": "pork", |
1305 | @@ -175,7 +175,7 @@ |
1306 | c.Assert(err, gc.IsNil) |
1307 | } |
1308 | |
1309 | -func (cs *NewConnSuite) TestConnStateDoesNotUpdateExistingSecrets(c *gc.C) { |
1310 | +func (*NewConnSuite) TestConnStateDoesNotUpdateExistingSecrets(c *gc.C) { |
1311 | attrs := dummy.SampleConfig().Merge(coretesting.Attrs{ |
1312 | "secret": "pork", |
1313 | }) |
1314 | @@ -212,7 +212,7 @@ |
1315 | c.Assert(err, gc.IsNil) |
1316 | } |
1317 | |
1318 | -func (cs *NewConnSuite) TestConnWithPassword(c *gc.C) { |
1319 | +func (*NewConnSuite) TestConnWithPassword(c *gc.C) { |
1320 | attrs := dummy.SampleConfig().Merge(coretesting.Attrs{ |
1321 | "admin-secret": "nutkin", |
1322 | }) |
1323 | |
1324 | === modified file 'provider/azure/config.go' |
1325 | --- provider/azure/config.go 2014-01-29 00:14:51 +0000 |
1326 | +++ provider/azure/config.go 2014-03-12 12:33:26 +0000 |
1327 | @@ -95,32 +95,40 @@ |
1328 | return cfg.Apply(envCfg.attrs) |
1329 | } |
1330 | |
1331 | -const boilerplateYAML = ` |
1332 | +var boilerplateYAML = ` |
1333 | # https://juju.ubuntu.com/docs/config-azure.html |
1334 | azure: |
1335 | type: azure |
1336 | |
1337 | - # location specifies the place where instances will be started, for |
1338 | - # example: West US, North Europe. |
1339 | + # location specifies the place where instances will be started, |
1340 | + # for example: West US, North Europe. |
1341 | + # |
1342 | location: West US |
1343 | - |
1344 | - # The following attributes specify Windows Azure Management information. |
1345 | - # See http://msdn.microsoft.com/en-us/library/windowsazure |
1346 | + |
1347 | + # The following attributes specify Windows Azure Management |
1348 | + # information. See: |
1349 | + # http://msdn.microsoft.com/en-us/library/windowsazure |
1350 | # for details. |
1351 | + # |
1352 | management-subscription-id: <00000000-0000-0000-0000-000000000000> |
1353 | management-certificate-path: /home/me/azure.pem |
1354 | |
1355 | # storage-account-name holds Windows Azure Storage info. |
1356 | + # |
1357 | storage-account-name: abcdefghijkl |
1358 | |
1359 | - # force-image-name overrides the OS image selection to use |
1360 | - # a fixed image for all deployments. Most useful for developers. |
1361 | + # force-image-name overrides the OS image selection to use a fixed |
1362 | + # image for all deployments. Most useful for developers. |
1363 | + # |
1364 | # force-image-name: b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-13_10-amd64-server-DEVELOPMENT-20130713-Juju_ALPHA-en-us-30GB |
1365 | |
1366 | - # image-stream chooses a simplestreams stream to select OS images from, |
1367 | - # for example daily or released images (or any other stream available on simplestreams). |
1368 | + # image-stream chooses a simplestreams stream to select OS images |
1369 | + # from, for example daily or released images (or any other stream |
1370 | + # available on simplestreams). |
1371 | + # |
1372 | # image-stream: "released" |
1373 | -` |
1374 | + |
1375 | +`[1:] |
1376 | |
1377 | func (prov azureEnvironProvider) BoilerplateConfig() string { |
1378 | return boilerplateYAML |
1379 | |
1380 | === modified file 'provider/common/bootstrap.go' |
1381 | --- provider/common/bootstrap.go 2014-03-05 19:41:34 +0000 |
1382 | +++ provider/common/bootstrap.go 2014-03-12 12:33:26 +0000 |
1383 | @@ -405,18 +405,3 @@ |
1384 | } |
1385 | return bootstrap.SetBootstrapTools(env, possibleTools) |
1386 | } |
1387 | - |
1388 | -// EnsureNotBootstrapped returns null if the environment is not bootstrapped, |
1389 | -// and an error if it is or if the function was not able to tell. |
1390 | -func EnsureNotBootstrapped(env environs.Environ) error { |
1391 | - _, err := bootstrap.LoadState(env.Storage()) |
1392 | - // If there is no error loading the bootstrap state, then we are |
1393 | - // bootstrapped. |
1394 | - if err == nil { |
1395 | - return fmt.Errorf("environment is already bootstrapped") |
1396 | - } |
1397 | - if err == environs.ErrNotBootstrapped { |
1398 | - return nil |
1399 | - } |
1400 | - return err |
1401 | -} |
1402 | |
1403 | === modified file 'provider/ec2/ec2.go' |
1404 | --- provider/ec2/ec2.go 2014-03-11 07:21:10 +0000 |
1405 | +++ provider/ec2/ec2.go 2014-03-12 12:33:26 +0000 |
1406 | @@ -179,18 +179,25 @@ |
1407 | # https://juju.ubuntu.com/docs/config-aws.html |
1408 | amazon: |
1409 | type: ec2 |
1410 | - # region specifies the ec2 region. It defaults to us-east-1. |
1411 | + |
1412 | + # region specifies the EC2 region. It defaults to us-east-1. |
1413 | + # |
1414 | # region: us-east-1 |
1415 | + |
1416 | + # access-key holds the EC2 access key. It defaults to the |
1417 | + # environment variable AWS_ACCESS_KEY_ID. |
1418 | # |
1419 | - # access-key holds the ec2 access key. It defaults to the environment |
1420 | - # variable AWS_ACCESS_KEY_ID. |
1421 | # access-key: <secret> |
1422 | - # |
1423 | - # secret-key holds the ec2 secret key. It defaults to the environment |
1424 | - # variable AWS_SECRET_ACCESS_KEY. |
1425 | - # |
1426 | - # image-stream chooses a simplestreams stream to select OS images from, |
1427 | - # for example daily or released images (or any other stream available on simplestreams). |
1428 | + |
1429 | + # secret-key holds the EC2 secret key. It defaults to the |
1430 | + # environment variable AWS_SECRET_ACCESS_KEY. |
1431 | + # |
1432 | + # secret-key: <secret> |
1433 | + |
1434 | + # image-stream chooses a simplestreams stream to select OS images |
1435 | + # from, for example daily or released images (or any other stream |
1436 | + # available on simplestreams). |
1437 | + # |
1438 | # image-stream: "released" |
1439 | |
1440 | `[1:] |
1441 | |
1442 | === modified file 'provider/joyent/config.go' |
1443 | --- provider/joyent/config.go 2014-03-10 00:10:29 +0000 |
1444 | +++ provider/joyent/config.go 2014-03-12 12:33:26 +0000 |
1445 | @@ -14,25 +14,46 @@ |
1446 | |
1447 | // boilerplateConfig will be shown in help output, so please keep it up to |
1448 | // date when you change environment configuration below. |
1449 | -const boilerplateConfig = `joyent: |
1450 | - type: joyent |
1451 | - |
1452 | - # SDC config |
1453 | - # Can be set via env variables, or specified here |
1454 | - # sdc-user: <secret> |
1455 | - # Can be set via env variables, or specified here |
1456 | - # sdc-key-id: <secret> |
1457 | - # region defaults to us-west-1, override if required |
1458 | - # sdc-region: us-west-1 |
1459 | - |
1460 | - # Manta config |
1461 | - # Can be set via env variables, or specified here |
1462 | - # manta-user: <secret> |
1463 | - # Can be set via env variables, or specified here |
1464 | - # manta-key-id: <secret> |
1465 | - # region defaults to us-east, override if required |
1466 | - # manta-region: us-east |
1467 | -` |
1468 | +var boilerplateConfig = ` |
1469 | +joyent: |
1470 | + type: joyent |
1471 | + |
1472 | + ## SDC config |
1473 | + |
1474 | + # sdc-user holds the SDC user. It can also be specified in the |
1475 | + # SDC_ACCOUNT environment variable. |
1476 | + # |
1477 | + # sdc-user: <secret> |
1478 | + |
1479 | + # sdc-key-id holds the fingerprint of one of user's SSH keys. It |
1480 | + # can also be specified in the SDC_KEY_ID environment variable. |
1481 | + # |
1482 | + # sdc-key-id: <secret> |
1483 | + |
1484 | + # sdc-region holds the region to use: us-west-1 (default), |
1485 | + # us-east-1, us-sw-1, eu-ams-1. Override if required. |
1486 | + # |
1487 | + # sdc-region: us-west-1 |
1488 | + |
1489 | + ## Manta config |
1490 | + |
1491 | + # manta-user holds the user's Manta account name. It can also be |
1492 | + # specified in the MANTA_USER environment variable. |
1493 | + # |
1494 | + # manta-user: <secret> |
1495 | + |
1496 | + # manta-key-id holds the fingerprint of one of the user's SSH |
1497 | + # keys. It can also be specified in the MANTA_KEY_ID environment |
1498 | + # variable. |
1499 | + # |
1500 | + # manta-key-id: <secret> |
1501 | + |
1502 | + # manta-region holds the Manta region to use. It defaults to |
1503 | + # us-east, override if required |
1504 | + # |
1505 | + # manta-region: us-east |
1506 | + |
1507 | +`[1:] |
1508 | |
1509 | const ( |
1510 | SdcAccount = "SDC_ACCOUNT" |
1511 | |
1512 | === modified file 'provider/local/environprovider.go' |
1513 | --- provider/local/environprovider.go 2014-03-09 20:48:29 +0000 |
1514 | +++ provider/local/environprovider.go 2014-03-12 12:33:26 +0000 |
1515 | @@ -230,17 +230,23 @@ |
1516 | # https://juju.ubuntu.com/docs/config-local.html |
1517 | local: |
1518 | type: local |
1519 | - # Override the directory that is used for the storage files and database. |
1520 | - # The default location is $JUJU_HOME/<ENV>. |
1521 | - |
1522 | - # $JUJU_HOME defaults to ~/.juju |
1523 | + |
1524 | + # root-dir holds the directory that is used for the storage files and |
1525 | + # database. The default location is $JUJU_HOME/<env-name>. |
1526 | + # $JUJU_HOME defaults to ~/.juju. Override if needed. |
1527 | + # |
1528 | # root-dir: ~/.juju/local |
1529 | - |
1530 | - # Override the storage port if you have multiple local providers, or if the |
1531 | - # default port is used by another program. |
1532 | + |
1533 | + # storage-port holds the port where the local provider starts the |
1534 | + # HTTP file server. Override the value if you have multiple local |
1535 | + # providers, or if the default port is used by another program. |
1536 | + # |
1537 | # storage-port: 8040 |
1538 | - |
1539 | - # Override the network bridge if you have changed the default lxc bridge |
1540 | + |
1541 | + # network-bridge holds the name of the LXC network bridge to use. |
1542 | + # Override if the default LXC network bridge is different. |
1543 | + # |
1544 | + # |
1545 | # network-bridge: lxcbr0 |
1546 | |
1547 | `[1:] |
1548 | |
1549 | === modified file 'provider/maas/environprovider.go' |
1550 | --- provider/maas/environprovider.go 2014-03-05 19:41:34 +0000 |
1551 | +++ provider/maas/environprovider.go 2014-03-12 12:33:26 +0000 |
1552 | @@ -64,12 +64,14 @@ |
1553 | # https://juju.ubuntu.com/docs/config-maas.html |
1554 | maas: |
1555 | type: maas |
1556 | - |
1557 | + |
1558 | # maas-server specifies the location of the MAAS server. It must |
1559 | # specify the base path. |
1560 | + # |
1561 | maas-server: 'http://192.168.1.1/MAAS/' |
1562 | - |
1563 | + |
1564 | # maas-oauth holds the OAuth credentials from MAAS. |
1565 | + # |
1566 | maas-oauth: '<add your OAuth credentials from MAAS here>' |
1567 | |
1568 | `[1:] |
1569 | |
1570 | === modified file 'provider/manual/environ.go' |
1571 | --- provider/manual/environ.go 2014-03-05 19:41:34 +0000 |
1572 | +++ provider/manual/environ.go 2014-03-12 12:33:26 +0000 |
1573 | @@ -188,6 +188,7 @@ |
1574 | } |
1575 | |
1576 | var newSSHStorage = func(sshHost, storageDir, storageTmpdir string) (storage.Storage, error) { |
1577 | + logger.Debugf("using ssh storage at host %q dir %q", sshHost, storageDir) |
1578 | return sshstorage.NewSSHStorage(sshstorage.NewSSHStorageParams{ |
1579 | Host: sshHost, |
1580 | StorageDir: storageDir, |
1581 | |
1582 | === modified file 'provider/openstack/provider.go' |
1583 | --- provider/openstack/provider.go 2014-03-11 07:21:10 +0000 |
1584 | +++ provider/openstack/provider.go 2014-03-12 12:33:26 +0000 |
1585 | @@ -67,59 +67,75 @@ |
1586 | # https://juju.ubuntu.com/docs/config-openstack.html |
1587 | openstack: |
1588 | type: openstack |
1589 | - # use-floating-ip specifies whether a floating IP address is required |
1590 | - # to give the nodes a public IP address. Some installations assign public IP |
1591 | - # addresses by default without requiring a floating IP address. |
1592 | + |
1593 | + # use-floating-ip specifies whether a floating IP address is |
1594 | + # required to give the nodes a public IP address. Some |
1595 | + # installations assign public IP addresses by default without |
1596 | + # requiring a floating IP address. |
1597 | + # |
1598 | # use-floating-ip: false |
1599 | |
1600 | - # use-default-secgroup specifies whether new machine instances should have the "default" |
1601 | - # Openstack security group assigned. |
1602 | + # use-default-secgroup specifies whether new machine instances |
1603 | + # should have the "default" Openstack security group assigned. |
1604 | + # |
1605 | # use-default-secgroup: false |
1606 | |
1607 | - # network specifies the network label or uuid to bring machines up on, in |
1608 | - # the case where multiple networks exist. It may be omitted otherwise. |
1609 | + # network specifies the network label or uuid to bring machines up |
1610 | + # on, in the case where multiple networks exist. It may be omitted |
1611 | + # otherwise. |
1612 | + # |
1613 | # network: <your network label or uuid> |
1614 | |
1615 | - # tools-metadata-url specifies the location of the Juju tools and metadata. It defaults to the |
1616 | - # global public tools metadata location https://streams.canonical.com/tools. |
1617 | - # tools-metadata-url: https://you-tools-metadata-url |
1618 | - |
1619 | - # image-metadata-url specifies the location of Ubuntu cloud image metadata. It defaults to the |
1620 | - # global public image metadata location https://cloud-images.ubuntu.com/releases. |
1621 | - # image-metadata-url: https://you-tools-metadata-url |
1622 | - |
1623 | - # image-stream chooses a simplestreams stream to select OS images from, |
1624 | - # for example daily or released images (or any other stream available on simplestreams). |
1625 | + # tools-metadata-url specifies the location of the Juju tools and |
1626 | + # metadata. It defaults to the global public tools metadata |
1627 | + # location https://streams.canonical.com/tools. |
1628 | + # |
1629 | + # tools-metadata-url: https://your-tools-metadata-url |
1630 | + |
1631 | + # image-metadata-url specifies the location of Ubuntu cloud image |
1632 | + # metadata. It defaults to the global public image metadata |
1633 | + # location https://cloud-images.ubuntu.com/releases. |
1634 | + # |
1635 | + # image-metadata-url: https://your-tools-metadata-url |
1636 | + |
1637 | + # image-stream chooses a simplestreams stream to select OS images |
1638 | + # from, for example daily or released images (or any other stream |
1639 | + # available on simplestreams). |
1640 | + # |
1641 | # image-stream: "released" |
1642 | |
1643 | - # auth-url defaults to the value of the environment variable OS_AUTH_URL, |
1644 | - # but can be specified here. |
1645 | + # auth-url defaults to the value of the environment variable |
1646 | + # OS_AUTH_URL, but can be specified here. |
1647 | + # |
1648 | # auth-url: https://yourkeystoneurl:443/v2.0/ |
1649 | |
1650 | - # tenant-name holds the openstack tenant name. It defaults to |
1651 | - # the environment variable OS_TENANT_NAME. |
1652 | + # tenant-name holds the openstack tenant name. It defaults to the |
1653 | + # environment variable OS_TENANT_NAME. |
1654 | + # |
1655 | # tenant-name: <your tenant name> |
1656 | |
1657 | - # region holds the openstack region. It defaults to |
1658 | - # the environment variable OS_REGION_NAME. |
1659 | + # region holds the openstack region. It defaults to the |
1660 | + # environment variable OS_REGION_NAME. |
1661 | + # |
1662 | # region: <your region> |
1663 | |
1664 | - # The auth-mode, username and password attributes |
1665 | - # are used for userpass authentication (the default). |
1666 | - |
1667 | + # The auth-mode, username and password attributes are used for |
1668 | + # userpass authentication (the default). |
1669 | + # |
1670 | # auth-mode holds the authentication mode. For user-password |
1671 | - # authentication, auth-mode should be "userpass" and username |
1672 | - # and password should be set appropriately; they default to |
1673 | - # the environment variables OS_USERNAME and OS_PASSWORD |
1674 | - # respectively. |
1675 | + # authentication, auth-mode should be "userpass" and username and |
1676 | + # password should be set appropriately; they default to the |
1677 | + # environment variables OS_USERNAME and OS_PASSWORD respectively. |
1678 | + # |
1679 | # auth-mode: userpass |
1680 | # username: <your username> |
1681 | # password: <secret> |
1682 | - |
1683 | - # For key-pair authentication, auth-mode should be "keypair" |
1684 | - # and access-key and secret-key should be set appropriately; they default to |
1685 | - # the environment variables OS_ACCESS_KEY and OS_SECRET_KEY |
1686 | - # respectively. |
1687 | + |
1688 | + # For key-pair authentication, auth-mode should be "keypair" and |
1689 | + # access-key and secret-key should be set appropriately; they |
1690 | + # default to the environment variables OS_ACCESS_KEY and |
1691 | + # OS_SECRET_KEY respectively. |
1692 | + # |
1693 | # auth-mode: keypair |
1694 | # access-key: <secret> |
1695 | # secret-key: <secret> |
1696 | @@ -127,45 +143,59 @@ |
1697 | # https://juju.ubuntu.com/docs/config-hpcloud.html |
1698 | hpcloud: |
1699 | type: openstack |
1700 | - |
1701 | - # use-floating-ip specifies whether a floating IP address is required |
1702 | - # to give the nodes a public IP address. Some installations assign public IP |
1703 | - # addresses by default without requiring a floating IP address. |
1704 | + |
1705 | + # use-floating-ip specifies whether a floating IP address is |
1706 | + # required to give the nodes a public IP address. Some |
1707 | + # installations assign public IP addresses by default without |
1708 | + # requiring a floating IP address. |
1709 | + # |
1710 | # use-floating-ip: false |
1711 | |
1712 | - # use-default-secgroup specifies whether new machine instances should have the "default" |
1713 | - # Openstack security group assigned. |
1714 | + # use-default-secgroup specifies whether new machine instances |
1715 | + # should have the "default" Openstack security group assigned. |
1716 | + # |
1717 | # use-default-secgroup: false |
1718 | |
1719 | - # tenant-name holds the openstack tenant name. In HPCloud, this is |
1720 | - # synonymous with the project-name It defaults to |
1721 | - # the environment variable OS_TENANT_NAME. |
1722 | + # tenant-name holds the openstack tenant name. In HPCloud, this is |
1723 | + # synonymous with the project-name It defaults to the environment |
1724 | + # variable OS_TENANT_NAME. |
1725 | + # |
1726 | # tenant-name: <your tenant name> |
1727 | - |
1728 | - # auth-url holds the keystone url for authentication. |
1729 | - # It defaults to the value of the environment variable OS_AUTH_URL. |
1730 | + |
1731 | + # image-stream chooses a simplestreams stream to select OS images |
1732 | + # from, for example daily or released images (or any other stream |
1733 | + # available on simplestreams). |
1734 | + # |
1735 | + # image-stream: "released" |
1736 | + |
1737 | + # auth-url holds the keystone url for authentication. It defaults |
1738 | + # to the value of the environment variable OS_AUTH_URL. |
1739 | + # |
1740 | # auth-url: https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/ |
1741 | |
1742 | - # region holds the HP Cloud region (e.g. az-1.region-a.geo-1). |
1743 | - # It defaults to the environment variable OS_REGION_NAME. |
1744 | + # region holds the HP Cloud region (e.g. az-1.region-a.geo-1). It |
1745 | + # defaults to the environment variable OS_REGION_NAME. |
1746 | + # |
1747 | # region: <your region> |
1748 | - |
1749 | + |
1750 | # auth-mode holds the authentication mode. For user-password |
1751 | - # authentication, auth-mode should be "userpass" and username |
1752 | - # and password should be set appropriately; they default to |
1753 | - # the environment variables OS_USERNAME and OS_PASSWORD |
1754 | - # respectively. |
1755 | + # authentication, auth-mode should be "userpass" and username and |
1756 | + # password should be set appropriately; they default to the |
1757 | + # environment variables OS_USERNAME and OS_PASSWORD respectively. |
1758 | + # |
1759 | # auth-mode: userpass |
1760 | # username: <your_username> |
1761 | # password: <your_password> |
1762 | - |
1763 | - # For key-pair authentication, auth-mode should be "keypair" |
1764 | - # and access-key and secret-key should be set appropriately; they default to |
1765 | - # the environment variables OS_ACCESS_KEY and OS_SECRET_KEY |
1766 | - # respectively. |
1767 | + |
1768 | + # For key-pair authentication, auth-mode should be "keypair" and |
1769 | + # access-key and secret-key should be set appropriately; they |
1770 | + # default to the environment variables OS_ACCESS_KEY and |
1771 | + # OS_SECRET_KEY respectively. |
1772 | + # |
1773 | # auth-mode: keypair |
1774 | # access-key: <secret> |
1775 | # secret-key: <secret> |
1776 | + |
1777 | `[1:] |
1778 | } |
1779 | |
1780 | |
1781 | === modified file 'state/apiserver/charms.go' |
1782 | --- state/apiserver/charms.go 2014-03-06 18:11:16 +0000 |
1783 | +++ state/apiserver/charms.go 2014-03-12 12:33:26 +0000 |
1784 | @@ -25,7 +25,7 @@ |
1785 | "github.com/errgo/errgo" |
1786 | |
1787 | "launchpad.net/juju-core/charm" |
1788 | - envtesting "launchpad.net/juju-core/environs/testing" |
1789 | + "launchpad.net/juju-core/environs" |
1790 | "launchpad.net/juju-core/names" |
1791 | "launchpad.net/juju-core/state" |
1792 | "launchpad.net/juju-core/state/api/params" |
1793 | @@ -392,7 +392,7 @@ |
1794 | if _, err := repackagedArchive.Seek(0, 0); err != nil { |
1795 | return errgo.Annotate(err, "cannot rewind the charm file reader") |
1796 | } |
1797 | - storage, err := envtesting.GetEnvironStorage(h.state) |
1798 | + storage, err := environs.GetStorage(h.state) |
1799 | if err != nil { |
1800 | return errgo.Annotate(err, "cannot access provider storage") |
1801 | } |
1802 | @@ -455,7 +455,7 @@ |
1803 | // saves the corresponding zip archive to the given charmArchivePath. |
1804 | func (h *charmsHandler) downloadCharm(name, charmArchivePath string) error { |
1805 | // Get the provider storage. |
1806 | - storage, err := envtesting.GetEnvironStorage(h.state) |
1807 | + storage, err := environs.GetStorage(h.state) |
1808 | if err != nil { |
1809 | return errgo.Annotate(err, "cannot access provider storage") |
1810 | } |
1811 | |
1812 | === modified file 'state/apiserver/charms_test.go' |
1813 | --- state/apiserver/charms_test.go 2014-02-27 14:11:56 +0000 |
1814 | +++ state/apiserver/charms_test.go 2014-03-12 12:33:26 +0000 |
1815 | @@ -18,7 +18,7 @@ |
1816 | gc "launchpad.net/gocheck" |
1817 | |
1818 | "launchpad.net/juju-core/charm" |
1819 | - envtesting "launchpad.net/juju-core/environs/testing" |
1820 | + "launchpad.net/juju-core/environs" |
1821 | jujutesting "launchpad.net/juju-core/juju/testing" |
1822 | "launchpad.net/juju-core/state" |
1823 | "launchpad.net/juju-core/state/api/params" |
1824 | @@ -168,7 +168,7 @@ |
1825 | expectedSHA256, _, err := utils.ReadSHA256(tempFile) |
1826 | c.Assert(err, gc.IsNil) |
1827 | name := charm.Quote(expectedURL.String()) |
1828 | - storage, err := envtesting.GetEnvironStorage(s.State) |
1829 | + storage, err := environs.GetStorage(s.State) |
1830 | c.Assert(err, gc.IsNil) |
1831 | expectedUploadURL, err := storage.URL(name) |
1832 | c.Assert(err, gc.IsNil) |
1833 | @@ -219,7 +219,7 @@ |
1834 | // should succeed, because it was repackaged during upload to |
1835 | // strip nested dirs. |
1836 | archiveName := strings.TrimPrefix(sch.BundleURL().RequestURI(), "/dummyenv/private/") |
1837 | - storage, err := envtesting.GetEnvironStorage(s.State) |
1838 | + storage, err := environs.GetStorage(s.State) |
1839 | c.Assert(err, gc.IsNil) |
1840 | reader, err := storage.Get(archiveName) |
1841 | c.Assert(err, gc.IsNil) |
1842 | |
1843 | === modified file 'state/apiserver/client/client_test.go' |
1844 | --- state/apiserver/client/client_test.go 2014-03-11 02:53:40 +0000 |
1845 | +++ state/apiserver/client/client_test.go 2014-03-12 12:33:26 +0000 |
1846 | @@ -17,10 +17,10 @@ |
1847 | coreCloudinit "launchpad.net/juju-core/cloudinit" |
1848 | "launchpad.net/juju-core/cloudinit/sshinit" |
1849 | "launchpad.net/juju-core/constraints" |
1850 | + "launchpad.net/juju-core/environs" |
1851 | "launchpad.net/juju-core/environs/cloudinit" |
1852 | "launchpad.net/juju-core/environs/config" |
1853 | - "launchpad.net/juju-core/environs/storage" |
1854 | - envtesting "launchpad.net/juju-core/environs/testing" |
1855 | + envstorage "launchpad.net/juju-core/environs/storage" |
1856 | ttesting "launchpad.net/juju-core/environs/tools/testing" |
1857 | "launchpad.net/juju-core/errors" |
1858 | "launchpad.net/juju-core/instance" |
1859 | @@ -1872,7 +1872,7 @@ |
1860 | // contains the correct data. |
1861 | sch, err := s.State.Charm(curl) |
1862 | c.Assert(err, gc.IsNil) |
1863 | - storage, err := envtesting.GetEnvironStorage(s.State) |
1864 | + storage, err := environs.GetStorage(s.State) |
1865 | c.Assert(err, gc.IsNil) |
1866 | uploads, err := storage.List(fmt.Sprintf("%s-%d-", curl.Name, curl.Revision)) |
1867 | c.Assert(err, gc.IsNil) |
1868 | @@ -1938,7 +1938,7 @@ |
1869 | } |
1870 | } |
1871 | |
1872 | -func (s *clientSuite) assertUploaded(c *gc.C, storage storage.Storage, bundleURL *url.URL, expectedSHA256 string) { |
1873 | +func (s *clientSuite) assertUploaded(c *gc.C, storage envstorage.Storage, bundleURL *url.URL, expectedSHA256 string) { |
1874 | archiveName := getArchiveName(bundleURL) |
1875 | reader, err := storage.Get(archiveName) |
1876 | c.Assert(err, gc.IsNil) |
1877 | |
1878 | === removed file 'utils/ssh/testing/fakessh.go' |
1879 | --- utils/ssh/testing/fakessh.go 2014-02-18 17:08:55 +0000 |
1880 | +++ utils/ssh/testing/fakessh.go 1970-01-01 00:00:00 +0000 |
1881 | @@ -1,80 +0,0 @@ |
1882 | -// Copyright 2013 Canonical Ltd. |
1883 | -// Licensed under the AGPLv3, see LICENCE file for details. |
1884 | - |
1885 | -package testing |
1886 | - |
1887 | -import ( |
1888 | - "fmt" |
1889 | - "io/ioutil" |
1890 | - "path/filepath" |
1891 | - |
1892 | - gc "launchpad.net/gocheck" |
1893 | - |
1894 | - "launchpad.net/juju-core/testing/testbase" |
1895 | -) |
1896 | - |
1897 | -// sshscript should only print the result on the first execution, |
1898 | -// to handle the case where it's called multiple times. On |
1899 | -// subsequent executions, it should find the next 'ssh' in $PATH |
1900 | -// and exec that. |
1901 | -var sshscript = `#!/bin/bash --norc |
1902 | -if [ ! -e "$0.run" ]; then |
1903 | - touch "$0.run" |
1904 | - if [ -e "$0.expected-input" ]; then |
1905 | - diff "$0.expected-input" - |
1906 | - exitcode=$? |
1907 | - if [ $exitcode -ne 0 ]; then |
1908 | - echo "ERROR: did not match expected input" >&2 |
1909 | - exit $exitcode |
1910 | - fi |
1911 | - else |
1912 | - head >/dev/null |
1913 | - fi |
1914 | - # stdout |
1915 | - %s |
1916 | - # stderr |
1917 | - %s |
1918 | - exit %d |
1919 | -else |
1920 | - export PATH=${PATH#*:} |
1921 | - exec ssh $* |
1922 | -fi` |
1923 | - |
1924 | -// InstallFakeSSH creates a fake "ssh" command in a new $PATH, |
1925 | -// updates $PATH, and returns a function to reset $PATH to its |
1926 | -// original value when called. |
1927 | -// |
1928 | -// input may be: |
1929 | -// - nil (ignore input) |
1930 | -// - a string (match input exactly) |
1931 | -// output may be: |
1932 | -// - nil (no output) |
1933 | -// - a string (stdout) |
1934 | -// - a slice of strings, of length two (stdout, stderr) |
1935 | -func InstallFakeSSH(c *gc.C, input, output interface{}, rc int) testbase.Restorer { |
1936 | - fakebin := c.MkDir() |
1937 | - ssh := filepath.Join(fakebin, "ssh") |
1938 | - switch input := input.(type) { |
1939 | - case nil: |
1940 | - case string: |
1941 | - sshexpectedinput := ssh + ".expected-input" |
1942 | - err := ioutil.WriteFile(sshexpectedinput, []byte(input), 0644) |
1943 | - c.Assert(err, gc.IsNil) |
1944 | - default: |
1945 | - c.Errorf("input has invalid type: %T", input) |
1946 | - } |
1947 | - var stdout, stderr string |
1948 | - switch output := output.(type) { |
1949 | - case nil: |
1950 | - case string: |
1951 | - stdout = fmt.Sprintf("cat<<EOF\n%s\nEOF", output) |
1952 | - case []string: |
1953 | - c.Assert(output, gc.HasLen, 2) |
1954 | - stdout = fmt.Sprintf("cat<<EOF\n%s\nEOF", output[0]) |
1955 | - stderr = fmt.Sprintf("cat>&2<<EOF\n%s\nEOF", output[1]) |
1956 | - } |
1957 | - script := fmt.Sprintf(sshscript, stdout, stderr, rc) |
1958 | - err := ioutil.WriteFile(ssh, []byte(script), 0777) |
1959 | - c.Assert(err, gc.IsNil) |
1960 | - return testbase.PatchEnvPathPrepend(fakebin) |
1961 | -} |
Reviewers: mp+210108_ code.launchpad. net,
Message:
Please take a look.
Description:
various: production code and logging improvements
Fixed 3 slightly annoying issues:
1. Refactored production code not to depend on
gocheck (manual provider and apiserver/charms).
2. Fixed and improved tools download output via
curl and better handling of errors.
3. Added debug logging to environs sshstorage and
httpstorage, and the manual provider.
Changes tested live with a manual and local environs
with added manually provisioned machines.
https:/ /code.launchpad .net/~dimitern/ juju-core/ 330-general- improvements/ +merge/ 210108
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/72860045/
Affected files (+207, -177 lines): bootstrap/ state.go cloudinit/ cloudinit. go cloudinit/ cloudinit_ test.go httpstorage/ storage. go manual/ bootstrap_ test.go manual/ fakessh. go manual/ init.go manual/ init_test. go manual/ provisioner_ test.go sshstorage/ storage. go testing/ storage. go manual/ environ. go /charms. go /charms_ test.go /client/ client_ test.go testing/ fakessh. go storage. go
A [revision details]
M environs/
M environs/
M environs/
M environs/
M environs/
D environs/
M environs/
M environs/
M environs/
M environs/
M environs/
M provider/
M state/apiserver
M state/apiserver
M state/apiserver
M utils/http.go
M utils/ssh/ssh.go
M utils/ssh/
A utils/storage/