github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 "math/rand" 9 "net" 10 11 "github.com/juju/errors" 12 "github.com/juju/utils/set" 13 "gopkg.in/mgo.v2" 14 "gopkg.in/mgo.v2/bson" 15 "gopkg.in/mgo.v2/txn" 16 17 "github.com/juju/juju/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 linkLayerDevices, closer := m.st.getCollection(linkLayerDevicesC) 25 defer closer() 26 27 linkLayerDeviceDocID := m.linkLayerDeviceDocIDFromName(name) 28 deviceAsString := m.deviceAsStringFromName(name) 29 30 var doc linkLayerDeviceDoc 31 err := linkLayerDevices.FindId(linkLayerDeviceDocID).One(&doc) 32 if err == mgo.ErrNotFound { 33 return nil, errors.NotFoundf("%s", deviceAsString) 34 } else if err != nil { 35 return nil, errors.Annotatef(err, "cannot get %s", deviceAsString) 36 } 37 return newLinkLayerDevice(m.st, doc), nil 38 } 39 40 func (m *Machine) linkLayerDeviceDocIDFromName(deviceName string) string { 41 return m.st.docID(m.linkLayerDeviceGlobalKeyFromName(deviceName)) 42 } 43 44 func (m *Machine) linkLayerDeviceGlobalKeyFromName(deviceName string) string { 45 return linkLayerDeviceGlobalKey(m.doc.Id, deviceName) 46 } 47 48 func (m *Machine) deviceAsStringFromName(deviceName string) string { 49 return fmt.Sprintf("device %q on machine %q", deviceName, m.doc.Id) 50 } 51 52 // AllLinkLayerDevices returns all exiting link-layer devices of the machine. 53 func (m *Machine) AllLinkLayerDevices() ([]*LinkLayerDevice, error) { 54 var allDevices []*LinkLayerDevice 55 callbackFunc := func(resultDoc *linkLayerDeviceDoc) { 56 allDevices = append(allDevices, newLinkLayerDevice(m.st, *resultDoc)) 57 } 58 59 if err := m.forEachLinkLayerDeviceDoc(nil, callbackFunc); err != nil { 60 return nil, errors.Trace(err) 61 } 62 return allDevices, nil 63 } 64 65 func (m *Machine) forEachLinkLayerDeviceDoc(docFieldsToSelect bson.D, callbackFunc func(resultDoc *linkLayerDeviceDoc)) error { 66 linkLayerDevices, closer := m.st.getCollection(linkLayerDevicesC) 67 defer closer() 68 69 query := linkLayerDevices.Find(bson.D{{"machine-id", m.doc.Id}}) 70 if docFieldsToSelect != nil { 71 query = query.Select(docFieldsToSelect) 72 } 73 iter := query.Iter() 74 75 var resultDoc linkLayerDeviceDoc 76 for iter.Next(&resultDoc) { 77 callbackFunc(&resultDoc) 78 } 79 80 return errors.Trace(iter.Close()) 81 } 82 83 // RemoveAllLinkLayerDevices removes all existing link-layer devices of the 84 // machine in a single transaction. No error is returned when some or all of the 85 // devices were already removed. 86 func (m *Machine) RemoveAllLinkLayerDevices() error { 87 ops, err := m.removeAllLinkLayerDevicesOps() 88 if err != nil { 89 return errors.Trace(err) 90 } 91 92 return m.st.runTransaction(ops) 93 } 94 95 func (m *Machine) removeAllLinkLayerDevicesOps() ([]txn.Op, error) { 96 var ops []txn.Op 97 callbackFunc := func(resultDoc *linkLayerDeviceDoc) { 98 removeOps := removeLinkLayerDeviceUnconditionallyOps(resultDoc.DocID) 99 ops = append(ops, removeOps...) 100 } 101 102 selectDocIDOnly := bson.D{{"_id", 1}} 103 if err := m.forEachLinkLayerDeviceDoc(selectDocIDOnly, callbackFunc); err != nil { 104 return nil, errors.Trace(err) 105 } 106 107 return ops, nil 108 } 109 110 // LinkLayerDeviceArgs contains the arguments accepted by Machine.SetLinkLayerDevices(). 111 type LinkLayerDeviceArgs struct { 112 // Name is the name of the device as it appears on the machine. 113 Name string 114 115 // MTU is the maximum transmission unit the device can handle. 116 MTU uint 117 118 // ProviderID is a provider-specific ID of the device. Empty when not 119 // supported by the provider. Cannot be cleared once set. 120 ProviderID network.Id 121 122 // Type is the type of the underlying link-layer device. 123 Type LinkLayerDeviceType 124 125 // MACAddress is the media access control address for the device. 126 MACAddress string 127 128 // IsAutoStart is true if the device should be activated on boot. 129 IsAutoStart bool 130 131 // IsUp is true when the device is up (enabled). 132 IsUp bool 133 134 // ParentName is the name of the parent device, which may be empty. If set, 135 // it needs to be an existing device on the same machine, unless the current 136 // device is inside a container, in which case ParentName can be a global 137 // key of a BridgeDevice on the host machine of the container. Traffic 138 // originating from a device egresses from its parent device. 139 ParentName string 140 } 141 142 // SetLinkLayerDevices sets link-layer devices on the machine, adding or 143 // updating existing devices as needed, in a single transaction. ProviderID 144 // field can be empty if not supported by the provider, but when set must be 145 // unique within the model, and cannot be unset once set. Errors are returned in 146 // the following cases: 147 // - Machine is no longer alive or is missing; 148 // - Model no longer alive; 149 // - errors.NotValidError, when any of the fields in args contain invalid values; 150 // - ErrProviderIDNotUnique, when one or more specified ProviderIDs are not unique; 151 // Setting new parent devices must be done in a separate call than setting their 152 // children on the same machine. 153 func (m *Machine) SetLinkLayerDevices(devicesArgs ...LinkLayerDeviceArgs) (err error) { 154 defer errors.DeferredAnnotatef(&err, "cannot set link-layer devices to machine %q", m.doc.Id) 155 156 if len(devicesArgs) == 0 { 157 logger.Warningf("no device addresses to set") 158 return nil 159 } 160 161 buildTxn := func(attempt int) ([]txn.Op, error) { 162 existingProviderIDs, err := m.st.allProviderIDsForModelLinkLayerDevices() 163 if err != nil { 164 return nil, errors.Trace(err) 165 } 166 newDocs, err := m.prepareToSetLinkLayerDevices(devicesArgs, existingProviderIDs) 167 if err != nil { 168 return nil, errors.Trace(err) 169 } 170 171 if attempt > 0 { 172 if err := checkModelActive(m.st); err != nil { 173 return nil, errors.Trace(err) 174 } 175 if err := m.isStillAlive(); err != nil { 176 return nil, errors.Trace(err) 177 } 178 } 179 180 ops := []txn.Op{ 181 assertModelActiveOp(m.st.ModelUUID()), 182 m.assertAliveOp(), 183 } 184 185 setDevicesOps, err := m.setDevicesFromDocsOps(newDocs) 186 if err != nil { 187 return nil, errors.Trace(err) 188 } 189 return append(ops, setDevicesOps...), nil 190 } 191 if err := m.st.run(buildTxn); err != nil { 192 return errors.Trace(err) 193 } 194 return nil 195 } 196 197 func (st *State) allProviderIDsForModelLinkLayerDevices() (set.Strings, error) { 198 return st.allProviderIDsForModelCollection(linkLayerDevicesC, "link-layer devices") 199 } 200 201 func (st *State) allProviderIDsForModelCollection(collectionName, entityLabelPlural string) (_ set.Strings, err error) { 202 defer errors.DeferredAnnotatef(&err, "cannot get ProviderIDs for all %s", entityLabelPlural) 203 204 entities, closer := st.getCollection(collectionName) 205 defer closer() 206 207 allProviderIDs := set.NewStrings() 208 var doc struct { 209 ProviderID string `bson:"providerid"` 210 } 211 212 pattern := fmt.Sprintf("^%s:.+$", st.ModelUUID()) 213 modelProviderIDs := bson.D{{"providerid", bson.D{{"$regex", pattern}}}} 214 onlyProviderIDField := bson.D{{"providerid", 1}} 215 216 iter := entities.Find(modelProviderIDs).Select(onlyProviderIDField).Iter() 217 for iter.Next(&doc) { 218 localProviderID := st.localID(doc.ProviderID) 219 allProviderIDs.Add(localProviderID) 220 } 221 if err := iter.Close(); err != nil { 222 return nil, errors.Trace(err) 223 } 224 return allProviderIDs, nil 225 } 226 227 func (m *Machine) prepareToSetLinkLayerDevices(devicesArgs []LinkLayerDeviceArgs, existingProviderIDs set.Strings) ([]linkLayerDeviceDoc, error) { 228 var pendingDocs []linkLayerDeviceDoc 229 pendingNames := set.NewStrings() 230 allProviderIDs := set.NewStrings(existingProviderIDs.Values()...) 231 232 for _, args := range devicesArgs { 233 newDoc, err := m.prepareOneSetLinkLayerDeviceArgs(&args, pendingNames, allProviderIDs) 234 if err != nil { 235 return nil, errors.Trace(err) 236 } 237 pendingNames.Add(args.Name) 238 pendingDocs = append(pendingDocs, *newDoc) 239 if args.ProviderID != "" { 240 allProviderIDs.Add(string(args.ProviderID)) 241 } 242 } 243 return pendingDocs, nil 244 } 245 246 func (m *Machine) prepareOneSetLinkLayerDeviceArgs(args *LinkLayerDeviceArgs, pendingNames, allProviderIDs set.Strings) (_ *linkLayerDeviceDoc, err error) { 247 defer errors.DeferredAnnotatef(&err, "invalid device %q", args.Name) 248 249 if err := m.validateSetLinkLayerDeviceArgs(args); err != nil { 250 return nil, errors.Trace(err) 251 } 252 253 if pendingNames.Contains(args.Name) { 254 return nil, errors.NewNotValid(nil, "Name specified more than once") 255 } 256 257 if allProviderIDs.Contains(string(args.ProviderID)) { 258 return nil, NewProviderIDNotUniqueError(args.ProviderID) 259 } 260 261 return m.newLinkLayerDeviceDocFromArgs(args), nil 262 } 263 264 func (m *Machine) validateSetLinkLayerDeviceArgs(args *LinkLayerDeviceArgs) error { 265 if args.Name == "" { 266 return errors.NotValidf("empty Name") 267 } 268 if !IsValidLinkLayerDeviceName(args.Name) { 269 logger.Warningf( 270 "link-layer device %q on machine %q has invalid name (using anyway)", 271 args.Name, m.Id(), 272 ) 273 } 274 275 if args.ParentName != "" { 276 if err := m.validateLinkLayerDeviceParent(args); err != nil { 277 return errors.Trace(err) 278 } 279 } 280 281 if !IsValidLinkLayerDeviceType(string(args.Type)) { 282 return errors.NotValidf("Type %q", args.Type) 283 } 284 285 if args.MACAddress != "" { 286 if _, err := net.ParseMAC(args.MACAddress); err != nil { 287 return errors.NotValidf("MACAddress %q", args.MACAddress) 288 } 289 } 290 return nil 291 } 292 293 func (m *Machine) validateLinkLayerDeviceParent(args *LinkLayerDeviceArgs) error { 294 hostMachineID, parentDeviceName, err := parseLinkLayerDeviceParentNameAsGlobalKey(args.ParentName) 295 if err != nil { 296 return errors.Trace(err) 297 } else if hostMachineID == "" { 298 // Not a global key, so validate as usual. 299 if err := m.validateParentDeviceNameWhenNotAGlobalKey(args); errors.IsNotFound(err) { 300 return errors.NewNotValid(err, "ParentName not valid") 301 } else if err != nil { 302 return errors.Trace(err) 303 } 304 return nil 305 } 306 ourParentMachineID, hasParent := m.ParentId() 307 if !hasParent { 308 // Using global key for ParentName not allowed for non-container machine 309 // devices. 310 return errors.NotValidf("ParentName %q for non-container machine %q", args.ParentName, m.Id()) 311 } 312 if hostMachineID != ourParentMachineID { 313 // ParentName as global key only allowed when the key's machine ID is 314 // the container's host machine. 315 return errors.NotValidf("ParentName %q on non-host machine %q", args.ParentName, hostMachineID) 316 } 317 318 err = m.verifyHostMachineParentDeviceExistsAndIsABridgeDevice(hostMachineID, parentDeviceName) 319 return errors.Trace(err) 320 } 321 322 func parseLinkLayerDeviceParentNameAsGlobalKey(parentName string) (hostMachineID, parentDeviceName string, err error) { 323 hostMachineID, parentDeviceName, canBeGlobalKey := parseLinkLayerDeviceGlobalKey(parentName) 324 if !canBeGlobalKey { 325 return "", "", nil 326 } else if hostMachineID == "" { 327 return "", "", errors.NotValidf("ParentName %q format", parentName) 328 } 329 return hostMachineID, parentDeviceName, nil 330 } 331 332 func (m *Machine) verifyHostMachineParentDeviceExistsAndIsABridgeDevice(hostMachineID, parentDeviceName string) error { 333 hostMachine, err := m.st.Machine(hostMachineID) 334 if errors.IsNotFound(err) || err == nil && hostMachine.Life() != Alive { 335 return errors.Errorf("host machine %q of parent device %q not found or not alive", hostMachineID, parentDeviceName) 336 } else if err != nil { 337 return errors.Trace(err) 338 } 339 340 parentDevice, err := hostMachine.LinkLayerDevice(parentDeviceName) 341 if errors.IsNotFound(err) { 342 return errors.NotFoundf("parent device %q on host machine %q", parentDeviceName, hostMachineID) 343 } else if err != nil { 344 return errors.Trace(err) 345 } 346 347 if parentDevice.Type() != BridgeDevice { 348 errorMessage := fmt.Sprintf( 349 "parent device %q on host machine %q must be of type %q, not type %q", 350 parentDeviceName, hostMachineID, BridgeDevice, parentDevice.Type(), 351 ) 352 return errors.NewNotValid(nil, errorMessage) 353 } 354 return nil 355 } 356 357 func (m *Machine) validateParentDeviceNameWhenNotAGlobalKey(args *LinkLayerDeviceArgs) error { 358 if !IsValidLinkLayerDeviceName(args.ParentName) { 359 logger.Warningf( 360 "parent link-layer device %q on machine %q has invalid name (using anyway)", 361 args.ParentName, m.Id(), 362 ) 363 } 364 if args.Name == args.ParentName { 365 return errors.NewNotValid(nil, "Name and ParentName must be different") 366 } 367 if err := m.verifyParentDeviceExists(args.ParentName); err != nil { 368 return errors.Trace(err) 369 } 370 return nil 371 } 372 373 func (m *Machine) verifyParentDeviceExists(parentName string) error { 374 if _, err := m.LinkLayerDevice(parentName); err != nil { 375 return errors.Trace(err) 376 } 377 return nil 378 } 379 380 func (m *Machine) newLinkLayerDeviceDocFromArgs(args *LinkLayerDeviceArgs) *linkLayerDeviceDoc { 381 linkLayerDeviceDocID := m.linkLayerDeviceDocIDFromName(args.Name) 382 383 providerID := string(args.ProviderID) 384 if providerID != "" { 385 providerID = m.st.docID(providerID) 386 } 387 388 modelUUID := m.st.ModelUUID() 389 390 return &linkLayerDeviceDoc{ 391 DocID: linkLayerDeviceDocID, 392 Name: args.Name, 393 ModelUUID: modelUUID, 394 MTU: args.MTU, 395 ProviderID: providerID, 396 MachineID: m.doc.Id, 397 Type: args.Type, 398 MACAddress: args.MACAddress, 399 IsAutoStart: args.IsAutoStart, 400 IsUp: args.IsUp, 401 ParentName: args.ParentName, 402 } 403 } 404 405 func (m *Machine) isStillAlive() error { 406 if machineAlive, err := isAlive(m.st, machinesC, m.doc.Id); err != nil { 407 return errors.Trace(err) 408 } else if !machineAlive { 409 return errors.Errorf("machine not found or not alive") 410 } 411 return nil 412 } 413 414 func (m *Machine) assertAliveOp() txn.Op { 415 return txn.Op{ 416 C: machinesC, 417 Id: m.doc.Id, 418 Assert: isAliveDoc, 419 } 420 } 421 422 func (m *Machine) setDevicesFromDocsOps(newDocs []linkLayerDeviceDoc) ([]txn.Op, error) { 423 devices, closer := m.st.getCollection(linkLayerDevicesC) 424 defer closer() 425 426 var ops []txn.Op 427 for _, newDoc := range newDocs { 428 var existingDoc linkLayerDeviceDoc 429 if err := devices.FindId(newDoc.DocID).One(&existingDoc); err == mgo.ErrNotFound { 430 // Device does not exist yet - insert it. 431 insertOps, err := m.insertLinkLayerDeviceOps(&newDoc) 432 if err != nil { 433 return nil, errors.Trace(err) 434 } 435 ops = append(ops, insertOps...) 436 } else if err == nil { 437 // Device already exists - update what's possible. 438 updateOps, err := m.updateLinkLayerDeviceOps(&existingDoc, &newDoc) 439 if err != nil { 440 return nil, errors.Trace(err) 441 } 442 ops = append(ops, updateOps...) 443 } else { 444 return nil, errors.Trace(err) 445 } 446 } 447 return ops, nil 448 } 449 450 func (m *Machine) insertLinkLayerDeviceOps(newDoc *linkLayerDeviceDoc) ([]txn.Op, error) { 451 modelUUID, linkLayerDeviceDocID := newDoc.ModelUUID, newDoc.DocID 452 453 var ops []txn.Op 454 if newDoc.ParentName != "" { 455 newParentDocID, err := m.parentDocIDFromDeviceDoc(newDoc) 456 if err != nil { 457 return nil, errors.Trace(err) 458 } 459 if newParentDocID != "" { 460 ops = append(ops, assertLinkLayerDeviceExistsOp(newParentDocID)) 461 ops = append(ops, incrementDeviceNumChildrenOp(newParentDocID)) 462 } 463 } 464 return append(ops, 465 insertLinkLayerDeviceDocOp(newDoc), 466 insertLinkLayerDevicesRefsOp(modelUUID, linkLayerDeviceDocID), 467 ), nil 468 } 469 470 func (m *Machine) parentDocIDFromDeviceDoc(doc *linkLayerDeviceDoc) (string, error) { 471 hostMachineID, parentName, err := parseLinkLayerDeviceParentNameAsGlobalKey(doc.ParentName) 472 if err != nil { 473 return "", errors.Trace(err) 474 } 475 if parentName == "" { 476 // doc.ParentName is not a global key, but on the same machine. 477 return m.linkLayerDeviceDocIDFromName(doc.ParentName), nil 478 } 479 // doc.ParentName is a global key, on a different host machine. 480 return m.st.docID(linkLayerDeviceGlobalKey(hostMachineID, parentName)), nil 481 } 482 483 func (m *Machine) updateLinkLayerDeviceOps(existingDoc, newDoc *linkLayerDeviceDoc) (ops []txn.Op, err error) { 484 var newParentDocID string 485 if newDoc.ParentName != "" { 486 newParentDocID, err = m.parentDocIDFromDeviceDoc(newDoc) 487 if err != nil { 488 return nil, errors.Trace(err) 489 } 490 } 491 var existingParentDocID string 492 if existingDoc.ParentName != "" { 493 existingParentDocID, err = m.parentDocIDFromDeviceDoc(existingDoc) 494 if err != nil { 495 return nil, errors.Trace(err) 496 } 497 } 498 499 if newParentDocID != "" && existingParentDocID != "" && newParentDocID != existingParentDocID { 500 ops = append(ops, 501 assertLinkLayerDeviceExistsOp(newParentDocID), 502 incrementDeviceNumChildrenOp(newParentDocID), 503 assertLinkLayerDeviceExistsOp(existingParentDocID), 504 decrementDeviceNumChildrenOp(existingParentDocID), 505 ) 506 } else if newParentDocID != "" && existingParentDocID == "" { 507 ops = append(ops, assertLinkLayerDeviceExistsOp(newParentDocID)) 508 ops = append(ops, incrementDeviceNumChildrenOp(newParentDocID)) 509 } else if newParentDocID == "" && existingParentDocID != "" { 510 ops = append(ops, assertLinkLayerDeviceExistsOp(existingParentDocID)) 511 ops = append(ops, decrementDeviceNumChildrenOp(existingParentDocID)) 512 } 513 return append(ops, updateLinkLayerDeviceDocOp(existingDoc, newDoc)), nil 514 } 515 516 // LinkLayerDeviceAddress contains an IP address assigned to a link-layer 517 // device. 518 type LinkLayerDeviceAddress struct { 519 // DeviceName is the name of the link-layer device that has this address. 520 DeviceName string 521 522 // ConfigMethod is the method used to configure this address. 523 ConfigMethod AddressConfigMethod 524 525 // ProviderID is the provider-specific ID of the address. Empty when not 526 // supported. Cannot be changed once set to non-empty. 527 ProviderID network.Id 528 529 // CIDRAddress is the IP address assigned to the device, in CIDR format 530 // (e.g. 10.20.30.5/24 or fc00:1234::/64). 531 CIDRAddress string 532 533 // DNSServers contains a list of DNS nameservers to use, which can be empty. 534 DNSServers []string 535 536 // DNSSearchDomains contains a list of DNS domain names to qualify 537 // hostnames, and can be empty. 538 DNSSearchDomains []string 539 540 // GatewayAddress is the address of the gateway to use, which can be empty. 541 GatewayAddress string 542 } 543 544 // SetDevicesAddresses sets the addresses of all devices in devicesAddresses, 545 // adding new or updating existing assignments as needed, in a single 546 // transaction. ProviderID field can be empty if not supported by the provider, 547 // but when set must be unique within the model. Errors are returned in the 548 // following cases: 549 // - Machine is no longer alive or is missing; 550 // - Subnet inferred from any CIDRAddress field in args is known but no longer 551 // alive (no error reported if the CIDRAddress does not match a known subnet); 552 // - Model no longer alive; 553 // - errors.NotValidError, when any of the fields in args contain invalid values; 554 // - errors.NotFoundError, when any DeviceName in args refers to unknown device; 555 // - ErrProviderIDNotUnique, when one or more specified ProviderIDs are not unique. 556 func (m *Machine) SetDevicesAddresses(devicesAddresses ...LinkLayerDeviceAddress) (err error) { 557 defer errors.DeferredAnnotatef(&err, "cannot set link-layer device addresses of machine %q", m.doc.Id) 558 559 if len(devicesAddresses) == 0 { 560 logger.Warningf("no device addresses to set") 561 return nil 562 } 563 564 buildTxn := func(attempt int) ([]txn.Op, error) { 565 existingProviderIDs, err := m.st.allProviderIDsForModelIPAddresses() 566 if err != nil { 567 return nil, errors.Trace(err) 568 } 569 newDocs, err := m.prepareToSetDevicesAddresses(devicesAddresses, existingProviderIDs) 570 if err != nil { 571 return nil, errors.Trace(err) 572 } 573 574 if attempt > 0 { 575 if err := checkModelActive(m.st); err != nil { 576 return nil, errors.Trace(err) 577 } 578 if err := m.isStillAlive(); err != nil { 579 return nil, errors.Trace(err) 580 } 581 } 582 583 ops := []txn.Op{ 584 assertModelActiveOp(m.st.ModelUUID()), 585 m.assertAliveOp(), 586 } 587 588 setAddressesOps, err := m.setDevicesAddressesFromDocsOps(newDocs) 589 if err != nil { 590 return nil, errors.Trace(err) 591 } 592 return append(ops, setAddressesOps...), nil 593 } 594 if err := m.st.run(buildTxn); err != nil { 595 return errors.Trace(err) 596 } 597 return nil 598 } 599 600 func (st *State) allProviderIDsForModelIPAddresses() (set.Strings, error) { 601 return st.allProviderIDsForModelCollection(ipAddressesC, "IP addresses") 602 } 603 604 func (m *Machine) prepareToSetDevicesAddresses(devicesAddresses []LinkLayerDeviceAddress, existingProviderIDs set.Strings) ([]ipAddressDoc, error) { 605 var pendingDocs []ipAddressDoc 606 allProviderIDs := set.NewStrings(existingProviderIDs.Values()...) 607 608 for _, args := range devicesAddresses { 609 newDoc, err := m.prepareOneSetDevicesAddresses(&args, allProviderIDs) 610 if err != nil { 611 return nil, errors.Trace(err) 612 } 613 pendingDocs = append(pendingDocs, *newDoc) 614 if args.ProviderID != "" { 615 allProviderIDs.Add(string(args.ProviderID)) 616 } 617 } 618 return pendingDocs, nil 619 } 620 621 func (m *Machine) prepareOneSetDevicesAddresses(args *LinkLayerDeviceAddress, allProviderIDs set.Strings) (_ *ipAddressDoc, err error) { 622 defer errors.DeferredAnnotatef(&err, "invalid address %q", args.CIDRAddress) 623 624 if err := m.validateSetDevicesAddressesArgs(args); err != nil { 625 return nil, errors.Trace(err) 626 } 627 628 if allProviderIDs.Contains(string(args.ProviderID)) { 629 return nil, NewProviderIDNotUniqueError(args.ProviderID) 630 } 631 632 return m.newIPAddressDocFromArgs(args) 633 } 634 635 func (m *Machine) validateSetDevicesAddressesArgs(args *LinkLayerDeviceAddress) error { 636 if args.CIDRAddress == "" { 637 return errors.NotValidf("empty CIDRAddress") 638 } 639 if _, _, err := net.ParseCIDR(args.CIDRAddress); err != nil { 640 return errors.NewNotValid(err, "CIDRAddress") 641 } 642 643 if args.DeviceName == "" { 644 return errors.NotValidf("empty DeviceName") 645 } 646 if !IsValidLinkLayerDeviceName(args.DeviceName) { 647 logger.Warningf( 648 "address %q on machine %q has invalid device name %q (using anyway)", 649 args.CIDRAddress, m.Id(), args.DeviceName, 650 ) 651 } 652 if err := m.verifyDeviceAlreadyExists(args.DeviceName); err != nil { 653 return errors.Trace(err) 654 } 655 656 if !IsValidAddressConfigMethod(string(args.ConfigMethod)) { 657 return errors.NotValidf("ConfigMethod %q", args.ConfigMethod) 658 } 659 660 if args.GatewayAddress != "" { 661 if ip := net.ParseIP(args.GatewayAddress); ip == nil { 662 return errors.NotValidf("GatewayAddress %q", args.GatewayAddress) 663 } 664 } 665 666 return nil 667 } 668 669 func (m *Machine) verifyDeviceAlreadyExists(deviceName string) error { 670 if _, err := m.LinkLayerDevice(deviceName); errors.IsNotFound(err) { 671 return errors.NotFoundf("DeviceName %q on machine %q", deviceName, m.Id()) 672 } else if err != nil { 673 return errors.Trace(err) 674 } 675 return nil 676 } 677 678 func (m *Machine) newIPAddressDocFromArgs(args *LinkLayerDeviceAddress) (*ipAddressDoc, error) { 679 ip, ipNet, err := net.ParseCIDR(args.CIDRAddress) 680 if err != nil { 681 // We already validated CIDRAddress earlier, so this cannot happen in 682 // practice, but we handle it anyway. 683 return nil, errors.Trace(err) 684 } 685 addressValue := ip.String() 686 subnetCIDR := ipNet.String() 687 subnet, err := m.st.Subnet(subnetCIDR) 688 if errors.IsNotFound(err) { 689 logger.Infof( 690 "address %q on machine %q uses unknown or machine-local subnet %q", 691 addressValue, m.Id(), subnetCIDR, 692 ) 693 } else if err != nil { 694 return nil, errors.Trace(err) 695 } else if err := m.verifySubnetAlive(subnet); err != nil { 696 return nil, errors.Trace(err) 697 } 698 699 globalKey := ipAddressGlobalKey(m.doc.Id, args.DeviceName, addressValue) 700 ipAddressDocID := m.st.docID(globalKey) 701 702 providerID := string(args.ProviderID) 703 if providerID != "" { 704 providerID = m.st.docID(providerID) 705 } 706 modelUUID := m.st.ModelUUID() 707 708 newDoc := &ipAddressDoc{ 709 DocID: ipAddressDocID, 710 ModelUUID: modelUUID, 711 ProviderID: providerID, 712 DeviceName: args.DeviceName, 713 MachineID: m.doc.Id, 714 SubnetCIDR: subnetCIDR, 715 ConfigMethod: args.ConfigMethod, 716 Value: addressValue, 717 DNSServers: args.DNSServers, 718 DNSSearchDomains: args.DNSSearchDomains, 719 GatewayAddress: args.GatewayAddress, 720 } 721 return newDoc, nil 722 } 723 724 func (m *Machine) verifySubnetAlive(subnet *Subnet) error { 725 if subnet.Life() != Alive { 726 return errors.Errorf("subnet %q is not alive", subnet.CIDR()) 727 } 728 return nil 729 } 730 731 func (m *Machine) setDevicesAddressesFromDocsOps(newDocs []ipAddressDoc) ([]txn.Op, error) { 732 addresses, closer := m.st.getCollection(ipAddressesC) 733 defer closer() 734 735 var ops []txn.Op 736 737 for _, newDoc := range newDocs { 738 deviceDocID := m.linkLayerDeviceDocIDFromName(newDoc.DeviceName) 739 ops = append(ops, assertLinkLayerDeviceExistsOp(deviceDocID)) 740 741 var existingDoc ipAddressDoc 742 err := addresses.FindId(newDoc.DocID).One(&existingDoc) 743 if err == mgo.ErrNotFound { 744 // Address does not exist yet - insert it. 745 ops = append(ops, insertIPAddressDocOp(&newDoc)) 746 } else if err == nil { 747 // Address already exists - update what's possible. 748 ops = append(ops, updateIPAddressDocOp(&existingDoc, &newDoc)) 749 } else { 750 return nil, errors.Trace(err) 751 } 752 753 ops, err = m.maybeAssertSubnetAliveOps(&newDoc, ops) 754 if err != nil { 755 return nil, errors.Trace(err) 756 } 757 } 758 return ops, nil 759 } 760 761 func (m *Machine) maybeAssertSubnetAliveOps(newDoc *ipAddressDoc, opsSoFar []txn.Op) ([]txn.Op, error) { 762 subnet, err := m.st.Subnet(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(newDoc.SubnetCIDR), 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.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 // AllAddresses returns the all addresses assigned to all devices of the 799 // machine. 800 func (m *Machine) AllAddresses() ([]*Address, error) { 801 var allAddresses []*Address 802 callbackFunc := func(resultDoc *ipAddressDoc) { 803 allAddresses = append(allAddresses, newIPAddress(m.st, *resultDoc)) 804 } 805 806 findQuery := findAddressesQuery(m.doc.Id, "") 807 if err := m.st.forEachIPAddressDoc(findQuery, nil, callbackFunc); err != nil { 808 return nil, errors.Trace(err) 809 } 810 return allAddresses, nil 811 } 812 813 // SetParentLinkLayerDevicesBeforeTheirChildren splits the given devicesArgs 814 // into multiple sets of args and calls SetLinkLayerDevices() for each set, such 815 // that child devices are set only after their parents. 816 func (m *Machine) SetParentLinkLayerDevicesBeforeTheirChildren(devicesArgs []LinkLayerDeviceArgs) error { 817 seenNames := set.NewStrings("") // sentinel for empty ParentName. 818 for { 819 argsToSet := []LinkLayerDeviceArgs{} 820 for _, args := range devicesArgs { 821 if seenNames.Contains(args.Name) { 822 // Already added earlier. 823 continue 824 } 825 if seenNames.Contains(args.ParentName) { 826 argsToSet = append(argsToSet, args) 827 } 828 } 829 if len(argsToSet) == 0 { 830 // We're done. 831 break 832 } 833 logger.Debugf("setting link-layer devices %+v", argsToSet) 834 if err := m.SetLinkLayerDevices(argsToSet...); IsProviderIDNotUniqueError(err) { 835 // FIXME: Make updating devices with unchanged ProviderID idempotent. 836 for i, args := range argsToSet { 837 args.ProviderID = "" 838 argsToSet[i] = args 839 } 840 if err := m.SetLinkLayerDevices(argsToSet...); err != nil { 841 return errors.Trace(err) 842 } 843 } else if err != nil { 844 return errors.Trace(err) 845 } 846 for _, args := range argsToSet { 847 seenNames.Add(args.Name) 848 } 849 } 850 return nil 851 } 852 853 // SetDevicesAddressesIdempotently calls SetDevicesAddresses() and if it fails 854 // with ErrProviderIDNotUnique, retries the call with all ProviderID fields in 855 // devicesAddresses set to empty. 856 func (m *Machine) SetDevicesAddressesIdempotently(devicesAddresses []LinkLayerDeviceAddress) error { 857 if err := m.SetDevicesAddresses(devicesAddresses...); IsProviderIDNotUniqueError(err) { 858 // FIXME: Make updating addresses with unchanged ProviderID idempotent. 859 for i, args := range devicesAddresses { 860 args.ProviderID = "" 861 devicesAddresses[i] = args 862 } 863 if err := m.SetDevicesAddresses(devicesAddresses...); err != nil { 864 return errors.Trace(err) 865 } 866 } else if err != nil { 867 return errors.Trace(err) 868 } 869 return nil 870 } 871 872 // SetContainerLinkLayerDevices sets the link-layer devices of the given 873 // containerMachine, setting each device linked to the corresponding 874 // BridgeDevice of the host machine m. 875 func (m *Machine) SetContainerLinkLayerDevices(containerMachine *Machine) error { 876 allDevices, err := m.AllLinkLayerDevices() 877 if err != nil { 878 return errors.Annotate(err, "cannot get host machine devices") 879 } 880 logger.Debugf("using host machine %q devices: %+v", m.Id(), allDevices) 881 882 var containerDevicesArgs []LinkLayerDeviceArgs 883 for _, hostDevice := range allDevices { 884 if hostDevice.Type() == BridgeDevice { 885 containerDeviceName := fmt.Sprintf("eth%d", len(containerDevicesArgs)) 886 generatedMAC := generateMACAddress() 887 args := LinkLayerDeviceArgs{ 888 Name: containerDeviceName, 889 Type: EthernetDevice, 890 MACAddress: generatedMAC, 891 MTU: hostDevice.MTU(), 892 IsUp: true, 893 IsAutoStart: true, 894 ParentName: hostDevice.globalKey(), 895 } 896 containerDevicesArgs = append(containerDevicesArgs, args) 897 } 898 } 899 logger.Debugf("prepared container %q network config: %+v", containerMachine.Id(), containerDevicesArgs) 900 901 if err := containerMachine.SetLinkLayerDevices(containerDevicesArgs...); err != nil { 902 return errors.Trace(err) 903 } 904 905 logger.Debugf("container %q network config set", containerMachine.Id()) 906 return nil 907 } 908 909 // MACAddressTemplate is used to generate a unique MAC address for a 910 // container. Every '%x' is replaced by a random hexadecimal digit, 911 // while the rest is kept as-is. 912 const macAddressTemplate = "00:16:3e:%02x:%02x:%02x" 913 914 // generateMACAddress creates a random MAC address within the space defined by 915 // macAddressTemplate above. 916 // 917 // TODO(dimitern): We should make a best effort to ensure the MAC address we 918 // generate is unique at least within the current environment. 919 func generateMACAddress() string { 920 digits := make([]interface{}, 3) 921 for i := range digits { 922 digits[i] = rand.Intn(256) 923 } 924 return fmt.Sprintf(macAddressTemplate, digits...) 925 }