github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/network/containerizer/shim.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package containerizer
     5  
     6  import (
     7  	"github.com/juju/collections/set"
     8  	"github.com/juju/errors"
     9  	jujucharm "gopkg.in/juju/charm.v6"
    10  
    11  	"github.com/juju/juju/core/constraints"
    12  	"github.com/juju/juju/core/instance"
    13  	"github.com/juju/juju/state"
    14  )
    15  
    16  // LinkLayerDevice is an indirection for state.LinkLayerDevice.
    17  // It facilitates testing the provisioner's use of this package.
    18  type LinkLayerDevice interface {
    19  	Name() string
    20  	Type() state.LinkLayerDeviceType
    21  	MACAddress() string
    22  	ParentName() string
    23  	ParentDevice() (LinkLayerDevice, error)
    24  	EthernetDeviceForBridge(name string) (state.LinkLayerDeviceArgs, error)
    25  	Addresses() ([]*state.Address, error)
    26  
    27  	// These are recruited in tests. See comment on Machine below.
    28  	MTU() uint
    29  	IsUp() bool
    30  	IsAutoStart() bool
    31  }
    32  
    33  // linkLayerDevice implements LinkLayerDevice.
    34  // We need our own implementation of the indirection above in order to mock the
    35  // return of ParentDevice, which in the state package returns a reference to a
    36  // raw state.LinkLayerDevice.
    37  type linkLayerDevice struct {
    38  	*state.LinkLayerDevice
    39  }
    40  
    41  // ParentDevice implements LinkLayerDevice by wrapping the response from the
    42  // inner device's call in a new instance of linkLayerDevice.
    43  func (l *linkLayerDevice) ParentDevice() (LinkLayerDevice, error) {
    44  	dev, err := l.LinkLayerDevice.ParentDevice()
    45  	if err != nil {
    46  		return nil, errors.Trace(err)
    47  	}
    48  	return &linkLayerDevice{dev}, nil
    49  }
    50  
    51  var _ LinkLayerDevice = (*linkLayerDevice)(nil)
    52  
    53  // Machine is an indirection for state.Machine,
    54  // describing a machine that is to host containers.
    55  type Machine interface {
    56  	Id() string
    57  	AllSpaces() (set.Strings, error)
    58  	LinkLayerDevicesForSpaces([]string) (map[string][]LinkLayerDevice, error)
    59  	SetLinkLayerDevices(devicesArgs ...state.LinkLayerDeviceArgs) (err error)
    60  	AllLinkLayerDevices() ([]LinkLayerDevice, error)
    61  
    62  	// TODO (manadart 2018-10-10) These methods are used in tests, which rely
    63  	// on the StateSuite. Some of them are recruited via the Container
    64  	// interface below, but they are all located here for simplicity.
    65  	// A better approach could be sought that does not require their
    66  	// presence here.
    67  	SetDevicesAddresses(devicesAddresses ...state.LinkLayerDeviceAddress) (err error)
    68  	SetParentLinkLayerDevicesBeforeTheirChildren(devicesArgs []state.LinkLayerDeviceArgs) error
    69  	SetConstraints(cons constraints.Value) (err error)
    70  	RemoveAllAddresses() error
    71  	Raw() *state.Machine
    72  }
    73  
    74  // MachineShim implements Machine.
    75  // It is required to mock the return of LinkLayerDevicesForSpaces,
    76  // which includes raw state.LinkLayerDevice references.
    77  type MachineShim struct {
    78  	*state.Machine
    79  }
    80  
    81  // LinkLayerDevicesForSpaces implements Machine by unwrapping the inner
    82  // state.Machine call and wrapping the raw state.LinkLayerDevice references
    83  // with the local LinkLayerDevice implementation.
    84  func (m *MachineShim) LinkLayerDevicesForSpaces(spaces []string) (map[string][]LinkLayerDevice, error) {
    85  	spaceDevs, err := m.Machine.LinkLayerDevicesForSpaces(spaces)
    86  	if err != nil {
    87  		return nil, errors.Trace(err)
    88  	}
    89  
    90  	wrapped := make(map[string][]LinkLayerDevice, len(spaceDevs))
    91  	for space, devs := range spaceDevs {
    92  		wrappedDevs := make([]LinkLayerDevice, len(devs))
    93  		for i, d := range devs {
    94  			wrappedDevs[i] = &linkLayerDevice{d}
    95  		}
    96  		wrapped[space] = wrappedDevs
    97  	}
    98  	return wrapped, nil
    99  }
   100  
   101  // AllLinkLayerDevices implements Machine by wrapping each
   102  // state.LinkLayerDevice reference in returned collection with the local
   103  // LinkLayerDevice implementation.
   104  func (m *MachineShim) AllLinkLayerDevices() ([]LinkLayerDevice, error) {
   105  	devs, err := m.Machine.AllLinkLayerDevices()
   106  	if err != nil {
   107  		return nil, errors.Trace(err)
   108  	}
   109  
   110  	wrapped := make([]LinkLayerDevice, len(devs))
   111  	for i, d := range devs {
   112  		wrapped[i] = &linkLayerDevice{d}
   113  	}
   114  	return wrapped, nil
   115  }
   116  
   117  // Raw returns the inner state.Machine reference.
   118  func (m *MachineShim) Raw() *state.Machine {
   119  	return m.Machine
   120  }
   121  
   122  // Machine is an indirection for state.Machine,
   123  // describing a container.
   124  type Container interface {
   125  	Machine
   126  	ContainerType() instance.ContainerType
   127  	DesiredSpaces() (set.Strings, error)
   128  }
   129  
   130  var _ Container = (*MachineShim)(nil)
   131  
   132  func (m *MachineShim) Units() ([]Unit, error) {
   133  	units, err := m.Machine.Units()
   134  	if err != nil {
   135  		return nil, errors.Trace(err)
   136  	}
   137  	wrapped := make([]Unit, len(units))
   138  	for i, u := range units {
   139  		wrapped[i] = &unitShim{u}
   140  	}
   141  	return wrapped, nil
   142  }
   143  
   144  // Unit, Application & Charm are used to facilitate mocks
   145  // for testing in apiserver/.../agent/provisioner.  This is a
   146  // by product of bad design.
   147  
   148  // unitShim implements Unit.
   149  // It is required to mock the return of Units from MachineShim.
   150  type unitShim struct {
   151  	*state.Unit
   152  }
   153  
   154  var _ Unit = (*unitShim)(nil)
   155  
   156  type Unit interface {
   157  	Application() (Application, error)
   158  	Name() string
   159  }
   160  
   161  func (u *unitShim) Application() (Application, error) {
   162  	app, err := u.Unit.Application()
   163  	if err != nil {
   164  		return nil, errors.Trace(err)
   165  	}
   166  	return &applicationShim{app}, nil
   167  }
   168  
   169  // applicationShim implements Application.
   170  // It is required to mock the return an Application from unitShim.
   171  type applicationShim struct {
   172  	*state.Application
   173  }
   174  
   175  var _ Application = (*applicationShim)(nil)
   176  
   177  type Application interface {
   178  	Charm() (Charm, bool, error)
   179  	Name() string
   180  }
   181  
   182  func (a *applicationShim) Charm() (Charm, bool, error) {
   183  	return a.Application.Charm()
   184  }
   185  
   186  type Charm interface {
   187  	LXDProfile() *jujucharm.LXDProfile
   188  	Revision() int
   189  }