func (c *showControllerCommand) convertAccountsForShow(controllerName string, controller *ShowControllerDetails) { accounts, err := c.store.AllAccounts(controllerName) if err != nil && !errors.IsNotFound(err) { controller.Errors = append(controller.Errors, err.Error()) } if len(accounts) > 0 { controller.Accounts = make(map[string]*AccountDetails) for accountName, account := range accounts { details := &AccountDetails{User: account.User} controller.Accounts[accountName] = details if c.showPasswords { details.Password = account.Password } if err := c.convertModelsForShow(controllerName, accountName, details); err != nil { controller.Errors = append(controller.Errors, err.Error()) } } } controller.CurrentAccount, err = c.store.CurrentAccount(controllerName) if err != nil && !errors.IsNotFound(err) { controller.Errors = append(controller.Errors, err.Error()) } }
// cleanupDyingUnit marks resources owned by the unit as dying, to ensure // they are cleaned up as well. func (st *State) cleanupDyingUnit(name string) error { unit, err := st.Unit(name) if errors.IsNotFound(err) { return nil } else if err != nil { return err } // Mark the unit as departing from its joined relations, allowing // related units to start converging to a state in which that unit // is gone as quickly as possible. relations, err := unit.RelationsJoined() if err != nil { return err } for _, relation := range relations { relationUnit, err := relation.Unit(unit) if errors.IsNotFound(err) { continue } else if err != nil { return err } if err := relationUnit.PrepareLeaveScope(); err != nil { return err } } // Mark storage attachments as dying, so that they are detached // and removed from state, allowing the unit to terminate. return st.cleanupUnitStorageAttachments(unit.UnitTag(), false) }
// NewResolvePendingResourceOps generates mongo transaction operations // to set the identified resource as active. // // Leaking mongo details (transaction ops) is a necessary evil since we // do not have any machinery to facilitate transactions between // different components. func (p ResourcePersistence) NewResolvePendingResourceOps(resID, pendingID string) ([]txn.Op, error) { if pendingID == "" { return nil, errors.New("missing pending ID") } oldDoc, err := p.getOnePending(resID, pendingID) if errors.IsNotFound(err) { return nil, errors.NotFoundf("pending resource %q (%s)", resID, pendingID) } if err != nil { return nil, errors.Trace(err) } pending, err := doc2resource(oldDoc) if err != nil { return nil, errors.Trace(err) } exists := true if _, err := p.getOne(resID); errors.IsNotFound(err) { exists = false } else if err != nil { return nil, errors.Trace(err) } ops := newResolvePendingResourceOps(pending, exists) return ops, nil }
// Remove removes the storage attachment from state, and may remove its storage // instance as well, if the storage instance is Dying and no other references to // it exist. It will fail if the storage attachment is not Dead. func (st *State) RemoveStorageAttachment(storage names.StorageTag, unit names.UnitTag) (err error) { defer errors.DeferredAnnotatef(&err, "cannot remove storage attachment %s:%s", storage.Id(), unit.Id()) buildTxn := func(attempt int) ([]txn.Op, error) { s, err := st.storageAttachment(storage, unit) if errors.IsNotFound(err) { return nil, jujutxn.ErrNoOperations } else if err != nil { return nil, errors.Trace(err) } inst, err := st.storageInstance(storage) if errors.IsNotFound(err) { // This implies that the attachment was removed // after the call to st.storageAttachment. return nil, jujutxn.ErrNoOperations } else if err != nil { return nil, errors.Trace(err) } ops, err := removeStorageAttachmentOps(st, s, inst) if err != nil { return nil, errors.Trace(err) } return ops, nil } return st.run(buildTxn) }
// findImageMetadata returns all image metadata or an error fetching them. // It looks for image metadata in state. // If none are found, we fall back on original image search in simple streams. func (p *ProvisionerAPI) findImageMetadata(imageConstraint *imagemetadata.ImageConstraint, env environs.Environ) ([]params.CloudImageMetadata, error) { // Look for image metadata in state. stateMetadata, err := p.imageMetadataFromState(imageConstraint) if err != nil && !errors.IsNotFound(err) { // look into simple stream if for some reason can't get from controller, // so do not exit on error. logger.Infof("could not get image metadata from controller: %v", err) } logger.Debugf("got from controller %d metadata", len(stateMetadata)) // No need to look in data sources if found in state. if len(stateMetadata) != 0 { return stateMetadata, nil } // If no metadata is found in state, fall back to original simple stream search. // Currently, an image metadata worker picks up this metadata periodically (daily), // and stores it in state. So potentially, this collection could be different // to what is in state. dsMetadata, err := p.imageMetadataFromDataSources(env, imageConstraint) if err != nil { if !errors.IsNotFound(err) { return nil, errors.Trace(err) } } logger.Debugf("got from data sources %d metadata", len(dsMetadata)) return dsMetadata, nil }
// Destroy, when called on a Alive unit, advances its lifecycle as far as // possible; it otherwise has no effect. In most situations, the unit's // life is just set to Dying; but if a principal unit that is not assigned // to a provisioned machine is Destroyed, it will be removed from state // directly. func (u *Unit) Destroy() (err error) { defer func() { if err == nil { // This is a white lie; the document might actually be removed. u.doc.Life = Dying } }() unit := &Unit{st: u.st, doc: u.doc} buildTxn := func(attempt int) ([]txn.Op, error) { if attempt > 0 { if err := unit.Refresh(); errors.IsNotFound(err) { return nil, statetxn.ErrNoOperations } else if err != nil { return nil, err } } switch ops, err := unit.destroyOps(); err { case errRefresh: case errAlreadyDying: return nil, statetxn.ErrNoOperations case nil: return ops, nil default: return nil, err } return nil, statetxn.ErrNoOperations } if err = unit.st.run(buildTxn); err == nil { if err = unit.Refresh(); errors.IsNotFound(err) { return nil } } return err }
// obliterateUnit removes a unit from state completely. It is not safe or // sane to obliterate any unit in isolation; its only reasonable use is in // the context of machine obliteration, in which we can be sure that unclean // shutdown of units is not going to leave a machine in a difficult state. func (st *State) obliterateUnit(unitName string) error { unit, err := st.Unit(unitName) if errors.IsNotFound(err) { return nil } else if err != nil { return err } // Unlike the machine, we *can* always destroy the unit, and (at least) // prevent further dependencies being added. If we're really lucky, the // unit will be removed immediately. if err := unit.Destroy(); err != nil { return errors.Annotatef(err, "cannot destroy unit %q", unitName) } if err := unit.Refresh(); errors.IsNotFound(err) { return nil } else if err != nil { return err } for _, subName := range unit.SubordinateNames() { if err := st.obliterateUnit(subName); err != nil { return err } } if err := unit.EnsureDead(); err != nil { return err } return unit.Remove() }
func (st *State) cleanupUnitStorageAttachments(unitTag names.UnitTag, remove bool) error { storageAttachments, err := st.UnitStorageAttachments(unitTag) if err != nil { return err } for _, storageAttachment := range storageAttachments { storageTag := storageAttachment.StorageInstance() err := st.DestroyStorageAttachment(storageTag, unitTag) if errors.IsNotFound(err) { continue } else if err != nil { return err } if !remove { continue } err = st.RemoveStorageAttachment(storageTag, unitTag) if errors.IsNotFound(err) { continue } else if err != nil { return err } } return nil }
func (h *localLoginHandlers) serveLoginPost(p httprequest.Params) (interface{}, error) { if err := p.Request.ParseForm(); err != nil { return nil, err } waitId := p.Request.Form.Get("waitid") if waitId == "" { return nil, errors.NotValidf("missing waitid") } username := p.Request.Form.Get("user") password := p.Request.Form.Get("password") if !names.IsValidUser(username) { return nil, errors.NotValidf("username %q", username) } userTag := names.NewUserTag(username) if !userTag.IsLocal() { return nil, errors.NotValidf("non-local username %q", username) } authenticator := h.authCtxt.authenticator(p.Request.Host) if _, err := authenticator.Authenticate(h.state, userTag, params.LoginRequest{ Credentials: password, }); err != nil { // Mark the interaction as done (but failed), // unblocking a pending "/auth/wait" request. if err := h.authCtxt.localUserInteractions.Done(waitId, userTag, err); err != nil { if !errors.IsNotFound(err) { logger.Warningf( "failed to record completion of interaction %q for %q", waitId, userTag.Id(), ) } } return nil, errors.Trace(err) } // Provide the client with a macaroon that they can use to // prove that they have logged in, and obtain a discharge // macaroon. m, err := h.authCtxt.CreateLocalLoginMacaroon(userTag) if err != nil { return nil, err } cookie, err := httpbakery.NewCookie(macaroon.Slice{m}) if err != nil { return nil, err } http.SetCookie(p.Response, cookie) // Mark the interaction as done, unblocking a pending // "/auth/wait" request. if err := h.authCtxt.localUserInteractions.Done( waitId, userTag, nil, ); err != nil { if errors.IsNotFound(err) { err = errors.New("login timed out") } return nil, err } return nil, nil }
// UserAccess returns the access the user has on the model state // and the host controller. func UserAccess(st *state.State, utag names.UserTag) (modelUser, controllerUser permission.UserAccess, err error) { var none permission.UserAccess modelUser, err = st.UserAccess(utag, st.ModelTag()) if err != nil && !errors.IsNotFound(err) { return none, none, errors.Trace(err) } controllerUser, err = state.ControllerAccess(st, utag) if err != nil && !errors.IsNotFound(err) { return none, none, errors.Trace(err) } // TODO(perrito666) remove the following section about everyone group // when groups are implemented, this accounts only for the lack of a local // ControllerUser when logging in from an external user that has not been granted // permissions on the controller but there are permissions for the special // everyone group. if !utag.IsLocal() { controllerUser, err = maybeUseGroupPermission(st.UserAccess, controllerUser, st.ControllerTag(), utag) if err != nil { return none, none, errors.Annotatef(err, "obtaining ControllerUser for everyone group") } } if permission.IsEmptyUserAccess(modelUser) && permission.IsEmptyUserAccess(controllerUser) { return none, none, errors.NotFoundf("model or controller user") } return modelUser, controllerUser, nil }
// GetCurrentModel returns the name of the current Juju model. // // If $JUJU_MODEL is set, use that. Otherwise, get the current // controller by reading $XDG_DATA_HOME/juju/current-controller, // and then identifying the current model for that controller // in models.yaml. If there is no current controller, or no // current model for that controller, then an empty string is // returned. It is not an error to have no default model. func GetCurrentModel(store jujuclient.ClientStore) (string, error) { if model := os.Getenv(osenv.JujuModelEnvKey); model != "" { return model, nil } currentController, err := ReadCurrentController() if err != nil { return "", errors.Trace(err) } if currentController == "" { return "", nil } currentAccount, err := store.CurrentAccount(currentController) if errors.IsNotFound(err) { return "", nil } else if err != nil { return "", errors.Trace(err) } currentModel, err := store.CurrentModel(currentController, currentAccount) if errors.IsNotFound(err) { return "", nil } else if err != nil { return "", errors.Trace(err) } return currentModel, nil }
// AddSpace creates and returns a new space. func (st *State) AddSpace(name string, providerId network.Id, subnets []string, isPublic bool) (newSpace *Space, err error) { defer errors.DeferredAnnotatef(&err, "adding space %q", name) if !names.IsValidSpace(name) { return nil, errors.NewNotValid(nil, "invalid space name") } spaceDoc := spaceDoc{ Life: Alive, Name: name, IsPublic: isPublic, ProviderId: string(providerId), } newSpace = &Space{doc: spaceDoc, st: st} ops := []txn.Op{{ C: spacesC, Id: name, Assert: txn.DocMissing, Insert: spaceDoc, }} if providerId != "" { ops = append(ops, st.networkEntityGlobalKeyOp("space", providerId)) } for _, subnetId := range subnets { // TODO:(mfoord) once we have refcounting for subnets we should // also assert that the refcount is zero as moving the space of a // subnet in use is not permitted. ops = append(ops, txn.Op{ C: subnetsC, Id: subnetId, Assert: txn.DocExists, Update: bson.D{{"$set", bson.D{{"space-name", name}}}}, }) } if err := st.runTransaction(ops); err == txn.ErrAborted { if _, err := st.Space(name); err == nil { return nil, errors.AlreadyExistsf("space %q", name) } for _, subnetId := range subnets { if _, err := st.Subnet(subnetId); errors.IsNotFound(err) { return nil, err } } if err := newSpace.Refresh(); err != nil { if errors.IsNotFound(err) { return nil, errors.Errorf("ProviderId %q not unique", providerId) } return nil, errors.Trace(err) } return nil, errors.Trace(err) } else if err != nil { return nil, err } return newSpace, nil }
// convertControllerDetails takes a map of Controllers and // the recently used model for each and creates a list of // amalgamated controller and model details. func (c *listControllersCommand) convertControllerDetails(storeControllers map[string]jujuclient.ControllerDetails) (map[string]ControllerItem, []string) { if len(storeControllers) == 0 { return nil, nil } errs := []string{} addError := func(msg, controllerName string, err error) { logger.Errorf(fmt.Sprintf("getting current %s for controller %s: %v", msg, controllerName, err)) errs = append(errs, msg) } controllers := map[string]ControllerItem{} for controllerName, details := range storeControllers { serverName := "" // The most recently connected-to address // is the first in the list. if len(details.APIEndpoints) > 0 { serverName = details.APIEndpoints[0] } var userName, modelName string accountName, err := c.store.CurrentAccount(controllerName) if err != nil { if !errors.IsNotFound(err) { addError("account name", controllerName, err) continue } } else { currentAccount, err := c.store.AccountByName(controllerName, accountName) if err != nil { addError("account details", controllerName, err) continue } userName = currentAccount.User currentModel, err := c.store.CurrentModel(controllerName, accountName) if err != nil { if !errors.IsNotFound(err) { addError("model", controllerName, err) continue } } modelName = currentModel } controllers[controllerName] = ControllerItem{ ModelName: modelName, User: userName, Server: serverName, APIEndpoints: details.APIEndpoints, ControllerUUID: details.ControllerUUID, CACert: details.CACert, } } return controllers, errs }
// ModelConfigDefaultValues returns the default config values to be used // when creating a new model, and the origin of those values. func (st *State) ModelConfigDefaultValues() (config.ModelDefaultAttributes, error) { model, err := st.Model() if err != nil { return nil, errors.Trace(err) } cloudName := model.Cloud() cloud, err := st.Cloud(cloudName) if err != nil { return nil, errors.Trace(err) } result := make(config.ModelDefaultAttributes) // Juju defaults defaultAttrs, err := st.defaultInheritedConfig() if err != nil { return nil, errors.Trace(err) } for k, v := range defaultAttrs { result[k] = config.AttributeDefaultValues{Default: v} } // Controller config ciCfg, err := st.controllerInheritedConfig() if err != nil && !errors.IsNotFound(err) { return nil, errors.Trace(err) } for k, v := range ciCfg { if ds, ok := result[k]; ok { ds.Controller = v result[k] = ds } else { result[k] = config.AttributeDefaultValues{Controller: v} } } // Region config for _, region := range cloud.Regions { rspec := &environs.RegionSpec{Cloud: cloudName, Region: region.Name} riCfg, err := st.regionInheritedConfig(rspec)() if err != nil { if errors.IsNotFound(err) { continue } return nil, errors.Trace(err) } for k, v := range riCfg { regCfg := config.RegionDefaultValue{Name: region.Name, Value: v} if ds, ok := result[k]; ok { ds.Regions = append(result[k].Regions, regCfg) result[k] = ds } else { result[k] = config.AttributeDefaultValues{Regions: []config.RegionDefaultValue{regCfg}} } } } return result, nil }
// getMaybeSignedMetadata returns metadata records matching the specified constraint in params. func getMaybeSignedMetadata(source DataSource, params GetMetadataParams, signed bool) ([]interface{}, *ResolveInfo, error) { makeIndexPath := func(basePath string) string { pathNoSuffix := fmt.Sprintf(basePath, params.StreamsVersion) indexPath := pathNoSuffix + UnsignedSuffix if signed { indexPath = pathNoSuffix + SignedSuffix } return indexPath } resolveInfo := &ResolveInfo{} resolveInfo.Source = source.Description() resolveInfo.Signed = signed indexPath := makeIndexPath(defaultIndexPath) logger.Tracef("looking for data index using path %s", indexPath) mirrorsPath := fmt.Sprintf(defaultMirrorsPath, params.StreamsVersion) cons := params.LookupConstraint indexRef, indexURL, err := fetchIndex( source, indexPath, mirrorsPath, cons.Params().CloudSpec, signed, params.ValueParams, ) logger.Tracef("looking for data index using URL %s", indexURL) if errors.IsNotFound(err) || errors.IsUnauthorized(err) { legacyIndexPath := makeIndexPath(defaultLegacyIndexPath) logger.Tracef("%s not accessed, actual error: %v", indexPath, err) logger.Tracef("%s not accessed, trying legacy index path: %s", indexPath, legacyIndexPath) indexPath = legacyIndexPath indexRef, indexURL, err = fetchIndex( source, indexPath, mirrorsPath, cons.Params().CloudSpec, signed, params.ValueParams, ) } resolveInfo.IndexURL = indexURL if err != nil { if errors.IsNotFound(err) || errors.IsUnauthorized(err) { logger.Tracef("cannot load index %q: %v", indexURL, err) } return nil, resolveInfo, err } logger.Tracef("read metadata index at %q", indexURL) items, err := indexRef.getLatestMetadataWithFormat(cons, ProductFormat, signed) if err != nil { if errors.IsNotFound(err) { logger.Debugf("skipping index %q because of missing information: %v", indexURL, err) return nil, resolveInfo, err } if _, ok := err.(*noMatchingProductsError); ok { logger.Debugf("%v", err) } } if indexRef.Source.Description() == "mirror" { resolveInfo.MirrorURL = indexRef.Source.(*urlDataSource).baseURL } return items, resolveInfo, err }
// HasPermission returns true if the specified user has the specified // permission on target. func HasPermission(userGetter userAccessFunc, utag names.Tag, requestedPermission permission.Access, target names.Tag) (bool, error) { validForKind := false switch requestedPermission { case permission.LoginAccess, permission.AddModelAccess, permission.SuperuserAccess: validForKind = target.Kind() == names.ControllerTagKind case permission.ReadAccess, permission.WriteAccess, permission.AdminAccess: validForKind = target.Kind() == names.ModelTagKind } if !validForKind { return false, nil } userTag, ok := utag.(names.UserTag) if !ok { // lets not reveal more than is strictly necessary return false, nil } user, err := userGetter(userTag, target) if err != nil && !errors.IsNotFound(err) { return false, errors.Annotatef(err, "while obtaining %s user", target.Kind()) } // there is a special case for external users, a group called everyone@external if target.Kind() == names.ControllerTagKind && !userTag.IsLocal() { controllerTag, ok := target.(names.ControllerTag) if !ok { return false, errors.NotValidf("controller tag") } // TODO(perrito666) remove the following section about everyone group // when groups are implemented, this accounts only for the lack of a local // ControllerUser when logging in from an external user that has not been granted // permissions on the controller but there are permissions for the special // everyone group. user, err = maybeUseGroupPermission(userGetter, user, controllerTag, userTag) if err != nil { return false, errors.Trace(err) } if permission.IsEmptyUserAccess(user) { return false, nil } } // returning this kind of information would be too much information to reveal too. if errors.IsNotFound(err) { return false, nil } modelPermission := user.Access.EqualOrGreaterModelAccessThan(requestedPermission) && target.Kind() == names.ModelTagKind controllerPermission := user.Access.EqualOrGreaterControllerAccessThan(requestedPermission) && target.Kind() == names.ControllerTagKind if !controllerPermission && !modelPermission { return false, nil } return true, nil }
func (c *addCredentialCommand) existingCredentialsForCloud() (*jujucloud.CloudCredential, error) { existingCredentials, err := c.store.CredentialForCloud(c.CloudName) if err != nil && !errors.IsNotFound(err) { return nil, errors.Annotate(err, "reading existing credentials for cloud") } if errors.IsNotFound(err) { existingCredentials = &jujucloud.CloudCredential{ AuthCredentials: make(map[string]jujucloud.Credential), } } return existingCredentials, nil }
// Print out the addresses of the API server endpoints. func (c *endpointCommand) Run(ctx *cmd.Context) error { apiendpoint, err := endpoint(c.EnvCommandBase, c.refresh) if err != nil && !errors.IsNotFound(err) { return err } if errors.IsNotFound(err) || len(apiendpoint.Addresses) == 0 { return errors.Errorf("no API endpoints available") } if c.all { return c.out.Write(ctx, apiendpoint.Addresses) } return c.out.Write(ctx, apiendpoint.Addresses[0:1]) }
// cleanupForceDestroyedMachine systematically destroys and removes all entities // that depend upon the supplied machine, and removes the machine from state. It's // expected to be used in response to destroy-machine --force. func (st *State) cleanupForceDestroyedMachine(machineId string) error { machine, err := st.Machine(machineId) if errors.IsNotFound(err) { return nil } else if err != nil { return err } if err := cleanupDyingMachineResources(machine); err != nil { return err } // In an ideal world, we'd call machine.Destroy() here, and thus prevent // new dependencies being added while we clean up the ones we know about. // But machine destruction is unsophisticated, and doesn't allow for // destruction while dependencies exist; so we just have to deal with that // possibility below. if err := st.cleanupContainers(machine); err != nil { return err } for _, unitName := range machine.doc.Principals { if err := st.obliterateUnit(unitName); err != nil { return err } } // We need to refresh the machine at this point, because the local copy // of the document will not reflect changes caused by the unit cleanups // above, and may thus fail immediately. if err := machine.Refresh(); errors.IsNotFound(err) { return nil } else if err != nil { return err } // TODO(fwereade): 2013-11-11 bug 1250104 // If this fails, it's *probably* due to a race in which new dependencies // were added while we cleaned up the old ones. If the cleanup doesn't run // again -- which it *probably* will anyway -- the issue can be resolved by // force-destroying the machine again; that's better than adding layer // upon layer of complication here. if err := machine.EnsureDead(); err != nil { return err } removePortsOps, err := machine.removePortsOps() if err != nil { return err } return st.runTransaction(removePortsOps) // Note that we do *not* remove the machine entirely: we leave it for the // provisioner to clean up, so that we don't end up with an unreferenced // instance that would otherwise be ignored when in provisioner-safe-mode. }
// removeStorageInstanceOps removes the storage instance with the given // tag from state, if the specified assertions hold true. func removeStorageInstanceOps( st *State, tag names.StorageTag, assert bson.D, ) ([]txn.Op, error) { ops := []txn.Op{{ C: storageInstancesC, Id: tag.Id(), Assert: assert, Remove: true, }} machineStorageOp := func(c string, id string) txn.Op { return txn.Op{ C: c, Id: id, Assert: bson.D{{"storageid", tag.Id()}}, Update: bson.D{{"$set", bson.D{{"storageid", ""}}}}, } } // If the storage instance has an assigned volume and/or filesystem, // unassign them. Any volumes and filesystems bound to the storage // will be destroyed. volume, err := st.storageInstanceVolume(tag) if err == nil { ops = append(ops, machineStorageOp( volumesC, volume.Tag().Id(), )) if volume.LifeBinding() == tag { ops = append(ops, destroyVolumeOps(st, volume)...) } } else if !errors.IsNotFound(err) { return nil, errors.Trace(err) } filesystem, err := st.storageInstanceFilesystem(tag) if err == nil { ops = append(ops, machineStorageOp( filesystemsC, filesystem.Tag().Id(), )) if filesystem.LifeBinding() == tag { ops = append(ops, destroyFilesystemOps(st, filesystem)...) } } else if !errors.IsNotFound(err) { return nil, errors.Trace(err) } return ops, nil }
func (s *statusSuite) TestStatusNotFoundError(c *gc.C) { err := state.NewStatusNotFound("foo") c.Assert(state.IsStatusNotFound(err), jc.IsTrue) c.Assert(errors.IsNotFound(err), jc.IsTrue) c.Assert(err.Error(), gc.Equals, `status for key "foo" not found`) c.Assert(state.IsStatusNotFound(errors.New("foo")), jc.IsFalse) }
// Handle is part of the StringsWorker interface. func (a *addresserHandler) Handle(ids []string) error { if a.releaser == nil { return nil } for _, id := range ids { logger.Debugf("received notification about address %v", id) addr, err := a.st.IPAddress(id) if err != nil { if errors.IsNotFound(err) { logger.Debugf("address %v was removed; skipping", id) continue } return err } if addr.Life() != state.Dead { logger.Debugf("address %v is not Dead (life %q); skipping", id, addr.Life()) continue } err = a.releaseIPAddress(addr) if err != nil { return err } logger.Debugf("address %v released", id) err = addr.Remove() if err != nil { return err } logger.Debugf("address %v removed", id) } return nil }
// Destroy ensures that the relation will be removed at some point; if no units // are currently in scope, it will be removed immediately. func (r *Relation) Destroy() (err error) { defer errors.Maskf(&err, "cannot destroy relation %q", r) if len(r.doc.Endpoints) == 1 && r.doc.Endpoints[0].Role == charm.RolePeer { return fmt.Errorf("is a peer relation") } defer func() { if err == nil { // This is a white lie; the document might actually be removed. r.doc.Life = Dying } }() rel := &Relation{r.st, r.doc} // In this context, aborted transactions indicate that the number of units // in scope have changed between 0 and not-0. The chances of 5 successive // attempts each hitting this change -- which is itself an unlikely one -- // are considered to be extremely small. buildTxn := func(attempt int) ([]txn.Op, error) { if attempt > 0 { if err := rel.Refresh(); errors.IsNotFound(err) { return []txn.Op{}, nil } else if err != nil { return nil, err } } ops, _, err := rel.destroyOps("") if err == errAlreadyDying { return nil, jujutxn.ErrNoOperations } else if err != nil { return nil, err } return ops, nil } return rel.st.run(buildTxn) }
// setPrivateMetadataSources sets the default tools metadata source // for tools syncing, and adds an image metadata source after verifying // the contents. func setPrivateMetadataSources(env environs.Environ, metadataDir string) ([]*imagemetadata.ImageMetadata, error) { logger.Infof("Setting default tools and image metadata sources: %s", metadataDir) tools.DefaultBaseURL = metadataDir imageMetadataDir := filepath.Join(metadataDir, storage.BaseImagesPath) if _, err := os.Stat(imageMetadataDir); err != nil { if !os.IsNotExist(err) { return nil, errors.Annotate(err, "cannot access image metadata") } return nil, nil } baseURL := fmt.Sprintf("file://%s", filepath.ToSlash(imageMetadataDir)) datasource := simplestreams.NewURLDataSource("bootstrap metadata", baseURL, utils.NoVerifySSLHostnames) // Read the image metadata, as we'll want to upload it to the environment. imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{}) existingMetadata, _, err := imagemetadata.Fetch( []simplestreams.DataSource{datasource}, imageConstraint, false) if err != nil && !errors.IsNotFound(err) { return nil, errors.Annotate(err, "cannot read image metadata") } // Add an image metadata datasource for constraint validation, etc. // TODO (anastasiamac 2015-09-26) Delete when search path is modified to look // into state first. environs.RegisterUserImageDataSourceFunc("bootstrap metadata", func(environs.Environ) (simplestreams.DataSource, error) { return datasource, nil }) logger.Infof("custom image metadata added to search path") return existingMetadata, nil }
func userAuthorizedToChangeAccess(st common.ModelManagerBackend, userIsAdmin bool, userTag names.UserTag) error { if userIsAdmin { // Just confirm that the model that has been given is a valid model. _, err := st.Model() if err != nil { return errors.Trace(err) } return nil } // Get the current user's ModelUser for the Model to see if the user has // permission to grant or revoke permissions on the model. currentUser, err := st.UserAccess(userTag, st.ModelTag()) if err != nil { if errors.IsNotFound(err) { // No, this user doesn't have permission. return common.ErrPerm } return errors.Annotate(err, "could not retrieve user") } if currentUser.Access != permission.AdminAccess { return common.ErrPerm } return nil }
func (m *ModelManagerAPI) dumpModelDB(args params.Entity) (map[string]interface{}, error) { modelTag, err := names.ParseModelTag(args.Tag) if err != nil { return nil, errors.Trace(err) } isModelAdmin, err := m.authorizer.HasPermission(permission.AdminAccess, modelTag) if err != nil { return nil, errors.Trace(err) } if !isModelAdmin && !m.isAdmin { return nil, common.ErrPerm } st := m.state if st.ModelTag() != modelTag { st, err = m.state.ForModel(modelTag) if err != nil { if errors.IsNotFound(err) { return nil, errors.Trace(common.ErrBadId) } return nil, errors.Trace(err) } defer st.Close() } return st.DumpAll() }
func (m *ModelManagerAPI) hasWriteAccess(modelTag names.ModelTag) (bool, error) { canWrite, err := m.authorizer.HasPermission(permission.WriteAccess, modelTag) if errors.IsNotFound(err) { return false, nil } return canWrite, err }
func (mi *maas1Instance) hardwareCharacteristics() (*instance.HardwareCharacteristics, error) { nodeArch, _, err := mi.architecture() if err != nil { return nil, errors.Annotate(err, "error determining architecture") } nodeCpuCount, err := mi.cpuCount() if err != nil { return nil, errors.Annotate(err, "error determining cpu count") } nodeMemoryMB, err := mi.memory() if err != nil { return nil, errors.Annotate(err, "error determining available memory") } zone, err := mi.zone() if err != nil { return nil, errors.Annotate(err, "error determining availability zone") } hc := &instance.HardwareCharacteristics{ Arch: &nodeArch, CpuCores: &nodeCpuCount, Mem: &nodeMemoryMB, AvailabilityZone: &zone, } nodeTags, err := mi.tagNames() if err != nil && !errors.IsNotFound(err) { return nil, errors.Annotate(err, "error determining tag names") } if len(nodeTags) > 0 { hc.Tags = &nodeTags } return hc, nil }
// HookVars returns an os.Environ-style list of strings necessary to run a hook // such that it can know what environment it's operating in, and can call back // into context. func (context *HookContext) HookVars(paths Paths) ([]string, error) { vars := context.proxySettings.AsEnvironmentValues() vars = append(vars, "CHARM_DIR="+paths.GetCharmDir(), // legacy, embarrassing "JUJU_CHARM_DIR="+paths.GetCharmDir(), "JUJU_CONTEXT_ID="+context.id, "JUJU_AGENT_SOCKET="+paths.GetJujucSocket(), "JUJU_UNIT_NAME="+context.unitName, "JUJU_ENV_UUID="+context.uuid, "JUJU_ENV_NAME="+context.envName, "JUJU_API_ADDRESSES="+strings.Join(context.apiAddrs, " "), "JUJU_METER_STATUS="+context.meterStatus.code, "JUJU_METER_INFO="+context.meterStatus.info, "JUJU_MACHINE_ID="+context.assignedMachineTag.Id(), "JUJU_AVAILABILITY_ZONE="+context.availabilityzone, ) if r, err := context.HookRelation(); err == nil { vars = append(vars, "JUJU_RELATION="+r.Name(), "JUJU_RELATION_ID="+r.FakeId(), "JUJU_REMOTE_UNIT="+context.remoteUnitName, ) } else if !errors.IsNotFound(err) { return nil, errors.Trace(err) } if context.actionData != nil { vars = append(vars, "JUJU_ACTION_NAME="+context.actionData.Name, "JUJU_ACTION_UUID="+context.actionData.Tag.Id(), "JUJU_ACTION_TAG="+context.actionData.Tag.String(), ) } return append(vars, OSDependentEnvVars(paths)...), nil }
func (m *Machine) validateLinkLayerDeviceParent(args *LinkLayerDeviceArgs) error { hostMachineID, parentDeviceName, err := parseLinkLayerDeviceParentNameAsGlobalKey(args.ParentName) if err != nil { return errors.Trace(err) } else if hostMachineID == "" { // Not a global key, so validate as usual. if err := m.validateParentDeviceNameWhenNotAGlobalKey(args); errors.IsNotFound(err) { return errors.NewNotValid(err, "ParentName not valid") } else if err != nil { return errors.Trace(err) } return nil } ourParentMachineID, hasParent := m.ParentId() if !hasParent { // Using global key for ParentName not allowed for non-container machine // devices. return errors.NotValidf("ParentName %q for non-container machine %q", args.ParentName, m.Id()) } if hostMachineID != ourParentMachineID { // ParentName as global key only allowed when the key's machine ID is // the container's host machine. return errors.NotValidf("ParentName %q on non-host machine %q", args.ParentName, hostMachineID) } err = m.verifyHostMachineParentDeviceExistsAndIsABridgeDevice(hostMachineID, parentDeviceName) return errors.Trace(err) }