github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/uniter/lxdprofile.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	names "gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/apiserver/facade"
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/state"
    15  	"github.com/juju/juju/state/watcher"
    16  )
    17  
    18  //go:generate mockgen -package mocks -destination mocks/lxdprofile.go github.com/juju/juju/apiserver/facades/agent/uniter LXDProfileBackend,LXDProfileMachine,LXDProfileUnit
    19  
    20  type LXDProfileBackend interface {
    21  	Machine(string) (LXDProfileMachine, error)
    22  	Unit(string) (LXDProfileUnit, error)
    23  }
    24  
    25  // LXDProfileMachine describes machine-receiver state methods
    26  // for executing a lxd profile upgrade.
    27  type LXDProfileMachine interface {
    28  	WatchLXDProfileUpgradeNotifications(string) (state.StringsWatcher, error)
    29  	Units() ([]LXDProfileUnit, error)
    30  	RemoveUpgradeCharmProfileData() error
    31  }
    32  
    33  // LXDProfileUnit describes unit-receiver state methods
    34  // for executing a lxd profile upgrade.
    35  type LXDProfileUnit interface {
    36  	Tag() names.Tag
    37  	AssignedMachineId() (string, error)
    38  }
    39  
    40  type LXDProfileAPI struct {
    41  	backend   LXDProfileBackend
    42  	resources facade.Resources
    43  
    44  	logger loggo.Logger
    45  
    46  	accessUnitOrMachine common.GetAuthFunc
    47  	AccessMachine       common.GetAuthFunc
    48  	accessUnit          common.GetAuthFunc
    49  }
    50  
    51  // NewLXDProfileAPI returns a new LXDProfileAPI. Currently both
    52  // GetAuthFuncs can used to determine current permissions.
    53  func NewLXDProfileAPI(
    54  	backend LXDProfileBackend,
    55  	resources facade.Resources,
    56  	authorizer facade.Authorizer,
    57  	accessMachine common.GetAuthFunc,
    58  	accessUnit common.GetAuthFunc,
    59  	logger loggo.Logger,
    60  ) *LXDProfileAPI {
    61  	logger.Tracef("NewLXDProfileAPI called with %s", authorizer.GetAuthTag())
    62  	return &LXDProfileAPI{
    63  		backend:             backend,
    64  		resources:           resources,
    65  		accessUnitOrMachine: common.AuthAny(accessUnit, accessMachine),
    66  		AccessMachine:       accessMachine,
    67  		accessUnit:          accessUnit,
    68  		logger:              logger,
    69  	}
    70  }
    71  
    72  // LXDProfileState implements the LXDProfileBackend indirection
    73  // over state.State.
    74  type LXDProfileState struct {
    75  	st *state.State
    76  }
    77  
    78  func (s LXDProfileState) Machine(id string) (LXDProfileMachine, error) {
    79  	m, err := s.st.Machine(id)
    80  	return &lxdProfileMachine{m}, err
    81  }
    82  
    83  func (s LXDProfileState) Unit(id string) (LXDProfileUnit, error) {
    84  	return s.st.Unit(id)
    85  }
    86  
    87  type lxdProfileMachine struct {
    88  	*state.Machine
    89  }
    90  
    91  // Units maintains the LXDProfileMachine indirection by wrapping the call to
    92  // state.Machine.Units().
    93  func (m *lxdProfileMachine) Units() ([]LXDProfileUnit, error) {
    94  	units, err := m.Machine.Units()
    95  	if err != nil {
    96  		return nil, errors.Trace(err)
    97  	}
    98  
    99  	wrapped := make([]LXDProfileUnit, len(units))
   100  	for i, u := range units {
   101  		wrapped[i] = u
   102  	}
   103  	return wrapped, nil
   104  }
   105  
   106  // NewExternalLXDProfileAPI can be used for API registration.
   107  func NewExternalLXDProfileAPI(
   108  	st *state.State,
   109  	resources facade.Resources,
   110  	authorizer facade.Authorizer,
   111  	accessMachine common.GetAuthFunc,
   112  	accessUnit common.GetAuthFunc,
   113  	logger loggo.Logger,
   114  ) *LXDProfileAPI {
   115  	return NewLXDProfileAPI(
   116  		LXDProfileState{st},
   117  		resources,
   118  		authorizer,
   119  		accessMachine, accessUnit,
   120  		logger,
   121  	)
   122  }
   123  
   124  // WatchLXDProfileUpgradeNotifications returns a StringsWatcher for observing
   125  // changes to the lxd profile changes.
   126  func (u *LXDProfileAPI) WatchLXDProfileUpgradeNotifications(args params.LXDProfileUpgrade) (params.StringsWatchResults, error) {
   127  	u.logger.Tracef("Starting WatchLXDProfileUpgradeNotifications with %+v", args)
   128  	result := params.StringsWatchResults{
   129  		Results: make([]params.StringsWatchResult, len(args.Entities)),
   130  	}
   131  	canAccess, err := u.accessUnitOrMachine()
   132  	if err != nil {
   133  		return params.StringsWatchResults{}, err
   134  	}
   135  	for i, entity := range args.Entities {
   136  		tag, err := names.ParseTag(entity.Tag)
   137  		if err != nil {
   138  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   139  			continue
   140  		}
   141  
   142  		if !canAccess(tag) {
   143  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   144  			continue
   145  		}
   146  		machine, err := u.getMachine(tag)
   147  		if err != nil {
   148  			result.Results[i].Error = common.ServerError(err)
   149  			continue
   150  		}
   151  
   152  		watcherId, initial, err := u.watchOneChangeLXDProfileUpgradeNotifications(machine, args.ApplicationName)
   153  		if err != nil {
   154  			result.Results[i].Error = common.ServerError(err)
   155  			continue
   156  		}
   157  
   158  		result.Results[i].StringsWatcherId = watcherId
   159  		result.Results[i].Changes = initial
   160  	}
   161  	return result, nil
   162  }
   163  
   164  func (u *LXDProfileAPI) watchOneChangeLXDProfileUpgradeNotifications(machine LXDProfileMachine, applicationName string) (string, []string, error) {
   165  	watch, err := machine.WatchLXDProfileUpgradeNotifications(applicationName)
   166  	if err != nil {
   167  		return "", nil, errors.Trace(err)
   168  	}
   169  
   170  	if changes, ok := <-watch.Changes(); ok {
   171  		return u.resources.Register(watch), changes, nil
   172  	}
   173  	return "", nil, watcher.EnsureErr(watch)
   174  }
   175  
   176  // RemoveUpgradeCharmProfileData is intended to clean up the LXDProfile status
   177  // to ensure that we start from a clean slate.
   178  func (u *LXDProfileAPI) RemoveUpgradeCharmProfileData(args params.Entities) (params.ErrorResults, error) {
   179  	u.logger.Tracef("Starting RemoveUpgradeCharmProfileData with %+v", args)
   180  	result := params.ErrorResults{
   181  		Results: make([]params.ErrorResult, len(args.Entities)),
   182  	}
   183  	canAccess, err := u.accessUnitOrMachine()
   184  	if err != nil {
   185  		return params.ErrorResults{}, err
   186  	}
   187  	for i, entity := range args.Entities {
   188  		tag, err := names.ParseTag(entity.Tag)
   189  		if err != nil {
   190  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   191  			continue
   192  		}
   193  
   194  		if !canAccess(tag) {
   195  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   196  			continue
   197  		}
   198  		machine, err := u.getMachine(tag)
   199  		if err != nil {
   200  			result.Results[i].Error = common.ServerError(err)
   201  			continue
   202  		}
   203  		err = machine.RemoveUpgradeCharmProfileData()
   204  		if err != nil {
   205  			result.Results[i].Error = common.ServerError(err)
   206  			continue
   207  		}
   208  	}
   209  	return result, nil
   210  }
   211  
   212  func (u *LXDProfileAPI) getMachine(tag names.Tag) (LXDProfileMachine, error) {
   213  	var id string
   214  	switch tag.Kind() {
   215  	case names.MachineTagKind:
   216  		id = tag.Id()
   217  	case names.UnitTagKind:
   218  		unit, err := u.backend.Unit(tag.Id())
   219  		if err != nil {
   220  
   221  		}
   222  		id, err = unit.AssignedMachineId()
   223  		if err != nil {
   224  			return nil, err
   225  		}
   226  	default:
   227  	}
   228  	return u.backend.Machine(id)
   229  }
   230  
   231  func (u *LXDProfileAPI) getUnit(tag names.Tag) (LXDProfileUnit, error) {
   232  	return u.backend.Unit(tag.Id())
   233  }