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