github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/common/cloud.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 "gopkg.in/juju/environschema.v1" 10 11 jujucloud "github.com/juju/juju/cloud" 12 "github.com/juju/juju/environs" 13 "github.com/juju/juju/environs/config" 14 ) 15 16 var logger = loggo.GetLogger("juju.cmd.juju.common") 17 18 type chooseCloudRegionError struct { 19 error 20 } 21 22 // IsChooseCloudRegionError reports whether or not the given 23 // error was returned from ChooseCloudRegion. 24 func IsChooseCloudRegionError(err error) bool { 25 _, ok := errors.Cause(err).(chooseCloudRegionError) 26 return ok 27 } 28 29 // CloudOrProvider finds and returns cloud or provider. 30 func CloudOrProvider(cloudName string, cloudByNameFunc func(string) (*jujucloud.Cloud, error)) (cloud *jujucloud.Cloud, err error) { 31 if cloud, err = cloudByNameFunc(cloudName); err != nil { 32 if !errors.IsNotFound(err) { 33 return nil, err 34 } 35 builtInClouds, err := BuiltInClouds() 36 if err != nil { 37 return nil, errors.Trace(err) 38 } 39 if builtIn, ok := builtInClouds[cloudName]; !ok { 40 return nil, errors.NotValidf("cloud %v", cloudName) 41 } else { 42 cloud = &builtIn 43 } 44 } 45 return cloud, nil 46 } 47 48 // ChooseCloudRegion returns the cloud.Region to use, based on the specified 49 // region name. If no region name is specified, and there is at least one 50 // region, we use the first region in the list. If there are no regions, then 51 // we return a region with no name, having the same endpoints as the cloud. 52 func ChooseCloudRegion(cloud jujucloud.Cloud, regionName string) (jujucloud.Region, error) { 53 if regionName != "" { 54 region, err := jujucloud.RegionByName(cloud.Regions, regionName) 55 if err != nil { 56 return jujucloud.Region{}, errors.Trace(chooseCloudRegionError{err}) 57 } 58 return *region, nil 59 } 60 if len(cloud.Regions) > 0 { 61 // No region was specified, use the first region in the list. 62 return cloud.Regions[0], nil 63 } 64 return jujucloud.Region{ 65 "", // no region name 66 cloud.Endpoint, 67 cloud.IdentityEndpoint, 68 cloud.StorageEndpoint, 69 }, nil 70 } 71 72 // BuiltInClouds returns cloud information for those 73 // providers which are built in to Juju. 74 func BuiltInClouds() (map[string]jujucloud.Cloud, error) { 75 allClouds := make(map[string]jujucloud.Cloud) 76 for _, providerType := range environs.RegisteredProviders() { 77 p, err := environs.Provider(providerType) 78 if err != nil { 79 return nil, errors.Trace(err) 80 } 81 detector, ok := p.(environs.CloudDetector) 82 if !ok { 83 continue 84 } 85 clouds, err := detector.DetectClouds() 86 if err != nil { 87 return nil, errors.Annotatef( 88 err, "detecting clouds for provider %q", 89 providerType, 90 ) 91 } 92 for _, cloud := range clouds { 93 allClouds[cloud.Name] = cloud 94 } 95 } 96 return allClouds, nil 97 } 98 99 // CloudByName returns a cloud for given name 100 // regardless of whether it's public, private or builtin cloud. 101 // Not to be confused with cloud.CloudByName which does not cater 102 // for built-in clouds like localhost. 103 func CloudByName(cloudName string) (*jujucloud.Cloud, error) { 104 cloud, err := jujucloud.CloudByName(cloudName) 105 if err != nil { 106 if errors.IsNotFound(err) { 107 // Check built in clouds like localhost (lxd). 108 builtinClouds, err := BuiltInClouds() 109 if err != nil { 110 return nil, errors.Trace(err) 111 } 112 aCloud, found := builtinClouds[cloudName] 113 if !found { 114 return nil, errors.NotFoundf("cloud %s", cloudName) 115 } 116 return &aCloud, nil 117 } 118 return nil, errors.Trace(err) 119 } 120 return cloud, nil 121 } 122 123 // CloudSchemaByType returns the Schema for a given cloud type. 124 // If the ProviderSchema is not implemented for the given cloud 125 // type, a NotFound error is returned. 126 func CloudSchemaByType(cloudType string) (environschema.Fields, error) { 127 provider, err := environs.Provider(cloudType) 128 if err != nil { 129 return nil, err 130 } 131 ps, ok := provider.(environs.ProviderSchema) 132 if !ok { 133 return nil, errors.NotImplementedf("environs.ProviderSchema") 134 } 135 providerSchema := ps.Schema() 136 if providerSchema == nil { 137 return nil, errors.New("Failed to retrieve Provider Schema") 138 } 139 return providerSchema, nil 140 } 141 142 // ProviderConfigSchemaSourceByType returns a config.ConfigSchemaSource 143 // for the environ provider, found for the given cloud type, or an error. 144 func ProviderConfigSchemaSourceByType(cloudType string) (config.ConfigSchemaSource, error) { 145 provider, err := environs.Provider(cloudType) 146 if err != nil { 147 return nil, err 148 } 149 if cs, ok := provider.(config.ConfigSchemaSource); ok { 150 return cs, nil 151 } 152 return nil, errors.NotImplementedf("config.ConfigSource") 153 } 154 155 // PrintConfigSchema is used to print model configuration schema. 156 type PrintConfigSchema struct { 157 Type string `yaml:"type,omitempty" json:"type,omitempty"` 158 Description string `yaml:"description,omitempty" json:"description,omitempty"` 159 }