github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/machineactions/machineactions.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Copyright 2016 Cloudbase Solutions
     3  // Licensed under the AGPLv3, see LICENCE file for details.
     4  
     5  // machineactions implements the the apiserver side of
     6  // running actions on machines
     7  package machineactions
     8  
     9  import (
    10  	"github.com/juju/juju/apiserver/common"
    11  	"github.com/juju/juju/apiserver/params"
    12  	"github.com/juju/juju/state"
    13  	"github.com/juju/names"
    14  )
    15  
    16  type Backend interface {
    17  	ActionByTag(tag names.ActionTag) (state.Action, error)
    18  	FindEntity(tag names.Tag) (state.Entity, error)
    19  	TagToActionReceiverFn(findEntity func(names.Tag) (state.Entity, error)) func(string) (state.ActionReceiver, error)
    20  	ConvertActions(ar state.ActionReceiver, fn common.GetActionsFn) ([]params.ActionResult, error)
    21  }
    22  
    23  // Facade implements the machineactions interface and is the concrete
    24  // implementation of the api end point.
    25  type Facade struct {
    26  	backend       Backend
    27  	resources     *common.Resources
    28  	accessMachine common.AuthFunc
    29  }
    30  
    31  // NewFacade creates a new server-side machineactions API end point.
    32  func NewFacade(
    33  	backend Backend,
    34  	resources *common.Resources,
    35  	authorizer common.Authorizer,
    36  ) (*Facade, error) {
    37  	if !authorizer.AuthMachineAgent() {
    38  		return nil, common.ErrPerm
    39  	}
    40  	return &Facade{
    41  		backend:       backend,
    42  		resources:     resources,
    43  		accessMachine: authorizer.AuthOwner,
    44  	}, nil
    45  }
    46  
    47  // Actions returns the Actions by Tags passed and ensures that the machine asking
    48  // for them is the machine that has the actions
    49  func (f *Facade) Actions(args params.Entities) params.ActionResults {
    50  	actionFn := common.AuthAndActionFromTagFn(f.accessMachine, f.backend.ActionByTag)
    51  	return common.Actions(args, actionFn)
    52  }
    53  
    54  // BeginActions marks the actions represented by the passed in Tags as running.
    55  func (f *Facade) BeginActions(args params.Entities) params.ErrorResults {
    56  	actionFn := common.AuthAndActionFromTagFn(f.accessMachine, f.backend.ActionByTag)
    57  	return common.BeginActions(args, actionFn)
    58  }
    59  
    60  // FinishActions saves the result of a completed Action
    61  func (f *Facade) FinishActions(args params.ActionExecutionResults) params.ErrorResults {
    62  	actionFn := common.AuthAndActionFromTagFn(f.accessMachine, f.backend.ActionByTag)
    63  	return common.FinishActions(args, actionFn)
    64  }
    65  
    66  // WatchActionNotifications returns a StringsWatcher for observing
    67  // incoming action calls to a machine.
    68  func (f *Facade) WatchActionNotifications(args params.Entities) params.StringsWatchResults {
    69  	tagToActionReceiver := f.backend.TagToActionReceiverFn(f.backend.FindEntity)
    70  	watchOne := common.WatchOneActionReceiverNotifications(tagToActionReceiver, f.resources.Register)
    71  	return common.WatchActionNotifications(args, f.accessMachine, watchOne)
    72  }
    73  
    74  // RunningActions lists the actions running for the entities passed in.
    75  // If we end up needing more than ListRunning at some point we could follow/abstract
    76  // what's done in the client actions package.
    77  func (f *Facade) RunningActions(args params.Entities) params.ActionsByReceivers {
    78  	canAccess := f.accessMachine
    79  	tagToActionReceiver := f.backend.TagToActionReceiverFn(f.backend.FindEntity)
    80  
    81  	response := params.ActionsByReceivers{
    82  		Actions: make([]params.ActionsByReceiver, len(args.Entities)),
    83  	}
    84  
    85  	for i, entity := range args.Entities {
    86  		currentResult := &response.Actions[i]
    87  		receiver, err := tagToActionReceiver(entity.Tag)
    88  		if err != nil {
    89  			currentResult.Error = common.ServerError(common.ErrBadId)
    90  			continue
    91  		}
    92  		currentResult.Receiver = receiver.Tag().String()
    93  
    94  		if !canAccess(receiver.Tag()) {
    95  			currentResult.Error = common.ServerError(common.ErrPerm)
    96  			continue
    97  		}
    98  
    99  		results, err := f.backend.ConvertActions(receiver, receiver.RunningActions)
   100  		if err != nil {
   101  			currentResult.Error = common.ServerError(err)
   102  			continue
   103  		}
   104  		currentResult.Actions = results
   105  	}
   106  
   107  	return response
   108  }