// AddNetwork creates a new network with the given params. If a // network with the same name or provider id already exists in state, // an error satisfying errors.IsAlreadyExists is returned. func (st *State) AddNetwork(args NetworkInfo) (n *Network, err error) { defer errors.Contextf(&err, "cannot add network %q", args.Name) if args.CIDR != "" { _, _, err := net.ParseCIDR(args.CIDR) if err != nil { return nil, err } } if args.Name == "" { return nil, fmt.Errorf("name must be not empty") } if !names.IsNetwork(args.Name) { return nil, fmt.Errorf("invalid name") } if args.ProviderId == "" { return nil, fmt.Errorf("provider id must be not empty") } if args.VLANTag < 0 || args.VLANTag > 4094 { return nil, fmt.Errorf("invalid VLAN tag %d: must be between 0 and 4094", args.VLANTag) } doc := newNetworkDoc(args) ops := []txn.Op{{ C: st.networks.Name, Id: args.Name, Assert: txn.DocMissing, Insert: doc, }} err = st.runTransaction(ops) switch err { case txn.ErrAborted: if _, err = st.Network(args.Name); err == nil { return nil, errors.AlreadyExistsf("network %q", args.Name) } else if err != nil { return nil, err } case nil: // We have a unique key restriction on the ProviderId field, // which will cause the insert to fail if there is another // record with the same provider id in the table. The txn // logic does not report insertion errors, so we check that // the record has actually been inserted correctly before // reporting success. if _, err = st.Network(args.Name); err != nil { return nil, errors.AlreadyExistsf("network with provider id %q", args.ProviderId) } return newNetwork(st, doc), nil } return nil, err }
// AddNetworkInterface creates a new network interface with the given // args for this machine. The machine must be alive and not yet // provisioned, and there must be no other interface with the same MAC // address on the same network, or the same name on that machine for // this to succeed. If a network interface already exists, the // returned error satisfies errors.IsAlreadyExists. func (m *Machine) AddNetworkInterface(args NetworkInterfaceInfo) (iface *NetworkInterface, err error) { defer errors.Contextf(&err, "cannot add network interface %q to machine %q", args.InterfaceName, m.doc.Id) if args.MACAddress == "" { return nil, fmt.Errorf("MAC address must be not empty") } if _, err = net.ParseMAC(args.MACAddress); err != nil { return nil, err } if args.InterfaceName == "" { return nil, fmt.Errorf("interface name must be not empty") } aliveAndNotProvisioned := append(isAliveDoc, bson.D{{"nonce", ""}}...) doc := newNetworkInterfaceDoc(args) doc.MachineId = m.doc.Id doc.Id = bson.NewObjectId() ops := []txn.Op{{ C: m.st.networks.Name, Id: args.NetworkName, Assert: txn.DocExists, }, { C: m.st.machines.Name, Id: m.doc.Id, Assert: aliveAndNotProvisioned, }, { C: m.st.networkInterfaces.Name, Id: doc.Id, Assert: txn.DocMissing, Insert: doc, }} err = m.st.runTransaction(ops) switch err { case txn.ErrAborted: if _, err = m.st.Network(args.NetworkName); err != nil { return nil, err } if err = m.Refresh(); err != nil { return nil, err } else if m.doc.Life != Alive { return nil, fmt.Errorf("machine is not alive") } else if m.doc.Nonce != "" { msg := "machine already provisioned: dynamic network interfaces not currently supported" return nil, fmt.Errorf(msg) } // Should never happen. logger.Errorf("unhandled assert while adding network interface doc %#v", doc) case nil: // We have a unique key restrictions on the following fields: // - InterfaceName, MachineId // - MACAddress, NetworkName // These will cause the insert to fail if there is another record // with the same combination of values in the table. // The txn logic does not report insertion errors, so we check // that the record has actually been inserted correctly before // reporting success. if err = m.st.networkInterfaces.FindId(doc.Id).One(&doc); err == nil { return newNetworkInterface(m.st, doc), nil } sel := bson.D{{"interfacename", args.InterfaceName}, {"machineid", m.doc.Id}} if err = m.st.networkInterfaces.Find(sel).One(nil); err == nil { return nil, errors.AlreadyExistsf("%q on machine %q", args.InterfaceName, m.doc.Id) } sel = bson.D{{"macaddress", args.MACAddress}, {"networkname", args.NetworkName}} if err = m.st.networkInterfaces.Find(sel).One(nil); err == nil { return nil, errors.AlreadyExistsf("MAC address %q on network %q", args.MACAddress, args.NetworkName) } // Should never happen. logger.Errorf("unknown error while adding network interface doc %#v", doc) } return nil, err }
func contextf(err error, format string, args ...interface{}) error { errors.Contextf(&err, format, args...) return err }