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 }