// handleBootstrapError cleans up after a failed bootstrap. func handleBootstrapError(err error, ctx environs.BootstrapContext, inst instance.Instance, env environs.Environ) { if err == nil { return } logger.Errorf("bootstrap failed: %v", err) ch := make(chan os.Signal, 1) ctx.InterruptNotify(ch) defer ctx.StopInterruptNotify(ch) defer close(ch) go func() { for _ = range ch { fmt.Fprintln(ctx.GetStderr(), "Cleaning up failed bootstrap") } }() if inst != nil { fmt.Fprintln(ctx.GetStderr(), "Stopping instance...") if stoperr := env.StopInstances([]instance.Instance{inst}); stoperr != nil { logger.Errorf("cannot stop failed bootstrap instance %q: %v", inst.Id(), stoperr) } else { // set to nil so we know we can safely delete the state file inst = nil } } // We only delete the bootstrap state file if either we didn't // start an instance, or we managed to cleanly stop it. if inst == nil { if rmerr := bootstrap.DeleteStateFile(env.Storage()); rmerr != nil { logger.Errorf("cannot delete bootstrap state file: %v", rmerr) } } }
// UploadTools uploads tools for the specified series and any other relevant series to // the environment storage, after which it sets the agent-version. If forceVersion is true, // we allow uploading even when the agent-version is already set in the environment. func UploadTools(ctx environs.BootstrapContext, env environs.Environ, toolsArch *string, forceVersion bool, bootstrapSeries ...string) error { logger.Infof("checking that upload is possible") // Check the series are valid. for _, series := range bootstrapSeries { if _, err := ubuntu.SeriesVersion(series); err != nil { return err } } // See that we are allowed to upload the tools. if err := validateUploadAllowed(env, toolsArch, forceVersion); err != nil { return err } // Make storage interruptible. interrupted := make(chan os.Signal, 1) interruptStorage := make(chan struct{}) ctx.InterruptNotify(interrupted) defer ctx.StopInterruptNotify(interrupted) defer close(interrupted) go func() { defer close(interruptStorage) // closing interrupts all uploads if _, ok := <-interrupted; ok { ctx.Infof("cancelling tools upload") } }() stor := newInterruptibleStorage(env.Storage(), interruptStorage) cfg := env.Config() explicitVersion := uploadVersion(version.Current.Number, nil) uploadSeries := SeriesToUpload(cfg, bootstrapSeries) ctx.Infof("uploading tools for series %s", uploadSeries) tools, err := sync.Upload(stor, &explicitVersion, uploadSeries...) if err != nil { return err } cfg, err = cfg.Apply(map[string]interface{}{ "agent-version": tools.Version.Number.String(), }) if err == nil { err = env.SetConfig(cfg) } if err != nil { return fmt.Errorf("failed to update environment configuration: %v", err) } return nil }