Example #1
0
// UpdateLatestToolsVersion looks up for the latest available version of
// juju tools and updates environementDoc with it.
func (e *Environment) UpdateLatestToolsVersion(ver version.Number) error {
	v := ver.String()
	// TODO(perrito666): I need to assert here that there isn't a newer
	// version in place.
	ops := []txn.Op{{
		C:      environmentsC,
		Id:     e.doc.UUID,
		Update: bson.D{{"$set", bson.D{{"available-tools", v}}}},
	}}
	err := e.st.runTransaction(ops)
	if err != nil {
		return errors.Trace(err)
	}
	return e.Refresh()
}
Example #2
0
// SetBootstrapTools returns the newest tools from the given tools list,
// and updates the agent-version configuration attribute.
func SetBootstrapTools(environ environs.Environ, possibleTools coretools.List) (coretools.List, error) {
	if len(possibleTools) == 0 {
		return nil, fmt.Errorf("no bootstrap tools available")
	}
	var newVersion version.Number
	newVersion, toolsList := possibleTools.Newest()
	logger.Infof("newest version: %s", newVersion)
	cfg := environ.Config()
	if agentVersion, _ := cfg.AgentVersion(); agentVersion != newVersion {
		cfg, err := cfg.Apply(map[string]interface{}{
			"agent-version": newVersion.String(),
		})
		if err == nil {
			err = environ.SetConfig(cfg)
		}
		if err != nil {
			return nil, fmt.Errorf("failed to update environment configuration: %v", err)
		}
	}
	bootstrapVersion := newVersion
	// We should only ever bootstrap the exact same version as the client,
	// or we risk bootstrap incompatibility. We still set agent-version to
	// the newest version, so the agent will immediately upgrade itself.
	if !isCompatibleVersion(newVersion, version.Current.Number) {
		compatibleVersion, compatibleTools := findCompatibleTools(possibleTools, version.Current.Number)
		if len(compatibleTools) == 0 {
			logger.Warningf(
				"failed to find %s tools, will attempt to use %s",
				version.Current.Number, newVersion,
			)
		} else {
			bootstrapVersion, toolsList = compatibleVersion, compatibleTools
		}
	}
	logger.Infof("picked bootstrap tools version: %s", bootstrapVersion)
	return toolsList, nil
}
Example #3
0
// BundleTools bundles all the current juju tools in gzipped tar
// format to the given writer.
// If forceVersion is not nil, a FORCE-VERSION file is included in
// the tools bundle so it will lie about its current version number.
func bundleTools(w io.Writer, forceVersion *version.Number) (tvers version.Binary, sha256Hash string, err error) {
	dir, err := ioutil.TempDir("", "juju-tools")
	if err != nil {
		return version.Binary{}, "", err
	}
	defer os.RemoveAll(dir)

	if err := copyExistingJujud(dir); err != nil {
		logger.Debugf("copy existing failed: %v", err)
		if err := buildJujud(dir); err != nil {
			return version.Binary{}, "", err
		}
	}

	if forceVersion != nil {
		logger.Debugf("forcing version to %s", forceVersion)
		if err := ioutil.WriteFile(filepath.Join(dir, "FORCE-VERSION"), []byte(forceVersion.String()), 0666); err != nil {
			return version.Binary{}, "", err
		}
	}
	cmd := exec.Command(filepath.Join(dir, names.Jujud), "version")
	out, err := cmd.CombinedOutput()
	if err != nil {
		return version.Binary{}, "", fmt.Errorf("cannot get version from %q: %v; %s", cmd.Args[0], err, out)
	}
	tvs := strings.TrimSpace(string(out))
	tvers, err = version.ParseBinary(tvs)
	if err != nil {
		return version.Binary{}, "", fmt.Errorf("invalid version %q printed by jujud", tvs)
	}

	sha256hash, err := archiveAndSHA256(w, dir)
	if err != nil {
		return version.Binary{}, "", err
	}
	return tvers, sha256hash, err
}
Example #4
0
// SetEnvironAgentVersion changes the agent version for the
// environment to the given version, only if the environment is in a
// stable state (all agents are running the current version).
func (st *State) SetEnvironAgentVersion(newVersion version.Number) error {
	for i := 0; i < 5; i++ {
		settings, err := readSettings(st, environGlobalKey)
		if err != nil {
			return err
		}
		agentVersion, ok := settings.Get("agent-version")
		if !ok {
			return fmt.Errorf("no agent version set in the environment")
		}
		currentVersion, ok := agentVersion.(string)
		if !ok {
			return fmt.Errorf("invalid agent version format: expected string, got %v", agentVersion)
		}
		if newVersion.String() == currentVersion {
			// Nothing to do.
			return nil
		}

		if err := st.checkCanUpgrade(currentVersion, newVersion.String()); err != nil {
			return err
		}

		ops := []txn.Op{{
			C:      st.settings.Name,
			Id:     environGlobalKey,
			Assert: bson.D{{"txn-revno", settings.txnRevno}},
			Update: bson.D{{"$set", bson.D{{"agent-version", newVersion.String()}}}},
		}}
		if err := st.runTransaction(ops); err == nil {
			return nil
		} else if err != txn.ErrAborted {
			return fmt.Errorf("cannot set agent-version: %v", err)
		}
	}
	return ErrExcessiveContention
}
Example #5
0
// SetEnvironAgentVersion changes the agent version for the
// environment to the given version, only if the environment is in a
// stable state (all agents are running the current version).
func (st *State) SetEnvironAgentVersion(newVersion version.Number) (err error) {
	buildTxn := func(attempt int) ([]txn.Op, error) {
		settings, err := readSettings(st, environGlobalKey)
		if err != nil {
			return nil, err
		}
		agentVersion, ok := settings.Get("agent-version")
		if !ok {
			return nil, fmt.Errorf("no agent version set in the environment")
		}
		currentVersion, ok := agentVersion.(string)
		if !ok {
			return nil, fmt.Errorf("invalid agent version format: expected string, got %v", agentVersion)
		}
		if newVersion.String() == currentVersion {
			// Nothing to do.
			return nil, jujutxn.ErrNoOperations
		}

		if err := st.checkCanUpgrade(currentVersion, newVersion.String()); err != nil {
			return nil, err
		}

		ops := []txn.Op{{
			C:      st.settings.Name,
			Id:     environGlobalKey,
			Assert: bson.D{{"txn-revno", settings.txnRevno}},
			Update: bson.D{{"$set", bson.D{{"agent-version", newVersion.String()}}}},
		}}
		return ops, nil
	}
	if err = st.run(buildTxn); err == jujutxn.ErrExcessiveContention {
		err = errors.Annotate(err, "cannot set agent version")
	}
	return err
}
Example #6
0
// SetAgentVersion sets the current agent version in the state's
// environment configuration.
// This is similar to state.SetEnvironAgentVersion but it doesn't require that
// the environment have all agents at the same version already.
func SetAgentVersion(st *state.State, vers version.Number) error {
	return st.UpdateEnvironConfig(map[string]interface{}{"agent-version": vers.String()}, nil, nil)
}