Merge lp:~axwalk/juju-core/lp1296475-block-sigint-bootstrap into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Merged
Approved by: Andrew Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 2481
Proposed branch: lp:~axwalk/juju-core/lp1296475-block-sigint-bootstrap
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 442 lines (+201/-23)
13 files modified
cmd/juju/bootstrap.go (+14/-1)
cmd/juju/bootstrap_test.go (+8/-5)
cmd/juju/common.go (+1/-0)
environs/bootstrap/bootstrap_test.go (+6/-6)
environs/bootstrap/export_test.go (+8/-0)
environs/bootstrap/interruptiblestorage.go (+62/-0)
environs/bootstrap/interruptiblestorage_test.go (+74/-0)
environs/bootstrap/synctools.go (+20/-5)
environs/interface.go (+2/-0)
provider/common/bootstrap.go (+3/-3)
provider/dummy/environs.go (+1/-1)
provider/local/environ.go (+1/-1)
provider/manual/environ.go (+1/-1)
To merge this branch: bzr merge lp:~axwalk/juju-core/lp1296475-block-sigint-bootstrap
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+212558@code.launchpad.net

Commit message

Block SIGINT during bootstrap

This change is to catch SIGINT during bootstrap
for all providers. Also, if SIGINT is delivered
while tools are being uploaded, the upload will
be cancelled.

If the user Ctrl-C's while the local provider's
bootstrap script is being executed, it will be
interrupted and will return and error to juju.
Juju will then attempt to destroy the environment
and remove the .jenv file.

We will now also send some very basic feedback to
stderr when uploading tools.

Fixes lp:1296475

https://codereview.appspot.com/76160046/

Description of the change

Block SIGINT during bootstrap

This change is to catch SIGINT during bootstrap
for all providers. Also, if SIGINT is delivered
while tools are being uploaded, the upload will
be cancelled.

If the user Ctrl-C's while the local provider's
bootstrap script is being executed, it will be
interrupted and will return and error to juju.
Juju will then attempt to destroy the environment
and remove the .jenv file.

We will now also send some very basic feedback to
stderr when uploading tools.

Fixes lp:1296475

https://codereview.appspot.com/76160046/

To post a comment you must log in.
Revision history for this message
Andrew Wilkins (axwalk) wrote :

Reviewers: mp+212558_code.launchpad.net,

Message:
Please take a look.

Description:
Block SIGINT during bootstrap

This change is to catch SIGINT during bootstrap
for all providers. Also, if SIGINT is delivered
while tools are being uploaded, the upload will
be cancelled.

If the user Ctrl-C's while the local provider's
bootstrap script is being executed, it will be
interrupted and will return and error to juju.
Juju will then attempt to destroy the environment
and remove the .jenv file.

We will now also send some very basic feedback to
stderr when uploading tools.

Fixes lp:1296475

https://code.launchpad.net/~axwalk/juju-core/lp1296475-block-sigint-bootstrap/+merge/212558

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/76160046/

Affected files (+192, -18 lines):
   A [revision details]
   M cmd/juju/bootstrap.go
   M cmd/juju/common.go
   M environs/bootstrap/bootstrap_test.go
   A environs/bootstrap/export_test.go
   A environs/bootstrap/interruptiblestorage.go
   A environs/bootstrap/interruptiblestorage_test.go
   M environs/bootstrap/synctools.go
   M provider/common/bootstrap.go
   M provider/dummy/environs.go
   M provider/local/environ.go
   M provider/manual/environ.go

Revision history for this message
Andrew Wilkins (axwalk) wrote :
Revision history for this message
Tim Penhey (thumper) wrote :

https://codereview.appspot.com/76160046/diff/20001/cmd/juju/bootstrap.go
File cmd/juju/bootstrap.go (right):

