Пример #1
0
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())
	}
}
Пример #2
0
// 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)
}
Пример #3
0
// 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
}
Пример #4
0
// 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)
}
Пример #5
0
// 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
}
Пример #6
0
// 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
}
Пример #7
0
// 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()
}
Пример #8
0
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
}
Пример #9
0
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
}
Пример #10
0
// 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
}
Пример #11
0
// 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
}
Пример #12
0
Файл: spaces.go Проект: bac/juju
// 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
}
Пример #14
0
// 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
}
Пример #15
0
// 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
}
Пример #16
0
// 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
}
Пример #17
0
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
}
Пример #18
0
// 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])
}
Пример #19
0
// 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.
}
Пример #20
0
// 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
}
Пример #21
0
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)
}
Пример #22
0
// 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
}
Пример #23
0
// 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)
}
Пример #24
0
// 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
}
Пример #25
0
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
}
Пример #26
0
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()
}
Пример #27
0
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
}
Пример #28
0
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
}
Пример #29
0
// 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
}
Пример #30
0
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)
}