Merge lp:~axwalk/juju-core/null-provider-customsources into lp:~go-bot/juju-core/trunk
- null-provider-customsources
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Andrew Wilkins |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1920 |
Proposed branch: | lp:~axwalk/juju-core/null-provider-customsources |
Merge into: | lp:~go-bot/juju-core/trunk |
Diff against target: |
300 lines (+98/-37) 8 files modified
cmd/juju/bootstrap.go (+2/-14) environs/httpstorage/storage.go (+1/-0) environs/interface.go (+10/-7) environs/manual/bootstrap.go (+1/-6) environs/manual/bootstrap_test.go (+4/-4) environs/sshstorage/storage.go (+1/-1) provider/null/environ.go (+36/-5) provider/null/environ_test.go (+43/-0) |
To merge this branch: | bzr merge lp:~axwalk/juju-core/null-provider-customsources |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+187978@code.launchpad.net |
Commit message
provider/null: define simplestreams tools source
This is somewhat involved, as there's some fixes
required (and one drive-by in sshstorage). The
change to use GetToolsSources is simple enough,
and matches what the local provider does.
The Environ override struct in cmd/juju/
had to so that the optional Environ interfaces were
still implemented. Overriding like that loses the
additional interfaces.
To do the above, environs.
changed to have a method that tells the environ to
use bootstrap storage, rather than returning a
bootstrap storage. The null provider has changed to
match, of course, as well as cmd/juju.
Description of the change
provider/null: define simplestreams tools source
This is somewhat involved, as there's some fixes
required (and one drive-by in sshstorage). The
change to use GetToolsSources is simple enough,
and matches what the local provider does.
The Environ override struct in cmd/juju/
had to so that the optional Environ interfaces were
still implemented. Overriding like that loses the
additional interfaces.
To do the above, environs.
changed to have a method that tells the environ to
use bootstrap storage, rather than returning a
bootstrap storage. The null provider has changed to
match, of course, as well as cmd/juju.
Andrew Wilkins (axwalk) wrote : | # |
William Reade (fwereade) wrote : | # |
Good direction, but a few notes:
https:/
File provider/
https:/
provider/
It's quite nice to do "var _" type asserts by the definition of the
type, given that we seem to be growing optional interfaces at a
reasonable rate. Compiled documentation, if you like, that stops you
having to read all the methods.
https:/
File provider/
https:/
provider/
EnableBootstrap
We should be locking here, shouldn't we? Even if it makes no practical
difference today, environs should be goroutine-safe.
https:/
provider/
storage.
storage.
This is starting to look awfully familiar. No action obviously right
today, but it feels like a bit of a smell.
https:/
File provider/
https:/
provider/
I don't see any tests for EnableBootstrap
Roger Peppe (rogpeppe) wrote : | # |
I never did like the optional Environ interfaces, and now I have another
reason - they break encapsulation.
My preferred solution here would be to remove all those interfaces so we
have One True Environ Interface, and leave the code as it was before.
Perhaps there's another way of solving this issue without adding the
fairly icky EnableBootstrap
bootstrap storage automatically if it detects that it has not been
bootstrapped? Then we could lose all the externally visible
BootstrapStorage stuff, perhaps.
Looks reasonable in general; some comments and suggestions below (the
sshstorage ones should be addressed in a separate CL).
https:/
File environs/
https:/
environs/
args.Environ.
move this down to just before it's used, perhaps?
https:/
File environs/
https:/
environs/
err != nil {
I'm not very happy about this. Why are we reading in
the entire input when we can stream it?
https:/
environs/
Given that we're using these paths unquoted in many places,
I'd like to see a sanity check that they don't contain
any dubious characters.
https:/
environs/
TMPFILE=`mktemp` && ((%s && mv $TMPFILE %s) || rm -f $TMPFILE)",
What's TMPDIR used for?
https:/
File provider/
https:/
provider/
EnableBootstrap
On 2013/09/27 09:47:33, fwereade wrote:
> We should be locking here, shouldn't we? Even if it makes no practical
> difference today, environs should be goroutine-safe.
+1
But also, why even have the option to disable bootstrap storage?
Will we ever need to do that? This method is used in one quite
specialised way - I don't see that we need to clutter its interface
too much. I'd lose the enable arg and the wasEnabled return value.
https:/
provider/
storage already disabled")
Can't we just make this method idempotent?
Andrew Wilkins (axwalk) wrote : | # |
Thanks for the reviews.
rog: agreed, it would be *much* nicer if this could be determined
automatically. I don't have a solution to that, though.
I'll send another CL to fix some sshstorage things.
https:/
File environs/
https:/
environs/
args.Environ.
On 2013/09/27 10:35:25, rog wrote:
> move this down to just before it's used, perhaps?
Done.
https:/
File environs/
https:/
environs/
err != nil {
On 2013/09/27 10:35:25, rog wrote:
> I'm not very happy about this. Why are we reading in
> the entire input when we can stream it?
Because we can't? There are multiple input streams to a long-lived bash
process, where the data input is interleaved with commands. If there's a
better way to do it, I'm happy to make changes.
https:/
environs/
On 2013/09/27 10:35:25, rog wrote:
> Given that we're using these paths unquoted in many places,
> I'd like to see a sanity check that they don't contain
> any dubious characters.
Where are we using them unquoted? I found one occurrence of s.remotepath
after adding a test (good call), but that doesn't equate to "in many
places". AFAICS, all other cases are ShQuoted.
https:/
environs/
TMPFILE=`mktemp` && ((%s && mv $TMPFILE %s) || rm -f $TMPFILE)",
On 2013/09/27 10:35:25, rog wrote:
> What's TMPDIR used for?
Just to influence mktemp. It was previously set elsewhere, and I just
failed to notice the obvious simplification. I'll update this to call
`mktemp --tmpdir=...`
https:/
File provider/
https:/
provider/
On 2013/09/27 09:47:33, fwereade wrote:
> It's quite nice to do "var _" type asserts by the definition of the
type, given
> that we seem to be growing optional interfaces at a reasonable rate.
Compiled
> documentation, if you like, that stops you having to read all the
methods.
Yeah, I was aware of the convention. As an experiment, I put the
assertion in a test, as it feels wrong to impose a package dependency
just for the assertion. Binary size won't change, but compilation speed
will take a hit.
But, point taken about documentation. I've added in here, and dropped
the assertion test. A short lived experiment ;)
https:/
File provider/
https:/
Andrew Wilkins (axwalk) wrote : | # |
Please take a look.
Roger Peppe (rogpeppe) wrote : | # |
> rog: agreed, it would be *much* nicer if this could be determined
automatically.
> I don't have a solution to that, though.
One possibility might be to make the null provider storage fall back to
bootstrap storage if the regular storage is not available. We could make
the null provider Prepare ssh to the bootstrap host and start a stub
server (in some portable language, so we don't need to push tools
across) that simply returns an error, say "awaiting bootstrap" to any
request; then at bootstrap time we'd replace that by the real storage
server.
This would all be more simple, of course, if we stipulated that the null
provider always bootstrapped using the current machine for the bootstrap
machine. I imagine that's off the cards though.
https:/
File environs/
https:/
environs/
err != nil {
On 2013/09/29 16:05:25, axw1 wrote:
> On 2013/09/27 10:35:25, rog wrote:
> > I'm not very happy about this. Why are we reading in
> > the entire input when we can stream it?
> Because we can't? There are multiple input streams to a long-lived
bash process,
> where the data input is interleaved with commands. If there's a better
way to do
> it, I'm happy to make changes.
I'm probably missing something, but it seems to me that
the buffer is passed to s.run, then encoded to base64
(line 145), the result of which is used for its length (line 148),
and then written with Write (line 157).
It seems to me that you could pass in the reader and length directly,
create a base64.Encoder use base64.EncodedLen and io.Copy to
the encoder to stream the input.
The down side is if there happen to be less bytes than
advertised in the stream, your remote script will get out of sync.
You could use a more robust input reader than
"head -q -c 999". How about using a here document instead?
"base64 -d << '@EOF' | (%s)"
Then you could ignore the expected length and stream
the input, relying on the shell to find the end of it.
https:/
environs/
On 2013/09/29 16:05:25, axw1 wrote:
> On 2013/09/27 10:35:25, rog wrote:
> > Given that we're using these paths unquoted in many places,
> > I'd like to see a sanity check that they don't contain
> > any dubious characters.
> Where are we using them unquoted? I found one occurrence of
s.remotepath after
> adding a test (good call), but that doesn't equate to "in many
places". AFAICS,
> all other cases are ShQuoted.
I'm not sure what I was thinking when I wrote that comment :)
https:/
environs/
TMPFILE=`mktemp` && ((%s && mv $TMPFILE %s) || rm -f $TMPFILE)",
On 2013/09/29 16:05:25, axw1 wrote:
> On 2013/09/27 10:35:25, rog wrote:
> > What's TMPDIR used for?
> Just to influence mktemp. It was previously set elsewhere, and I just...
Andrew Wilkins (axwalk) wrote : | # |
On 2013/09/30 13:31:08, rog wrote:
> > rog: agreed, it would be *much* nicer if this could be determined
> automatically.
> > I don't have a solution to that, though.
> One possibility might be to make the null provider storage fall back
to
> bootstrap storage if the regular storage is not available. We could
make the
> null provider Prepare ssh to the bootstrap host and start a stub
server (in some
> portable language, so we don't need to push tools across) that simply
returns an
> error, say "awaiting bootstrap" to any request; then at bootstrap time
we'd
> replace that by the real storage server.
I'll have to have a think about that some. I don't really like the idea
of requiring additional VMs/interpreter
want to expand to other target OSs. Anyway, can we deal with this
outside of this CL? I can open a tech-debt bug to investigate it after
1.16.0 is out.
> This would all be more simple, of course, if we stipulated that the
null
> provider always bootstrapped using the current machine for the
bootstrap
> machine. I imagine that's off the cards though.
I think so. Having to connect to the bootstrap machine is (if only a
little) more onerous than necessary.
https:/
> File environs/
https:/
> environs/
err != nil
> {
> On 2013/09/29 16:05:25, axw1 wrote:
> > On 2013/09/27 10:35:25, rog wrote:
> > > I'm not very happy about this. Why are we reading in
> > > the entire input when we can stream it?
> >
> > Because we can't? There are multiple input streams to a long-lived
bash
> process,
> > where the data input is interleaved with commands. If there's a
better way to
> do
> > it, I'm happy to make changes.
> I'm probably missing something, but it seems to me that
> the buffer is passed to s.run, then encoded to base64
> (line 145), the result of which is used for its length (line 148),
> and then written with Write (line 157).
Now we're even; I don't know what *I* was thinking when I wrote what I
did ;)
Yes, I think you're right and we could just Write with a chained reader.
I will handle this in an update to
https:/
> It seems to me that you could pass in the reader and length directly,
> create a base64.Encoder use base64.EncodedLen and io.Copy to
> the encoder to stream the input.
> The down side is if there happen to be less bytes than
> advertised in the stream, your remote script will get out of sync.
> You could use a more robust input reader than
> "head -q -c 999". How about using a here document instead?
> "base64 -d << '@EOF' | (%s)"
> Then you could ignore the expected length and stream
> the input, relying on the shell to find the end of it.
This is pretty similar to how I did it originally, though the input was
in a here-doc on the command line ;) I'm not familiar with that @EOF
syntax - will have to read up.
https:/
> environs/sshst...
Mark Ramm (mark-ramm) wrote : | # |
> I'll have to have a think about that some. I don't really like the idea
> of requiring additional VMs/interpreter
> want to expand to other target OSs. Anyway, can we deal with this
> outside of this CL? I can open a tech-debt bug to investigate it after
> 1.16.0 is out.
I don't think supporting bootstrap nodes running anything other than Ubuntu is an important feature at this time. Of course someday that may not be true -- but unlike unit machines, I don't see any compelling market forces for being OS agnostic on the bootstrap node.
That said, I'm generally a proponent of getting this landed, and creating a follow up task to handle any kind of "one true environment interface" style cleanup later. Just my opinion, and I will bow to the feelings of the group.
Side note -- have we considered using MongoDB and GridFS to provide a standard fallback storage provider everywhere that there's not "object storage" in the cloud already?
Andrew Wilkins (axwalk) wrote : | # |
> I don't think supporting bootstrap nodes running anything other than Ubuntu is
> an important feature at this time. Of course someday that may not be true --
> but unlike unit machines, I don't see any compelling market forces for being
> OS agnostic on the bootstrap node.
Fair enough, I'll bear that in mind.
> That said, I'm generally a proponent of getting this landed, and creating a
> follow up task to handle any kind of "one true environment interface" style
> cleanup later. Just my opinion, and I will bow to the feelings of the group.
>
> Side note -- have we considered using MongoDB and GridFS to provide a standard
> fallback storage provider everywhere that there's not "object storage" in the
> cloud already?
I haven't, though it's known that the current storage solution is a bit weak, and won't stand up in an HA environment. This is just a first cut - we can do better. GridFS sounds like a pretty reasonable option.
Tim Penhey (thumper) wrote : | # |
LGTM with one comment on base test suite.
https:/
File provider/
https:/
provider/
I'd recommend using the LoggingSuite just because it catches the logging
that may happen anywhere, and puts it in the test log, so it is visible
in the test failures.
Andrew Wilkins (axwalk) wrote : | # |
Thanks for the review.
https:/
File provider/
https:/
provider/
On 2013/10/02 04:26:49, thumper wrote:
> I'd recommend using the LoggingSuite just because it catches the
logging that
> may happen anywhere, and puts it in the test log, so it is visible in
the test
> failures.
Done.
Preview Diff
1 | === modified file 'cmd/juju/bootstrap.go' |
2 | --- cmd/juju/bootstrap.go 2013-09-30 16:23:40 +0000 |
3 | +++ cmd/juju/bootstrap.go 2013-10-02 05:19:29 +0000 |
4 | @@ -18,7 +18,6 @@ |
5 | "launchpad.net/juju-core/environs/bootstrap" |
6 | "launchpad.net/juju-core/environs/config" |
7 | "launchpad.net/juju-core/environs/configstore" |
8 | - "launchpad.net/juju-core/environs/storage" |
9 | "launchpad.net/juju-core/environs/sync" |
10 | envtools "launchpad.net/juju-core/environs/tools" |
11 | "launchpad.net/juju-core/errors" |
12 | @@ -75,11 +74,9 @@ |
13 | // If the environment has a special bootstrap Storage, use it wherever |
14 | // we'd otherwise use environ.Storage. |
15 | if bs, ok := environ.(environs.BootstrapStorager); ok { |
16 | - bootstrapStorage, err := bs.BootstrapStorage() |
17 | - if err != nil { |
18 | - return fmt.Errorf("failed to acquire bootstrap storage: %v", err) |
19 | + if err := bs.EnableBootstrapStorage(); err != nil { |
20 | + return fmt.Errorf("failed to enable bootstrap storage: %v", err) |
21 | } |
22 | - environ = &bootstrapStorageEnviron{environ, bootstrapStorage} |
23 | } |
24 | // TODO (wallyworld): 2013-09-20 bug 1227931 |
25 | // We can set a custom tools data source instead of doing an |
26 | @@ -230,12 +227,3 @@ |
27 | } |
28 | return unique.Values() |
29 | } |
30 | - |
31 | -type bootstrapStorageEnviron struct { |
32 | - environs.Environ |
33 | - bootstrapStorage storage.Storage |
34 | -} |
35 | - |
36 | -func (b *bootstrapStorageEnviron) Storage() storage.Storage { |
37 | - return b.bootstrapStorage |
38 | -} |
39 | |
40 | === modified file 'environs/httpstorage/storage.go' |
41 | --- environs/httpstorage/storage.go 2013-09-23 10:05:53 +0000 |
42 | +++ environs/httpstorage/storage.go 2013-10-02 05:19:29 +0000 |
43 | @@ -141,6 +141,7 @@ |
44 | if err != nil { |
45 | return err |
46 | } |
47 | + |
48 | // Here we wrap up the reader. For some freaky unexplainable reason, the |
49 | // http library will call Close on the reader if it has a Close method |
50 | // available. Since we sometimes reuse the reader, especially when |
51 | |
52 | === modified file 'environs/interface.go' |
53 | --- environs/interface.go 2013-09-27 08:14:36 +0000 |
54 | +++ environs/interface.go 2013-10-02 05:19:29 +0000 |
55 | @@ -64,15 +64,18 @@ |
56 | PublicStorage() storage.StorageReader |
57 | } |
58 | |
59 | -// BootstrapStorager is an interface that returns a environs.Storage that may |
60 | -// be used before the bootstrap machine agent has been provisioned. |
61 | +// BootstrapStorager is an interface through which an Environ may be |
62 | +// instructed to use a special "bootstrap storage". Bootstrap storage |
63 | +// is one that may be used before the bootstrap machine agent has been |
64 | +// provisioned. |
65 | // |
66 | -// This is useful for environments where the storage is managed by the machine |
67 | -// agent once bootstrapped. |
68 | +// This is useful for environments where the storage is managed by the |
69 | +// machine agent once bootstrapped. |
70 | type BootstrapStorager interface { |
71 | - // BootstrapStorager returns an environs.Storage that may be used while |
72 | - // bootstrapping a machine. |
73 | - BootstrapStorage() (storage.Storage, error) |
74 | + // EnableBootstrapStorage enables bootstrap storage, returning an |
75 | + // error if enablement failed. If nil is returned, then calling |
76 | + // this again will have no effect and will return nil. |
77 | + EnableBootstrapStorage() error |
78 | } |
79 | |
80 | // ConfigGetter implements access to an environments configuration. |
81 | |
82 | === modified file 'environs/manual/bootstrap.go' |
83 | --- environs/manual/bootstrap.go 2013-09-30 19:40:06 +0000 |
84 | +++ environs/manual/bootstrap.go 2013-10-02 05:19:29 +0000 |
85 | @@ -24,7 +24,6 @@ |
86 | // manages its own local storage. |
87 | type LocalStorageEnviron interface { |
88 | environs.Environ |
89 | - environs.BootstrapStorager |
90 | localstorage.LocalStorageConfig |
91 | } |
92 | |
93 | @@ -65,11 +64,6 @@ |
94 | return ErrProvisioned |
95 | } |
96 | |
97 | - bootstrapStorage, err := args.Environ.BootstrapStorage() |
98 | - if err != nil { |
99 | - return err |
100 | - } |
101 | - |
102 | hc, series, err := detectSeriesAndHardwareCharacteristics(args.Host) |
103 | if err != nil { |
104 | return fmt.Errorf("error detecting hardware characteristics: %v", err) |
105 | @@ -87,6 +81,7 @@ |
106 | |
107 | // Store the state file. If provisioning fails, we'll remove the file. |
108 | logger.Infof("Saving bootstrap state file to bootstrap storage") |
109 | + bootstrapStorage := args.Environ.Storage() |
110 | err = common.SaveState( |
111 | bootstrapStorage, |
112 | &common.BootstrapState{ |
113 | |
114 | === modified file 'environs/manual/bootstrap_test.go' |
115 | --- environs/manual/bootstrap_test.go 2013-09-30 19:40:06 +0000 |
116 | +++ environs/manual/bootstrap_test.go 2013-10-02 05:19:29 +0000 |
117 | @@ -33,8 +33,8 @@ |
118 | sharedStorageDir string |
119 | } |
120 | |
121 | -func (e *localStorageEnviron) BootstrapStorage() (storage.Storage, error) { |
122 | - return e.storage, nil |
123 | +func (e *localStorageEnviron) Storage() storage.Storage { |
124 | + return e.storage |
125 | } |
126 | |
127 | func (e *localStorageEnviron) StorageAddr() string { |
128 | @@ -86,7 +86,7 @@ |
129 | err := Bootstrap(args) |
130 | c.Assert(err, gc.IsNil) |
131 | |
132 | - bootstrapState, err := common.LoadState(s.env.storage) |
133 | + bootstrapState, err := common.LoadState(s.env.Storage()) |
134 | c.Assert(err, gc.IsNil) |
135 | c.Assert( |
136 | bootstrapState.StateInstances, |
137 | @@ -117,7 +117,7 @@ |
138 | |
139 | // Since the script failed, the state file should have been |
140 | // removed from storage. |
141 | - _, err = common.LoadState(s.env.storage) |
142 | + _, err = common.LoadState(s.env.Storage()) |
143 | c.Check(err, gc.Equals, environs.ErrNotBootstrapped) |
144 | } |
145 | |
146 | |
147 | === modified file 'environs/sshstorage/storage.go' |
148 | --- environs/sshstorage/storage.go 2013-09-24 01:55:30 +0000 |
149 | +++ environs/sshstorage/storage.go 2013-10-02 05:19:29 +0000 |
150 | @@ -260,7 +260,7 @@ |
151 | return err |
152 | } |
153 | buf := make([]byte, length) |
154 | - if _, err := r.Read(buf); err != nil { |
155 | + if _, err := io.ReadFull(r, buf); err != nil { |
156 | return err |
157 | } |
158 | path = utils.ShQuote(path) |
159 | |
160 | === modified file 'provider/null/environ.go' |
161 | --- provider/null/environ.go 2013-09-30 19:40:06 +0000 |
162 | +++ provider/null/environ.go 2013-10-02 05:19:29 +0000 |
163 | @@ -14,8 +14,10 @@ |
164 | "launchpad.net/juju-core/environs/config" |
165 | "launchpad.net/juju-core/environs/httpstorage" |
166 | "launchpad.net/juju-core/environs/manual" |
167 | + "launchpad.net/juju-core/environs/simplestreams" |
168 | "launchpad.net/juju-core/environs/sshstorage" |
169 | "launchpad.net/juju-core/environs/storage" |
170 | + envtools "launchpad.net/juju-core/environs/tools" |
171 | "launchpad.net/juju-core/instance" |
172 | "launchpad.net/juju-core/provider/common" |
173 | "launchpad.net/juju-core/state" |
174 | @@ -38,10 +40,15 @@ |
175 | ) |
176 | |
177 | type nullEnviron struct { |
178 | - cfg *environConfig |
179 | - cfgmutex sync.Mutex |
180 | + cfg *environConfig |
181 | + cfgmutex sync.Mutex |
182 | + bootstrapStorage *sshstorage.SSHStorage |
183 | + bootstrapStorageMutex sync.Mutex |
184 | } |
185 | |
186 | +var _ environs.BootstrapStorager = (*nullEnviron)(nil) |
187 | +var _ envtools.SupportsCustomSources = (*nullEnviron)(nil) |
188 | + |
189 | var errNoStartInstance = errors.New("null provider cannot start instances") |
190 | var errNoStopInstance = errors.New("null provider cannot stop instances") |
191 | |
192 | @@ -120,15 +127,39 @@ |
193 | return instances, err |
194 | } |
195 | |
196 | -// Implements environs/bootstrap.BootstrapStorage. |
197 | -func (e *nullEnviron) BootstrapStorage() (storage.Storage, error) { |
198 | +// Implements environs.BootstrapStorager. |
199 | +func (e *nullEnviron) EnableBootstrapStorage() error { |
200 | + e.bootstrapStorageMutex.Lock() |
201 | + defer e.bootstrapStorageMutex.Unlock() |
202 | + if e.bootstrapStorage != nil { |
203 | + return nil |
204 | + } |
205 | cfg := e.envConfig() |
206 | storageDir := e.StorageDir() |
207 | storageTmpdir := path.Join(dataDir, storageTmpSubdir) |
208 | - return sshstorage.NewSSHStorage(cfg.sshHost(), storageDir, storageTmpdir) |
209 | + bootstrapStorage, err := sshstorage.NewSSHStorage(cfg.sshHost(), storageDir, storageTmpdir) |
210 | + if err != nil { |
211 | + return err |
212 | + } |
213 | + e.bootstrapStorage = bootstrapStorage |
214 | + return nil |
215 | +} |
216 | + |
217 | +// GetToolsSources returns a list of sources which are |
218 | +// used to search for simplestreams tools metadata. |
219 | +func (e *nullEnviron) GetToolsSources() ([]simplestreams.DataSource, error) { |
220 | + // Add the simplestreams source off private storage. |
221 | + return []simplestreams.DataSource{ |
222 | + storage.NewStorageSimpleStreamsDataSource(e.Storage(), storage.BaseToolsPath), |
223 | + }, nil |
224 | } |
225 | |
226 | func (e *nullEnviron) Storage() storage.Storage { |
227 | + e.bootstrapStorageMutex.Lock() |
228 | + defer e.bootstrapStorageMutex.Unlock() |
229 | + if e.bootstrapStorage != nil { |
230 | + return e.bootstrapStorage |
231 | + } |
232 | return httpstorage.Client(e.envConfig().storageAddr()) |
233 | } |
234 | |
235 | |
236 | === modified file 'provider/null/environ_test.go' |
237 | --- provider/null/environ_test.go 2013-09-26 09:02:09 +0000 |
238 | +++ provider/null/environ_test.go 2013-10-02 05:19:29 +0000 |
239 | @@ -4,14 +4,24 @@ |
240 | package null |
241 | |
242 | import ( |
243 | + "io/ioutil" |
244 | + "os" |
245 | + "path/filepath" |
246 | + "strings" |
247 | + |
248 | gc "launchpad.net/gocheck" |
249 | |
250 | "launchpad.net/juju-core/environs" |
251 | "launchpad.net/juju-core/environs/manual" |
252 | + "launchpad.net/juju-core/environs/sshstorage" |
253 | + "launchpad.net/juju-core/environs/tools" |
254 | "launchpad.net/juju-core/instance" |
255 | + jc "launchpad.net/juju-core/testing/checkers" |
256 | + "launchpad.net/juju-core/testing/testbase" |
257 | ) |
258 | |
259 | type environSuite struct { |
260 | + testbase.LoggingSuite |
261 | env *nullEnviron |
262 | } |
263 | |
264 | @@ -79,3 +89,36 @@ |
265 | c.Assert(s.env.SharedStorageAddr(), gc.Equals, "") |
266 | c.Assert(s.env.SharedStorageDir(), gc.Equals, "") |
267 | } |
268 | + |
269 | +func (s *environSuite) TestEnvironSupportsCustomSources(c *gc.C) { |
270 | + sources, err := tools.GetMetadataSources(s.env) |
271 | + c.Assert(err, gc.IsNil) |
272 | + c.Assert(len(sources), gc.Equals, 2) |
273 | + url, err := sources[0].URL("") |
274 | + c.Assert(err, gc.IsNil) |
275 | + c.Assert(strings.Contains(url, "/tools"), jc.IsTrue) |
276 | +} |
277 | + |
278 | +func (s *environSuite) TestEnvironBootstrapStorager(c *gc.C) { |
279 | + const sshScript = "#!/bin/sh\necho JUJU-RC: $RC" |
280 | + bin := c.MkDir() |
281 | + ssh := filepath.Join(bin, "ssh") |
282 | + err := ioutil.WriteFile(ssh, []byte(sshScript), 0755) |
283 | + c.Assert(err, gc.IsNil) |
284 | + s.PatchEnvironment("PATH", bin+":"+os.Getenv("PATH")) |
285 | + |
286 | + s.PatchEnvironment("RC", "99") // simulate ssh failure |
287 | + err = s.env.EnableBootstrapStorage() |
288 | + c.Assert(err, gc.ErrorMatches, "exit code 99") |
289 | + c.Assert(s.env.Storage(), gc.Not(gc.FitsTypeOf), new(sshstorage.SSHStorage)) |
290 | + |
291 | + s.PatchEnvironment("RC", "0") |
292 | + err = s.env.EnableBootstrapStorage() |
293 | + c.Assert(err, gc.IsNil) |
294 | + c.Assert(s.env.Storage(), gc.FitsTypeOf, new(sshstorage.SSHStorage)) |
295 | + |
296 | + // Check idempotency |
297 | + err = s.env.EnableBootstrapStorage() |
298 | + c.Assert(err, gc.IsNil) |
299 | + c.Assert(s.env.Storage(), gc.FitsTypeOf, new(sshstorage.SSHStorage)) |
300 | +} |
Reviewers: mp+187978_ code.launchpad. net,
Message:
Please take a look.
Description:
provider/null: define simplestreams tools source
This is somewhat involved, as there's some fixes
required (and one drive-by in sshstorage). The
change to use GetToolsSources is simple enough,
and matches what the local provider does.
The Environ override struct in cmd/juju/ bootstrap. go
had to so that the optional Environ interfaces were
still implemented. Overriding like that loses the
additional interfaces.
To do the above, environs. BootstrapStorag er has been
changed to have a method that tells the environ to
use bootstrap storage, rather than returning a
bootstrap storage. The null provider has changed to
match, of course, as well as cmd/juju.
https:/ /code.launchpad .net/~axwalk/ juju-core/ null-provider- customsources/ +merge/ 187978
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/14011046/
Affected files (+66, -32 lines): bootstrap. go httpstorage/ storage. go interface. go manual/ bootstrap. go sshstorage/ storage. go null/environ. go null/environ_ test.go
A [revision details]
M cmd/juju/
M environs/
M environs/
M environs/
M environs/
M provider/
M provider/
Index: [revision details] 20130927021656- yolgm6vq7sjrlf6 b
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: tarmac-
+New revision: <email address hidden>
Index: environs/ interface. go interface. go' interface. go 2013-09-26 09:18:36 +0000 interface. go 2013-09-27 05:19:30 +0000 StorageReader
=== modified file 'environs/
--- environs/
+++ environs/
@@ -69,15 +69,18 @@
PublicStorage() storage.
}
-// BootstrapStorager is an interface that returns a environs.Storage that Storage enables or disables bootstrap storage, Storage( enable bool) (wasEnabled bool, err error)
may
-// be used before the bootstrap machine agent has been provisioned.
+// BootstrapStorager is an interface through which an Environ may be
+// instructed to use a special "bootstrap storage". Bootstrap storage
+// is one that may be used before the bootstrap machine agent has been
+// provisioned.
//
-// This is useful for environments where the storage is managed by the
machine
-// agent once bootstrapped.
+// This is useful for environments where the storage is managed by the
+// machine agent once bootstrapped.
type BootstrapStorager interface {
- // BootstrapStorager returns an environs.Storage that may be used while
- // bootstrapping a machine.
- BootstrapStorage() (storage.Storage, error)
+ // EnableBootstrap
+ // depending on the flag, and returns the previous state and an
+ // error if enablement failed.
+ EnableBootstrap
}
// ConfigGetter implements access to an environments configuration.
Index: cmd/juju/ bootstrap. go bootstrap. go' bootstrap. go 2013-09-25 06:22:54 +0000 bootstrap. go 2013-09-27 05:19:30 +0000 net/juju- core/environs/ bootstrap" net/juju- core/environs/ config" net/juju- core/envir. ..
=== modified file 'cmd/juju/
--- cmd/juju/
+++ cmd/juju/
@@ -18,7 +18,6 @@
"launchpad.
"launchpad.
"launchpad.