github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "github.com/juju/names" 12 13 "github.com/juju/juju/apiserver/common" 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/mongo" 16 "github.com/juju/juju/state" 17 "github.com/juju/juju/state/multiwatcher" 18 ) 19 20 func init() { 21 common.RegisterStandardFacade("Agent", 2, NewAgentAPIV2) 22 } 23 24 // AgentAPIV2 implements the version 2 of the API provided to an agent. 25 type AgentAPIV2 struct { 26 *common.PasswordChanger 27 *common.RebootFlagClearer 28 *common.ModelWatcher 29 30 st *state.State 31 auth common.Authorizer 32 } 33 34 // NewAgentAPIV2 returns an object implementing version 2 of the Agent API 35 // with the given authorizer representing the currently logged in client. 36 func NewAgentAPIV2(st *state.State, resources *common.Resources, auth common.Authorizer) (*AgentAPIV2, error) { 37 // Agents are defined to be any user that's not a client user. 38 if !auth.AuthMachineAgent() && !auth.AuthUnitAgent() { 39 return nil, common.ErrPerm 40 } 41 getCanChange := func() (common.AuthFunc, error) { 42 return auth.AuthOwner, nil 43 } 44 return &AgentAPIV2{ 45 PasswordChanger: common.NewPasswordChanger(st, getCanChange), 46 RebootFlagClearer: common.NewRebootFlagClearer(st, getCanChange), 47 ModelWatcher: common.NewModelWatcher(st, resources, auth), 48 st: st, 49 auth: auth, 50 }, nil 51 } 52 53 func (api *AgentAPIV2) GetEntities(args params.Entities) params.AgentGetEntitiesResults { 54 results := params.AgentGetEntitiesResults{ 55 Entities: make([]params.AgentGetEntitiesResult, len(args.Entities)), 56 } 57 for i, entity := range args.Entities { 58 tag, err := names.ParseTag(entity.Tag) 59 if err != nil { 60 results.Entities[i].Error = common.ServerError(err) 61 continue 62 } 63 result, err := api.getEntity(tag) 64 result.Error = common.ServerError(err) 65 results.Entities[i] = result 66 } 67 return results 68 } 69 70 func (api *AgentAPIV2) getEntity(tag names.Tag) (result params.AgentGetEntitiesResult, err error) { 71 // Allow only for the owner agent. 72 // Note: having a bulk API call for this is utter madness, given that 73 // this check means we can only ever return a single object. 74 if !api.auth.AuthOwner(tag) { 75 err = common.ErrPerm 76 return 77 } 78 entity0, err := api.st.FindEntity(tag) 79 if err != nil { 80 return 81 } 82 entity, ok := entity0.(state.Lifer) 83 if !ok { 84 err = common.NotSupportedError(tag, "life cycles") 85 return 86 } 87 result.Life = params.Life(entity.Life().String()) 88 if machine, ok := entity.(*state.Machine); ok { 89 result.Jobs = stateJobsToAPIParamsJobs(machine.Jobs()) 90 result.ContainerType = machine.ContainerType() 91 } 92 return 93 } 94 95 func (api *AgentAPIV2) StateServingInfo() (result state.StateServingInfo, err error) { 96 if !api.auth.AuthModelManager() { 97 err = common.ErrPerm 98 return 99 } 100 return api.st.StateServingInfo() 101 } 102 103 // MongoIsMaster is called by the IsMaster API call 104 // instead of mongo.IsMaster. It exists so it can 105 // be overridden by tests. 106 var MongoIsMaster = mongo.IsMaster 107 108 func (api *AgentAPIV2) IsMaster() (params.IsMasterResult, error) { 109 if !api.auth.AuthModelManager() { 110 return params.IsMasterResult{}, common.ErrPerm 111 } 112 113 switch tag := api.auth.GetAuthTag().(type) { 114 case names.MachineTag: 115 machine, err := api.st.Machine(tag.Id()) 116 if err != nil { 117 return params.IsMasterResult{}, common.ErrPerm 118 } 119 120 session := api.st.MongoSession() 121 isMaster, err := MongoIsMaster(session, machine) 122 return params.IsMasterResult{Master: isMaster}, err 123 default: 124 return params.IsMasterResult{}, errors.Errorf("authenticated entity is not a Machine") 125 } 126 } 127 128 func stateJobsToAPIParamsJobs(jobs []state.MachineJob) []multiwatcher.MachineJob { 129 pjobs := make([]multiwatcher.MachineJob, len(jobs)) 130 for i, job := range jobs { 131 pjobs[i] = multiwatcher.MachineJob(job.String()) 132 } 133 return pjobs 134 }