// DesiredVersion reports the Agent Version that we want that agent to be running func (u *UpgraderAPI) DesiredVersion(args params.Entities) (params.VersionResults, error) { results := make([]params.VersionResult, len(args.Entities)) if len(args.Entities) == 0 { return params.VersionResults{}, nil } agentVersion, _, err := u.getGlobalAgentVersion() if err != nil { return params.VersionResults{}, common.ServerError(err) } // Is the desired version greater than the current API server version? isNewerVersion := agentVersion.Compare(version.Current.Number) > 0 for i, entity := range args.Entities { err := common.ErrPerm if u.authorizer.AuthOwner(entity.Tag) { if !isNewerVersion || u.entityIsManager(entity.Tag) { results[i].Version = &agentVersion } else { logger.Debugf("desired version is %s, but current version is %s and agent is not a manager node", agentVersion, version.Current.Number) results[i].Version = &version.Current.Number } err = nil } results[i].Error = common.ServerError(err) } return params.VersionResults{Results: results}, nil }
// UpdateLatestRevisions retrieves the latest revision information from the charm store for all deployed charms // and records this information in state. func (api *CharmRevisionUpdaterAPI) UpdateLatestRevisions() (params.ErrorResult, error) { // First get the uuid for the environment to use when querying the charm store. env, err := api.state.Environment() if err != nil { return params.ErrorResult{Error: common.ServerError(err)}, nil } uuid := env.UUID() deployedCharms, err := fetchAllDeployedCharms(api.state) if err != nil { return params.ErrorResult{Error: common.ServerError(err)}, nil } // Look up the revision information for all the deployed charms. curls, err := retrieveLatestCharmInfo(deployedCharms, uuid) if err != nil { return params.ErrorResult{Error: common.ServerError(err)}, nil } // Add the charms and latest revision info to state as charm placeholders. for _, curl := range curls { if err = api.state.AddStoreCharmPlaceholder(curl); err != nil { return params.ErrorResult{Error: common.ServerError(err)}, nil } } return params.ErrorResult{}, nil }
// WatchAuthorisedKeys starts a watcher to track changes to the authorised ssh keys // for the specified machines. // The current implementation relies on global authorised keys being stored in the environment config. // This will change as new user management and authorisation functionality is added. func (api *KeyUpdaterAPI) WatchAuthorisedKeys(arg params.Entities) (params.NotifyWatchResults, error) { results := make([]params.NotifyWatchResult, len(arg.Entities)) canRead, err := api.getCanRead() if err != nil { return params.NotifyWatchResults{}, err } for i, entity := range arg.Entities { // 1. Check permissions if !canRead(entity.Tag) { results[i].Error = common.ServerError(common.ErrPerm) continue } // 2. Check entity exists if _, err := api.state.FindEntity(entity.Tag); err != nil { if errors.IsNotFound(err) { results[i].Error = common.ServerError(common.ErrPerm) } else { results[i].Error = common.ServerError(err) } continue } // 3. Watch fr changes var err error watch := api.state.WatchForEnvironConfigChanges() // Consume the initial event. if _, ok := <-watch.Changes(); ok { results[i].NotifyWatcherId = api.resources.Register(watch) } else { err = watcher.MustErr(watch) } results[i].Error = common.ServerError(err) } return params.NotifyWatchResults{Results: results}, nil }
func (api *UserManagerAPI) AddUser(args params.EntityPasswords) (params.ErrorResults, error) { result := params.ErrorResults{ Results: make([]params.ErrorResult, len(args.Changes)), } if len(args.Changes) == 0 { return result, nil } canWrite, err := api.getCanWrite() if err != nil { result.Results[0].Error = common.ServerError(err) return result, err } for i, arg := range args.Changes { if !canWrite(arg.Tag) { result.Results[0].Error = common.ServerError(common.ErrPerm) continue } _, err := api.state.AddUser(arg.Tag, arg.Password) if err != nil { err = fmt.Errorf("Failed to create user: %v", err) result.Results[i].Error = common.ServerError(err) continue } } return result, nil }
func (api *UserManagerAPI) RemoveUser(args params.Entities) (params.ErrorResults, error) { result := params.ErrorResults{ Results: make([]params.ErrorResult, len(args.Entities)), } if len(args.Entities) == 0 { return result, nil } canWrite, err := api.getCanWrite() if err != nil { return result, err } for i, arg := range args.Entities { if !canWrite(arg.Tag) { result.Results[i].Error = common.ServerError(common.ErrPerm) continue } user, err := api.state.User(arg.Tag) if err != nil { result.Results[i].Error = common.ServerError(common.ErrPerm) continue } err = user.Deactivate() if err != nil { result.Results[i].Error = common.ServerError(fmt.Errorf("Failed to remove user: %s", err)) continue } } return result, nil }
// SetRsyslogCert sets the rsyslog CACert. func (api *RsyslogAPI) SetRsyslogCert(args params.SetRsyslogCertParams) (params.ErrorResult, error) { var result params.ErrorResult if !api.canModify { result.Error = common.ServerError(common.ErrBadCreds) return result, nil } if _, err := cert.ParseCert(string(args.CACert)); err != nil { result.Error = common.ServerError(err) return result, nil } attrs := map[string]interface{}{"rsyslog-ca-cert": string(args.CACert)} if err := api.st.UpdateEnvironConfig(attrs, nil, nil); err != nil { result.Error = common.ServerError(err) } return result, nil }
// AuthorisedKeys reports the authorised ssh keys for the specified machines. // The current implementation relies on global authorised keys being stored in the environment config. // This will change as new user management and authorisation functionality is added. func (api *KeyUpdaterAPI) AuthorisedKeys(arg params.Entities) (params.StringsResults, error) { if len(arg.Entities) == 0 { return params.StringsResults{}, nil } results := make([]params.StringsResult, len(arg.Entities)) // For now, authorised keys are global, common to all machines. var keys []string config, configErr := api.state.EnvironConfig() if configErr == nil { keys = ssh.SplitAuthorisedKeys(config.AuthorizedKeys()) } canRead, err := api.getCanRead() if err != nil { return params.StringsResults{}, err } for i, entity := range arg.Entities { // 1. Check permissions if !canRead(entity.Tag) { results[i].Error = common.ServerError(common.ErrPerm) continue } // 2. Check entity exists if _, err := api.state.FindEntity(entity.Tag); err != nil { if errors.IsNotFound(err) { results[i].Error = common.ServerError(common.ErrPerm) } else { results[i].Error = common.ServerError(err) } continue } // 3. Get keys var err error if configErr == nil { results[i].Result = keys } else { err = configErr } results[i].Error = common.ServerError(err) } return params.StringsResults{Results: results}, nil }
func (api *API) GetEntities(args params.Entities) params.AgentGetEntitiesResults { results := params.AgentGetEntitiesResults{ Entities: make([]params.AgentGetEntitiesResult, len(args.Entities)), } for i, entity := range args.Entities { result, err := api.getEntity(entity.Tag) result.Error = common.ServerError(err) results.Entities[i] = result } return results }
// Tools finds the tools necessary for the given agents. func (u *UnitUpgraderAPI) Tools(args params.Entities) (params.ToolsResults, error) { result := params.ToolsResults{ Results: make([]params.ToolsResult, len(args.Entities)), } for i, entity := range args.Entities { result.Results[i].Error = common.ServerError(common.ErrPerm) if u.authorizer.AuthOwner(entity.Tag) { result.Results[i] = u.getMachineTools(entity.Tag) } } return result, nil }
func (u *UnitUpgraderAPI) getMachineTools(tag string) params.ToolsResult { var result params.ToolsResult machine, err := u.getAssignedMachine(tag) if err != nil { result.Error = common.ServerError(err) return result } machineTools, err := machine.AgentTools() if err != nil { result.Error = common.ServerError(err) return result } // For older 1.16 upgrader workers, we need to supply a tools URL since the worker will attempt to // download the tools even though they already have been fetched by the machine agent. Newer upgrader // workers do not have this problem. So to be compatible across all versions, we return the full // tools metadata. // TODO (wallyworld) - remove in 1.20, just return machineTools cfg, err := u.st.EnvironConfig() if err != nil { result.Error = common.ServerError(err) return result } // SSLHostnameVerification defaults to true, so we need to // invert that, for backwards-compatibility (older versions // will have DisableSSLHostnameVerification: false by default). result.DisableSSLHostnameVerification = !cfg.SSLHostnameVerification() env, err := environs.New(cfg) if err != nil { result.Error = common.ServerError(err) return result } agentTools, err := envtools.FindExactTools( env, machineTools.Version.Number, machineTools.Version.Series, machineTools.Version.Arch) if err != nil { result.Error = common.ServerError(err) return result } result.Tools = agentTools return result }
// AddMachinesV2 adds new machines with the supplied parameters. func (c *Client) AddMachinesV2(args params.AddMachines) (params.AddMachinesResults, error) { results := params.AddMachinesResults{ Machines: make([]params.AddMachinesResult, len(args.MachineParams)), } for i, p := range args.MachineParams { m, err := c.addOneMachine(p) results.Machines[i].Error = common.ServerError(err) if err == nil { results.Machines[i].Machine = m.Id() } } return results, nil }
// DesiredVersion reports the Agent Version that we want that unit to be running. // The desired version is what the unit's assigned machine is running. func (u *UnitUpgraderAPI) DesiredVersion(args params.Entities) (params.VersionResults, error) { result := make([]params.VersionResult, len(args.Entities)) if len(args.Entities) == 0 { return params.VersionResults{}, nil } for i, entity := range args.Entities { err := common.ErrPerm if u.authorizer.AuthOwner(entity.Tag) { result[i].Version, err = u.getMachineToolsVersion(entity.Tag) } result[i].Error = common.ServerError(err) } return params.VersionResults{Results: result}, nil }
// WatchAPIVersion starts a watcher to track if there is a new version // of the API that we want to upgrade to. The watcher tracks changes to // the unit's assigned machine since that's where the required agent version is stored. func (u *UnitUpgraderAPI) WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) { result := params.NotifyWatchResults{ Results: make([]params.NotifyWatchResult, len(args.Entities)), } for i, agent := range args.Entities { err := common.ErrPerm if u.authorizer.AuthOwner(agent.Tag) { var watcherId string watcherId, err = u.watchAssignedMachine(agent.Tag) if err == nil { result.Results[i].NotifyWatcherId = watcherId } } result.Results[i].Error = common.ServerError(err) } return result, nil }
// FindTools returns a List containing all tools matching the given parameters. func (c *Client) FindTools(args params.FindToolsParams) (params.FindToolsResults, error) { result := params.FindToolsResults{} // Get the existing environment config from the state. envConfig, err := c.api.state.EnvironConfig() if err != nil { return result, err } env, err := environs.New(envConfig) if err != nil { return result, err } filter := coretools.Filter{ Arch: args.Arch, Series: args.Series, } result.List, err = envtools.FindTools(env, args.MajorVersion, args.MinorVersion, filter, envtools.DoNotAllowRetry) result.Error = common.ServerError(err) return result, nil }
// WatchLoggingConfig starts a watcher to track changes to the logging config // for the agents specified.. Unfortunately the current infrastruture makes // watching parts of the config non-trivial, so currently any change to the // config will cause the watcher to notify the client. func (api *LoggerAPI) WatchLoggingConfig(arg params.Entities) params.NotifyWatchResults { result := make([]params.NotifyWatchResult, len(arg.Entities)) for i, entity := range arg.Entities { err := common.ErrPerm if api.authorizer.AuthOwner(entity.Tag) { watch := api.state.WatchForEnvironConfigChanges() // Consume the initial event. Technically, API calls to Watch // 'transmit' the initial event in the Watch response. But // NotifyWatchers have no state to transmit. if _, ok := <-watch.Changes(); ok { result[i].NotifyWatcherId = api.resources.Register(watch) err = nil } else { err = watcher.MustErr(watch) } } result[i].Error = common.ServerError(err) } return params.NotifyWatchResults{Results: result} }
// LoggingConfig reports the logging configuration for the agents specified. func (api *LoggerAPI) LoggingConfig(arg params.Entities) params.StringResults { if len(arg.Entities) == 0 { return params.StringResults{} } results := make([]params.StringResult, len(arg.Entities)) config, configErr := api.state.EnvironConfig() for i, entity := range arg.Entities { err := common.ErrPerm if api.authorizer.AuthOwner(entity.Tag) { if configErr == nil { results[i].Result = config.LoggingConfig() err = nil } else { err = configErr } } results[i].Error = common.ServerError(err) } return params.StringResults{Results: results} }
// GetRsyslogConfig returns a RsyslogConfigResult. func (api *RsyslogAPI) GetRsyslogConfig(args params.Entities) (params.RsyslogConfigResults, error) { result := params.RsyslogConfigResults{ Results: make([]params.RsyslogConfigResult, len(args.Entities)), } cfg, err := api.st.EnvironConfig() if err != nil { return result, err } for i := range args.Entities { rsyslogCfg, err := newRsyslogConfig(cfg, api) if err == nil { result.Results[i] = params.RsyslogConfigResult{ CACert: rsyslogCfg.CACert, Port: rsyslogCfg.Port, HostPorts: rsyslogCfg.HostPorts, } } else { result.Results[i].Error = common.ServerError(err) } } return result, nil }
// WatchAPIVersion starts a watcher to track if there is a new version // of the API that we want to upgrade to func (u *UpgraderAPI) WatchAPIVersion(args params.Entities) (params.NotifyWatchResults, error) { result := params.NotifyWatchResults{ Results: make([]params.NotifyWatchResult, len(args.Entities)), } for i, agent := range args.Entities { err := common.ErrPerm if u.authorizer.AuthOwner(agent.Tag) { watch := u.st.WatchForEnvironConfigChanges() // Consume the initial event. Technically, API // calls to Watch 'transmit' the initial event // in the Watch response. But NotifyWatchers // have no state to transmit. if _, ok := <-watch.Changes(); ok { result.Results[i].NotifyWatcherId = u.resources.Register(watch) err = nil } else { err = watcher.MustErr(watch) } } result.Results[i].Error = common.ServerError(err) } return result, nil }
// WatchForRsyslogChanges starts a watcher to track if there are changes // that require we update the rsyslog.d configurations for a machine and/or unit. func (api *RsyslogAPI) WatchForRsyslogChanges(args params.Entities) (params.NotifyWatchResults, error) { result := params.NotifyWatchResults{ Results: make([]params.NotifyWatchResult, len(args.Entities)), } for i := range args.Entities { err := common.ErrPerm if api.authorizer.AuthMachineAgent() || api.authorizer.AuthUnitAgent() { watch := api.st.WatchAPIHostPorts() // Consume the initial event. Technically, API // calls to Watch 'transmit' the initial event // in the Watch response. But NotifyWatchers // have no state to transmit. if _, ok := <-watch.Changes(); ok { result.Results[i].NotifyWatcherId = api.resources.Register(watch) err = nil } else { err = watcher.MustErr(watch) } } result.Results[i].Error = common.ServerError(err) } return result, nil }
func serverError(err error) error { if err := common.ServerError(err); err != nil { return err } return nil }