Example #1
0
func checkToolsAvailability(cfg *config.Config, finder toolsFinder) (version.Number, error) {
	currentVersion, ok := cfg.AgentVersion()
	if !ok || currentVersion == version.Zero {
		return version.Zero, nil
	}

	env, err := newEnvirons(cfg)
	if err != nil {
		return version.Zero, errors.Annotatef(err, "cannot make environ")
	}

	// finder receives major and minor as parameters as it uses them to filter versions and
	// only return patches for the passed major.minor (from major.minor.patch).
	// We'll try the released stream first, then fall back to the current configured stream
	// if no released tools are found.
	vers, err := finder(env, currentVersion.Major, currentVersion.Minor, tools.ReleasedStream, coretools.Filter{})
	preferredStream := tools.PreferredStream(&currentVersion, cfg.Development(), cfg.AgentStream())
	if preferredStream != tools.ReleasedStream && errors.Cause(err) == coretools.ErrNoMatches {
		vers, err = finder(env, currentVersion.Major, currentVersion.Minor, preferredStream, coretools.Filter{})
	}
	if err != nil {
		return version.Zero, errors.Annotatef(err, "cannot find available tools")
	}
	// Newest also returns a list of the items in this list matching with the
	// newest version.
	newest, _ := vers.Newest()
	return newest, nil
}
Example #2
0
File: conn.go Project: bac/juju
// DefaultVersions returns a slice of unique 'versions' for the current
// environment's preferred series and host architecture, as well supported LTS
// series for the host architecture. Additionally, it ensures that 'versions'
// for amd64 are returned if that is not the current host's architecture.
func DefaultVersions(conf *config.Config) []version.Binary {
	var versions []version.Binary
	supported := series.SupportedLts()
	defaultSeries := set.NewStrings(supported...)
	defaultSeries.Add(config.PreferredSeries(conf))
	defaultSeries.Add(series.HostSeries())
	agentVersion, set := conf.AgentVersion()
	if !set {
		agentVersion = jujuversion.Current
	}
	for _, s := range defaultSeries.Values() {
		versions = append(versions, version.Binary{
			Number: agentVersion,
			Arch:   arch.HostArch(),
			Series: s,
		})
		if arch.HostArch() != "amd64" {
			versions = append(versions, version.Binary{
				Number: agentVersion,
				Arch:   "amd64",
				Series: s,
			})

		}
	}
	return versions
}
Example #3
0
// checkEnvironConfig returns an error if the config is definitely invalid.
func checkEnvironConfig(cfg *config.Config) error {
	if cfg.AdminSecret() != "" {
		return fmt.Errorf("admin-secret should never be written to the state")
	}
	if _, ok := cfg.AgentVersion(); !ok {
		return fmt.Errorf("agent-version must always be set in state")
	}
	return nil
}
Example #4
0
func (c *ModelConfigCreator) checkVersion(base *config.Config, attrs map[string]interface{}) error {
	baseVersion, ok := base.AgentVersion()
	if !ok {
		return errors.Errorf("agent-version not found in base config")
	}

	// If there is no agent-version specified, use the current version.
	// otherwise we need to check for tools
	value, ok := attrs["agent-version"]
	if !ok {
		attrs["agent-version"] = baseVersion.String()
		return nil
	}
	versionStr, ok := value.(string)
	if !ok {
		return errors.Errorf("agent-version must be a string but has type '%T'", value)
	}
	versionNumber, err := version.Parse(versionStr)
	if err != nil {
		return errors.Trace(err)
	}

	n := versionNumber.Compare(baseVersion)
	switch {
	case n > 0:
		return errors.Errorf(
			"agent-version (%s) cannot be greater than the controller (%s)",
			versionNumber, baseVersion,
		)
	case n == 0:
		// If the version is the same as the base config,
		// then assume tools are available.
		return nil
	case n < 0:
		if c.FindTools == nil {
			return errors.New(
				"agent-version does not match base config, " +
					"and no tools-finder is supplied",
			)
		}
	}

	// Look to see if we have tools available for that version.
	list, err := c.FindTools(versionNumber)
	if err != nil {
		return errors.Trace(err)
	}
	if len(list) == 0 {
		return errors.Errorf("no tools found for version %s", versionNumber)
	}
	logger.Tracef("found tools: %#v", list)
	return nil
}
Example #5
0
// bootstrapConfig returns a copy of the supplied configuration with the
// admin-secret and ca-private-key attributes removed. If the resulting
// config is not suitable for bootstrapping an environment, an error is
// returned.
// This function is copied from environs in here so we can avoid an import loop
func bootstrapConfig(cfg *config.Config) (*config.Config, error) {
	m := cfg.AllAttrs()
	// We never want to push admin-secret or the root CA private key to the cloud.
	delete(m, "admin-secret")
	delete(m, "ca-private-key")
	cfg, err := config.New(config.NoDefaults, m)
	if err != nil {
		return nil, err
	}
	if _, ok := cfg.AgentVersion(); !ok {
		return nil, fmt.Errorf("model configuration has no agent-version")
	}
	return cfg, nil
}
Example #6
0
// checkModelConfig returns an error if the config is definitely invalid.
func checkModelConfig(cfg *config.Config) error {
	allAttrs := cfg.AllAttrs()
	for _, attr := range disallowedModelConfigAttrs {
		if _, ok := allAttrs[attr]; ok {
			return errors.Errorf(attr + " should never be written to the state")
		}
	}
	if _, ok := cfg.AgentVersion(); !ok {
		return errors.Errorf("agent-version must always be set in state")
	}
	for attr := range allAttrs {
		if controller.ControllerOnlyAttribute(attr) {
			return errors.Errorf("cannot set controller attribute %q on a model", attr)
		}
	}
	return nil
}
Example #7
0
// Open implements environs.EnvironProvider.Open.
func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Infof("opening environment %q", cfg.Name())
	if _, ok := cfg.AgentVersion(); !ok {
		newCfg, err := cfg.Apply(map[string]interface{}{
			"agent-version": version.Current.Number.String(),
		})
		if err != nil {
			return nil, err
		}
		cfg = newCfg
	}
	// Set the "namespace" attribute. We do this here, and not in Prepare,
	// for backwards compatibility: older versions did not store the namespace
	// in config.
	if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" {
		username := os.Getenv("USER")
		if username == "" {
			u, err := userCurrent()
			if err != nil {
				return nil, fmt.Errorf("failed to determine username for namespace: %v", err)
			}
			username = u.Username
		}
		var err error
		namespace = fmt.Sprintf("%s-%s", username, cfg.Name())
		cfg, err = cfg.Apply(map[string]interface{}{"namespace": namespace})
		if err != nil {
			return nil, fmt.Errorf("failed to create namespace: %v", err)
		}
	}
	// Do the initial validation on the config.
	localConfig, err := providerInstance.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	if err := VerifyPrerequisites(localConfig.container()); err != nil {
		return nil, fmt.Errorf("failed verification of local provider prerequisites: %v", err)
	}
	environ := &localEnviron{name: cfg.Name()}
	if err := environ.SetConfig(cfg); err != nil {
		return nil, fmt.Errorf("failure setting config: %v", err)
	}
	return environ, nil
}
Example #8
0
// initVersions collects state relevant to an upgrade decision. The returned
// agent and client versions, and the list of currently available tools, will
// always be accurate; the chosen version, and the flag indicating development
// mode, may remain blank until uploadTools or validate is called.
func (c *UpgradeJujuCommand) initVersions(client *api.Client, cfg *config.Config) (*upgradeContext, error) {
	agent, ok := cfg.AgentVersion()
	if !ok {
		// Can't happen. In theory.
		return nil, fmt.Errorf("incomplete environment configuration")
	}
	if c.Version == agent {
		return nil, errUpToDate
	}
	clientVersion := version.Current.Number
	findResult, err := client.FindTools(clientVersion.Major, -1, "", "")
	var availableTools coretools.List
	if params.IsCodeNotImplemented(err) {
		availableTools, err = findTools1dot17(cfg)
	} else {
		availableTools = findResult.List
	}
	if err != nil {
		return nil, err
	}
	err = findResult.Error
	if findResult.Error != nil {
		if !params.IsCodeNotFound(err) {
			return nil, err
		}
		if !c.UploadTools {
			// No tools found and we shouldn't upload any, so if we are not asking for a
			// major upgrade, pretend there is no more recent version available.
			if c.Version == version.Zero && agent.Major == clientVersion.Major {
				return nil, errUpToDate
			}
			return nil, err
		}
	}
	return &upgradeContext{
		agent:     agent,
		client:    clientVersion,
		chosen:    c.Version,
		tools:     availableTools,
		apiClient: client,
		config:    cfg,
	}, nil
}
Example #9
0
func checkToolsAvailability(cfg *config.Config, finder toolsFinder) (version.Number, error) {
	currentVersion, ok := cfg.AgentVersion()
	if !ok || currentVersion == version.Zero {
		return version.Zero, nil
	}

	env, err := newEnvirons(cfg)
	if err != nil {
		return version.Zero, errors.Annotatef(err, "cannot make environ")
	}

	// finder receives major and minor as parameters as it uses them to filter versions and
	// only return patches for the passed major.minor (from major.minor.patch).
	vers, err := finder(env, currentVersion.Major, currentVersion.Minor, tools.ReleasedStream, coretools.Filter{})
	if err != nil {
		return version.Zero, errors.Annotatef(err, "canot find available tools")
	}
	// Newest also returns a list of the items in this list matching with the
	// newest version.
	newest, _ := vers.Newest()
	return newest, nil
}
Example #10
0
// PrepareForCreateEnvironment is specified in the EnvironProvider interface.
func (p environProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
	attrs := map[string]interface{}{
		// We must not proxy SSH through the API server in a
		// local provider environment. Besides not being useful,
		// it may not work; there is no requirement for sshd to
		// be available on machine-0.
		"proxy-ssh": false,
	}
	if _, ok := cfg.AgentVersion(); !ok {
		attrs["agent-version"] = version.Current.Number.String()
	}
	if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" {
		username := os.Getenv("USER")
		if username == "" {
			u, err := userCurrent()
			if err != nil {
				return nil, errors.Annotate(err, "failed to determine username for namespace")
			}
			username = u.Username
		}
		attrs["namespace"] = fmt.Sprintf("%s-%s", username, cfg.Name())
	}

	setIfNotBlank := func(key, value string) {
		if value != "" {
			attrs[key] = value
		}
	}
	// If the user has specified no values for any of the four normal
	// proxies, then look in the environment and set them.
	logger.Tracef("Look for proxies?")
	if cfg.HttpProxy() == "" &&
		cfg.HttpsProxy() == "" &&
		cfg.FtpProxy() == "" &&
		cfg.NoProxy() == "" {
		proxySettings := proxy.DetectProxies()
		logger.Tracef("Proxies detected %#v", proxySettings)
		setIfNotBlank(config.HttpProxyKey, proxySettings.Http)
		setIfNotBlank(config.HttpsProxyKey, proxySettings.Https)
		setIfNotBlank(config.FtpProxyKey, proxySettings.Ftp)
		setIfNotBlank(config.NoProxyKey, proxySettings.NoProxy)
	}
	if version.Current.OS == version.Ubuntu {
		if cfg.AptHttpProxy() == "" &&
			cfg.AptHttpsProxy() == "" &&
			cfg.AptFtpProxy() == "" {
			proxySettings, err := detectPackageProxies()
			if err != nil {
				return nil, errors.Trace(err)
			}
			setIfNotBlank(config.AptHttpProxyKey, proxySettings.Http)
			setIfNotBlank(config.AptHttpsProxyKey, proxySettings.Https)
			setIfNotBlank(config.AptFtpProxyKey, proxySettings.Ftp)
		}
	}

	cfg, err := cfg.Apply(attrs)
	if err != nil {
		return nil, errors.Trace(err)
	}
	// Make sure everything is valid.
	cfg, err = p.Validate(cfg, nil)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return cfg, nil
}
Example #11
0
// PrepareForBootstrap implements environs.EnvironProvider.PrepareForBootstrap.
func (p environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
	attrs := map[string]interface{}{
		// We must not proxy SSH through the API server in a
		// local provider environment. Besides not being useful,
		// it may not work; there is no requirement for sshd to
		// be available on machine-0.
		"proxy-ssh": false,
	}
	if _, ok := cfg.AgentVersion(); !ok {
		attrs["agent-version"] = version.Current.String()
	}
	if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" {
		username := os.Getenv("USER")
		if username == "" {
			u, err := userCurrent()
			if err != nil {
				return nil, errors.Annotate(err, "failed to determine username for namespace")
			}
			username = u.Username
		}
		attrs["namespace"] = fmt.Sprintf("%s-%s", username, cfg.Name())
	}

	setIfNotBlank := func(key, value string) {
		if value != "" {
			attrs[key] = value
		}
	}
	// If the user has specified no values for any of the four normal
	// proxies, then look in the environment and set them.
	logger.Tracef("Look for proxies?")
	if cfg.HttpProxy() == "" &&
		cfg.HttpsProxy() == "" &&
		cfg.FtpProxy() == "" &&
		cfg.NoProxy() == "" {
		proxySettings := proxy.DetectProxies()
		logger.Tracef("Proxies detected %#v", proxySettings)
		setIfNotBlank(config.HttpProxyKey, proxySettings.Http)
		setIfNotBlank(config.HttpsProxyKey, proxySettings.Https)
		setIfNotBlank(config.FtpProxyKey, proxySettings.Ftp)
		setIfNotBlank(config.NoProxyKey, proxySettings.NoProxy)
	}
	if jujuos.HostOS() == jujuos.Ubuntu {
		if cfg.AptHttpProxy() == "" &&
			cfg.AptHttpsProxy() == "" &&
			cfg.AptFtpProxy() == "" {
			proxySettings, err := detectPackageProxies()
			if err != nil {
				return nil, errors.Trace(err)
			}
			setIfNotBlank(config.AptHttpProxyKey, proxySettings.Http)
			setIfNotBlank(config.AptHttpsProxyKey, proxySettings.Https)
			setIfNotBlank(config.AptFtpProxyKey, proxySettings.Ftp)
		}
	}

	cfg, err := cfg.Apply(attrs)
	if err != nil {
		return nil, errors.Trace(err)
	}
	// Make sure everything is valid.
	cfg, err = p.Validate(cfg, nil)
	if err != nil {
		return nil, errors.Trace(err)
	}

	// The user must not set bootstrap-ip; this is determined by the provider,
	// and its presence used to determine whether the environment has yet been
	// bootstrapped.
	if _, ok := cfg.UnknownAttrs()["bootstrap-ip"]; ok {
		return nil, errors.Errorf("bootstrap-ip must not be specified")
	}
	err = checkLocalPort(cfg.StatePort(), "state port")
	if err != nil {
		return nil, errors.Trace(err)
	}
	err = checkLocalPort(cfg.APIPort(), "API port")
	if err != nil {
		return nil, errors.Trace(err)
	}

	return p.Open(cfg)
}
Example #12
0
func finalizeInstanceBootstrapConfig(
	ctx environs.BootstrapContext,
	icfg *instancecfg.InstanceConfig,
	args BootstrapParams,
	cfg *config.Config,
	customImageMetadata []*imagemetadata.ImageMetadata,
) error {
	if icfg.APIInfo != nil || icfg.Controller.MongoInfo != nil {
		return errors.New("machine configuration already has api/state info")
	}
	controllerCfg := icfg.Controller.Config
	caCert, hasCACert := controllerCfg.CACert()
	if !hasCACert {
		return errors.New("controller configuration has no ca-cert")
	}
	icfg.APIInfo = &api.Info{
		Password: args.AdminSecret,
		CACert:   caCert,
		ModelTag: names.NewModelTag(cfg.UUID()),
	}
	icfg.Controller.MongoInfo = &mongo.MongoInfo{
		Password: args.AdminSecret,
		Info:     mongo.Info{CACert: caCert},
	}

	// These really are directly relevant to running a controller.
	// Initially, generate a controller certificate with no host IP
	// addresses in the SAN field. Once the controller is up and the
	// NIC addresses become known, the certificate can be regenerated.
	cert, key, err := controller.GenerateControllerCertAndKey(caCert, args.CAPrivateKey, nil)
	if err != nil {
		return errors.Annotate(err, "cannot generate controller certificate")
	}
	icfg.Bootstrap.StateServingInfo = params.StateServingInfo{
		StatePort:    controllerCfg.StatePort(),
		APIPort:      controllerCfg.APIPort(),
		Cert:         string(cert),
		PrivateKey:   string(key),
		CAPrivateKey: args.CAPrivateKey,
	}
	if _, ok := cfg.AgentVersion(); !ok {
		return errors.New("controller model configuration has no agent-version")
	}

	icfg.Bootstrap.ControllerModelConfig = cfg
	icfg.Bootstrap.CustomImageMetadata = customImageMetadata
	icfg.Bootstrap.ControllerCloudName = args.CloudName
	icfg.Bootstrap.ControllerCloud = args.Cloud
	icfg.Bootstrap.ControllerCloudRegion = args.CloudRegion
	icfg.Bootstrap.ControllerCloudCredential = args.CloudCredential
	icfg.Bootstrap.ControllerCloudCredentialName = args.CloudCredentialName
	icfg.Bootstrap.ControllerConfig = args.ControllerConfig
	icfg.Bootstrap.ControllerInheritedConfig = args.ControllerInheritedConfig
	icfg.Bootstrap.RegionInheritedConfig = args.Cloud.RegionConfig
	icfg.Bootstrap.HostedModelConfig = args.HostedModelConfig
	icfg.Bootstrap.Timeout = args.DialOpts.Timeout
	icfg.Bootstrap.GUI = guiArchive(args.GUIDataSourceBaseURL, func(msg string) {
		ctx.Infof(msg)
	})
	return nil
}