46
56
func (s *BootstrapSuite) TearDownTest(c *gc.C) {
57
s.ToolsFixture.TearDownTest(c)
47
58
s.MgoSuite.TearDownTest(c)
48
59
s.LoggingSuite.TearDownTest(c)
63
type bootstrapRetryTest struct {
66
expectedAllowRetry []bool
68
// If version != "", version.Current will be
69
// set to it for the duration of the test.
71
// If addVersionToSource is true, then "version"
72
// above will be populated in the tools source.
73
addVersionToSource bool
76
var bootstrapRetryTests = []bootstrapRetryTest{{
77
info: "no tools uploaded, first check has no retries; no matching binary in source; sync fails with no second attempt",
78
expectedAllowRetry: []bool{false},
79
err: "no matching tools available",
80
version: "1.16.0-precise-amd64",
82
info: "no tools uploaded, first check has no retries; matching binary in source; check after sync has retries",
83
expectedAllowRetry: []bool{false, true},
84
err: "tools not found",
85
version: "1.16.0-precise-amd64",
86
addVersionToSource: true,
88
info: "no tools uploaded, first check has no retries; no matching binary in source; check after upload has retries",
89
expectedAllowRetry: []bool{false, true},
90
err: "tools not found",
91
version: "1.15.1-precise-amd64", // dev version to force upload
93
info: "new tools uploaded, so we want to allow retries to give them a chance at showing up",
94
args: []string{"--upload-tools"},
95
expectedAllowRetry: []bool{true},
96
err: "no matching tools available",
99
// Test test checks that bootstrap calls FindTools with the expected allowRetry flag.
100
func (s *BootstrapSuite) TestAllowRetries(c *gc.C) {
101
for i, test := range bootstrapRetryTests {
102
c.Logf("test %d: %s\n", i, test.info)
103
s.runAllowRetriesTest(c, test)
107
func (s *BootstrapSuite) runAllowRetriesTest(c *gc.C, test bootstrapRetryTest) {
108
var extraVersions []version.Binary
109
if test.version != "" {
110
testVersion := version.MustParseBinary(test.version)
111
restore := testbase.PatchValue(&version.Current, testVersion)
113
if test.addVersionToSource {
114
extraVersions = append(extraVersions, testVersion)
117
_, fake := makeEmptyFakeHome(c)
119
defer createToolsStore(c, extraVersions...)()
121
var findToolsRetryValues []bool
122
mockFindTools := func(cloudInst environs.ConfigGetter, majorVersion, minorVersion int,
123
filter coretools.Filter, allowRetry bool) (list coretools.List, err error) {
124
findToolsRetryValues = append(findToolsRetryValues, allowRetry)
125
return nil, errors.NotFoundf("tools")
128
restore := envtools.TestingPatchBootstrapFindTools(mockFindTools)
131
_, errc := runCommand(nullContext(), new(BootstrapCommand), test.args...)
133
c.Check(findToolsRetryValues, gc.DeepEquals, test.expectedAllowRetry)
134
c.Assert(err, gc.ErrorMatches, test.err)
52
137
func (s *BootstrapSuite) TestTest(c *gc.C) {
53
138
uploadTools = mockUploadTools
54
defer func() { uploadTools = tools.Upload }()
139
defer func() { uploadTools = sync.Upload }()
56
141
for i, test := range bootstrapTests {
57
142
c.Logf("\ntest %d: %s", i, test.info)
92
177
if uploadCount == 0 {
93
178
usefulVersion := version.Current
94
179
usefulVersion.Series = env.Config().DefaultSeries()
95
envtesting.UploadFakeToolsVersion(c, env.Storage(), usefulVersion)
180
envtesting.AssertUploadFakeToolsVersions(c, env.Storage(), usefulVersion)
98
183
// Run command and check for uploads.
99
opc, errc := runCommand(nil, new(BootstrapCommand), test.args...)
184
opc, errc := runCommand(nullContext(), new(BootstrapCommand), test.args...)
100
185
if uploadCount > 0 {
101
186
for i := 0; i < uploadCount; i++ {
102
187
c.Check((<-opc).(dummy.OpPutFile).Env, gc.Equals, "peckham")
104
list, err := environs.FindAvailableTools(env, version.Current.Major)
189
list, err := envtools.FindTools(
190
env, version.Current.Major, version.Current.Minor, coretools.Filter{}, envtools.DoNotAllowRetry)
105
191
c.Check(err, gc.IsNil)
106
192
c.Logf("found: " + list.String())
107
193
urls := list.URLs()
122
208
if !c.Check(<-errc, gc.IsNil) {
211
if len(test.uploads) > 0 {
212
indexFile := (<-opc).(dummy.OpPutFile)
213
c.Check(indexFile.FileName, gc.Equals, "tools/streams/v1/index.json")
214
productFile := (<-opc).(dummy.OpPutFile)
215
c.Check(productFile.FileName, gc.Equals, "tools/streams/v1/com.ubuntu.juju:released:tools.json")
125
217
opPutBootstrapVerifyFile := (<-opc).(dummy.OpPutFile)
126
218
c.Check(opPutBootstrapVerifyFile.Env, gc.Equals, "peckham")
127
c.Check(opPutBootstrapVerifyFile.FileName, gc.Equals, "bootstrap-verify")
219
c.Check(opPutBootstrapVerifyFile.FileName, gc.Equals, environs.VerificationFilename)
221
opPutBootstrapInitFile := (<-opc).(dummy.OpPutFile)
222
c.Check(opPutBootstrapInitFile.Env, gc.Equals, "peckham")
223
c.Check(opPutBootstrapInitFile.FileName, gc.Equals, "provider-state")
129
225
opBootstrap := (<-opc).(dummy.OpBootstrap)
130
226
c.Check(opBootstrap.Env, gc.Equals, "peckham")
131
227
c.Check(opBootstrap.Constraints, gc.DeepEquals, test.constraints)
229
store, err := configstore.Default()
230
c.Assert(err, gc.IsNil)
133
231
// Check a CA cert/key was generated by reloading the environment.
134
env, err := environs.NewFromName("peckham")
232
env, err = environs.NewFromName("peckham", store)
135
233
c.Assert(err, gc.IsNil)
136
234
_, hasCert := env.Config().CACert()
137
235
c.Check(hasCert, gc.Equals, true)
158
256
args: []string{"--series", "fine"},
159
257
err: `--series requires --upload-tools`,
161
info: "bad environment",
162
args: []string{"-e", "brokenenv"},
163
err: `environment configuration has no admin-secret`,
259
info: "bad environment",
260
version: "1.2.3-precise-amd64",
261
args: []string{"-e", "brokenenv"},
262
err: `dummy.Bootstrap is broken`,
165
264
info: "constraints",
166
265
args: []string{"--constraints", "mem=4G cpu-cores=4"},
167
266
constraints: constraints.MustParse("mem=4G cpu-cores=4"),
169
268
info: "--upload-tools picks all reasonable series",
170
version: "1.2.3-hostseries-hostarch",
269
version: "1.2.3-saucy-amd64",
171
270
args: []string{"--upload-tools"},
172
271
uploads: []string{
173
"1.2.3.1-hostseries-hostarch", // from version.Current
174
"1.2.3.1-defaultseries-hostarch", // from env.Config().DefaultSeries()
175
"1.2.3.1-precise-hostarch", // from environs/config.DefaultSeries
272
"1.2.3.1-saucy-amd64", // from version.Current
273
"1.2.3.1-raring-amd64", // from env.Config().DefaultSeries()
274
"1.2.3.1-precise-amd64", // from environs/config.DefaultSeries
178
277
info: "--upload-tools only uploads each file once",
179
version: "1.2.3-precise-hostarch",
278
version: "1.2.3-precise-amd64",
180
279
args: []string{"--upload-tools"},
181
280
uploads: []string{
182
"1.2.3.1-defaultseries-hostarch",
183
"1.2.3.1-precise-hostarch",
281
"1.2.3.1-raring-amd64",
282
"1.2.3.1-precise-amd64",
186
info: "--upload-tools accepts specific series even if they're crazy",
187
version: "1.2.3-hostseries-hostarch",
285
info: "--upload-tools rejects invalid series",
286
version: "1.2.3-saucy-amd64",
188
287
args: []string{"--upload-tools", "--series", "ping,ping,pong"},
190
"1.2.3.1-hostseries-hostarch",
191
"1.2.3.1-ping-hostarch",
192
"1.2.3.1-pong-hostarch",
194
err: "no matching tools available",
288
err: `invalid series "ping"`,
196
290
info: "--upload-tools always bumps build number",
197
version: "1.2.3.4-defaultseries-hostarch",
291
version: "1.2.3.4-raring-amd64",
198
292
args: []string{"--upload-tools"},
199
293
uploads: []string{
200
"1.2.3.5-defaultseries-hostarch",
201
"1.2.3.5-precise-hostarch",
294
"1.2.3.5-raring-amd64",
295
"1.2.3.5-precise-amd64",
299
func (s *BootstrapSuite) TestBootstrapTwice(c *gc.C) {
300
env, fake := makeEmptyFakeHome(c)
302
defaultSeriesVersion := version.Current
303
defaultSeriesVersion.Series = env.Config().DefaultSeries()
304
restore := createToolsStore(c, defaultSeriesVersion)
307
ctx := coretesting.Context(c)
308
code := cmd.Main(&BootstrapCommand{}, ctx, nil)
309
c.Check(code, gc.Equals, 0)
311
ctx2 := coretesting.Context(c)
312
code2 := cmd.Main(&BootstrapCommand{}, ctx2, nil)
313
c.Check(code2, gc.Equals, 1)
314
c.Check(coretesting.Stderr(ctx2), gc.Equals, "error: environment is already bootstrapped\n")
315
c.Check(coretesting.Stdout(ctx2), gc.Equals, "")
205
318
func (s *BootstrapSuite) TestAutoSync(c *gc.C) {
206
319
// Prepare a mock storage for testing and store the
207
320
// dummy tools in there.
264
378
code = cmd.Main(&BootstrapCommand{}, ctx, []string{"--source", source})
265
379
c.Check(code, gc.Equals, 0)
267
// Now check the available tools which are the 1.0.0 tools.
268
checkTools(c, env, v100All)
381
// Now check the available tools which are the 1.2.0 envtools.
382
checkTools(c, env, v120All)
385
func (s *BootstrapSuite) setupAutoUploadTest(c *gc.C, vers, series string) environs.Environ {
386
uploadTools = mockUploadTools
387
s.AddCleanup(func(*gc.C) { uploadTools = sync.Upload })
389
// Prepare a mock storage for testing and store the
390
// dummy tools in there.
391
restore := createToolsStore(c)
392
s.AddCleanup(func(*gc.C) { restore() })
394
// Change the tools location to be the test location and also
395
// the version and ensure their later restoring.
396
// Set the current version to be something for which there are no tools
397
// so we can test that an upload is forced.
398
origVersion := version.Current
399
version.Current.Number = version.MustParse(vers)
400
version.Current.Series = series
401
s.AddCleanup(func(*gc.C) { version.Current = origVersion })
403
// Create home with dummy provider and remove all
405
env, fake := makeEmptyFakeHome(c)
406
s.AddCleanup(func(*gc.C) { fake.Restore() })
410
func (s *BootstrapSuite) TestAutoUploadAfterFailedSync(c *gc.C) {
411
otherSeries := "precise"
412
if otherSeries == version.Current.Series {
413
otherSeries = "raring"
415
env := s.setupAutoUploadTest(c, "1.7.3", otherSeries)
416
// Run command and check for that upload has been run for tools matching the current juju version.
417
opc, errc := runCommand(nullContext(), new(BootstrapCommand))
418
c.Assert(<-errc, gc.IsNil)
419
c.Assert((<-opc).(dummy.OpPutFile).Env, gc.Equals, "peckham")
420
list, err := envtools.FindTools(env, version.Current.Major, version.Current.Minor, coretools.Filter{}, false)
421
c.Assert(err, gc.IsNil)
422
c.Logf("found: " + list.String())
424
c.Assert(urls, gc.HasLen, 2)
425
expectedVers := []version.Binary{
426
version.MustParseBinary(fmt.Sprintf("1.7.3.1-%s-%s", otherSeries, version.Current.Arch)),
427
version.MustParseBinary(fmt.Sprintf("1.7.3.1-%s-%s", version.Current.Series, version.Current.Arch)),
429
for _, vers := range expectedVers {
430
c.Logf("seeking: " + vers.String())
431
_, found := urls[vers]
432
c.Check(found, gc.Equals, true)
436
func (s *BootstrapSuite) TestAutoUploadOnlyForDev(c *gc.C) {
437
s.setupAutoUploadTest(c, "1.8.3", "precise")
438
_, errc := runCommand(nullContext(), new(BootstrapCommand))
440
c.Assert(err, gc.ErrorMatches, "no matching tools available")
443
func (s *BootstrapSuite) TestMissingToolsError(c *gc.C) {
444
s.setupAutoUploadTest(c, "1.8.3", "precise")
445
context := coretesting.Context(c)
446
code := cmd.Main(&BootstrapCommand{}, context, nil)
447
c.Assert(code, gc.Equals, 1)
448
errText := context.Stderr.(*bytes.Buffer).String()
449
errText = strings.Replace(errText, "\n", "", -1)
450
expectedErrText := strings.Replace(fmt.Sprintf(".*%s.*", NoToolsNoUploadMessage), "\n", "", -1)
451
c.Assert(errText, gc.Matches, expectedErrText)
454
func uploadToolsAlwaysFails(stor storage.Storage, forceVersion *version.Number, series ...string) (*coretools.Tools, error) {
455
return nil, fmt.Errorf("an error")
458
func (s *BootstrapSuite) TestMissingToolsUploadFailedError(c *gc.C) {
459
s.setupAutoUploadTest(c, "1.7.3", "precise")
460
uploadTools = uploadToolsAlwaysFails
461
context := coretesting.Context(c)
462
code := cmd.Main(&BootstrapCommand{}, context, nil)
463
c.Assert(code, gc.Equals, 1)
464
errText := context.Stderr.(*bytes.Buffer).String()
465
errText = strings.Replace(errText, "\n", "", -1)
466
expectedErrText := strings.Replace(fmt.Sprintf(".*%s.*", NoToolsMessage), "\n", "", -1)
467
c.Assert(errText, gc.Matches, expectedErrText)
271
470
// createToolsStore creates the fake tools store.
272
func createToolsStore(c *gc.C) func() {
273
storage, err := envtesting.NewEC2HTTPTestStorage("127.0.0.1")
471
func createToolsStore(c *gc.C, additionalBinaries ...version.Binary) func() {
472
stor, err := envtesting.NewEC2HTTPTestStorage("127.0.0.1")
274
473
c.Assert(err, gc.IsNil)
275
474
origLocation := sync.DefaultToolsLocation
276
sync.DefaultToolsLocation = storage.Location()
475
sync.DefaultToolsLocation = stor.Location()
277
476
for _, vers := range vAll {
278
storage.PutBinary(vers)
479
for _, vers := range additionalBinaries {
280
482
restore := func() {
281
483
sync.DefaultToolsLocation = origLocation
303
// makeEmptyFakeHome creates a faked home without tools.
505
// makeEmptyFakeHome creates a faked home without envtools.
304
506
func makeEmptyFakeHome(c *gc.C) (environs.Environ, *coretesting.FakeHome) {
305
507
fake := coretesting.MakeFakeHome(c, envConfig)
307
env, err := environs.NewFromName("peckham")
509
store, err := configstore.Default()
510
c.Assert(err, gc.IsNil)
511
env, err := environs.PrepareFromName("peckham", store)
308
512
c.Assert(err, gc.IsNil)
309
513
envtesting.RemoveAllTools(c, env)
313
// checkTools check if the environment contains the passed tools.
314
func checkTools(c *gc.C, env environs.Environ, tools []version.Binary) {
315
list, err := environs.FindAvailableTools(env, version.Current.Major)
517
// checkTools check if the environment contains the passed envtools.
518
func checkTools(c *gc.C, env environs.Environ, expected []version.Binary) {
519
list, err := envtools.FindTools(
520
env, version.Current.Major, version.Current.Minor, coretools.Filter{}, envtools.DoNotAllowRetry)
316
521
c.Check(err, gc.IsNil)
317
522
c.Logf("found: " + list.String())
318
523
urls := list.URLs()
319
c.Check(urls, gc.HasLen, len(tools))
524
c.Check(urls, gc.HasLen, len(expected))
323
v100d64 = version.MustParseBinary("1.0.0-defaultseries-amd64")
528
v100d64 = version.MustParseBinary("1.0.0-raring-amd64")
324
529
v100p64 = version.MustParseBinary("1.0.0-precise-amd64")
325
530
v100q32 = version.MustParseBinary("1.0.0-quantal-i386")
326
531
v100q64 = version.MustParseBinary("1.0.0-quantal-amd64")
532
v120d64 = version.MustParseBinary("1.2.0-raring-amd64")
533
v120p64 = version.MustParseBinary("1.2.0-precise-amd64")
534
v120q32 = version.MustParseBinary("1.2.0-quantal-i386")
535
v120q64 = version.MustParseBinary("1.2.0-quantal-amd64")
327
536
v190p32 = version.MustParseBinary("1.9.0-precise-i386")
328
537
v190q64 = version.MustParseBinary("1.9.0-quantal-amd64")
329
538
v200p64 = version.MustParseBinary("2.0.0-precise-amd64")
330
539
v100All = []version.Binary{
331
540
v100d64, v100p64, v100q64, v100q32,
542
v120All = []version.Binary{
543
v120d64, v120p64, v120q64, v120q32,
333
545
vAll = []version.Binary{
334
546
v100d64, v100p64, v100q32, v100q64,
547
v120d64, v120p64, v120q32, v120q64,
335
548
v190p32, v190q64,