github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/common/networkingcommon/networkconfigapi.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // The networkconfigapi package implements the network config parts
     5  // common to machiner and provisioner interface
     6  
     7  package networkingcommon
     8  
     9  import (
    10  	"net"
    11  
    12  	"github.com/juju/errors"
    13  	"gopkg.in/juju/names.v2"
    14  
    15  	"github.com/juju/juju/apiserver/common"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/environs/context"
    18  	"github.com/juju/juju/state"
    19  	"github.com/juju/juju/state/stateenvirons"
    20  )
    21  
    22  type NetworkConfigAPI struct {
    23  	st           *state.State
    24  	getCanModify common.GetAuthFunc
    25  
    26  	callContext context.ProviderCallContext
    27  }
    28  
    29  func NewNetworkConfigAPI(st *state.State, callCtx context.ProviderCallContext, getCanModify common.GetAuthFunc) *NetworkConfigAPI {
    30  	return &NetworkConfigAPI{
    31  		st:           st,
    32  		getCanModify: getCanModify,
    33  		callContext:  callCtx,
    34  	}
    35  }
    36  
    37  // SetObservedNetworkConfig reads the network config for the machine identified
    38  // by the input args. This config is merged with the new network config supplied
    39  // in the same args and updated if it has changed.
    40  func (api *NetworkConfigAPI) SetObservedNetworkConfig(args params.SetMachineNetworkConfig) error {
    41  	m, err := api.getMachineForSettingNetworkConfig(args.Tag)
    42  	if err != nil {
    43  		return errors.Trace(err)
    44  	}
    45  	if m.IsContainer() {
    46  		return nil
    47  	}
    48  	observedConfig := args.Config
    49  	logger.Tracef("observed network config of machine %q: %+v", m.Id(), observedConfig)
    50  	if len(observedConfig) == 0 {
    51  		logger.Infof("not updating machine %q network config: no observed network config found", m.Id())
    52  		return nil
    53  	}
    54  
    55  	providerConfig, err := api.getOneMachineProviderNetworkConfig(m)
    56  	if errors.IsNotProvisioned(err) {
    57  		logger.Infof("not updating machine %q network config: %v", m.Id(), err)
    58  		return nil
    59  	}
    60  	if err != nil {
    61  		return errors.Trace(err)
    62  	}
    63  	mergedConfig := observedConfig
    64  	if len(providerConfig) != 0 {
    65  		mergedConfig = MergeProviderAndObservedNetworkConfigs(providerConfig, observedConfig)
    66  		logger.Tracef("merged observed and provider network config for machine %q: %+v", m.Id(), mergedConfig)
    67  	}
    68  
    69  	mergedConfig, err = api.fixUpFanSubnets(mergedConfig)
    70  	if err != nil {
    71  		return errors.Trace(err)
    72  	}
    73  
    74  	return api.setOneMachineNetworkConfig(m, mergedConfig)
    75  }
    76  
    77  // fixUpFanSubnets takes network config and updates FAN subnets with proper CIDR, providerId and providerSubnetId.
    78  // The method how fan overlay is cut into segments is described in network/fan.go.
    79  func (api *NetworkConfigAPI) fixUpFanSubnets(networkConfig []params.NetworkConfig) ([]params.NetworkConfig, error) {
    80  	subnets, err := api.st.AllSubnets()
    81  	if err != nil {
    82  		return nil, errors.Trace(err)
    83  	}
    84  
    85  	var fanSubnets []*state.Subnet
    86  	var fanCIDRs []*net.IPNet
    87  	for _, subnet := range subnets {
    88  		if subnet.FanOverlay() != "" {
    89  			fanSubnets = append(fanSubnets, subnet)
    90  			_, net, err := net.ParseCIDR(subnet.CIDR())
    91  			if err != nil {
    92  				return nil, errors.Trace(err)
    93  			}
    94  			fanCIDRs = append(fanCIDRs, net)
    95  		}
    96  	}
    97  	for i := range networkConfig {
    98  		localIP := net.ParseIP(networkConfig[i].Address)
    99  		for j, fanSubnet := range fanSubnets {
   100  			if fanCIDRs[j].Contains(localIP) {
   101  				networkConfig[i].CIDR = fanSubnet.CIDR()
   102  				networkConfig[i].ProviderId = string(fanSubnet.ProviderId())
   103  				networkConfig[i].ProviderSubnetId = string(fanSubnet.ProviderNetworkId())
   104  				break
   105  			}
   106  		}
   107  	}
   108  	logger.Tracef("Final network config after fixing up FAN subnets %+v", networkConfig)
   109  	return networkConfig, nil
   110  }
   111  
   112  // SetProviderNetworkConfig sets the provider supplied network configuration
   113  // contained in the input args against each machine supplied with said args.
   114  func (api *NetworkConfigAPI) SetProviderNetworkConfig(args params.Entities) (params.ErrorResults, error) {
   115  	logger.Tracef("SetProviderNetworkConfig %+v", args)
   116  	result := params.ErrorResults{
   117  		Results: make([]params.ErrorResult, len(args.Entities)),
   118  	}
   119  
   120  	for i, arg := range args.Entities {
   121  		m, err := api.getMachineForSettingNetworkConfig(arg.Tag)
   122  		if err != nil {
   123  			result.Results[i].Error = common.ServerError(err)
   124  			continue
   125  		}
   126  
   127  		if m.IsContainer() {
   128  			continue
   129  		}
   130  
   131  		providerConfig, err := api.getOneMachineProviderNetworkConfig(m)
   132  		if err != nil {
   133  			result.Results[i].Error = common.ServerError(err)
   134  			continue
   135  		} else if len(providerConfig) == 0 {
   136  			continue
   137  		}
   138  		logger.Tracef("provider network config for %q: %+v", m.Id(), providerConfig)
   139  
   140  		if err := api.setOneMachineNetworkConfig(m, providerConfig); err != nil {
   141  			result.Results[i].Error = common.ServerError(err)
   142  			continue
   143  		}
   144  	}
   145  	return result, nil
   146  }
   147  
   148  func (api *NetworkConfigAPI) getMachineForSettingNetworkConfig(machineTag string) (*state.Machine, error) {
   149  	canModify, err := api.getCanModify()
   150  	if err != nil {
   151  		return nil, errors.Trace(err)
   152  	}
   153  
   154  	tag, err := names.ParseMachineTag(machineTag)
   155  	if err != nil {
   156  		return nil, errors.Trace(err)
   157  	}
   158  	if !canModify(tag) {
   159  		return nil, errors.Trace(common.ErrPerm)
   160  	}
   161  
   162  	m, err := api.getMachine(tag)
   163  	if errors.IsNotFound(err) {
   164  		return nil, errors.Trace(common.ErrPerm)
   165  	} else if err != nil {
   166  		return nil, errors.Trace(err)
   167  	}
   168  
   169  	if m.IsContainer() {
   170  		logger.Debugf("not updating network config for container %q", m.Id())
   171  	}
   172  
   173  	return m, nil
   174  }
   175  
   176  func (api *NetworkConfigAPI) getMachine(tag names.MachineTag) (*state.Machine, error) {
   177  	entity, err := api.st.FindEntity(tag)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	return entity.(*state.Machine), nil
   182  }
   183  
   184  func (api *NetworkConfigAPI) getOneMachineProviderNetworkConfig(m *state.Machine) ([]params.NetworkConfig, error) {
   185  	manual, err := m.IsManual()
   186  	if err != nil {
   187  		return nil, errors.Trace(err)
   188  	}
   189  
   190  	if manual {
   191  		logger.Infof("provider network config not supported on manually provisioned machines")
   192  		return nil, nil
   193  	}
   194  
   195  	model, err := api.st.Model()
   196  	if err != nil {
   197  		return nil, errors.Trace(err)
   198  	}
   199  	netEnviron, err := NetworkingEnvironFromModelConfig(
   200  		stateenvirons.EnvironConfigGetter{
   201  			State: api.st,
   202  			Model: model,
   203  		},
   204  	)
   205  	if errors.IsNotSupported(err) {
   206  		logger.Infof("provider network config not supported: %v", err)
   207  		return nil, nil
   208  	} else if err != nil {
   209  		return nil, errors.Annotate(err, "cannot get provider network config")
   210  	}
   211  
   212  	instId, err := m.InstanceId()
   213  	if err != nil {
   214  		return nil, errors.Trace(err)
   215  	}
   216  
   217  	interfaceInfos, err := netEnviron.NetworkInterfaces(api.callContext, instId)
   218  	if errors.IsNotSupported(err) {
   219  		// It's possible to have a networking environ, but not support
   220  		// NetworkInterfaces(). In leiu of adding SupportsNetworkInterfaces():
   221  		logger.Infof("provider network interfaces not supported: %v", err)
   222  		return nil, nil
   223  	} else if err != nil {
   224  		return nil, errors.Annotatef(err, "cannot get network interfaces of %q", instId)
   225  	}
   226  	if len(interfaceInfos) == 0 {
   227  		logger.Infof("no provider network interfaces found")
   228  		return nil, nil
   229  	}
   230  
   231  	providerConfig := NetworkConfigFromInterfaceInfo(interfaceInfos)
   232  	logger.Tracef("provider network config instance %q: %+v", instId, providerConfig)
   233  
   234  	return providerConfig, nil
   235  }
   236  
   237  func (api *NetworkConfigAPI) setOneMachineNetworkConfig(
   238  	m *state.Machine, networkConfig []params.NetworkConfig,
   239  ) error {
   240  	devicesArgs, devicesAddrs := NetworkConfigsToStateArgs(networkConfig)
   241  
   242  	logger.Debugf("setting devices: %+v", devicesArgs)
   243  	if err := m.SetParentLinkLayerDevicesBeforeTheirChildren(devicesArgs); err != nil {
   244  		return errors.Trace(err)
   245  	}
   246  
   247  	logger.Debugf("setting addresses: %+v", devicesAddrs)
   248  	if err := m.SetDevicesAddressesIdempotently(devicesAddrs); err != nil {
   249  		return errors.Trace(err)
   250  	}
   251  
   252  	logger.Debugf("updated machine %q network config", m.Id())
   253  	return nil
   254  }