// ServiceGet returns the configuration for the named service. func ServiceGet(st *state.State, p params.ServiceGet) (params.ServiceGetResults, error) { service, err := st.Service(p.ServiceName) if err != nil { return params.ServiceGetResults{}, err } settings, err := service.ConfigSettings() if err != nil { return params.ServiceGetResults{}, err } charm, _, err := service.Charm() if err != nil { return params.ServiceGetResults{}, err } configInfo := describe(settings, charm.Config()) var constraints constraints.Value if service.IsPrincipal() { constraints, err = service.Constraints() if err != nil { return params.ServiceGetResults{}, err } } return params.ServiceGetResults{ Service: p.ServiceName, Charm: charm.Meta().Name, Config: configInfo, Constraints: constraints, }, nil }
// UpdateConfigSettings changes a service's charm config settings. Values set // to nil will be deleted; unknown and invalid values will return an error. func (s *Service) UpdateConfigSettings(changes charm.Settings) error { charm, _, err := s.Charm() if err != nil { return err } changes, err = charm.Config().ValidateSettings(changes) if err != nil { return 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 service // name, so the actual impact of a race is non-threatening. node, err := readSettings(s.st, s.settingsKey()) if err != nil { return err } for name, value := range changes { if value == nil { node.Delete(name) } else { node.Set(name, value) } } _, err = node.Write() return err }
// Run fetches the configuration of the service and formats // the result as a YAML string. func (c *GetCommand) Run(ctx *cmd.Context) error { conn, err := juju.NewConnFromName(c.EnvName) if err != nil { return err } defer conn.Close() svc, err := conn.State.Service(c.ServiceName) if err != nil { return err } svcfg, err := svc.Config() if err != nil { return err } charm, _, err := svc.Charm() if err != nil { return err } chcfg := charm.Config().Options config := merge(svcfg.Map(), chcfg) result := map[string]interface{}{ "service": svc.Name(), "charm": charm.Meta().Name, "settings": config, } return c.out.Write(ctx, result) }
func (s *clientSuite) TestClientServiceDeployPrincipal(c *C) { // TODO(fwereade): test ToMachineSpec directly on srvClient, when we // manage to extract it as a package and can thus do it conveniently. store, restore := makeMockCharmStore() defer restore() curl, bundle := addCharm(c, store, "dummy") mem4g := constraints.MustParse("mem=4G") err := s.APIState.Client().ServiceDeploy( curl.String(), "service", 3, "", mem4g, ) c.Assert(err, IsNil) service, err := s.State.Service("service") c.Assert(err, IsNil) charm, force, err := service.Charm() c.Assert(err, IsNil) c.Assert(force, Equals, false) c.Assert(charm.URL(), DeepEquals, curl) c.Assert(charm.Meta(), DeepEquals, bundle.Meta()) c.Assert(charm.Config(), DeepEquals, bundle.Config()) cons, err := service.Constraints() c.Assert(err, IsNil) c.Assert(cons, DeepEquals, mem4g) units, err := service.AllUnits() c.Assert(err, IsNil) for _, unit := range units { mid, err := unit.AssignedMachineId() c.Assert(err, IsNil) machine, err := s.State.Machine(mid) c.Assert(err, IsNil) cons, err := machine.Constraints() c.Assert(err, IsNil) c.Assert(cons, DeepEquals, mem4g) } }
// CharmInfo returns information about the requested charm. func (c *Client) CharmInfo(args params.CharmInfo) (api.CharmInfo, error) { curl, err := charm.ParseURL(args.CharmURL) if err != nil { return api.CharmInfo{}, err } charm, err := c.api.state.Charm(curl) if err != nil { return api.CharmInfo{}, err } info := api.CharmInfo{ Revision: charm.Revision(), URL: curl.String(), Config: charm.Config(), Meta: charm.Meta(), } return info, nil }
// ConfigSettings returns the complete set of service charm config settings // available to the unit. Unset values will be replaced with the default // value for the associated option, and may thus be nil when no default is // specified. func (u *Unit) ConfigSettings() (charm.Settings, error) { if u.doc.CharmURL == nil { return nil, fmt.Errorf("unit charm not set") } settings, err := readSettings(u.st, serviceSettingsKey(u.doc.Service, u.doc.CharmURL)) if err != nil { return nil, err } charm, err := u.st.Charm(u.doc.CharmURL) if err != nil { return nil, err } result := charm.Config().DefaultSettings() for name, value := range settings.Map() { result[name] = value } return result, nil }
func (s *clientSuite) TestClientServiceDeploySubordinate(c *C) { store, restore := makeMockCharmStore() defer restore() curl, bundle := addCharm(c, store, "logging") err := s.APIState.Client().ServiceDeploy( curl.String(), "service-name", 0, "", constraints.Value{}, ) service, err := s.State.Service("service-name") c.Assert(err, IsNil) charm, force, err := service.Charm() c.Assert(err, IsNil) c.Assert(force, Equals, false) c.Assert(charm.URL(), DeepEquals, curl) c.Assert(charm.Meta(), DeepEquals, bundle.Meta()) c.Assert(charm.Config(), DeepEquals, bundle.Config()) units, err := service.AllUnits() c.Assert(err, IsNil) c.Assert(units, HasLen, 0) }
func (s *clientSuite) TestClientCharmInfo(c *C) { // Use wordpress for tests so that we can compare Provides and Requires. charm := s.AddTestingCharm(c, "wordpress") for i, t := range clientCharmInfoTests { c.Logf("test %d. %s", i, t.about) info, err := s.APIState.Client().CharmInfo(t.url) if t.err != "" { c.Assert(err, ErrorMatches, t.err) continue } c.Assert(err, IsNil) expected := &api.CharmInfo{ Revision: charm.Revision(), URL: charm.URL().String(), Config: charm.Config(), Meta: charm.Meta(), } c.Assert(info, DeepEquals, expected) } }