github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/machine_linklayerdevices.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "fmt" 8 "net" 9 10 "github.com/juju/collections/set" 11 "github.com/juju/errors" 12 "github.com/juju/mgo/v3" 13 "github.com/juju/mgo/v3/bson" 14 "github.com/juju/mgo/v3/txn" 15 jujutxn "github.com/juju/txn/v3" 16 17 corenetwork "github.com/juju/juju/core/network" 18 ) 19 20 // LinkLayerDevice returns the link-layer device matching the given name. An 21 // error satisfying errors.IsNotFound() is returned when no such device exists 22 // on the machine. 23 func (m *Machine) LinkLayerDevice(name string) (*LinkLayerDevice, error) { 24 devID := linkLayerDeviceDocIDFromName(m.st, m.doc.Id, name) 25 dev, err := m.st.LinkLayerDevice(devID) 26 return dev, errors.Trace(err) 27 } 28 29 func linkLayerDeviceDocIDFromName(st *State, machineID, deviceName string) string { 30 return st.docID(linkLayerDeviceGlobalKey(machineID, deviceName)) 31 } 32 33 // AllLinkLayerDevices returns all exiting link-layer devices of the machine. 34 func (m *Machine) AllLinkLayerDevices() ([]*LinkLayerDevice, error) { 35 var allDevices []*LinkLayerDevice 36 callbackFunc := func(resultDoc *linkLayerDeviceDoc) { 37 allDevices = append(allDevices, newLinkLayerDevice(m.st, *resultDoc)) 38 } 39 40 if err := m.forEachLinkLayerDeviceDoc(nil, callbackFunc); err != nil { 41 return nil, errors.Trace(err) 42 } 43 return allDevices, nil 44 } 45 46 func (m *Machine) forEachLinkLayerDeviceDoc( 47 docFieldsToSelect bson.D, callbackFunc func(resultDoc *linkLayerDeviceDoc), 48 ) error { 49 linkLayerDevices, closer := m.st.db().GetCollection(linkLayerDevicesC) 50 defer closer() 51 52 query := linkLayerDevices.Find(bson.D{{"machine-id", m.doc.Id}}) 53 if docFieldsToSelect != nil { 54 query = query.Select(docFieldsToSelect) 55 } 56 iter := query.Iter() 57 58 var resultDoc linkLayerDeviceDoc 59 for iter.Next(&resultDoc) { 60 callbackFunc(&resultDoc) 61 } 62 63 return errors.Trace(iter.Close()) 64 } 65 66 // AllProviderInterfaceInfos returns the provider details for all of 67 // the link layer devices belonging to this machine. These can be used 68 // to identify the devices when interacting with the provider 69 // directly (for example, releasing container addresses). 70 func (m *Machine) AllProviderInterfaceInfos() ([]corenetwork.ProviderInterfaceInfo, error) { 71 devices, err := m.AllLinkLayerDevices() 72 if err != nil { 73 return nil, errors.Trace(err) 74 } 75 result := make([]corenetwork.ProviderInterfaceInfo, len(devices)) 76 for i, device := range devices { 77 result[i].InterfaceName = device.Name() 78 result[i].HardwareAddress = device.MACAddress() 79 result[i].ProviderId = device.ProviderID() 80 } 81 return result, nil 82 } 83 84 // RemoveAllLinkLayerDevices removes all existing link-layer devices of the 85 // machine in a single transaction. No error is returned when some or all of the 86 // devices were already removed. 87 func (m *Machine) RemoveAllLinkLayerDevices() error { 88 ops, err := m.removeAllLinkLayerDevicesOps() 89 if err != nil { 90 return errors.Trace(err) 91 } 92 if len(ops) == 0 { 93 return nil 94 } 95 return m.st.db().RunTransaction(ops) 96 } 97 98 func (m *Machine) removeAllLinkLayerDevicesOps() ([]txn.Op, error) { 99 var ops []txn.Op 100 callbackFunc := func(resultDoc *linkLayerDeviceDoc) { 101 removeOps := removeLinkLayerDeviceUnconditionallyOps(resultDoc.DocID) 102 ops = append(ops, removeOps...) 103 if resultDoc.ProviderID != "" { 104 providerId := corenetwork.Id(resultDoc.ProviderID) 105 op := m.st.networkEntityGlobalKeyRemoveOp("linklayerdevice", providerId) 106 ops = append(ops, op) 107 } 108 } 109 110 if err := m.forEachLinkLayerDeviceDoc(nil, callbackFunc); err != nil { 111 return nil, errors.Trace(err) 112 } 113 114 return ops, nil 115 } 116 117 // LinkLayerDeviceArgs contains the arguments accepted by Machine.SetLinkLayerDevices(). 118 type LinkLayerDeviceArgs struct { 119 // Name is the name of the device as it appears on the machine. 120 Name string 121 122 // MTU is the maximum transmission unit the device can handle. 123 MTU uint 124 125 // ProviderID is a provider-specific ID of the device. Empty when not 126 // supported by the provider. Cannot be cleared once set. 127 ProviderID corenetwork.Id 128 129 // Type is the type of the underlying link-layer device. 130 Type corenetwork.LinkLayerDeviceType 131 132 // MACAddress is the media access control address for the device. 133 MACAddress string 134 135 // IsAutoStart is true if the device should be activated on boot. 136 IsAutoStart bool 137 138 // IsUp is true when the device is up (enabled). 139 IsUp bool 140 141 // ParentName is the name of the parent device, which may be empty. If set, 142 // it needs to be an existing device on the same machine, unless the current 143 // device is inside a container, in which case ParentName can be a global 144 // key of a BridgeDevice on the host machine of the container. Traffic 145 // originating from a device egresses from its parent device. 146 ParentName string 147 148 // If this is device is part of a virtual switch, this field indicates 149 // the type of switch (e.g. an OVS bridge ) this port belongs to. 150 VirtualPortType corenetwork.VirtualPortType 151 } 152 153 // AddLinkLayerDeviceOps returns transaction operations for adding the input 154 // link-layer device and the supplied addresses to the machine. 155 // TODO (manadart 2020-07-22): This method is currently used only for adding 156 // machine sourced devices and addresses. 157 // If it is used in future to set provider devices, the provider ID args must 158 // be included and the global ID collection must be maintained and verified. 159 func (m *Machine) AddLinkLayerDeviceOps( 160 devArgs LinkLayerDeviceArgs, addrArgs ...LinkLayerDeviceAddress, 161 ) ([]txn.Op, error) { 162 devDoc := m.newLinkLayerDeviceDocFromArgs(&devArgs) 163 ops := []txn.Op{insertLinkLayerDeviceDocOp(devDoc)} 164 for _, addr := range addrArgs { 165 address, subnet, err := addr.addressAndSubnet() 166 if err != nil { 167 return nil, errors.Trace(err) 168 } 169 170 newDoc := ipAddressDoc{ 171 DeviceName: devDoc.Name, 172 DocID: devDoc.DocID + "#ip#" + address, 173 ModelUUID: m.doc.ModelUUID, 174 MachineID: m.doc.Id, 175 SubnetCIDR: subnet, 176 ConfigMethod: addr.ConfigMethod, 177 Value: address, 178 DNSServers: addr.DNSServers, 179 DNSSearchDomains: addr.DNSSearchDomains, 180 GatewayAddress: addr.GatewayAddress, 181 IsDefaultGateway: addr.IsDefaultGateway, 182 Origin: addr.Origin, 183 } 184 ops = append(ops, insertIPAddressDocOp(&newDoc)) 185 } 186 187 return ops, nil 188 } 189 190 // SetLinkLayerDevices sets link-layer devices on the machine, adding or 191 // updating existing devices as needed, in a single transaction. ProviderID 192 // field can be empty if not supported by the provider, but when set must be 193 // unique within the model, and cannot be unset once set. Errors are returned in 194 // the following cases: 195 // - Machine is no longer alive or is missing; 196 // - Model no longer alive; 197 // - errors.NotValidError, when any of the fields in args contain invalid values; 198 // 199 // Deprecated: (manadart 2020-10-12) This method is only used by tests and is in 200 // the process of removal. Do not add new usages of it. 201 func (m *Machine) SetLinkLayerDevices(devicesArgs ...LinkLayerDeviceArgs) (err error) { 202 defer errors.DeferredAnnotatef(&err, "cannot set link-layer devices to machine %q", m.doc.Id) 203 204 if len(devicesArgs) == 0 { 205 logger.Debugf("no device addresses to set") 206 return nil 207 } 208 209 buildTxn := func(attempt int) ([]txn.Op, error) { 210 newDocs, err := m.prepareToSetLinkLayerDevices(devicesArgs) 211 if err != nil { 212 return nil, errors.Trace(err) 213 } 214 215 if m.doc.Life != Alive { 216 return nil, errors.Errorf("machine %q not alive", m.doc.Id) 217 } 218 if attempt > 0 { 219 allIds, err := m.st.allProviderIDsForLinkLayerDevices() 220 if err != nil { 221 return nil, errors.Trace(err) 222 } 223 for _, args := range devicesArgs { 224 if allIds.Contains(string(args.ProviderID)) { 225 return nil, errors.Annotatef( 226 newProviderIDNotUniqueError(args.ProviderID), "invalid device %q", args.Name) 227 } 228 } 229 } 230 231 setDevicesOps, err := m.setDevicesFromDocsOps(newDocs) 232 if err != nil { 233 return nil, errors.Trace(err) 234 } 235 if len(setDevicesOps) == 0 { 236 logger.Debugf("no changes to LinkLayerDevices for machine %q", m.Id()) 237 return nil, jujutxn.ErrNoOperations 238 } 239 return append([]txn.Op{m.assertAliveOp()}, setDevicesOps...), nil 240 } 241 if err := m.st.db().Run(buildTxn); err != nil { 242 return errors.Trace(err) 243 } 244 return nil 245 } 246 247 func (st *State) allProviderIDsForLinkLayerDevices() (set.Strings, error) { 248 return st.allProviderIDsForEntity("linklayerdevice") 249 } 250 251 func (st *State) allProviderIDsForEntity(entityName string) (set.Strings, error) { 252 idCollection, closer := st.db().GetCollection(providerIDsC) 253 defer closer() 254 255 allProviderIDs := set.NewStrings() 256 var doc struct { 257 ID string `bson:"_id"` 258 } 259 260 pattern := fmt.Sprintf("^%s:%s:.+$", st.ModelUUID(), entityName) 261 modelProviderIDs := bson.D{{"_id", bson.D{{"$regex", pattern}}}} 262 iter := idCollection.Find(modelProviderIDs).Iter() 263 for iter.Next(&doc) { 264 localProviderID := st.localID(doc.ID)[len(entityName)+1:] 265 allProviderIDs.Add(localProviderID) 266 } 267 if err := iter.Close(); err != nil { 268 return nil, errors.Trace(err) 269 } 270 return allProviderIDs, nil 271 } 272 273 func (m *Machine) prepareToSetLinkLayerDevices(devicesArgs []LinkLayerDeviceArgs) ([]linkLayerDeviceDoc, error) { 274 var pendingDocs []linkLayerDeviceDoc 275 pendingNames := set.NewStrings() 276 277 for _, args := range devicesArgs { 278 newDoc, err := m.prepareOneSetLinkLayerDeviceArgs(&args, pendingNames) 279 if err != nil { 280 return nil, errors.Trace(err) 281 } 282 pendingNames.Add(args.Name) 283 pendingDocs = append(pendingDocs, *newDoc) 284 } 285 return pendingDocs, nil 286 } 287 288 func (m *Machine) prepareOneSetLinkLayerDeviceArgs( 289 args *LinkLayerDeviceArgs, pendingNames set.Strings, 290 ) (_ *linkLayerDeviceDoc, err error) { 291 defer errors.DeferredAnnotatef(&err, "invalid device %q", args.Name) 292 293 if pendingNames.Contains(args.Name) { 294 return nil, errors.NewNotValid(nil, "Name specified more than once") 295 } 296 297 return m.newLinkLayerDeviceDocFromArgs(args), nil 298 } 299 300 func parseLinkLayerDeviceParentNameAsGlobalKey(parentName string) (hostMachineID, parentDeviceName string, err error) { 301 hostMachineID, parentDeviceName, canBeGlobalKey := parseLinkLayerDeviceGlobalKey(parentName) 302 if !canBeGlobalKey { 303 return "", "", nil 304 } else if hostMachineID == "" { 305 return "", "", errors.NotValidf("ParentName %q format", parentName) 306 } 307 return hostMachineID, parentDeviceName, nil 308 } 309 310 func (m *Machine) newLinkLayerDeviceDocFromArgs(args *LinkLayerDeviceArgs) *linkLayerDeviceDoc { 311 linkLayerDeviceDocID := linkLayerDeviceDocIDFromName(m.st, m.doc.Id, args.Name) 312 313 providerID := string(args.ProviderID) 314 modelUUID := m.st.ModelUUID() 315 316 return &linkLayerDeviceDoc{ 317 DocID: linkLayerDeviceDocID, 318 Name: args.Name, 319 ModelUUID: modelUUID, 320 MTU: args.MTU, 321 ProviderID: providerID, 322 MachineID: m.doc.Id, 323 Type: args.Type, 324 MACAddress: args.MACAddress, 325 IsAutoStart: args.IsAutoStart, 326 IsUp: args.IsUp, 327 ParentName: args.ParentName, 328 VirtualPortType: args.VirtualPortType, 329 } 330 } 331 332 func (m *Machine) isStillAlive() error { 333 if machineAlive, err := isAlive(m.st, machinesC, m.doc.Id); err != nil { 334 return errors.Trace(err) 335 } else if !machineAlive { 336 return errors.Errorf("machine not found or not alive") 337 } 338 return nil 339 } 340 341 func (m *Machine) assertAliveOp() txn.Op { 342 return txn.Op{ 343 C: machinesC, 344 Id: m.doc.Id, 345 Assert: isAliveDoc, 346 } 347 } 348 349 func (m *Machine) setDevicesFromDocsOps(newDocs []linkLayerDeviceDoc) ([]txn.Op, error) { 350 devices, closer := m.st.db().GetCollection(linkLayerDevicesC) 351 defer closer() 352 353 var ops []txn.Op 354 for _, newDoc := range newDocs { 355 var existingDoc linkLayerDeviceDoc 356 if err := devices.FindId(newDoc.DocID).One(&existingDoc); err == mgo.ErrNotFound { 357 // Device does not exist yet - insert it. 358 insertOps, err := m.insertLinkLayerDeviceOps(&newDoc) 359 if err != nil { 360 return nil, errors.Trace(err) 361 } 362 ops = append(ops, insertOps...) 363 } else if err == nil { 364 // Device already exists - update what's possible. 365 updateOps, err := m.updateLinkLayerDeviceOps(&existingDoc, &newDoc) 366 if err != nil { 367 return nil, errors.Trace(err) 368 } 369 ops = append(ops, updateOps...) 370 } else { 371 return nil, errors.Trace(err) 372 } 373 } 374 return ops, nil 375 } 376 377 func (m *Machine) insertLinkLayerDeviceOps(newDoc *linkLayerDeviceDoc) ([]txn.Op, error) { 378 var ops []txn.Op 379 if newDoc.ProviderID != "" { 380 id := corenetwork.Id(newDoc.ProviderID) 381 ops = append(ops, m.st.networkEntityGlobalKeyOp("linklayerdevice", id)) 382 } 383 return append(ops, insertLinkLayerDeviceDocOp(newDoc)), nil 384 } 385 386 func (m *Machine) parentDocIDFromDeviceDoc(doc *linkLayerDeviceDoc) (string, error) { 387 hostMachineID, parentName, err := parseLinkLayerDeviceParentNameAsGlobalKey(doc.ParentName) 388 if err != nil { 389 return "", errors.Trace(err) 390 } 391 if parentName == "" { 392 // doc.ParentName is not a global key, but on the same machine. 393 return linkLayerDeviceDocIDFromName(m.st, m.doc.Id, doc.ParentName), nil 394 } 395 // doc.ParentName is a global key, on a different host machine. 396 return m.st.docID(linkLayerDeviceGlobalKey(hostMachineID, parentName)), nil 397 } 398 399 func (m *Machine) updateLinkLayerDeviceOps(existingDoc, newDoc *linkLayerDeviceDoc) (ops []txn.Op, err error) { 400 // None of the ops in this function are assert-only, 401 // so callers can know if there are any changes by just checking len(ops). 402 var newParentDocID string 403 if newDoc.ParentName != "" { 404 newParentDocID, err = m.parentDocIDFromDeviceDoc(newDoc) 405 if err != nil { 406 return nil, errors.Trace(err) 407 } 408 } 409 var existingParentDocID string 410 if existingDoc.ParentName != "" { 411 existingParentDocID, err = m.parentDocIDFromDeviceDoc(existingDoc) 412 if err != nil { 413 return nil, errors.Trace(err) 414 } 415 } 416 417 if newParentDocID != "" && existingParentDocID != "" && newParentDocID != existingParentDocID { 418 ops = append(ops, 419 assertLinkLayerDeviceExistsOp(newParentDocID), 420 assertLinkLayerDeviceExistsOp(existingParentDocID), 421 ) 422 } else if newParentDocID != "" && existingParentDocID == "" { 423 ops = append(ops, assertLinkLayerDeviceExistsOp(newParentDocID)) 424 } else if newParentDocID == "" && existingParentDocID != "" { 425 ops = append(ops, assertLinkLayerDeviceExistsOp(existingParentDocID)) 426 } 427 updateDeviceOp, deviceHasChanges := updateLinkLayerDeviceDocOp(existingDoc, newDoc) 428 if deviceHasChanges { 429 // we only include the op if it will actually change something 430 ops = append(ops, updateDeviceOp) 431 } 432 433 if newDoc.ProviderID != "" { 434 if existingDoc.ProviderID != "" && existingDoc.ProviderID != newDoc.ProviderID { 435 return nil, errors.Errorf("cannot change ProviderID of link layer device %q", existingDoc.Name) 436 } 437 if existingDoc.ProviderID != newDoc.ProviderID { 438 // Need to insert the new provider id in providerIDsC 439 id := corenetwork.Id(newDoc.ProviderID) 440 ops = append(ops, m.st.networkEntityGlobalKeyOp("linklayerdevice", id)) 441 } 442 } 443 return ops, nil 444 } 445 446 // LinkLayerDeviceAddress contains an IP address assigned to a link-layer 447 // device. 448 type LinkLayerDeviceAddress struct { 449 // DeviceName is the name of the link-layer device that has this address. 450 DeviceName string 451 452 // ConfigMethod is the method used to configure this address. 453 ConfigMethod corenetwork.AddressConfigType 454 455 // ProviderID is the provider-specific ID of the address. Empty when not 456 // supported. Cannot be changed once set to non-empty. 457 ProviderID corenetwork.Id 458 459 // ProviderNetworkID is the provider-specific network ID of the address. 460 // It can be left empty if not supported or known. 461 ProviderNetworkID corenetwork.Id 462 463 // ProviderSubnetID is the provider-specific subnet ID to which the 464 // device is attached. 465 ProviderSubnetID corenetwork.Id 466 467 // CIDRAddress is the IP address assigned to the device, in CIDR format 468 // (e.g. 10.20.30.5/24 or fc00:1234::/64). 469 CIDRAddress string 470 471 // DNSServers contains a list of DNS nameservers to use, which can be empty. 472 DNSServers []string 473 474 // DNSSearchDomains contains a list of DNS domain names to qualify 475 // hostnames, and can be empty. 476 DNSSearchDomains []string 477 478 // GatewayAddress is the address of the gateway to use, which can be empty. 479 GatewayAddress string 480 481 // IsDefaultGateway is set to true if this address on this device is the 482 // default gw on a machine. 483 IsDefaultGateway bool 484 485 // Origin represents the authoritative source of the address. 486 // it is set using precedence, with "provider" overriding "machine". 487 // It is used to determine whether the address is no longer recognised 488 // and is safe to remove. 489 Origin corenetwork.Origin 490 491 // IsSecondary if true, indicates that this address is 492 // not the primary address associated with the NIC. 493 IsSecondary bool 494 } 495 496 // TODO (manadart 2020-07-21): This is silly. We already received the args 497 // as an address/subnet pair and validated them when transforming them to 498 // the CIDRAddress. Now we unpack and validate again. 499 // When the old link-layer update logic is removed, just pass it all 500 // through as-is. 501 // This method can then be removed and previous callers 502 // then need not include an error return. 503 func (a *LinkLayerDeviceAddress) addressAndSubnet() (string, string, error) { 504 ip, ipNet, err := net.ParseCIDR(a.CIDRAddress) 505 if err != nil { 506 return "", "", errors.Trace(err) 507 } 508 return ip.String(), ipNet.String(), nil 509 } 510 511 // SetDevicesAddresses sets the addresses of all devices in devicesAddresses, 512 // adding new or updating existing assignments as needed, in a single 513 // transaction. ProviderID field can be empty if not supported by the provider, 514 // but when set must be unique within the model. Errors are returned in the 515 // following cases: 516 // - Machine is no longer alive or is missing; 517 // - Subnet inferred from any CIDRAddress field in args is known but no longer 518 // alive (no error reported if the CIDRAddress does not match a known subnet); 519 // - Model no longer alive; 520 // - errors.NotValidError, when any of the fields in args contain invalid values; 521 // - errors.NotFoundError, when any DeviceName in args refers to unknown device; 522 // - ErrProviderIDNotUnique, when one or more specified ProviderIDs are not unique. 523 // 524 // Deprecated: (manadart 2021-05-04) This method is only used by tests and is in 525 // the process of removal. Do not add new usages of it. 526 func (m *Machine) SetDevicesAddresses(devicesAddresses ...LinkLayerDeviceAddress) (err error) { 527 defer errors.DeferredAnnotatef(&err, "cannot set link-layer device addresses of machine %q", m.doc.Id) 528 if len(devicesAddresses) == 0 { 529 logger.Debugf("no device addresses to set") 530 return nil 531 } 532 533 buildTxn := func(attempt int) ([]txn.Op, error) { 534 newDocs, err := m.prepareToSetDevicesAddresses(devicesAddresses) 535 if err != nil { 536 return nil, errors.Trace(err) 537 } 538 539 if m.doc.Life != Alive { 540 return nil, errors.Errorf("machine %q not alive", m.doc.Id) 541 } 542 543 setAddressesOps, err := m.setDevicesAddressesFromDocsOps(newDocs) 544 if err != nil { 545 return nil, errors.Trace(err) 546 } 547 if len(setAddressesOps) == 0 { 548 logger.Debugf("no changes to DevicesAddresses for machine %q", m.Id()) 549 return nil, jujutxn.ErrNoOperations 550 } 551 return append([]txn.Op{m.assertAliveOp()}, setAddressesOps...), nil 552 } 553 if err := m.st.db().Run(buildTxn); err != nil { 554 return errors.Trace(err) 555 } 556 return nil 557 } 558 559 func (m *Machine) prepareToSetDevicesAddresses(devicesAddresses []LinkLayerDeviceAddress) ([]ipAddressDoc, error) { 560 var pendingDocs []ipAddressDoc 561 for _, args := range devicesAddresses { 562 newDoc, err := m.prepareOneSetDevicesAddresses(&args) 563 if err != nil { 564 return nil, errors.Trace(err) 565 } 566 pendingDocs = append(pendingDocs, *newDoc) 567 } 568 return pendingDocs, nil 569 } 570 571 func (m *Machine) prepareOneSetDevicesAddresses(args *LinkLayerDeviceAddress) (_ *ipAddressDoc, err error) { 572 defer errors.DeferredAnnotatef(&err, "invalid address %q", args.CIDRAddress) 573 574 if err := m.validateSetDevicesAddressesArgs(args); err != nil { 575 return nil, errors.Trace(err) 576 } 577 return m.newIPAddressDocFromArgs(args) 578 } 579 580 func (m *Machine) validateSetDevicesAddressesArgs(args *LinkLayerDeviceAddress) error { 581 if args.CIDRAddress == "" { 582 return errors.NotValidf("empty CIDRAddress") 583 } 584 if _, _, err := net.ParseCIDR(args.CIDRAddress); err != nil { 585 return errors.NewNotValid(err, "CIDRAddress") 586 } 587 588 if args.DeviceName == "" { 589 return errors.NotValidf("empty DeviceName") 590 } 591 if !corenetwork.IsValidLinkLayerDeviceName(args.DeviceName) { 592 logger.Warningf( 593 "address %q on machine %q has invalid device name %q (using anyway)", 594 args.CIDRAddress, m.Id(), args.DeviceName, 595 ) 596 } 597 if err := m.verifyDeviceAlreadyExists(args.DeviceName); err != nil { 598 return errors.Trace(err) 599 } 600 601 if args.GatewayAddress != "" { 602 if ip := net.ParseIP(args.GatewayAddress); ip == nil { 603 return errors.NotValidf("GatewayAddress %q", args.GatewayAddress) 604 } 605 } 606 607 return nil 608 } 609 610 func (m *Machine) verifyDeviceAlreadyExists(deviceName string) error { 611 if _, err := m.LinkLayerDevice(deviceName); errors.IsNotFound(err) { 612 return errors.NotFoundf("DeviceName %q on machine %q", deviceName, m.Id()) 613 } else if err != nil { 614 return errors.Trace(err) 615 } 616 return nil 617 } 618 619 func (m *Machine) newIPAddressDocFromArgs(args *LinkLayerDeviceAddress) (*ipAddressDoc, error) { 620 ip, ipNet, err := net.ParseCIDR(args.CIDRAddress) 621 if err != nil { 622 // We already validated CIDRAddress earlier, so this cannot happen in 623 // practice, but we handle it anyway. 624 return nil, errors.Trace(err) 625 } 626 addressValue := ip.String() 627 subnetCIDR := ipNet.String() 628 subnet, err := m.st.SubnetByCIDR(subnetCIDR) 629 if errors.IsNotFound(err) { 630 logger.Debugf( 631 "address %q on machine %q uses unknown or machine-local subnet %q", 632 addressValue, m.Id(), subnetCIDR, 633 ) 634 } else if err != nil { 635 return nil, errors.Trace(err) 636 } else if err := m.verifySubnetAlive(subnet); err != nil { 637 return nil, errors.Trace(err) 638 } 639 640 globalKey := ipAddressGlobalKey(m.doc.Id, args.DeviceName, addressValue) 641 ipAddressDocID := m.st.docID(globalKey) 642 643 modelUUID := m.st.ModelUUID() 644 645 newDoc := &ipAddressDoc{ 646 DocID: ipAddressDocID, 647 ModelUUID: modelUUID, 648 ProviderID: args.ProviderID.String(), 649 ProviderNetworkID: args.ProviderNetworkID.String(), 650 ProviderSubnetID: args.ProviderSubnetID.String(), 651 DeviceName: args.DeviceName, 652 MachineID: m.doc.Id, 653 SubnetCIDR: subnetCIDR, 654 ConfigMethod: args.ConfigMethod, 655 Value: addressValue, 656 DNSServers: args.DNSServers, 657 DNSSearchDomains: args.DNSSearchDomains, 658 GatewayAddress: args.GatewayAddress, 659 IsDefaultGateway: args.IsDefaultGateway, 660 Origin: args.Origin, 661 } 662 return newDoc, nil 663 } 664 665 func (m *Machine) verifySubnetAlive(subnet *Subnet) error { 666 if subnet.Life() != Alive { 667 return errors.Errorf("subnet %q is not alive", subnet.CIDR()) 668 } 669 return nil 670 } 671 672 func (m *Machine) setDevicesAddressesFromDocsOps(newDocs []ipAddressDoc) ([]txn.Op, error) { 673 addresses, closer := m.st.db().GetCollection(ipAddressesC) 674 defer closer() 675 676 providerIDAddrs := make(map[string]string) 677 678 var ops []txn.Op 679 for _, newDoc := range newDocs { 680 var thisDeviceOps []txn.Op 681 hasChanges := false 682 deviceDocID := linkLayerDeviceDocIDFromName(m.st, m.doc.Id, newDoc.DeviceName) 683 thisDeviceOps = append(thisDeviceOps, assertLinkLayerDeviceExistsOp(deviceDocID)) 684 685 var existingDoc ipAddressDoc 686 switch err := addresses.FindId(newDoc.DocID).One(&existingDoc); err { 687 case mgo.ErrNotFound: 688 // Address does not exist yet - insert it. 689 hasChanges = true 690 thisDeviceOps = append(thisDeviceOps, insertIPAddressDocOp(&newDoc)) 691 692 pIDOps, err := m.maybeAddAddressProviderIDOps(providerIDAddrs, newDoc, "") 693 if err != nil { 694 return nil, errors.Trace(err) 695 } 696 thisDeviceOps = append(thisDeviceOps, pIDOps...) 697 698 case nil: 699 // Address already exists - update what's possible. 700 var ipOp txn.Op 701 ipOp, hasChanges = updateIPAddressDocOp(&existingDoc, &newDoc) 702 thisDeviceOps = append(thisDeviceOps, ipOp) 703 704 pIDOps, err := m.maybeAddAddressProviderIDOps(providerIDAddrs, newDoc, existingDoc.ProviderID) 705 if err != nil { 706 return nil, errors.Trace(err) 707 } 708 if len(pIDOps) > 0 { 709 hasChanges = true 710 thisDeviceOps = append(thisDeviceOps, pIDOps...) 711 } 712 713 default: 714 return nil, errors.Trace(err) 715 } 716 717 thisDeviceOps, err := m.maybeAssertSubnetAliveOps(&newDoc, thisDeviceOps) 718 if err != nil { 719 return nil, errors.Trace(err) 720 } 721 if hasChanges { 722 ops = append(ops, thisDeviceOps...) 723 } 724 } 725 return ops, nil 726 } 727 728 // maybeAddAddressProviderIDOps ensures that the address provider ID is valid 729 // and that we only accrue a transaction operation to add the ID if we have 730 // not already. 731 func (m *Machine) maybeAddAddressProviderIDOps( 732 providerIDAddrs map[string]string, doc ipAddressDoc, oldProviderID string, 733 ) ([]txn.Op, error) { 734 if doc.ProviderID == "" { 735 return nil, nil 736 } 737 if doc.ProviderID == oldProviderID { 738 return nil, nil 739 } 740 if oldProviderID != "" { 741 return nil, errors.Errorf("cannot change provider ID of link address %q", doc.Value) 742 } 743 744 // If this provider ID has been added for the same address, 745 // it is valid, but do not attempt to add the ID again. 746 // If we have different addresses with the same provider ID, 747 // return an error. 748 addr, ok := providerIDAddrs[doc.ProviderID] 749 if ok { 750 if addr == doc.Value { 751 return nil, nil 752 } 753 return nil, errors.Annotatef( 754 newProviderIDNotUniqueError(corenetwork.Id(doc.ProviderID)), "multiple addresses %q, %q", addr, doc.Value) 755 } 756 757 providerIDAddrs[doc.ProviderID] = doc.Value 758 return []txn.Op{m.st.networkEntityGlobalKeyOp("address", corenetwork.Id(doc.ProviderID))}, nil 759 } 760 761 func (m *Machine) maybeAssertSubnetAliveOps(newDoc *ipAddressDoc, opsSoFar []txn.Op) ([]txn.Op, error) { 762 subnet, err := m.st.SubnetByCIDR(newDoc.SubnetCIDR) 763 if errors.IsNotFound(err) { 764 // Subnet is machine-local, no need to assert whether it's alive. 765 return opsSoFar, nil 766 } else if err != nil { 767 return nil, errors.Trace(err) 768 } 769 if err := m.verifySubnetAlive(subnet); err != nil { 770 return nil, errors.Trace(err) 771 } 772 773 // Subnet exists and is still alive, assert that is stays that way. 774 return append(opsSoFar, txn.Op{ 775 C: subnetsC, 776 Id: m.st.docID(subnet.ID()), 777 Assert: isAliveDoc, 778 }), nil 779 } 780 781 // RemoveAllAddresses removes all assigned addresses to all devices of the 782 // machine, in a single transaction. No error is returned when some or all of 783 // the addresses were already removed. 784 func (m *Machine) RemoveAllAddresses() error { 785 ops, err := m.removeAllAddressesOps() 786 if err != nil { 787 return errors.Trace(err) 788 } 789 790 return m.st.db().RunTransaction(ops) 791 } 792 793 func (m *Machine) removeAllAddressesOps() ([]txn.Op, error) { 794 findQuery := findAddressesQuery(m.doc.Id, "") 795 return m.st.removeMatchingIPAddressesDocOps(findQuery) 796 } 797 798 // AllDeviceAddresses returns all known addresses assigned to 799 // link-layer devices on the machine. 800 func (m *Machine) AllDeviceAddresses() ([]*Address, error) { 801 var allAddresses []*Address 802 callbackFunc := func(doc *ipAddressDoc) { 803 allAddresses = append(allAddresses, newIPAddress(m.st, *doc)) 804 } 805 806 findQuery := findAddressesQuery(m.doc.Id, "") 807 if err := m.st.forEachIPAddressDoc(findQuery, callbackFunc); err != nil { 808 return nil, errors.Trace(err) 809 } 810 return allAddresses, nil 811 } 812 813 // AllSpaces returns the set of spaceIDs that this machine is 814 // actively connected to. 815 // TODO(jam): 2016-12-18 This should evolve to look at the 816 // LinkLayerDevices directly, instead of using the Addresses 817 // the devices are in to link back to spaces. 818 func (m *Machine) AllSpaces() (set.Strings, error) { 819 subnets, err := m.st.AllSubnets() 820 if err != nil { 821 return nil, errors.Annotate(err, "retrieving subnets") 822 } 823 824 spaces := set.NewStrings() 825 callback := func(doc *ipAddressDoc) { 826 // Don't bother with these. They are not in a space. 827 if doc.ConfigMethod == corenetwork.ConfigLoopback || doc.SubnetCIDR == "" { 828 return 829 } 830 831 for _, sub := range subnets { 832 if sub.CIDR() == doc.SubnetCIDR { 833 spaces.Add(sub.spaceID) 834 break 835 } 836 } 837 } 838 if err := m.st.forEachIPAddressDoc(findAddressesQuery(m.doc.Id, ""), callback); err != nil { 839 return nil, errors.Trace(err) 840 } 841 842 return spaces, nil 843 }