// fetchData gets all the data from the given path relative to the given base URL. // It returns the data found and the full URL used. func fetchData(baseURL, path string, requireSigned bool) (data []byte, dataURL string, err error) { dataURL = baseURL if !strings.HasSuffix(dataURL, "/") { dataURL += "/" } dataURL += path resp, err := http.Get(dataURL) if err != nil { return nil, dataURL, errors.NotFoundf("invalid URL %q", dataURL) } defer resp.Body.Close() if resp.StatusCode == http.StatusNotFound { return nil, dataURL, errors.NotFoundf("cannot find URL %q", dataURL) } if resp.StatusCode == http.StatusUnauthorized { return nil, dataURL, errors.Unauthorizedf("unauthorised access to URL %q", dataURL) } if resp.StatusCode != http.StatusOK { return nil, dataURL, fmt.Errorf("cannot access URL %q, %q", dataURL, resp.Status) } if requireSigned { data, err = DecodeCheckSignature(resp.Body) } else { data, err = ioutil.ReadAll(resp.Body) } if err != nil { return nil, dataURL, fmt.Errorf("cannot read URL data, %v", err) } return data, dataURL, nil }
// getImageIdsPath returns the path to the metadata file containing image ids the specified constraint. func (indexRef *indexReference) getImageIdsPath(ic *ImageConstraint) (string, error) { prodIds, err := ic.Ids() if err != nil { return "", err } var containsImageIds bool for _, metadata := range indexRef.Indexes { if metadata.DataType != imageIds { continue } containsImageIds = true var cloudSpecMatches bool for _, cs := range metadata.Clouds { if cs == ic.CloudSpec { cloudSpecMatches = true break } } var prodSpecMatches bool for _, pid := range metadata.ProductIds { if containsString(prodIds, pid) { prodSpecMatches = true break } } if cloudSpecMatches && prodSpecMatches { return metadata.ProductsFilePath, nil } } if !containsImageIds { return "", errors.NotFoundf("index file missing %q data", imageIds) } return "", errors.NotFoundf("index file missing data for cloud %v and product name(s) %q", ic.CloudSpec, prodIds) }
// AgentTools returns the tools that the agent is currently running. // It an error that satisfies IsNotFound if the tools have not yet been set. func (u *Unit) AgentTools() (*tools.Tools, error) { if u.doc.Tools == nil { return nil, errors.NotFoundf("agent tools for unit %q", u) } tools := *u.doc.Tools return &tools, nil }
// getUser fetches information about the user with the // given name into the provided userDoc. func (st *State) getUser(name string, udoc *userDoc) error { err := st.users.Find(D{{"_id", name}}).One(udoc) if err == mgo.ErrNotFound { err = errors.NotFoundf("user %q", name) } return err }
// removeSettings removes the Settings for key. func removeSettings(st *State, key string) error { err := st.settings.RemoveId(key) if err == mgo.ErrNotFound { return errors.NotFoundf("settings") } return nil }
// FindEntity returns the entity with the given tag. // // The returned value can be of type *Machine, *Unit, // *User, *Service or *Environment, depending // on the tag. func (st *State) FindEntity(tag string) (Entity, error) { kind, id, err := names.ParseTag(tag, "") // TODO(fwereade): when lp:1199352 (relation lacks Tag) is fixed, add // support for relation entities here. switch kind { case names.MachineTagKind: return st.Machine(id) case names.UnitTagKind: return st.Unit(id) case names.UserTagKind: return st.User(id) case names.ServiceTagKind: return st.Service(id) case names.EnvironTagKind: conf, err := st.EnvironConfig() if err != nil { return nil, err } // Return an invalid entity error if the requested environment is not // the current one. if id != conf.Name() { return nil, errors.NotFoundf("environment %q", id) } return st.Environment() } return nil, err }
// settingsDecRefOps returns a list of operations that decrement the // ref count of the service settings identified by serviceName and // curl. If the ref count is set to zero, the appropriate setting and // ref count documents will both be deleted. func settingsDecRefOps(st *State, serviceName string, curl *charm.URL) ([]txn.Op, error) { key := serviceSettingsKey(serviceName, curl) var doc settingsRefsDoc if err := st.settingsrefs.FindId(key).One(&doc); err == mgo.ErrNotFound { return nil, errors.NotFoundf("service %q settings for charm %q", serviceName, curl) } else if err != nil { return nil, err } if doc.RefCount == 1 { return []txn.Op{{ C: st.settingsrefs.Name, Id: key, Assert: D{{"refcount", 1}}, Remove: true, }, { C: st.settings.Name, Id: key, Remove: true, }}, nil } return []txn.Op{{ C: st.settingsrefs.Name, Id: key, Assert: D{{"refcount", D{{"$gt", 1}}}}, Update: D{{"$inc", D{{"refcount", -1}}}}, }}, nil }
// AgentTools returns the tools that the agent is currently running. // It returns an error that satisfies IsNotFound if the tools have not yet been set. func (m *Machine) AgentTools() (*tools.Tools, error) { if m.doc.Tools == nil { return nil, errors.NotFoundf("agent tools for machine %v", m) } tools := *m.doc.Tools return &tools, nil }
func (st *fakeLifeState) Lifer(tag string) (state.Lifer, error) { if lifer, ok := st.entities[tag]; ok { if lifer.err != nil { return nil, lifer.err } return lifer, nil } return nil, errors.NotFoundf("entity %q", tag) }
func readConstraints(st *State, id string) (constraints.Value, error) { doc := constraintsDoc{} if err := st.constraints.FindId(id).One(&doc); err == mgo.ErrNotFound { return constraints.Value{}, errors.NotFoundf("constraints") } else if err != nil { return constraints.Value{}, err } return doc.value(), nil }
func (st *fakeRemoverState) Remover(tag string) (state.Remover, error) { if remover, ok := st.entities[tag]; ok { if remover.err != nil { return nil, remover.err } return remover, nil } return nil, errors.NotFoundf("entity %q", tag) }
// Refresh refreshes the contents of the relation from the underlying // state. It returns an error that satisfies IsNotFound if the relation has been // removed. func (r *Relation) Refresh() error { doc := relationDoc{} err := r.st.relations.FindId(r.doc.Key).One(&doc) if err == mgo.ErrNotFound { return errors.NotFoundf("relation %v", r) } if err != nil { return fmt.Errorf("cannot refresh relation %v: %v", r, err) } if r.doc.Id != doc.Id { // The relation has been destroyed and recreated. This is *not* the // same relation; if we pretend it is, we run the risk of violating // the lifecycle-only-advances guarantee. return errors.NotFoundf("relation %v", r) } r.doc = doc return nil }
// Refresh refreshes the contents of the Service from the underlying // state. It returns an error that satisfies IsNotFound if the service has // been removed. func (s *Service) Refresh() error { err := s.st.services.FindId(s.doc.Name).One(&s.doc) if err == mgo.ErrNotFound { return errors.NotFoundf("service %q", s) } if err != nil { return fmt.Errorf("cannot refresh service %q: %v", s, err) } return nil }
func (st *fakeState) FindEntity(tag string) (state.Entity, error) { entity, ok := st.entities[tag] if !ok { return nil, errors.NotFoundf("entity %q", tag) } if err := entity.error(); err != nil { return nil, err } return entity, nil }
// constraints is a helper function to return a unit's deployment constraints. func (u *Unit) constraints() (*constraints.Value, error) { cons, err := readConstraints(u.st, u.globalKey()) if errors.IsNotFoundError(err) { // Lack of constraints indicates lack of unit. return nil, errors.NotFoundf("unit") } else if err != nil { return nil, err } return &cons, nil }
// Refresh refreshes the contents of the Unit from the underlying // state. It an error that satisfies IsNotFound if the unit has been removed. func (u *Unit) Refresh() error { err := u.st.units.FindId(u.doc.Name).One(&u.doc) if err == mgo.ErrNotFound { return errors.NotFoundf("unit %q", u) } if err != nil { return fmt.Errorf("cannot refresh unit %q: %v", u, err) } return nil }
// Relation returns the existing relation with the given id. func (st *State) Relation(id int) (*Relation, error) { doc := relationDoc{} err := st.relations.Find(D{{"id", id}}).One(&doc) if err == mgo.ErrNotFound { return nil, errors.NotFoundf("relation %d", id) } if err != nil { return nil, fmt.Errorf("cannot get relation %d: %v", id, err) } return newRelation(st, &doc), nil }
// KeyRelation returns the existing relation with the given key (which can // be derived unambiguously from the relation's endpoints). func (st *State) KeyRelation(key string) (*Relation, error) { doc := relationDoc{} err := st.relations.Find(D{{"_id", key}}).One(&doc) if err == mgo.ErrNotFound { return nil, errors.NotFoundf("relation %q", key) } if err != nil { return nil, fmt.Errorf("cannot get relation %q: %v", key, err) } return newRelation(st, &doc), nil }
// newUnitName returns the next unit name. func (s *Service) newUnitName() (string, error) { change := mgo.Change{Update: D{{"$inc", D{{"unitseq", 1}}}}} result := serviceDoc{} if _, err := s.st.services.Find(D{{"_id", s.doc.Name}}).Apply(change, &result); err == mgo.ErrNotFound { return "", errors.NotFoundf("service %q", s) } else if err != nil { return "", fmt.Errorf("cannot increment unit sequence: %v", err) } name := s.doc.Name + "/" + strconv.Itoa(result.UnitSeq) return name, nil }
// Get is specified in the StorageReader interface. func (storage *azureStorage) Get(name string) (io.ReadCloser, error) { context, err := storage.getStorageContext() if err != nil { return nil, err } reader, err := context.GetBlob(storage.getContainer(), name) if gwacl.IsNotFoundError(err) { return nil, errors.NotFoundf("file %q not found", name) } return reader, err }
// Containers returns the container ids belonging to a parent machine. // TODO(wallyworld): move this method to a service func (m *Machine) Containers() ([]string, error) { var mc machineContainers err := m.st.containerRefs.FindId(m.Id()).One(&mc) if err == nil { return mc.Children, nil } if err == mgo.ErrNotFound { return nil, errors.NotFoundf("container info for machine %v", m.Id()) } return nil, err }
func getInstanceData(st *State, id string) (instanceData, error) { var instData instanceData err := st.instanceData.FindId(id).One(&instData) if err == mgo.ErrNotFound { return instanceData{}, errors.NotFoundf("instance data for machine %v", id) } if err != nil { return instanceData{}, fmt.Errorf("cannot get instance data for machine %v: %v", id, err) } return instData, nil }
// getStatus retrieves the status document associated with the given // globalKey and copies it to outStatusDoc, which needs to be created // by the caller before. func getStatus(st *State, globalKey string) (statusDoc, error) { var doc statusDoc err := st.statuses.FindId(globalKey).One(&doc) if err == mgo.ErrNotFound { return statusDoc{}, errors.NotFoundf("status") } if err != nil { return statusDoc{}, fmt.Errorf("cannot get status %q: %v", globalKey, err) } return doc, nil }
// Machine returns the machine with the given id. func (st *State) Machine(id string) (*Machine, error) { mdoc := &machineDoc{} sel := D{{"_id", id}} err := st.machines.Find(sel).One(mdoc) if err == mgo.ErrNotFound { return nil, errors.NotFoundf("machine %s", id) } if err != nil { return nil, fmt.Errorf("cannot get machine %s: %v", id, err) } return newMachine(st, mdoc), nil }
// Refresh refreshes the contents of the machine from the underlying // state. It returns an error that satisfies IsNotFound if the machine has // been removed. func (m *Machine) Refresh() error { doc := machineDoc{} err := m.st.machines.FindId(m.doc.Id).One(&doc) if err == mgo.ErrNotFound { return errors.NotFoundf("machine %v", m) } if err != nil { return fmt.Errorf("cannot refresh machine %v: %v", m, err) } m.doc = doc return nil }
// SetPublicAddress sets the public address of the unit. func (u *Unit) SetPublicAddress(address string) (err error) { ops := []txn.Op{{ C: u.st.units.Name, Id: u.doc.Name, Assert: txn.DocExists, Update: D{{"$set", D{{"publicaddress", address}}}}, }} if err := u.st.runTransaction(ops); err != nil { return fmt.Errorf("cannot set public address of unit %q: %v", u, onAbort(err, errors.NotFoundf("unit"))) } u.doc.PublicAddress = address return nil }
// retrieveFileObject retrieves the information of the named file, including // its download URL and its contents, as a MAASObject. // // This may return many different errors, but specifically, it returns // (a pointer to) errors.NotFoundError if the file did not exist. // // The function takes out a lock on the storage object. func (stor *maasStorage) retrieveFileObject(name string) (gomaasapi.MAASObject, error) { obj, err := stor.addressFileObject(name).Get() if err != nil { noObj := gomaasapi.MAASObject{} serverErr, ok := err.(gomaasapi.ServerError) if ok && serverErr.StatusCode == 404 { return noObj, errors.NotFoundf("file '%s' not found", name) } msg := fmt.Errorf("could not access file '%s': %v", name, err) return noObj, msg } return obj, nil }
// Unit returns a unit by name. func (st *State) Unit(name string) (*Unit, error) { if !names.IsUnit(name) { return nil, fmt.Errorf("%q is not a valid unit name", name) } doc := unitDoc{} err := st.units.FindId(name).One(&doc) if err == mgo.ErrNotFound { return nil, errors.NotFoundf("unit %q", name) } if err != nil { return nil, fmt.Errorf("cannot get unit %q: %v", name, err) } return newUnit(st, &doc), nil }
// Charm returns the charm with the given URL. func (st *State) Charm(curl *charm.URL) (*Charm, error) { cdoc := &charmDoc{} err := st.charms.Find(D{{"_id", curl}}).One(cdoc) if err == mgo.ErrNotFound { return nil, errors.NotFoundf("charm %q", curl) } if err != nil { return nil, fmt.Errorf("cannot get charm %q: %v", curl, err) } if err := cdoc.Meta.Check(); err != nil { return nil, fmt.Errorf("malformed charm metadata found in state: %v", err) } return newCharm(st, cdoc) }
// Write writes changes made to c back onto its node. Changes are written // as a delta applied on top of the latest version of the node, to prevent // overwriting unrelated changes made to the node since it was last read. func (c *Settings) Write() ([]ItemChange, error) { changes := []ItemChange{} updates := map[string]interface{}{} deletions := map[string]int{} for key := range cacheKeys(c.disk, c.core) { old, ondisk := c.disk[key] new, incore := c.core[key] if new == old { continue } var change ItemChange escapedKey := escapeReplacer.Replace(key) switch { case incore && ondisk: change = ItemChange{ItemModified, key, old, new} updates[escapedKey] = new case incore && !ondisk: change = ItemChange{ItemAdded, key, nil, new} updates[escapedKey] = new case ondisk && !incore: change = ItemChange{ItemDeleted, key, old, nil} deletions[escapedKey] = 1 default: panic("unreachable") } changes = append(changes, change) } if len(changes) == 0 { return []ItemChange{}, nil } sort.Sort(itemChangeSlice(changes)) ops := []txn.Op{{ C: c.st.settings.Name, Id: c.key, Assert: txn.DocExists, Update: D{ {"$set", updates}, {"$unset", deletions}, }, }} err := c.st.runTransaction(ops) if err == txn.ErrAborted { return nil, errors.NotFoundf("settings") } if err != nil { return nil, fmt.Errorf("cannot write settings: %v", err) } c.disk = copyMap(c.core, nil) return changes, nil }