Example #1
0
File: deploy.go Project: makyo/juju
// charmSeries determine what series to use with a charm.
// Order of preference is:
// - user requested or defined by bundle when deploying
// - default from charm metadata supported series
// - model default
// - charm store default
func charmSeries(
	requestedSeries, seriesFromCharm string,
	supportedSeries []string,
	force bool,
	conf *config.Config,
	fromBundle bool,
) (string, string, error) {
	// User has requested a series and we have a new charm with series in metadata.
	if requestedSeries != "" && seriesFromCharm == "" {
		if !force && !isSeriesSupported(requestedSeries, supportedSeries) {
			return "", "", charm.NewUnsupportedSeriesError(requestedSeries, supportedSeries)
		}
		if fromBundle {
			return requestedSeries, msgBundleSeries, nil
		} else {
			return requestedSeries, msgUserRequestedSeries, nil
		}
	}

	// User has requested a series and it's an old charm for a single series.
	if seriesFromCharm != "" {
		if !force && requestedSeries != "" && requestedSeries != seriesFromCharm {
			return "", "", charm.NewUnsupportedSeriesError(requestedSeries, []string{seriesFromCharm})
		}
		if requestedSeries != "" {
			if fromBundle {
				return requestedSeries, msgBundleSeries, nil
			} else {
				return requestedSeries, msgUserRequestedSeries, nil
			}
		}
		return seriesFromCharm, msgSingleCharmSeries, nil
	}

	// Use charm default.
	if len(supportedSeries) > 0 {
		return supportedSeries[0], msgDefaultCharmSeries, nil
	}

	// Use model default supported series.
	if defaultSeries, ok := conf.DefaultSeries(); ok {
		if !force && !isSeriesSupported(defaultSeries, supportedSeries) {
			return "", "", charm.NewUnsupportedSeriesError(defaultSeries, supportedSeries)
		}
		return defaultSeries, msgDefaultModelSeries, nil
	}

	// Use latest LTS.
	latestLtsSeries := config.LatestLtsSeries()
	if !force && !isSeriesSupported(latestLtsSeries, supportedSeries) {
		return "", "", charm.NewUnsupportedSeriesError(latestLtsSeries, supportedSeries)
	}
	return latestLtsSeries, msgLatestLTSSeries, nil
}
Example #2
0
// SeriesToUpload returns the supplied series with duplicates removed if
// non-empty; otherwise it returns a default list of series we should
// probably upload, based on cfg.
func SeriesToUpload(cfg *config.Config, series []string) []string {
	unique := set.NewStrings(series...)
	if unique.IsEmpty() {
		unique.Add(version.Current.Series)
		for _, toolsSeries := range ToolsLtsSeries {
			unique.Add(toolsSeries)
		}
		if series, ok := cfg.DefaultSeries(); ok {
			unique.Add(series)
		}
	}
	return unique.SortedValues()
}
Example #3
0
File: store.go Project: bac/juju
func resolveCharm(
	resolveWithChannel func(*charm.URL) (*charm.URL, csparams.Channel, []string, error),
	conf *config.Config,
	url *charm.URL,
) (*charm.URL, csparams.Channel, []string, error) {
	if url.Schema != "cs" {
		return nil, csparams.NoChannel, nil, errors.Errorf("unknown schema for charm URL %q", url)
	}
	// If the user hasn't explicitly asked for a particular series,
	// query for the charm that matches the model's default series.
	// If this fails, we'll fall back to asking for whatever charm is available.
	defaultedSeries := false
	if url.Series == "" {
		if s, ok := conf.DefaultSeries(); ok {
			defaultedSeries = true
			// TODO(katco): Don't update the value passed in. Not only
			// is there no indication that this method will do so, we
			// return a charm.URL which signals to the developer that
			// we don't modify the original.
			url.Series = s
		}
	}

	resultURL, channel, supportedSeries, err := resolveWithChannel(url)
	if defaultedSeries && errors.Cause(err) == csparams.ErrNotFound {
		// we tried to use the model's default the series, but the store said it doesn't exist.
		// retry without the defaulted series, to take what we can get.
		url.Series = ""
		resultURL, channel, supportedSeries, err = resolveWithChannel(url)
	}
	if err != nil {
		return nil, csparams.NoChannel, nil, errors.Trace(err)
	}
	if resultURL.Series != "" && len(supportedSeries) == 0 {
		supportedSeries = []string{resultURL.Series}
	}
	return resultURL, channel, supportedSeries, nil
}
Example #4
0
// resolveCharmURL returns a resolved charm URL, given a charm location string.
// If the series is not resolved, the environment default-series is used, or if
// not set, the series is resolved with the state server.
func resolveCharmURL(url string, client *api.Client, conf *config.Config) (*charm.URL, error) {
	ref, series, err := charm.ParseReference(url)
	if err != nil {
		return nil, err
	}
	// If series is not set, use configured default series
	if series == "" {
		if defaultSeries, ok := conf.DefaultSeries(); ok {
			series = defaultSeries
		}
	}
	// Otherwise, look up the best supported series for this charm
	if series == "" {
		if ref.Schema == "local" {
			possibleUrl := &charm.URL{Reference: ref, Series: "precise"}
			logger.Errorf(`The series is not specified in the environment (default-series) or with the charm. Did you mean:
	%s`, possibleUrl.String())
			return nil, fmt.Errorf("cannot resolve series for charm: %q", ref)
		}
		return client.ResolveCharm(ref)
	}
	return &charm.URL{Reference: ref, Series: series}, nil
}
Example #5
0
// resolveCharmURL returns a resolved charm URL, given a charm location string.
// If the series is not resolved, the environment default-series is used, or if
// not set, the series is resolved with the state server.
func resolveCharmURL(url string, client *api.Client, conf *config.Config) (*charm.URL, error) {
	ref, err := charm.ParseReference(url)
	if err != nil {
		return nil, err
	}
	// If series is not set, use configured default series
	if ref.Series == "" {
		if defaultSeries, ok := conf.DefaultSeries(); ok {
			ref.Series = defaultSeries
		}
	}
	if ref.Series != "" {
		return ref.URL("")
	}
	// Otherwise, look up the best supported series for this charm
	if ref.Schema != "local" {
		return client.ResolveCharm(ref)
	}
	possibleURL := *ref
	possibleURL.Series = "precise"
	logger.Errorf("The series is not specified in the environment (default-series) or with the charm. Did you mean:\n\t%s", &possibleURL)
	return nil, fmt.Errorf("cannot resolve series for charm: %q", ref)
}
Example #6
0
// resolveCharmURL resolves the given charm URL string
// by looking it up in the appropriate charm repository.
// If it is a charm store charm URL, the given csParams will
// be used to access the charm store repository.
// If it is a local charm URL, the local charm repository at
// the given repoPath will be used. The given configuration
// will be used to add any necessary attributes to the repo
// and to resolve the default series if possible.
//
// resolveCharmURL also returns the charm repository holding
// the charm.
func resolveCharmURL(curlStr string, csParams charmrepo.NewCharmStoreParams, repoPath string, conf *config.Config) (*charm.URL, charmrepo.Interface, error) {
	ref, err := charm.ParseReference(curlStr)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	repo, err := charmrepo.InferRepository(ref, csParams, repoPath)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	repo = config.SpecializeCharmRepo(repo, conf)
	if ref.Series == "" {
		if defaultSeries, ok := conf.DefaultSeries(); ok {
			ref.Series = defaultSeries
		}
	}
	if ref.Schema == "local" && ref.Series == "" {
		possibleURL := *ref
		possibleURL.Series = "trusty"
		logger.Errorf("The series is not specified in the environment (default-series) or with the charm. Did you mean:\n\t%s", &possibleURL)
		return nil, nil, errors.Errorf("cannot resolve series for charm: %q", ref)
	}
	if ref.Series != "" && ref.Revision != -1 {
		// The URL is already fully resolved; do not
		// bother with an unnecessary round-trip to the
		// charm store.
		curl, err := ref.URL("")
		if err != nil {
			panic(err)
		}
		return curl, repo, nil
	}
	curl, err := repo.Resolve(ref)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	return curl, repo, nil
}