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  }