func (st *State) Close() (err error) { defer errors.Contextf(&err, "closing state failed") err1 := st.watcher.Stop() err2 := st.pwatcher.Stop() st.mu.Lock() var err3 error if st.allManager != nil { err3 = st.allManager.Stop() } st.mu.Unlock() st.db.Session.Close() var i int for i, err = range []error{err1, err2, err3} { if err != nil { switch i { case 0: err = errors.Annotatef(err, "failed to stop state watcher") case 1: err = errors.Annotatef(err, "failed to stop presence watcher") case 2: err = errors.Annotatef(err, "failed to stop all manager") } return err } } return nil }
// cacheAPIInfo updates the local environment settings (.jenv file) // with the provided apiInfo, assuming we've just successfully // connected to the API server. func cacheAPIInfo(info configstore.EnvironInfo, apiInfo *api.Info) (err error) { defer errors.Contextf(&err, "failed to cache API credentials") environUUID := "" if apiInfo.EnvironTag != "" { tag, err := names.ParseEnvironTag(apiInfo.Tag) if err != nil { return err } environUUID = tag.Id() } info.SetAPIEndpoint(configstore.APIEndpoint{ Addresses: apiInfo.Addrs, CACert: string(apiInfo.CACert), EnvironUUID: environUUID, }) tag, err := names.ParseUserTag(apiInfo.Tag) if err != nil { return err } info.SetAPICredentials(configstore.APICredentials{ User: tag.Id(), Password: apiInfo.Password, }) return info.Write() }
// 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.IsValidNetwork(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 }
// cacheAPIInfo updates the local environment settings (.jenv file) // with the provided apiInfo, assuming we've just successfully // connected to the API server. func cacheAPIInfo(info configstore.EnvironInfo, apiInfo *api.Info) (err error) { defer errors.Contextf(&err, "failed to cache API credentials") var environUUID string if apiInfo.EnvironTag != nil { environUUID = apiInfo.EnvironTag.Id() } info.SetAPIEndpoint(configstore.APIEndpoint{ Addresses: apiInfo.Addrs, CACert: string(apiInfo.CACert), EnvironUUID: environUUID, }) tag, ok := apiInfo.Tag.(names.UserTag) if !ok { return errors.Errorf("apiInfo.Tag was of type %T, expecting names.UserTag", apiInfo.Tag) } info.SetAPICredentials(configstore.APICredentials{ // This looks questionable. We have a tag, say "user-admin", but then only // the Id portion of the tag is recorded, "admin", so this is really a // username, not a tag, and cannot be reconstructed accurately. User: tag.Id(), Password: apiInfo.Password, }) return info.Write() }
// 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 }
func (*errorsSuite) TestContextfNotNewer(c *gc.C) { err := fmt.Errorf("simple error") errors.Contextf(&err, "annotate") c.Assert(err, gc.ErrorMatches, "annotate: simple error") }