github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/agent/agent.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // Package agent implements the API interfaces 5 // used by the machine agent. 6 7 package agent 8 9 import ( 10 "github.com/juju/errors" 11 "gopkg.in/juju/names.v2" 12 13 "github.com/juju/juju/apiserver/common" 14 "github.com/juju/juju/apiserver/common/cloudspec" 15 "github.com/juju/juju/apiserver/facade" 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/mongo" 18 "github.com/juju/juju/state" 19 "github.com/juju/juju/state/multiwatcher" 20 "github.com/juju/juju/state/stateenvirons" 21 "github.com/juju/juju/state/watcher" 22 ) 23 24 func init() { 25 common.RegisterStandardFacade("Agent", 2, NewAgentAPIV2) 26 } 27 28 // AgentAPIV2 implements the version 2 of the API provided to an agent. 29 type AgentAPIV2 struct { 30 *common.PasswordChanger 31 *common.RebootFlagClearer 32 *common.ModelWatcher 33 *common.ControllerConfigAPI 34 cloudspec.CloudSpecAPI 35 36 st *state.State 37 auth facade.Authorizer 38 resources facade.Resources 39 } 40 41 // NewAgentAPIV2 returns an object implementing version 2 of the Agent API 42 // with the given authorizer representing the currently logged in client. 43 func NewAgentAPIV2(st *state.State, resources facade.Resources, auth facade.Authorizer) (*AgentAPIV2, error) { 44 // Agents are defined to be any user that's not a client user. 45 if !auth.AuthMachineAgent() && !auth.AuthUnitAgent() { 46 return nil, common.ErrPerm 47 } 48 getCanChange := func() (common.AuthFunc, error) { 49 return auth.AuthOwner, nil 50 } 51 environConfigGetter := stateenvirons.EnvironConfigGetter{st} 52 return &AgentAPIV2{ 53 PasswordChanger: common.NewPasswordChanger(st, getCanChange), 54 RebootFlagClearer: common.NewRebootFlagClearer(st, getCanChange), 55 ModelWatcher: common.NewModelWatcher(st, resources, auth), 56 ControllerConfigAPI: common.NewControllerConfig(st), 57 CloudSpecAPI: cloudspec.NewCloudSpec(environConfigGetter.CloudSpec, common.AuthFuncForTag(st.ModelTag())), 58 st: st, 59 auth: auth, 60 resources: resources, 61 }, nil 62 } 63 64 func (api *AgentAPIV2) GetEntities(args params.Entities) params.AgentGetEntitiesResults { 65 results := params.AgentGetEntitiesResults{ 66 Entities: make([]params.AgentGetEntitiesResult, len(args.Entities)), 67 } 68 for i, entity := range args.Entities { 69 tag, err := names.ParseTag(entity.Tag) 70 if err != nil { 71 results.Entities[i].Error = common.ServerError(err) 72 continue 73 } 74 result, err := api.getEntity(tag) 75 result.Error = common.ServerError(err) 76 results.Entities[i] = result 77 } 78 return results 79 } 80 81 func (api *AgentAPIV2) getEntity(tag names.Tag) (result params.AgentGetEntitiesResult, err error) { 82 // Allow only for the owner agent. 83 // Note: having a bulk API call for this is utter madness, given that 84 // this check means we can only ever return a single object. 85 if !api.auth.AuthOwner(tag) { 86 err = common.ErrPerm 87 return 88 } 89 entity0, err := api.st.FindEntity(tag) 90 if err != nil { 91 return 92 } 93 entity, ok := entity0.(state.Lifer) 94 if !ok { 95 err = common.NotSupportedError(tag, "life cycles") 96 return 97 } 98 result.Life = params.Life(entity.Life().String()) 99 if machine, ok := entity.(*state.Machine); ok { 100 result.Jobs = stateJobsToAPIParamsJobs(machine.Jobs()) 101 result.ContainerType = machine.ContainerType() 102 } 103 return 104 } 105 106 func (api *AgentAPIV2) StateServingInfo() (result params.StateServingInfo, err error) { 107 if !api.auth.AuthModelManager() { 108 err = common.ErrPerm 109 return 110 } 111 info, err := api.st.StateServingInfo() 112 if err != nil { 113 return params.StateServingInfo{}, errors.Trace(err) 114 } 115 result = params.StateServingInfo{ 116 APIPort: info.APIPort, 117 StatePort: info.StatePort, 118 Cert: info.Cert, 119 PrivateKey: info.PrivateKey, 120 CAPrivateKey: info.CAPrivateKey, 121 SharedSecret: info.SharedSecret, 122 SystemIdentity: info.SystemIdentity, 123 } 124 125 return result, nil 126 } 127 128 // MongoIsMaster is called by the IsMaster API call 129 // instead of mongo.IsMaster. It exists so it can 130 // be overridden by tests. 131 var MongoIsMaster = mongo.IsMaster 132 133 func (api *AgentAPIV2) IsMaster() (params.IsMasterResult, error) { 134 if !api.auth.AuthModelManager() { 135 return params.IsMasterResult{}, common.ErrPerm 136 } 137 138 switch tag := api.auth.GetAuthTag().(type) { 139 case names.MachineTag: 140 machine, err := api.st.Machine(tag.Id()) 141 if err != nil { 142 return params.IsMasterResult{}, common.ErrPerm 143 } 144 145 session := api.st.MongoSession() 146 isMaster, err := MongoIsMaster(session, machine) 147 return params.IsMasterResult{Master: isMaster}, err 148 default: 149 return params.IsMasterResult{}, errors.Errorf("authenticated entity is not a Machine") 150 } 151 } 152 153 func stateJobsToAPIParamsJobs(jobs []state.MachineJob) []multiwatcher.MachineJob { 154 pjobs := make([]multiwatcher.MachineJob, len(jobs)) 155 for i, job := range jobs { 156 pjobs[i] = multiwatcher.MachineJob(job.String()) 157 } 158 return pjobs 159 } 160 161 // WatchCredentials watches for changes to the specified credentials. 162 func (api *AgentAPIV2) WatchCredentials(args params.Entities) (params.NotifyWatchResults, error) { 163 if !api.auth.AuthModelManager() { 164 return params.NotifyWatchResults{}, common.ErrPerm 165 } 166 167 results := params.NotifyWatchResults{ 168 Results: make([]params.NotifyWatchResult, len(args.Entities)), 169 } 170 for i, entity := range args.Entities { 171 credentialTag, err := names.ParseCloudCredentialTag(entity.Tag) 172 if err != nil { 173 results.Results[i].Error = common.ServerError(err) 174 continue 175 } 176 watch := api.st.WatchCredential(credentialTag) 177 // Consume the initial event. Technically, API calls to Watch 178 // 'transmit' the initial event in the Watch response. But 179 // NotifyWatchers have no state to transmit. 180 if _, ok := <-watch.Changes(); ok { 181 results.Results[i].NotifyWatcherId = api.resources.Register(watch) 182 } else { 183 err = watcher.EnsureErr(watch) 184 results.Results[i].Error = common.ServerError(err) 185 } 186 } 187 return results, nil 188 }