// DetectRegions implements environs.CloudRegionDetector. func (EnvironProvider) DetectRegions() ([]cloud.Region, error) { // If OS_REGION_NAME and OS_AUTH_URL are both set, // return return a region using them. creds := identity.CredentialsFromEnv() if creds.Region == "" { return nil, errors.NewNotFound(nil, "OS_REGION_NAME environment variable not set") } if creds.URL == "" { return nil, errors.NewNotFound(nil, "OS_AUTH_URL environment variable not set") } return []cloud.Region{{ Name: creds.Region, Endpoint: creds.URL, }}, nil }
func (s *PersistenceSuite) TestNewResourcePendingResourceOpsNotFound(c *gc.C) { pendingID := "some-unique-ID-001" stored, expected := newResource(c, "a-service", "spam") stored.PendingID = pendingID doc := expected // a copy doc.DocID = pendingResourceID(stored.ID, pendingID) doc.PendingID = pendingID s.base.ReturnOne = doc notFound := errors.NewNotFound(nil, "") s.stub.SetErrors(nil, notFound) p := NewPersistence(s.base) ops, err := p.NewResolvePendingResourceOps(stored.ID, stored.PendingID) c.Assert(err, jc.ErrorIsNil) s.stub.CheckCallNames(c, "One", "One") s.stub.CheckCall(c, 0, "One", "resources", "resource#a-service/spam#pending-some-unique-ID-001", &doc) c.Check(ops, jc.DeepEquals, []txn.Op{{ C: "resources", Id: doc.DocID, Assert: txn.DocExists, Remove: true, }, { C: "resources", Id: expected.DocID, Assert: txn.DocMissing, Insert: &expected, }}) }
func (s *ResourcePersistenceSuite) TestSetResourceNotFound(c *gc.C) { applicationname := "a-application" res, doc := newPersistenceResource(c, applicationname, "spam") s.base.ReturnOne = doc expected := doc // a copy expected.StoragePath = "" p := NewResourcePersistence(s.base) notFound := errors.NewNotFound(nil, "") ignoredErr := errors.New("<never reached>") s.stub.SetErrors(notFound, nil, nil, nil, ignoredErr) err := p.SetResource(res.Resource) c.Assert(err, jc.ErrorIsNil) s.stub.CheckCallNames(c, "One", "Run", "ApplicationExistsOps", "RunTransaction", ) s.stub.CheckCall(c, 3, "RunTransaction", []txn.Op{{ C: "resources", Id: "resource#a-application/spam", Assert: txn.DocMissing, Insert: &expected, }, { C: "application", Id: "a-application", Assert: txn.DocExists, }}) }
// cancelDeployment cancels a template deployment. func (env *azureEnviron) cancelDeployment(name string) error { deploymentsClient := resources.DeploymentsClient{env.resources} logger.Debugf("- canceling deployment %q", name) var cancelResult autorest.Response if err := env.callAPI(func() (autorest.Response, error) { var err error cancelResult, err = deploymentsClient.Cancel(env.resourceGroup, name) return cancelResult, err }); err != nil { if cancelResult.Response != nil { switch cancelResult.StatusCode { case http.StatusNotFound: return errors.NewNotFound(err, fmt.Sprintf("deployment %q not found", name)) case http.StatusConflict: if err, ok := errorutils.ServiceError(err); ok { if err.Code == serviceErrorCodeDeploymentCannotBeCancelled { // Deployments can only canceled while they're running. return nil } } } } return errors.Annotatef(err, "canceling deployment %q", name) } return nil }
// RestoreError makes a best effort at converting the given error // back into an error originally converted by ServerError(). If the // error could not be converted then false is returned. func RestoreError(err error) (error, bool) { err = errors.Cause(err) if apiErr, ok := err.(*params.Error); !ok { return err, false } else if apiErr == nil { return nil, true } if params.ErrCode(err) == "" { return err, false } msg := err.Error() if singleton, ok := singletonError(err); ok { return singleton, true } // TODO(ericsnow) Support the other error types handled by ServerError(). switch { case params.IsCodeUnauthorized(err): return errors.NewUnauthorized(nil, msg), true case params.IsCodeNotFound(err): // TODO(ericsnow) UnknownModelError should be handled here too. // ...by parsing msg? return errors.NewNotFound(nil, msg), true case params.IsCodeAlreadyExists(err): return errors.NewAlreadyExists(nil, msg), true case params.IsCodeNotAssigned(err): return errors.NewNotAssigned(nil, msg), true case params.IsCodeHasAssignedUnits(err): // TODO(ericsnow) Handle state.HasAssignedUnitsError here. // ...by parsing msg? return err, false case params.IsCodeNoAddressSet(err): // TODO(ericsnow) Handle isNoAddressSetError here. // ...by parsing msg? return err, false case params.IsCodeNotProvisioned(err): return errors.NewNotProvisioned(nil, msg), true case params.IsCodeUpgradeInProgress(err): // TODO(ericsnow) Handle state.UpgradeInProgressError here. // ...by parsing msg? return err, false case params.IsCodeMachineHasAttachedStorage(err): // TODO(ericsnow) Handle state.HasAttachmentsError here. // ...by parsing msg? return err, false case params.IsCodeNotSupported(err): return errors.NewNotSupported(nil, msg), true case params.IsBadRequest(err): return errors.NewBadRequest(nil, msg), true case params.IsMethodNotAllowed(err): return errors.NewMethodNotAllowed(nil, msg), true case params.ErrCode(err) == params.CodeDischargeRequired: // TODO(ericsnow) Handle DischargeRequiredError here. return err, false default: return err, false } }
// getRegion returns the cloud.Region to use, based on the specified // region name, and the region name selected if none was specified. // // If no region name is specified, and there is at least one region, // we use the first region in the list. // // If no region name is specified, and there are no regions at all, // then we synthesise a region from the cloud's endpoint information // and just pass this on to the provider. func getRegion(cloud *jujucloud.Cloud, cloudName, regionName string) (jujucloud.Region, error) { if len(cloud.Regions) == 0 { // The cloud does not specify regions, so assume // that the cloud provider does not have a concept // of regions, or has no pre-defined regions, and // defer validation to the provider. region := jujucloud.Region{ regionName, cloud.Endpoint, cloud.StorageEndpoint, } return region, nil } if regionName == "" { // No region was specified, use the first region in the list. return cloud.Regions[0], nil } for _, region := range cloud.Regions { // Do a case-insensitive comparison if strings.EqualFold(region.Name, regionName) { return region, nil } } return jujucloud.Region{}, errors.NewNotFound(nil, fmt.Sprintf( "region %q in cloud %q not found (expected one of %q)\nalternatively, try %q", regionName, cloudName, cloudRegionNames(cloud), "juju update-clouds", )) }
func (c OpenstackCredentials) detectCredential() (*cloud.Credential, string, string, error) { creds := identity.CredentialsFromEnv() if creds.TenantName == "" { return nil, "", "", errors.NewNotFound(nil, "OS_TENANT_NAME environment variable not set") } if creds.User == "" { return nil, "", "", errors.NewNotFound(nil, "neither OS_USERNAME nor OS_ACCESS_KEY environment variable not set") } if creds.Secrets == "" { return nil, "", "", errors.NewNotFound(nil, "neither OS_PASSWORD nor OS_SECRET_KEY environment variable not set") } user, err := utils.LocalUsername() if err != nil { return nil, "", "", errors.Trace(err) } // If OS_USERNAME or NOVA_USERNAME is set, assume userpass. var credential cloud.Credential if os.Getenv("OS_USERNAME") != "" || os.Getenv("NOVA_USERNAME") != "" { user = creds.User credential = cloud.NewCredential( cloud.UserPassAuthType, map[string]string{ credAttrUserName: creds.User, credAttrPassword: creds.Secrets, credAttrTenantName: creds.TenantName, credAttrDomainName: creds.DomainName, }, ) } else { credential = cloud.NewCredential( cloud.AccessKeyAuthType, map[string]string{ credAttrAccessKey: creds.User, credAttrSecretKey: creds.Secrets, credAttrTenantName: creds.TenantName, }, ) } region := creds.Region if region == "" { region = "<unspecified>" } credential.Label = fmt.Sprintf("openstack region %q project %q user %q", region, creds.TenantName, user) return &credential, user, creds.Region, nil }
func convertRawAPIError(err error) error { if err2, ok := err.(*googleapi.Error); ok { if err2.Code == http.StatusNotFound { return errors.NewNotFound(err, "") } } return err }
func (s *JoyentStorage) Get(name string) (io.ReadCloser, error) { b, err := s.manta.GetObject(s.containerName, name) if err != nil { return nil, errors.NewNotFound(err, fmt.Sprintf("cannot find %s", name)) } r := byteCloser{bytes.NewReader(b)} return r, nil }
// DeleteContainer deletes the named container from the storage account. func (s *JoyentStorage) DeleteContainer(containerName string) error { err := s.manta.DeleteDirectory(containerName) if err == nil && strings.EqualFold(s.containerName, containerName) { s.madeContainer = false } if je.IsResourceNotFound(err) { return errors.NewNotFound(err, fmt.Sprintf("cannot delete %s, not found", containerName)) } return err }
// VerifyService implements resource/state.RawState. func (st rawState) VerifyService(id string) error { svc, err := st.base.Service(id) if err != nil { return errors.Trace(err) } if svc.Life() != corestate.Alive { return errors.NewNotFound(nil, fmt.Sprintf("service %q dying or dead", id)) } return nil }
// removeModelUser removes a user from the database. func (st *State) removeModelUser(user names.UserTag) error { ops := removeModelUserOps(st.ModelUUID(), user) err := st.runTransaction(ops) if err == txn.ErrAborted { err = errors.NewNotFound(nil, fmt.Sprintf("model user %q does not exist", user.Canonical())) } if err != nil { return errors.Trace(err) } return nil }
// RemoveControllerUser removes a user from the database. func (st *State) removeControllerUser(user names.UserTag) error { ops := removeControllerUserOps(st.ControllerUUID(), user) err := st.runTransaction(ops) if err == txn.ErrAborted { err = errors.NewNotFound(nil, fmt.Sprintf("controller user %q does not exist", user.Id())) } if err != nil { return errors.Trace(err) } return nil }
func (r *globalProviderRegistry) Provider(providerType string) (EnvironProvider, error) { if alias, ok := r.aliases[providerType]; ok { providerType = alias } p, ok := r.providers[providerType] if !ok { return nil, errors.NewNotFound( nil, fmt.Sprintf("no registered provider for %q", providerType), ) } return p, nil }
// RegionByName finds the region in the given slice with the // specified name, with case folding. func RegionByName(regions []Region, name string) (*Region, error) { for _, region := range regions { if !strings.EqualFold(region.Name, name) { continue } return ®ion, nil } return nil, errors.NewNotFound(nil, fmt.Sprintf( "region %q not found (expected one of %q)", name, RegionNames(regions), )) }
// getVPCSubnetIDsForAvailabilityZone returns a sorted list of subnet IDs, which // are both in the given vpcID and the given zoneName. If allowedSubnetIDs is // not empty, the returned list will only contain IDs present there. Returns an // error satisfying errors.IsNotFound() when no results match. func getVPCSubnetIDsForAvailabilityZone( apiClient vpcAPIClient, vpcID, zoneName string, allowedSubnetIDs []string, ) ([]string, error) { allowedSubnets := set.NewStrings(allowedSubnetIDs...) vpc := &ec2.VPC{Id: vpcID} subnets, err := getVPCSubnets(apiClient, vpc) if err != nil && !isVPCNotUsableError(err) { return nil, errors.Annotatef(err, "cannot get VPC %q subnets", vpcID) } else if isVPCNotUsableError(err) { // We're reusing getVPCSubnets(), but not while validating a VPC // pre-bootstrap, so we should change vpcNotUsableError to a simple // NotFoundError. message := fmt.Sprintf("VPC %q has no subnets in AZ %q", vpcID, zoneName) return nil, errors.NewNotFound(err, message) } matchingSubnetIDs := set.NewStrings() for _, subnet := range subnets { if subnet.AvailZone != zoneName { logger.Infof("skipping subnet %q (in VPC %q): not in the chosen AZ %q", subnet.Id, vpcID, zoneName) continue } if !allowedSubnets.IsEmpty() && !allowedSubnets.Contains(subnet.Id) { logger.Infof("skipping subnet %q (in VPC %q, AZ %q): not matching spaces constraints", subnet.Id, vpcID, zoneName) continue } matchingSubnetIDs.Add(subnet.Id) } if matchingSubnetIDs.IsEmpty() { message := fmt.Sprintf("VPC %q has no subnets in AZ %q", vpcID, zoneName) return nil, errors.NewNotFound(nil, message) } sortedIDs := matchingSubnetIDs.SortedValues() logger.Infof("found %d subnets in VPC %q matching AZ %q and constraints: %v", len(sortedIDs), vpcID, zoneName, sortedIDs) return sortedIDs, nil }
func (s *ResourcePersistenceSuite) TestNewResourcePendingResourceOpsNotFound(c *gc.C) { pendingID := "some-unique-ID-001" stored, expected := newPersistenceResource(c, "a-application", "spam") stored.PendingID = pendingID doc := expected // a copy doc.DocID = pendingResourceID(stored.ID, pendingID) doc.PendingID = pendingID s.base.ReturnOne = doc notFound := errors.NewNotFound(nil, "") s.stub.SetErrors(nil, notFound) p := NewResourcePersistence(s.base) // TODO(macgreagoir) We need to keep using time.Now() for now, while we // have NewResolvePendingResourceOps returning LastPolled based on // timeNow(). lp:1558657 lastPolled := time.Now().UTC().Round(time.Second) ops, err := p.NewResolvePendingResourceOps(stored.ID, stored.PendingID) c.Assert(err, jc.ErrorIsNil) s.stub.CheckCallNames(c, "One", "One") s.stub.CheckCall(c, 0, "One", "resources", "resource#a-application/spam#pending-some-unique-ID-001", &doc) csresourceDoc := expected csresourceDoc.DocID = "resource#a-application/spam#charmstore" csresourceDoc.Username = "" csresourceDoc.Timestamp = coretesting.ZeroTime() csresourceDoc.StoragePath = "" csresourceDoc.LastPolled = lastPolled res := ops[2].Insert.(*resourceDoc) res.LastPolled = res.LastPolled.Round(time.Second) c.Check(ops, jc.DeepEquals, []txn.Op{ { C: "resources", Id: doc.DocID, Assert: txn.DocExists, Remove: true, }, { C: "resources", Id: expected.DocID, Assert: txn.DocMissing, Insert: &expected, }, { C: "resources", Id: csresourceDoc.DocID, Assert: txn.DocMissing, Insert: &csresourceDoc, }, }) }
// deleteResource deletes a resource with the given name from the resource // group, using the provided "Deleter". If the resource does not exist, an // error satisfying errors.IsNotFound will be returned. func deleteResource(callAPI callAPIFunc, deleter resourceDeleter, resourceGroup, name string) error { var result autorest.Response if err := callAPI(func() (autorest.Response, error) { var err error result, err = deleter.Delete(resourceGroup, name, nil) return result, err }); err != nil { if result.Response != nil && result.StatusCode == http.StatusNotFound { return errors.NewNotFound(err, fmt.Sprintf("resource %q not found", name)) } return errors.Annotate(err, "canceling deployment") } return nil }
func (s *ResourcePersistenceSuite) TestSetUnitResourceNotFound(c *gc.C) { applicationname := "a-application" unitname := "a-application/0" res, _ := newPersistenceUnitResource(c, applicationname, unitname, "eggs") p := NewResourcePersistence(s.base) notFound := errors.NewNotFound(nil, "") s.stub.SetErrors(notFound) err := p.SetUnitResource("a-application/0", res) s.stub.CheckCallNames(c, "One") c.Check(err, jc.Satisfies, errors.IsNotFound) c.Check(err, gc.ErrorMatches, `resource "eggs" not found`) }
func (s *ResourcePersistenceSuite) TestNewResourcePendingResourceOpsNotFound(c *gc.C) { pendingID := "some-unique-ID-001" stored, expected := newPersistenceResource(c, "a-service", "spam") stored.PendingID = pendingID doc := expected // a copy doc.DocID = pendingResourceID(stored.ID, pendingID) doc.PendingID = pendingID s.base.ReturnOne = doc notFound := errors.NewNotFound(nil, "") s.stub.SetErrors(nil, notFound) p := NewResourcePersistence(s.base) lastPolled := time.Now().UTC().Round(time.Second) ops, err := p.NewResolvePendingResourceOps(stored.ID, stored.PendingID) c.Assert(err, jc.ErrorIsNil) s.stub.CheckCallNames(c, "One", "One") s.stub.CheckCall(c, 0, "One", "resources", "resource#a-service/spam#pending-some-unique-ID-001", &doc) csresourceDoc := expected csresourceDoc.DocID = "resource#a-service/spam#charmstore" csresourceDoc.Username = "" csresourceDoc.Timestamp = time.Time{} csresourceDoc.StoragePath = "" csresourceDoc.LastPolled = lastPolled res := ops[2].Insert.(*resourceDoc) res.LastPolled = res.LastPolled.Round(time.Second) c.Check(ops, jc.DeepEquals, []txn.Op{ { C: "resources", Id: doc.DocID, Assert: txn.DocExists, Remove: true, }, { C: "resources", Id: expected.DocID, Assert: txn.DocMissing, Insert: &expected, }, { C: "resources", Id: csresourceDoc.DocID, Assert: txn.DocMissing, Insert: &csresourceDoc, }, }) }
// RemoveModelUser removes a user from the database. func (st *State) RemoveModelUser(user names.UserTag) error { ops := []txn.Op{{ C: modelUsersC, Id: modelUserID(user), Assert: txn.DocExists, Remove: true, }} err := st.runTransaction(ops) if err == txn.ErrAborted { err = errors.NewNotFound(nil, fmt.Sprintf("model user %q does not exist", user.Canonical())) } if err != nil { return errors.Trace(err) } return nil }
// RemoveEnvironmentUser removes a user from the database. func (st *State) RemoveEnvironmentUser(user names.UserTag) error { ops := []txn.Op{{ C: envUsersC, Id: envUserID(user), Assert: txn.DocExists, Remove: true, }} err := st.runTransaction(ops) if err == txn.ErrAborted { err = errors.NewNotFound(err, fmt.Sprintf("env user %q does not exist", user.Username())) } if err != nil { return errors.Trace(err) } return nil }
func defaultCloud(cloudClient CloudAPI) (names.CloudTag, jujucloud.Cloud, error) { cloudTag, err := cloudClient.DefaultCloud() if err != nil { if params.IsCodeNotFound(err) { return names.CloudTag{}, jujucloud.Cloud{}, errors.NewNotFound(nil, ` there is no default cloud defined, please specify one using: juju add-model [flags] <model-name> cloud[/region]`[1:]) } return names.CloudTag{}, jujucloud.Cloud{}, errors.Trace(err) } cloud, err := cloudClient.Cloud(cloudTag) if err != nil { return names.CloudTag{}, jujucloud.Cloud{}, errors.Trace(err) } return cloudTag, cloud, nil }
func (env *azureEnviron) getStorageAccountLocked(refresh bool) (*storage.Account, error) { if !refresh && env.storageAccount != nil { return env.storageAccount, nil } client := storage.AccountsClient{env.storage} var account storage.Account if err := env.callAPI(func() (autorest.Response, error) { var err error account, err = client.GetProperties(env.resourceGroup, env.storageAccountName) return account.Response, err }); err != nil { if account.Response.Response != nil && account.Response.StatusCode == http.StatusNotFound { return nil, errors.NewNotFound(err, fmt.Sprintf("storage account not found")) } return nil, errors.Annotate(err, "getting storage account") } env.storageAccount = &account return env.storageAccount, nil }
// Get implements storage.StorageReader.Get. func (s *SSHStorage) Get(name string) (io.ReadCloser, error) { logger.Debugf("getting %q from storage", name) path, err := s.path(name) if err != nil { return nil, err } out, err := s.runf(flockShared, "base64 < %s", utils.ShQuote(path)) if err != nil { err := err.(SSHStorageError) if strings.Contains(err.Output, "No such file") { return nil, errors.NewNotFound(err, "") } return nil, err } decoded, err := base64.StdEncoding.DecodeString(out) if err != nil { return nil, err } return ioutil.NopCloser(bytes.NewBuffer(decoded)), nil }
// getStorageAccountKey returns the key for the storage account. func getStorageAccountKey( callAPI callAPIFunc, client armstorage.AccountsClient, resourceGroup, accountName string, ) (*armstorage.AccountKey, error) { logger.Debugf("getting keys for storage account %q", accountName) var listKeysResult armstorage.AccountListKeysResult if err := callAPI(func() (autorest.Response, error) { var err error listKeysResult, err = client.ListKeys(resourceGroup, accountName) return listKeysResult.Response, err }); err != nil { if listKeysResult.Response.Response != nil && listKeysResult.StatusCode == http.StatusNotFound { return nil, errors.NewNotFound(err, "storage account keys not found") } return nil, errors.Annotate(err, "listing storage account keys") } if listKeysResult.Keys == nil { return nil, errors.NotFoundf("storage account keys") } // We need a storage key with full permissions. var fullKey *armstorage.AccountKey for _, key := range *listKeysResult.Keys { logger.Debugf("storage account key: %#v", key) // At least some of the time, Azure returns the permissions // in title-case, which does not match the constant. if strings.ToUpper(string(key.Permissions)) != string(armstorage.FULL) { continue } fullKey = &key break } if fullKey == nil { return nil, errors.NotFoundf( "storage account key with %q permission", armstorage.FULL, ) } return fullKey, nil }
func (environProviderCredentials) detectEnvCredentials() (*cloud.CloudCredential, error) { auth, err := aws.EnvAuth() if err != nil { return nil, errors.NewNotFound(err, "credentials not found") } accessKeyCredential := cloud.NewCredential( cloud.AccessKeyAuthType, map[string]string{ "access-key": auth.AccessKey, "secret-key": auth.SecretKey, }, ) user, err := utils.LocalUsername() if err != nil { return nil, errors.Trace(err) } accessKeyCredential.Label = fmt.Sprintf("aws credential %q", user) return &cloud.CloudCredential{ AuthCredentials: map[string]cloud.Credential{ user: accessKeyCredential, }}, nil }
// Get implements storage.StorageReader.Get. func (f *fileStorageReader) Get(name string) (io.ReadCloser, error) { if isInternalPath(name) { return nil, &os.PathError{ Op: "Get", Path: name, Err: os.ErrNotExist, } } filename := f.fullPath(name) fi, err := os.Stat(filename) if err != nil { if os.IsNotExist(err) { err = errors.NewNotFound(err, "") } return nil, err } else if fi.IsDir() { return nil, errors.NotFoundf("no such file with name %q", name) } file, err := os.Open(filename) if err != nil { return nil, err } return file, nil }
// CreateModel creates a new model using the account and // model config specified in the args. func (m *ModelManagerAPI) CreateModel(args params.ModelCreateArgs) (params.ModelInfo, error) { result := params.ModelInfo{} canAddModel, err := m.authorizer.HasPermission(permission.AddModelAccess, m.state.ControllerTag()) if err != nil { return result, errors.Trace(err) } if !canAddModel { return result, common.ErrPerm } // Get the controller model first. We need it both for the state // server owner and the ability to get the config. controllerModel, err := m.state.ControllerModel() if err != nil { return result, errors.Trace(err) } ownerTag, err := names.ParseUserTag(args.OwnerTag) if err != nil { return result, errors.Trace(err) } var cloudTag names.CloudTag cloudRegionName := args.CloudRegion if args.CloudTag != "" { var err error cloudTag, err = names.ParseCloudTag(args.CloudTag) if err != nil { return result, errors.Trace(err) } } else { cloudTag = names.NewCloudTag(controllerModel.Cloud()) } if cloudRegionName == "" && cloudTag.Id() == controllerModel.Cloud() { cloudRegionName = controllerModel.CloudRegion() } cloud, err := m.state.Cloud(cloudTag.Id()) if err != nil { if errors.IsNotFound(err) && args.CloudTag != "" { // A cloud was specified, and it was not found. // Annotate the error with the supported clouds. clouds, err := m.state.Clouds() if err != nil { return result, errors.Trace(err) } cloudNames := make([]string, 0, len(clouds)) for tag := range clouds { cloudNames = append(cloudNames, tag.Id()) } sort.Strings(cloudNames) return result, errors.NewNotFound(err, fmt.Sprintf( "cloud %q not found, expected one of %q", cloudTag.Id(), cloudNames, )) } return result, errors.Annotate(err, "getting cloud definition") } var cloudCredentialTag names.CloudCredentialTag if args.CloudCredentialTag != "" { var err error cloudCredentialTag, err = names.ParseCloudCredentialTag(args.CloudCredentialTag) if err != nil { return result, errors.Trace(err) } } else { if ownerTag == controllerModel.Owner() { cloudCredentialTag, _ = controllerModel.CloudCredential() } else { // TODO(axw) check if the user has one and only one // cloud credential, and if so, use it? For now, we // require the user to specify a credential unless // the cloud does not require one. var hasEmpty bool for _, authType := range cloud.AuthTypes { if authType != jujucloud.EmptyAuthType { continue } hasEmpty = true break } if !hasEmpty { return result, errors.NewNotValid(nil, "no credential specified") } } } var credential *jujucloud.Credential if cloudCredentialTag != (names.CloudCredentialTag{}) { credentialValue, err := m.state.CloudCredential(cloudCredentialTag) if err != nil { return result, errors.Annotate(err, "getting credential") } credential = &credentialValue } cloudSpec, err := environs.MakeCloudSpec(cloud, cloudTag.Id(), cloudRegionName, credential) if err != nil { return result, errors.Trace(err) } controllerCfg, err := m.state.ControllerConfig() if err != nil { return result, errors.Trace(err) } newConfig, err := m.newModelConfig(cloudSpec, args, controllerModel) if err != nil { return result, errors.Annotate(err, "failed to create config") } // Create the Environ. env, err := environs.New(environs.OpenParams{ Cloud: cloudSpec, Config: newConfig, }) if err != nil { return result, errors.Annotate(err, "failed to open environ") } if err := env.Create(environs.CreateParams{ ControllerUUID: controllerCfg.ControllerUUID(), }); err != nil { return result, errors.Annotate(err, "failed to create environ") } storageProviderRegistry := stateenvirons.NewStorageProviderRegistry(env) // NOTE: check the agent-version of the config, and if it is > the current // version, it is not supported, also check existing tools, and if we don't // have tools for that version, also die. model, st, err := m.state.NewModel(state.ModelArgs{ CloudName: cloudTag.Id(), CloudRegion: cloudRegionName, CloudCredential: cloudCredentialTag, Config: newConfig, Owner: ownerTag, StorageProviderRegistry: storageProviderRegistry, }) if err != nil { return result, errors.Annotate(err, "failed to create new model") } defer st.Close() return m.getModelInfo(model.ModelTag()) }
func convertToolsError(err *error) { if isToolsError(*err) { *err = errors.NewNotFound(*err, "") } }