Example #1
0
// 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
}