github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/instancepoller/instancepoller.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package instancepoller
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/utils/clock"
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/apiserver/common"
    13  	"github.com/juju/juju/apiserver/facade"
    14  	"github.com/juju/juju/apiserver/params"
    15  	"github.com/juju/juju/state"
    16  	"github.com/juju/juju/status"
    17  )
    18  
    19  func init() {
    20  	common.RegisterStandardFacade("InstancePoller", 3, newInstancePollerAPI)
    21  }
    22  
    23  // InstancePollerAPI provides access to the InstancePoller API facade.
    24  type InstancePollerAPI struct {
    25  	*common.LifeGetter
    26  	*common.ModelWatcher
    27  	*common.ModelMachinesWatcher
    28  	*common.InstanceIdGetter
    29  	*common.StatusGetter
    30  
    31  	st            StateInterface
    32  	resources     facade.Resources
    33  	authorizer    facade.Authorizer
    34  	accessMachine common.GetAuthFunc
    35  	clock         clock.Clock
    36  }
    37  
    38  // newInstancePollerAPI wraps NewInstancePollerAPI for RegisterStandardFacade.
    39  func newInstancePollerAPI(
    40  	st *state.State,
    41  	resources facade.Resources,
    42  	authorizer facade.Authorizer,
    43  ) (*InstancePollerAPI, error) {
    44  	return NewInstancePollerAPI(st, resources, authorizer, clock.WallClock)
    45  }
    46  
    47  // NewInstancePollerAPI creates a new server-side InstancePoller API
    48  // facade.
    49  func NewInstancePollerAPI(
    50  	st *state.State,
    51  	resources facade.Resources,
    52  	authorizer facade.Authorizer,
    53  	clock clock.Clock,
    54  ) (*InstancePollerAPI, error) {
    55  
    56  	if !authorizer.AuthModelManager() {
    57  		// InstancePoller must run as environment manager.
    58  		return nil, common.ErrPerm
    59  	}
    60  	accessMachine := common.AuthFuncForTagKind(names.MachineTagKind)
    61  	sti := getState(st)
    62  
    63  	// Life() is supported for machines.
    64  	lifeGetter := common.NewLifeGetter(
    65  		sti,
    66  		accessMachine,
    67  	)
    68  	// ModelConfig() and WatchForModelConfigChanges() are allowed
    69  	// with unrestriced access.
    70  	modelWatcher := common.NewModelWatcher(
    71  		sti,
    72  		resources,
    73  		authorizer,
    74  	)
    75  	// WatchModelMachines() is allowed with unrestricted access.
    76  	machinesWatcher := common.NewModelMachinesWatcher(
    77  		sti,
    78  		resources,
    79  		authorizer,
    80  	)
    81  	// InstanceId() is supported for machines.
    82  	instanceIdGetter := common.NewInstanceIdGetter(
    83  		sti,
    84  		accessMachine,
    85  	)
    86  	// Status() is supported for machines.
    87  	statusGetter := common.NewStatusGetter(
    88  		sti,
    89  		accessMachine,
    90  	)
    91  
    92  	return &InstancePollerAPI{
    93  		LifeGetter:           lifeGetter,
    94  		ModelWatcher:         modelWatcher,
    95  		ModelMachinesWatcher: machinesWatcher,
    96  		InstanceIdGetter:     instanceIdGetter,
    97  		StatusGetter:         statusGetter,
    98  		st:                   sti,
    99  		resources:            resources,
   100  		authorizer:           authorizer,
   101  		accessMachine:        accessMachine,
   102  		clock:                clock,
   103  	}, nil
   104  }
   105  
   106  func (a *InstancePollerAPI) getOneMachine(tag string, canAccess common.AuthFunc) (StateMachine, error) {
   107  	machineTag, err := names.ParseMachineTag(tag)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	if !canAccess(machineTag) {
   112  		return nil, common.ErrPerm
   113  	}
   114  	entity, err := a.st.FindEntity(machineTag)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	machine, ok := entity.(StateMachine)
   119  	if !ok {
   120  		return nil, common.NotSupportedError(
   121  			machineTag, fmt.Sprintf("expected machine, got %T", entity),
   122  		)
   123  	}
   124  	return machine, nil
   125  }
   126  
   127  // ProviderAddresses returns the list of all known provider addresses
   128  // for each given entity. Only machine tags are accepted.
   129  func (a *InstancePollerAPI) ProviderAddresses(args params.Entities) (params.MachineAddressesResults, error) {
   130  	result := params.MachineAddressesResults{
   131  		Results: make([]params.MachineAddressesResult, len(args.Entities)),
   132  	}
   133  	canAccess, err := a.accessMachine()
   134  	if err != nil {
   135  		return result, err
   136  	}
   137  	for i, arg := range args.Entities {
   138  		machine, err := a.getOneMachine(arg.Tag, canAccess)
   139  		if err == nil {
   140  			addrs := machine.ProviderAddresses()
   141  			result.Results[i].Addresses = params.FromNetworkAddresses(addrs...)
   142  		}
   143  		result.Results[i].Error = common.ServerError(err)
   144  	}
   145  	return result, nil
   146  }
   147  
   148  // SetProviderAddresses updates the list of known provider addresses
   149  // for each given entity. Only machine tags are accepted.
   150  func (a *InstancePollerAPI) SetProviderAddresses(args params.SetMachinesAddresses) (params.ErrorResults, error) {
   151  	result := params.ErrorResults{
   152  		Results: make([]params.ErrorResult, len(args.MachineAddresses)),
   153  	}
   154  	canAccess, err := a.accessMachine()
   155  	if err != nil {
   156  		return result, err
   157  	}
   158  	for i, arg := range args.MachineAddresses {
   159  		machine, err := a.getOneMachine(arg.Tag, canAccess)
   160  		if err == nil {
   161  			addrsToSet := params.NetworkAddresses(arg.Addresses...)
   162  			err = machine.SetProviderAddresses(addrsToSet...)
   163  		}
   164  		result.Results[i].Error = common.ServerError(err)
   165  	}
   166  	return result, nil
   167  }
   168  
   169  // InstanceStatus returns the instance status for each given entity.
   170  // Only machine tags are accepted.
   171  func (a *InstancePollerAPI) InstanceStatus(args params.Entities) (params.StatusResults, error) {
   172  	result := params.StatusResults{
   173  		Results: make([]params.StatusResult, len(args.Entities)),
   174  	}
   175  	canAccess, err := a.accessMachine()
   176  	if err != nil {
   177  		return result, err
   178  	}
   179  	for i, arg := range args.Entities {
   180  		machine, err := a.getOneMachine(arg.Tag, canAccess)
   181  		if err == nil {
   182  			var statusInfo status.StatusInfo
   183  			statusInfo, err = machine.InstanceStatus()
   184  			result.Results[i].Status = statusInfo.Status.String()
   185  			result.Results[i].Info = statusInfo.Message
   186  			result.Results[i].Data = statusInfo.Data
   187  			result.Results[i].Since = statusInfo.Since
   188  		}
   189  		result.Results[i].Error = common.ServerError(err)
   190  	}
   191  	return result, nil
   192  }
   193  
   194  // SetInstanceStatus updates the instance status for each given
   195  // entity. Only machine tags are accepted.
   196  func (a *InstancePollerAPI) SetInstanceStatus(args params.SetStatus) (params.ErrorResults, error) {
   197  	result := params.ErrorResults{
   198  		Results: make([]params.ErrorResult, len(args.Entities)),
   199  	}
   200  	canAccess, err := a.accessMachine()
   201  	if err != nil {
   202  		return result, err
   203  	}
   204  	for i, arg := range args.Entities {
   205  		machine, err := a.getOneMachine(arg.Tag, canAccess)
   206  		if err == nil {
   207  			now := a.clock.Now()
   208  			s := status.StatusInfo{
   209  				Status:  status.Status(arg.Status),
   210  				Message: arg.Info,
   211  				Data:    arg.Data,
   212  				Since:   &now,
   213  			}
   214  			err = machine.SetInstanceStatus(s)
   215  			if status.Status(arg.Status) == status.ProvisioningError {
   216  				s.Status = status.Error
   217  				if err == nil {
   218  					err = machine.SetStatus(s)
   219  				}
   220  			}
   221  		}
   222  		result.Results[i].Error = common.ServerError(err)
   223  	}
   224  	return result, nil
   225  }
   226  
   227  // AreManuallyProvisioned returns whether each given entity is
   228  // manually provisioned or not. Only machine tags are accepted.
   229  func (a *InstancePollerAPI) AreManuallyProvisioned(args params.Entities) (params.BoolResults, error) {
   230  	result := params.BoolResults{
   231  		Results: make([]params.BoolResult, len(args.Entities)),
   232  	}
   233  	canAccess, err := a.accessMachine()
   234  	if err != nil {
   235  		return result, err
   236  	}
   237  	for i, arg := range args.Entities {
   238  		machine, err := a.getOneMachine(arg.Tag, canAccess)
   239  		if err == nil {
   240  			result.Results[i].Result, err = machine.IsManual()
   241  		}
   242  		result.Results[i].Error = common.ServerError(err)
   243  	}
   244  	return result, nil
   245  }