https://codereview.appspot.com/76160046/diff/20001/cmd/juju/bootstrap.go#newcode112
cmd/juju/bootstrap.go:112: fmt.Fprintln(ctx.GetStderr(), "Interrupt
signalled: waiting for bootstrap to exit")
You could use the new awesome:
   ctx.Infof("Interrupt signalled: waiting for bootstrap to exit")

https://codereview.appspot.com/76160046/diff/20001/cmd/juju/common.go
File cmd/juju/common.go (right):

https://codereview.appspot.com/76160046/diff/20001/cmd/juju/common.go#newcode44
cmd/juju/common.go:44: fmt.Fprintf(ctx.GetStderr(), "%s failed,
destroying environment\n", action)
ctx.Infof("%s failed, destroying environment", action)

A new line is added to the end if missing.

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/interruptiblestorage.go
File environs/bootstrap/interruptiblestorage.go (right):

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/interruptiblestorage.go#newcode48
environs/bootstrap/interruptiblestorage.go:48: n, err = r.Reader.Read(p)
Is it expected that this will continue until finished even if
interrupted?

Is there a race condition here between the return 0, interruptedError
below and this assignment?

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/synctools.go
File environs/bootstrap/synctools.go (right):

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/synctools.go#newcode35
environs/bootstrap/synctools.go:35: logger.Infof("checking that upload
is possible")
we could change this now to use the Verbosef method (if we add it to the
BootstrapContext interface)

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/synctools.go#newcode56
environs/bootstrap/synctools.go:56: fmt.Fprintln(ctx.GetStderr(),
"cancelling tools upload")
we should put Infof and Verbosef onto the bootstrap context I think.

https://codereview.appspot.com/76160046/

Revision history for this message
Andrew Wilkins (axwalk) wrote :

Please take a look.

https://codereview.appspot.com/76160046/diff/20001/cmd/juju/bootstrap.go
File cmd/juju/bootstrap.go (right):

https://codereview.appspot.com/76160046/diff/20001/cmd/juju/bootstrap.go#newcode112
cmd/juju/bootstrap.go:112: fmt.Fprintln(ctx.GetStderr(), "Interrupt
signalled: waiting for bootstrap to exit")
On 2014/03/26 02:41:47, thumper wrote:
> You could use the new awesome:
> ctx.Infof("Interrupt signalled: waiting for bootstrap to exit")

Done.

https://codereview.appspot.com/76160046/diff/20001/cmd/juju/common.go
File cmd/juju/common.go (right):

https://codereview.appspot.com/76160046/diff/20001/cmd/juju/common.go#newcode44
cmd/juju/common.go:44: fmt.Fprintf(ctx.GetStderr(), "%s failed,
destroying environment\n", action)
On 2014/03/26 02:41:47, thumper wrote:
> ctx.Infof("%s failed, destroying environment", action)

> A new line is added to the end if missing.

Done.

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/interruptiblestorage.go
File environs/bootstrap/interruptiblestorage.go (right):

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/interruptiblestorage.go#newcode48
environs/bootstrap/interruptiblestorage.go:48: n, err = r.Reader.Read(p)
On 2014/03/26 02:41:47, thumper wrote:
> Is it expected that this will continue until finished even if
interrupted?

> Is there a race condition here between the return 0, interruptedError
below and
> this assignment?

Yes, good call. Updated to use locals rather than named results.

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/synctools.go
File environs/bootstrap/synctools.go (right):

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/synctools.go#newcode35
environs/bootstrap/synctools.go:35: logger.Infof("checking that upload
is possible")
On 2014/03/26 02:41:47, thumper wrote:
> we could change this now to use the Verbosef method (if we add it to
the
> BootstrapContext interface)

I don't think this particular one should be logged to stderr, but I have
added Infof/Verbosef to BootstrapContext and changed the other ones
over.

https://codereview.appspot.com/76160046/diff/20001/environs/bootstrap/synctools.go#newcode56
environs/bootstrap/synctools.go:56: fmt.Fprintln(ctx.GetStderr(),
"cancelling tools upload")
On 2014/03/26 02:41:47, thumper wrote:
> we should put Infof and Verbosef onto the bootstrap context I think.

Done.

https://codereview.appspot.com/76160046/

Revision history for this message
Tim Penhey (thumper) wrote :
Revision history for this message
Wayne Witzel III (wwitzel3) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmd/juju/bootstrap.go'
2--- cmd/juju/bootstrap.go 2014-03-18 05:03:38 +0000
3+++ cmd/juju/bootstrap.go 2014-03-26 03:32:09 +0000
4@@ -100,6 +100,19 @@
5 if err := bootstrap.EnsureNotBootstrapped(environ); err != nil {
6 return err
7 }
8+
9+ // Block interruption during bootstrap. Providers may also
10+ // register for interrupt notification so they can exit early.
11+ interrupted := make(chan os.Signal, 1)
12+ defer close(interrupted)
13+ ctx.InterruptNotify(interrupted)
14+ defer ctx.StopInterruptNotify(interrupted)
15+ go func() {
16+ for _ = range interrupted {
17+ ctx.Infof("Interrupt signalled: waiting for bootstrap to exit")
18+ }
19+ }()
20+
21 // If --metadata-source is specified, override the default tools metadata source so
22 // SyncTools can use it, and also upload any image metadata.
23 if c.MetadataSource != "" {
24@@ -122,7 +135,7 @@
25 c.UploadTools = true
26 }
27 if c.UploadTools {
28- err = bootstrap.UploadTools(environ, c.Constraints.Arch, true, c.Series...)
29+ err = bootstrap.UploadTools(ctx, environ, c.Constraints.Arch, true, c.Series...)
30 if err != nil {
31 return err
32 }
33
34=== modified file 'cmd/juju/bootstrap_test.go'
35--- cmd/juju/bootstrap_test.go 2014-03-24 20:08:45 +0000
36+++ cmd/juju/bootstrap_test.go 2014-03-26 03:32:09 +0000
37@@ -374,7 +374,9 @@
38 ctx2 := coretesting.Context(c)
39 code2 := cmd.Main(&BootstrapCommand{}, ctx2, nil)
40 c.Check(code2, gc.Equals, 1)
41- c.Check(coretesting.Stderr(ctx2), gc.Equals, "error: environment is already bootstrapped\n")
42+ expectedErrText := "Bootstrap failed, destroying environment\n"
43+ expectedErrText += "error: environment is already bootstrapped\n"
44+ c.Check(coretesting.Stderr(ctx2), gc.Equals, expectedErrText)
45 c.Check(coretesting.Stdout(ctx2), gc.Equals, "")
46 }
47
48@@ -540,8 +542,8 @@
49 code := cmd.Main(&BootstrapCommand{}, context, nil)
50 c.Assert(code, gc.Equals, 1)
51 errText := context.Stderr.(*bytes.Buffer).String()
52- errText = strings.Replace(errText, "\n", "", -1)
53- expectedErrText := "error: cannot upload bootstrap tools: Juju cannot bootstrap because no tools are available for your environment.*"
54+ expectedErrText := "Bootstrap failed, destroying environment\n"
55+ expectedErrText += "error: cannot upload bootstrap tools: Juju cannot bootstrap because no tools are available for your environment(.|\n)*"
56 c.Assert(errText, gc.Matches, expectedErrText)
57 }
58
59@@ -556,8 +558,9 @@
60 code := cmd.Main(&BootstrapCommand{}, context, nil)
61 c.Assert(code, gc.Equals, 1)
62 errText := context.Stderr.(*bytes.Buffer).String()
63- errText = strings.Replace(errText, "\n", "", -1)
64- expectedErrText := "error: cannot upload bootstrap tools: an error"
65+ expectedErrText := "uploading tools for series \\[precise raring\\]\n"
66+ expectedErrText += "Bootstrap failed, destroying environment\n"
67+ expectedErrText += "error: cannot upload bootstrap tools: an error\n"
68 c.Assert(errText, gc.Matches, expectedErrText)
69 }
70
71
72=== modified file 'cmd/juju/common.go'
73--- cmd/juju/common.go 2014-03-10 00:45:41 +0000
74+++ cmd/juju/common.go 2014-03-26 03:32:09 +0000
75@@ -39,6 +39,7 @@
76 }
77 cleanup := func() {
78 if !existing {
79+ ctx.Infof("%s failed, destroying environment", action)
80 destroyPreparedEnviron(environ, store, resultErr, action)
81 }
82 }
83
84=== modified file 'environs/bootstrap/bootstrap_test.go'
85--- environs/bootstrap/bootstrap_test.go 2014-03-19 22:02:00 +0000
86+++ environs/bootstrap/bootstrap_test.go 2014-03-26 03:32:09 +0000
87@@ -216,7 +216,7 @@
88 s.setDummyStorage(c, env)
89 envtesting.RemoveFakeTools(c, env.Storage())
90 arch := "ppc64"
91- _, err := bootstrap.EnsureToolsAvailability(env, env.Config().DefaultSeries(), &arch)
92+ _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), &arch)
93 c.Assert(err, gc.NotNil)
94 stripped := strings.Replace(err.Error(), "\n", "", -1)
95 c.Assert(stripped,
96@@ -232,7 +232,7 @@
97 env := newEnviron("foo", useDefaultKeys, nil)
98 s.setDummyStorage(c, env)
99 envtesting.RemoveFakeTools(c, env.Storage())
100- _, err := bootstrap.EnsureToolsAvailability(env, env.Config().DefaultSeries(), nil)
101+ _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), nil)
102 c.Assert(err, gc.NotNil)
103 stripped := strings.Replace(err.Error(), "\n", "", -1)
104 c.Assert(stripped,
105@@ -245,7 +245,7 @@
106 env := newEnviron("foo", useDefaultKeys, map[string]interface{}{"agent-version": "1.16.0"})
107 s.setDummyStorage(c, env)
108 envtesting.RemoveFakeTools(c, env.Storage())
109- _, err := bootstrap.EnsureToolsAvailability(env, env.Config().DefaultSeries(), nil)
110+ _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), nil)
111 c.Assert(err, gc.NotNil)
112 stripped := strings.Replace(err.Error(), "\n", "", -1)
113 c.Assert(stripped,
114@@ -259,7 +259,7 @@
115 env := newEnviron("foo", useDefaultKeys, nil)
116 s.setDummyStorage(c, env)
117 envtesting.RemoveFakeTools(c, env.Storage())
118- _, err := bootstrap.EnsureToolsAvailability(env, env.Config().DefaultSeries(), nil)
119+ _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), nil)
120 c.Assert(err, gc.NotNil)
121 stripped := strings.Replace(err.Error(), "\n", "", -1)
122 c.Assert(stripped,
123@@ -309,7 +309,7 @@
124 return "arm64"
125 })
126 arch := "arm64"
127- agentTools, err := bootstrap.EnsureToolsAvailability(env, env.Config().DefaultSeries(), &arch)
128+ agentTools, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), &arch)
129 c.Assert(err, gc.IsNil)
130 c.Assert(agentTools, gc.HasLen, 1)
131 expectedVers := version.Current
132@@ -352,7 +352,7 @@
133 return "arm64"
134 })
135 arch := "arm64"
136- err := bootstrap.UploadTools(env, &arch, allowRelease, "precise")
137+ err := bootstrap.UploadTools(coretesting.Context(c), env, &arch, allowRelease, "precise")
138 if errMessage != "" {
139 stripped := strings.Replace(err.Error(), "\n", "", -1)
140 c.Assert(stripped, gc.Matches, errMessage)
141
142=== added file 'environs/bootstrap/export_test.go'
143--- environs/bootstrap/export_test.go 1970-01-01 00:00:00 +0000
144+++ environs/bootstrap/export_test.go 2014-03-26 03:32:09 +0000
145@@ -0,0 +1,8 @@
146+// Copyright 2014 Canonical Ltd.
147+// Licensed under the AGPLv3, see LICENCE file for details.
148+
149+package bootstrap
150+
151+var (
152+ NewInterruptibleStorage = newInterruptibleStorage
153+)
154
155=== added file 'environs/bootstrap/interruptiblestorage.go'
156--- environs/bootstrap/interruptiblestorage.go 1970-01-01 00:00:00 +0000
157+++ environs/bootstrap/interruptiblestorage.go 2014-03-26 03:32:09 +0000
158@@ -0,0 +1,62 @@
159+// Copyright 2014 Canonical Ltd.
160+// Licensed under the AGPLv3, see LICENCE file for details.
161+
162+package bootstrap
163+
164+import (
165+ "errors"
166+ "io"
167+
168+ "launchpad.net/juju-core/environs/storage"
169+)
170+
171+var interruptedError = errors.New("interrupted")
172+
173+// interruptibleStorage is a storage.Storage that sits
174+// between the user and another Storage, allowing the
175+// Put method to be interrupted.
176+type interruptibleStorage struct {
177+ storage.Storage
178+ interrupt <-chan struct{}
179+}
180+
181+// newInterruptibleStorage wraps the provided Storage so that Put
182+// will immediately return an error if the provided channel is
183+// closed.
184+func newInterruptibleStorage(s storage.Storage, interrupt <-chan struct{}) storage.Storage {
185+ return &interruptibleStorage{s, interrupt}
186+}
187+
188+type interruptibleReader struct {
189+ io.Reader
190+ interrupt <-chan struct{}
191+}
192+
193+func (r *interruptibleReader) Read(p []byte) (int, error) {
194+ // if the interrupt channel is already
195+ // closed, just drop out immediately.
196+ select {
197+ case <-r.interrupt:
198+ return 0, interruptedError
199+ default:
200+ }
201+
202+ // read and wait for interruption concurrently
203+ var n int
204+ var err error
205+ done := make(chan struct{})
206+ go func() {
207+ defer close(done)
208+ n, err = r.Reader.Read(p)
209+ }()
210+ select {
211+ case <-done:
212+ return n, err
213+ case <-r.interrupt:
214+ return 0, interruptedError
215+ }
216+}
217+
218+func (s *interruptibleStorage) Put(name string, r io.Reader, length int64) error {
219+ return s.Storage.Put(name, &interruptibleReader{r, s.interrupt}, length)
220+}
221
222=== added file 'environs/bootstrap/interruptiblestorage_test.go'
223--- environs/bootstrap/interruptiblestorage_test.go 1970-01-01 00:00:00 +0000
224+++ environs/bootstrap/interruptiblestorage_test.go 2014-03-26 03:32:09 +0000
225@@ -0,0 +1,74 @@
226+// Copyright 2014 Canonical Ltd.
227+// Licensed under the AGPLv3, see LICENCE file for details.
228+
229+package bootstrap_test
230+
231+import (
232+ "fmt"
233+
234+ gc "launchpad.net/gocheck"
235+
236+ "launchpad.net/juju-core/environs/bootstrap"
237+ envtesting "launchpad.net/juju-core/environs/testing"
238+ "launchpad.net/juju-core/testing/testbase"
239+)
240+
241+type interruptibleStorageSuite struct {
242+ testbase.LoggingSuite
243+}
244+
245+var _ = gc.Suite(&interruptibleStorageSuite{})
246+
247+type errorReader struct {
248+ close chan struct{}
249+ wait chan struct{}
250+ called int
251+ err error
252+}
253+
254+func (r *errorReader) Read(buf []byte) (int, error) {
255+ if r.close != nil {
256+ close(r.close)
257+ }
258+ if r.wait != nil {
259+ <-r.wait
260+ }
261+ r.called++
262+ return 0, r.err
263+}
264+
265+func (s *interruptibleStorageSuite) TestInterruptStorage(c *gc.C) {
266+ closer, stor, _ := envtesting.CreateLocalTestStorage(c)
267+ s.AddCleanup(func(c *gc.C) { closer.Close() })
268+ reader := &errorReader{
269+ err: fmt.Errorf("read failed"),
270+ }
271+ interrupted := make(chan struct{})
272+ istor := bootstrap.NewInterruptibleStorage(stor, interrupted)
273+
274+ err := istor.Put("name", reader, 3)
275+ c.Assert(err, gc.ErrorMatches, ".*: read failed")
276+ c.Assert(reader.called, gc.Equals, 1)
277+
278+ // If the channel is already closed, then the
279+ // underlying reader is never deferred to.
280+ close(interrupted)
281+ err = istor.Put("name", reader, 3)
282+ c.Assert(err, gc.ErrorMatches, ".*: interrupted")
283+ c.Assert(reader.called, gc.Equals, 1)
284+}
285+
286+func (s *interruptibleStorageSuite) TestInterruptStorageConcurrently(c *gc.C) {
287+ closer, stor, _ := envtesting.CreateLocalTestStorage(c)
288+ s.AddCleanup(func(c *gc.C) { closer.Close() })
289+ reader := &errorReader{
290+ close: make(chan struct{}),
291+ wait: make(chan struct{}),
292+ err: fmt.Errorf("read failed"),
293+ }
294+ istor := bootstrap.NewInterruptibleStorage(stor, reader.close)
295+ err := istor.Put("name", reader, 3)
296+ c.Assert(err, gc.ErrorMatches, ".*: interrupted")
297+ c.Assert(reader.called, gc.Equals, 0) // reader is blocked
298+ close(reader.wait)
299+}
300
301=== modified file 'environs/bootstrap/synctools.go'
302--- environs/bootstrap/synctools.go 2014-03-19 22:02:00 +0000
303+++ environs/bootstrap/synctools.go 2014-03-26 03:32:09 +0000
304@@ -5,6 +5,7 @@
305
306 import (
307 "fmt"
308+ "os"
309
310 "launchpad.net/juju-core/environs"
311 "launchpad.net/juju-core/environs/config"
312@@ -30,7 +31,7 @@
313 // the environment storage, after which it sets the agent-version. If forceVersion is true,
314 // we allow uploading release tools versions and allow uploading even when the agent-version is
315 // already set in the environment.
316-func UploadTools(env environs.Environ, toolsArch *string, forceVersion bool, bootstrapSeries ...string) error {
317+func UploadTools(ctx environs.BootstrapContext, env environs.Environ, toolsArch *string, forceVersion bool, bootstrapSeries ...string) error {
318 logger.Infof("checking that upload is possible")
319 // Check the series are valid.
320 for _, series := range bootstrapSeries {
321@@ -43,11 +44,25 @@
322 return err
323 }
324
325+ // Make storage interruptible.
326+ interrupted := make(chan os.Signal, 1)
327+ interruptStorage := make(chan struct{})
328+ ctx.InterruptNotify(interrupted)
329+ defer ctx.StopInterruptNotify(interrupted)
330+ defer close(interrupted)
331+ go func() {
332+ defer close(interruptStorage) // closing interrupts all uploads
333+ if _, ok := <-interrupted; ok {
334+ ctx.Infof("cancelling tools upload")
335+ }
336+ }()
337+ stor := newInterruptibleStorage(env.Storage(), interruptStorage)
338+
339 cfg := env.Config()
340 explicitVersion := uploadVersion(version.Current.Number, nil)
341 uploadSeries := SeriesToUpload(cfg, bootstrapSeries)
342- logger.Infof("uploading tools for series %s", uploadSeries)
343- tools, err := sync.Upload(env.Storage(), &explicitVersion, uploadSeries...)
344+ ctx.Infof("uploading tools for series %s", uploadSeries)
345+ tools, err := sync.Upload(stor, &explicitVersion, uploadSeries...)
346 if err != nil {
347 return err
348 }
349@@ -131,7 +146,7 @@
350
351 // EnsureToolsAvailability verifies the tools are available. If no tools are
352 // found, it will automatically synchronize them.
353-func EnsureToolsAvailability(env environs.Environ, series string, toolsArch *string) (coretools.List, error) {
354+func EnsureToolsAvailability(ctx environs.BootstrapContext, env environs.Environ, series string, toolsArch *string) (coretools.List, error) {
355 cfg := env.Config()
356 var vers *version.Number
357 if agentVersion, ok := cfg.AgentVersion(); ok {
358@@ -160,7 +175,7 @@
359 // No tools available so our only hope is to build locally and upload.
360 logger.Warningf("no prepackaged tools available")
361 uploadSeries := SeriesToUpload(cfg, nil)
362- if err := UploadTools(env, toolsArch, false, append(uploadSeries, series)...); err != nil {
363+ if err := UploadTools(ctx, env, toolsArch, false, append(uploadSeries, series)...); err != nil {
364 logger.Errorf("%s", noToolsMessage)
365 return nil, fmt.Errorf("cannot upload bootstrap tools: %v", err)
366 }
367
368=== modified file 'environs/interface.go'
369--- environs/interface.go 2014-03-17 07:44:21 +0000
370+++ environs/interface.go 2014-03-26 03:32:09 +0000
371@@ -183,6 +183,8 @@
372 GetStdin() io.Reader
373 GetStdout() io.Writer
374 GetStderr() io.Writer
375+ Infof(format string, params ...interface{})
376+ Verbosef(format string, params ...interface{})
377
378 // InterruptNotify starts watching for interrupt signals
379 // on behalf of the caller, sending them to the supplied
380
381=== modified file 'provider/common/bootstrap.go'
382--- provider/common/bootstrap.go 2014-03-21 14:39:23 +0000
383+++ provider/common/bootstrap.go 2014-03-26 03:32:09 +0000
384@@ -42,7 +42,7 @@
385 defer func() { handleBootstrapError(err, ctx, inst, env) }()
386
387 // First thing, ensure we have tools otherwise there's no point.
388- selectedTools, err := EnsureBootstrapTools(env, env.Config().DefaultSeries(), cons.Arch)
389+ selectedTools, err := EnsureBootstrapTools(ctx, env, env.Config().DefaultSeries(), cons.Arch)
390 if err != nil {
391 return err
392 }
393@@ -403,8 +403,8 @@
394 // EnsureBootstrapTools finds tools, syncing with an external tools source as
395 // necessary; it then selects the newest tools to bootstrap with, and sets
396 // agent-version.
397-func EnsureBootstrapTools(env environs.Environ, series string, arch *string) (coretools.List, error) {
398- possibleTools, err := bootstrap.EnsureToolsAvailability(env, series, arch)
399+func EnsureBootstrapTools(ctx environs.BootstrapContext, env environs.Environ, series string, arch *string) (coretools.List, error) {
400+ possibleTools, err := bootstrap.EnsureToolsAvailability(ctx, env, series, arch)
401 if err != nil {
402 return nil, err
403 }
404
405=== modified file 'provider/dummy/environs.go'
406--- provider/dummy/environs.go 2014-03-18 05:03:38 +0000
407+++ provider/dummy/environs.go 2014-03-26 03:32:09 +0000
408@@ -543,7 +543,7 @@
409 }
410
411 func (e *environ) Bootstrap(ctx environs.BootstrapContext, cons constraints.Value) error {
412- selectedTools, err := common.EnsureBootstrapTools(e, e.Config().DefaultSeries(), cons.Arch)
413+ selectedTools, err := common.EnsureBootstrapTools(ctx, e, e.Config().DefaultSeries(), cons.Arch)
414 if err != nil {
415 return err
416 }
417
418=== modified file 'provider/local/environ.go'
419--- provider/local/environ.go 2014-03-25 06:35:04 +0000
420+++ provider/local/environ.go 2014-03-26 03:32:09 +0000
421@@ -118,7 +118,7 @@
422 }
423
424 vers := version.Current
425- selectedTools, err := common.EnsureBootstrapTools(env, vers.Series, &vers.Arch)
426+ selectedTools, err := common.EnsureBootstrapTools(ctx, env, vers.Series, &vers.Arch)
427 if err != nil {
428 return err
429 }
430
431=== modified file 'provider/manual/environ.go'
432--- provider/manual/environ.go 2014-03-25 13:18:46 +0000
433+++ provider/manual/environ.go 2014-03-26 03:32:09 +0000
434@@ -113,7 +113,7 @@
435 if err != nil {
436 return err
437 }
438- selectedTools, err := common.EnsureBootstrapTools(e, series, hc.Arch)
439+ selectedTools, err := common.EnsureBootstrapTools(ctx, e, series, hc.Arch)
440 if err != nil {
441 return err
442 }

Subscribers

People subscribed via source and target branches

to status/vote changes: