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