// splitApplicationAndCharmConfigFromYAML extracts app specific settings from a charm config YAML
// and returns those app settings plus a YAML with just the charm settings left behind.
962523
func splitApplicationAndCharmConfigFromYAML(modelType state.ModelType, inYaml, appName string) (
	appCfg map[string]interface{},
	outYaml string,
	_ error,
) {
	var allSettings map[string]map[string]interface{}
	if err := goyaml.Unmarshal([]byte(inYaml), &allSettings); err != nil {
		return nil, "", errors.Annotate(err, "cannot parse settings data")
	}
	settings, ok := allSettings[appName]
	if !ok {
		return nil, "", errors.Errorf("no settings found for %q", appName)
	}

	providerSchema, _, err := applicationConfigSchema(modelType)
	if err != nil {
		return nil, "", errors.Trace(err)
	}
	appConfigKeys := application.KnownConfigKeys(providerSchema)

	appConfigAttrs := make(map[string]interface{})
	for k, v := range settings {
		if appConfigKeys.Contains(k) {
			appConfigAttrs[k] = v
			delete(settings, k)
		}
	}
	if len(settings) == 0 {
		return appConfigAttrs, "", nil
	}

	allSettings[appName] = settings
	charmConfig, err := goyaml.Marshal(allSettings)
	if err != nil {
		return nil, "", errors.Annotate(err, "cannot marshall charm settings")
	}
	return appConfigAttrs, string(charmConfig), nil
}
69730
func (c *configCommand) setConfigFromFile(client applicationAPI, ctx *cmd.Context) error {
	var (
		b   []byte
		err error
	)
	if c.configFile.Path == "-" {
		buf := bytes.Buffer{}
		if _, err := buf.ReadFrom(ctx.Stdin); err != nil {
			return errors.Trace(err)
		}
		b = buf.Bytes()
	} else {
		b, err = c.configFile.Read(ctx)
		if err != nil {
			return errors.Trace(err)
		}
	}
	return errors.Trace(block.ProcessBlockedError(
		client.Update(
			params.ApplicationUpdate{
				ApplicationName: c.applicationName,
				SettingsYAML:    string(b),
				Generation:      c.branchName,
			},
		), block.BlockChange))
}
1189476
func (st *State) AllCharms() ([]*Charm, error) {
	charmsCollection, closer := st.db().GetCollection(charmsC)
	defer closer()
	var cdoc charmDoc
	var charms []*Charm
	iter := charmsCollection.Find(nsLife.notDead()).Iter()
	for iter.Next(&cdoc) {
		ch := newCharm(st, &cdoc)
		charms = append(charms, ch)
	}
	return charms, errors.Trace(iter.Close())
}
233627
func (r RepoLogger) ParseLogLevelConfig(conf string) (map[string]LogLevel, error) {
	setlist := strings.Split(conf, ",")
	out := make(map[string]LogLevel)
	for _, setstring := range setlist {
		setting := strings.Split(setstring, "=")
		if len(setting) != 2 {
			return nil, errors.New("oddly structured `pkg=level` option: " + setstring)
		}
		l, err := ParseLevel(setting[1])
		if err != nil {
			return nil, err
		}
		out[setting[0]] = l
	}
	return out, nil
}
74639
func (c *Client) UnsetApplicationConfig(branchName, application string, options []string) error {
	if c.BestAPIVersion() < 6 {
		return errors.NotSupportedf("UnsetApplicationConfig not supported by this version of Juju")
	}
	args := params.ApplicationConfigUnsetArgs{
		Args: []params.ApplicationUnset{{
			ApplicationName: application,
			BranchName:      branchName,
			Options:         options,
		}},
	}
	var results params.ErrorResults
	err := c.facade.FacadeCall("UnsetApplicationsConfig", args, &results)
	if err != nil {
		return errors.Trace(err)
	}
	return results.OneError()
}
325296
func (v *VersionInfo) MarshalYAML() (interface{}, error) {

	return &struct {
		SemVer         string `yaml:"semver"`
		ShaLong        string `yaml:"shaLong"`
		BuildTimestamp int64  `yaml:"buildTimestamp"`
		Branch         string `yaml:"branch"`
		Arch           string `yaml:"arch"`
	}{
		SemVer:         v.SemVer,
		ShaLong:        v.ShaLong,
		BuildTimestamp: v.BuildTimestamp.Unix(),
		Branch:         v.Branch,
		Arch:           v.Arch,
	}, nil
}
545320
func (a *Application) SetCharm(cfg SetCharmConfig) (err error) {
	defer errors.DeferredAnnotatef(
		&err, "cannot upgrade application %q to charm %q", a, cfg.Charm,
	)
	if cfg.Charm.Meta().Subordinate != a.doc.Subordinate {
		return errors.Errorf("cannot change an application's subordinacy")
	}
	currentCharm, err := a.st.Charm(a.doc.CharmURL)
	if err != nil {
		return errors.Trace(err)
	}
	if cfg.Charm.Meta().Deployment != currentCharm.Meta().Deployment {
		if currentCharm.Meta().Deployment == nil ||
			cfg.Charm.Meta().Deployment.DeploymentType != currentCharm.Meta().Deployment.DeploymentType {
			return errors.New("cannot change a charm's deployment type")
		}
	}
	// For old style charms written for only one series, we still retain
	// this check. Newer charms written for multi-series have a URL
	// with series = "".
	if cfg.Charm.URL().Series != "" {
		if cfg.Charm.URL().Series != a.doc.Series {
			return errors.Errorf("cannot change an application's series")
		}
	} else if !cfg.ForceSeries {
		supported := false
		for _, oneSeries := range cfg.Charm.Meta().Series {
			if oneSeries == a.doc.Series {
				supported = true
				break
			}
		}
		if !supported {
			supportedSeries := "no series"
			if len(cfg.Charm.Meta().Series) > 0 {
				supportedSeries = strings.Join(cfg.Charm.Meta().Series, ", ")
			}
			return errors.Errorf("only these series are supported: %v", supportedSeries)
		}
	} else {
		// Even with forceSeries=true, we do not allow a charm to be used which is for
		// a different OS. This assumes the charm declares it has supported series which
		// we can check for OS compatibility. Otherwise, we just accept the series supplied.
		currentOS, err := series.GetOSFromSeries(a.doc.Series)
		if err != nil {
			// We don't expect an error here but there's not much we can
			// do to recover.
			return err
		}
		supportedOS := false
		supportedSeries := cfg.Charm.Meta().Series
		for _, chSeries := range supportedSeries {
			charmSeriesOS, err := series.GetOSFromSeries(chSeries)
			if err != nil {
				return nil
			}
			if currentOS == charmSeriesOS {
				supportedOS = true
				break
			}
		}
		if !supportedOS && len(supportedSeries) > 0 {
			return errors.Errorf("OS %q not supported by charm", currentOS)
		}
	}

	updatedSettings, err := cfg.Charm.Config().ValidateSettings(cfg.ConfigSettings)
	if err != nil {
		return errors.Annotate(err, "validating config settings")
	}

	// we don't need to check that this is a charm.LXDProfiler, as we can
	// state that the function exists.
	if profile := cfg.Charm.LXDProfile(); profile != nil {
		// Validate the config devices, to ensure we don't apply an invalid
		// profile, if we know it's never going to work.
		if err := profile.ValidateConfigDevices(); err != nil && !cfg.Force {
			return errors.Annotate(err, "validating lxd profile")
		}
	}

	var newCharmModifiedVersion int
	channel := string(cfg.Channel)
	acopy := &Application{a.st, a.doc}
	buildTxn := func(attempt int) ([]txn.Op, error) {
		a := acopy
		if attempt > 0 {
			if err := a.Refresh(); err != nil {
				return nil, errors.Trace(err)
			}
		}

		// NOTE: We're explicitly allowing SetCharm to succeed
		// when the application is Dying, because application/charm
		// upgrades should still be allowed to apply to dying
		// applications and units, so that bugs in departed/broken
		// hooks can be addressed at runtime.
		if a.Life() == Dead {
			return nil, ErrDead
		}

		// Record the current value of charmModifiedVersion, so we can
		// set the value on the method receiver's in-memory document
		// structure. We increment the version only when we change the
		// charm URL.
		newCharmModifiedVersion = a.doc.CharmModifiedVersion

		ops := []txn.Op{{
			C:  applicationsC,
			Id: a.doc.DocID,
			Assert: append(notDeadDoc, bson.DocElem{
				"charmmodifiedversion", a.doc.CharmModifiedVersion,
			}),
		}}

		if a.doc.CharmURL.String() == cfg.Charm.URL().String() {
			// Charm URL already set; just update the force flag and channel.
			ops = append(ops, txn.Op{
				C:  applicationsC,
				Id: a.doc.DocID,
				Update: bson.D{{"$set", bson.D{
					{"cs-channel", channel},
					{"forcecharm", cfg.ForceUnits},
				}}},
			})
		} else {
			chng, err := a.changeCharmOps(
				cfg.Charm,
				channel,
				updatedSettings,
				cfg.ForceUnits,
				cfg.ResourceIDs,
				cfg.StorageConstraints,
			)
			if err != nil {
				return nil, errors.Trace(err)
			}
			ops = append(ops, chng...)
			newCharmModifiedVersion++
		}

		return ops, nil
	}
	if err := a.st.db().Run(buildTxn); err != nil {
		return err
	}
	a.doc.CharmURL = cfg.Charm.URL()
	a.doc.Channel = channel
	a.doc.ForceCharm = cfg.ForceUnits
	a.doc.CharmModifiedVersion = newCharmModifiedVersion
	return nil
}
463267
func (api *APIBase) CharmConfig(args params.ApplicationGetArgs) (params.ApplicationGetConfigResults, error) {
	if err := api.checkCanRead(); err != nil {
		return params.ApplicationGetConfigResults{}, err
	}
	results := params.ApplicationGetConfigResults{
		Results: make([]params.ConfigResult, len(args.Args)),
	}
	for i, arg := range args.Args {
		config, err := api.getCharmConfig(arg.BranchName, arg.ApplicationName)
		results.Results[i].Config = config
		results.Results[i].Error = common.ServerError(err)
	}
	return results, nil
}
903365
func (a *ActionAPI) ApplicationsCharmsActions(args params.Entities) (params.ApplicationsCharmActionsResults, error) {
	result := params.ApplicationsCharmActionsResults{Results: make([]params.ApplicationCharmActionsResult, len(args.Entities))}
	if err := a.checkCanWrite(); err != nil {
		return result, errors.Trace(err)
	}

	for i, entity := range args.Entities {
		currentResult := &result.Results[i]
		svcTag, err := names.ParseApplicationTag(entity.Tag)
		if err != nil {
			currentResult.Error = common.ServerError(common.ErrBadId)
			continue
		}
		currentResult.ApplicationTag = svcTag.String()
		svc, err := a.state.Application(svcTag.Id())
		if err != nil {
			currentResult.Error = common.ServerError(err)
			continue
		}
		ch, _, err := svc.Charm()
		if err != nil {
			currentResult.Error = common.ServerError(err)
			continue
		}
		if actions := ch.Actions(); actions != nil {
			charmActions := make(map[string]params.ActionSpec)
			for key, value := range actions.ActionSpecs {
				charmActions[key] = params.ActionSpec{
					Description: value.Description,
					Params:      value.Params,
				}
			}
			currentResult.Actions = charmActions
		}
	}
	return result, nil
}
458948
func (a *Application) ApplicationConfig() (application.ConfigAttributes, error) {
	config, err := readSettings(a.st.db(), settingsC, a.applicationConfigKey())
	if errors.IsNotFound(err) || len(config.Keys()) == 0 {
		return application.ConfigAttributes(nil), nil
	} else if err != nil {
		return nil, errors.Annotatef(err, "application config for application %q", a.doc.Name)
	}
	return application.ConfigAttributes(config.Map()), nil
}
499391
func (c *Client) ChangeApplicationofBareMetalServer(id string, appID string) error {
	values := url.Values{
		"SUBID": {id},
		"APPID": {appID},
	}

	return c.post(`baremetal/app_change`, values, nil)
}
586188
func appConfig() (*config, error) {
	configURL := os.Getenv("CAMLI_APP_CONFIG_URL")
	if configURL == "" {
		return nil, fmt.Errorf("Publisher application needs a CAMLI_APP_CONFIG_URL env var")
	}
	cl, err := app.Client()
	if err != nil {
		return nil, fmt.Errorf("could not get a client to fetch extra config: %v", err)
	}
	conf := &config{}
	pause := time.Second
	giveupTime := time.Now().Add(time.Hour)
	for {
		err := cl.GetJSON(context.TODO(), configURL, conf)
		if err == nil {
			break
		}
		if time.Now().After(giveupTime) {
			logger.Fatalf("Giving up on starting: could not get app config at %v: %v", configURL, err)
		}
		logger.Printf("could not get app config at %v: %v. Will retry in a while.", configURL, err)
		time.Sleep(pause)
		pause *= 2
	}
	return conf, nil
}
497163
func (u *Unit) SetCharmURL(curl *charm.URL) error {
	if curl == nil {
		return fmt.Errorf("cannot set nil charm url")
	}

	db, closer := u.st.newDB()
	defer closer()
	units, closer := db.GetCollection(unitsC)
	defer closer()
	charms, closer := db.GetCollection(charmsC)
	defer closer()

	buildTxn := func(attempt int) ([]txn.Op, error) {
		if attempt > 0 {
			// NOTE: We're explicitly allowing SetCharmURL to succeed
			// when the unit is Dying, because application/charm upgrades
			// should still be allowed to apply to dying units, so
			// that bugs in departed/broken hooks can be addressed at
			// runtime.
			if notDead, err := isNotDeadWithSession(units, u.doc.DocID); err != nil {
				return nil, errors.Trace(err)
			} else if !notDead {
				return nil, ErrDead
			}
		}
		sel := bson.D{{"_id", u.doc.DocID}, {"charmurl", curl}}
		if count, err := units.Find(sel).Count(); err != nil {
			return nil, errors.Trace(err)
		} else if count == 1 {
			// Already set
			return nil, jujutxn.ErrNoOperations
		}
		if count, err := charms.FindId(curl.String()).Count(); err != nil {
			return nil, errors.Trace(err)
		} else if count < 1 {
			return nil, errors.Errorf("unknown charm url %q", curl)
		}

		// Add a reference to the application settings for the new charm.
		incOps, err := appCharmIncRefOps(u.st, u.doc.Application, curl, false)
		if err != nil {
			return nil, errors.Trace(err)
		}

		// Set the new charm URL.
		differentCharm := bson.D{{"charmurl", bson.D{{"$ne", curl}}}}
		ops := append(incOps,
			txn.Op{
				C:      unitsC,
				Id:     u.doc.DocID,
				Assert: append(notDeadDoc, differentCharm...),
				Update: bson.D{{"$set", bson.D{{"charmurl", curl}}}},
			})
		if u.doc.CharmURL != nil {
			// Drop the reference to the old charm.
			// Since we can force this now, let's.. There is no point hanging on to the old charm.
			op := &ForcedOperation{Force: true}
			decOps, err := appCharmDecRefOps(u.st, u.doc.Application, u.doc.CharmURL, true, op)
			if err != nil {
				// No need to stop further processing if the old key could not be removed.
				logger.Errorf("could not remove old charm references for %v:%v", u.doc.CharmURL, err)
			}
			if len(op.Errors) != 0 {
				logger.Errorf("could not remove old charm references for %v:%v", u.doc.CharmURL, op.Errors)
			}
			ops = append(ops, decOps...)
		}
		return ops, nil
	}
	err := u.st.db().Run(buildTxn)
	if err == nil {
		u.doc.CharmURL = curl
	}
	return err
}
1249121
func SplitYAMLFile(body []byte, strict bool) ([]wfv1.Workflow, error) {
	manifestsStrings := yamlSeparator.Split(string(body), -1)
	manifests := make([]wfv1.Workflow, 0)
	for _, manifestStr := range manifestsStrings {
		if strings.TrimSpace(manifestStr) == "" {
			continue
		}
		var wf wfv1.Workflow
		var opts []yaml.JSONOpt
		if strict {
			opts = append(opts, yaml.DisallowUnknownFields) // nolint
		}
		err := yaml.Unmarshal([]byte(manifestStr), &wf, opts...)
		if wf.Kind != "" && wf.Kind != workflow.Kind {
			// If we get here, it was a k8s manifest which was not of type 'Workflow'
			// We ignore these since we only care about Workflow manifests.
			continue
		}
		if err != nil {
			return nil, errors.New(errors.CodeBadRequest, err.Error())
		}
		manifests = append(manifests, wf)
	}
	return manifests, nil
}
51134
func (a *Application) UpdateCharmConfig(branchName string, changes charm.Settings) error {
	ch, _, err := a.Charm()
	if err != nil {
		return errors.Trace(err)
	}
	changes, err = ch.Config().ValidateSettings(changes)
	if err != nil {
		return errors.Trace(err)
	}

	// TODO(fwereade) state.Settings is itself really problematic in just
	// about every use case. This needs to be resolved some time; but at
	// least the settings docs are keyed by charm url as well as application
	// name, so the actual impact of a race is non-threatening.
	current, err := readSettings(a.st.db(), settingsC, a.charmConfigKey())
	if err != nil {
		return errors.Annotatef(err, "charm config for application %q", a.doc.Name)
	}

	if branchName == model.GenerationMaster {
		return errors.Trace(a.updateMasterConfig(current, changes))
	}
	return errors.Trace(a.updateBranchConfig(branchName, current, changes))
}
728326
func (s Services) MarshalYAML() (interface{}, error) {
	services := map[string]ServiceConfig{}
	for _, service := range s {
		services[service.Name] = service
	}
	return services, nil
}
362337
func (c *Client) CharmRelations(application string) ([]string, error) {
	var results params.ApplicationCharmRelationsResults
	args := params.ApplicationCharmRelations{ApplicationName: application}
	err := c.facade.FacadeCall("CharmRelations", args, &results)
	return results.CharmRelations, err
}