github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/provider/cloudsigma/provider.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // Juju provider for CloudSigma 5 6 package cloudsigma 7 8 import ( 9 "fmt" 10 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 "github.com/juju/utils" 14 15 "github.com/juju/juju/cloud" 16 "github.com/juju/juju/environs" 17 "github.com/juju/juju/environs/config" 18 "github.com/juju/juju/environs/simplestreams" 19 "github.com/juju/juju/storage/provider/registry" 20 ) 21 22 var logger = loggo.GetLogger("juju.provider.cloudsigma") 23 24 const ( 25 providerType = "cloudsigma" 26 ) 27 28 func getImageSource(env environs.Environ) (simplestreams.DataSource, error) { 29 e, ok := env.(*environ) 30 if !ok { 31 return nil, errors.NotSupportedf("non-cloudsigma model") 32 } 33 return simplestreams.NewURLDataSource("cloud images", fmt.Sprintf(CloudsigmaCloudImagesURLTemplate, e.ecfg.region()), utils.VerifySSLHostnames, simplestreams.SPECIFIC_CLOUD_DATA, false), nil 34 } 35 36 type environProvider struct { 37 environProviderCredentials 38 } 39 40 var providerInstance = environProvider{} 41 42 // check the provider implements environs.EnvironProvider interface 43 var _ environs.EnvironProvider = (*environProvider)(nil) 44 45 func init() { 46 // This will only happen in binaries that actually import this provider 47 // somewhere. To enable a provider, import it in the "providers/all" 48 // package; please do *not* import individual providers anywhere else, 49 // except in direct tests for that provider. 50 environs.RegisterProvider("cloudsigma", providerInstance) 51 environs.RegisterImageDataSourceFunc("cloud sigma image source", getImageSource) 52 registry.RegisterEnvironStorageProviders(providerType) 53 } 54 55 // Open opens the environment and returns it. 56 // The configuration must have come from a previously 57 // prepared environment. 58 func (environProvider) Open(cfg *config.Config) (environs.Environ, error) { 59 logger.Infof("opening model %q", cfg.Name()) 60 61 env := &environ{name: cfg.Name()} 62 if err := env.SetConfig(cfg); err != nil { 63 return nil, err 64 } 65 66 return env, nil 67 } 68 69 // RestrictedConfigAttributes are provider specific attributes stored in 70 // the config that really cannot or should not be changed across 71 // environments running inside a single juju server. 72 func (environProvider) RestrictedConfigAttributes() []string { 73 return []string{"region"} 74 } 75 76 // PrepareForCreateEnvironment prepares an environment for creation. Any 77 // additional configuration attributes are added to the config passed in 78 // and returned. This allows providers to add additional required config 79 // for new environments that may be created in an existing juju server. 80 func (environProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) { 81 // Not even sure if this will ever make sense. 82 return nil, errors.NotImplementedf("PrepareForCreateEnvironment") 83 } 84 85 // BootstrapConfig is defined by EnvironProvider. 86 func (environProvider) BootstrapConfig(args environs.BootstrapConfigParams) (*config.Config, error) { 87 cfg := args.Config 88 switch authType := args.Credentials.AuthType(); authType { 89 case cloud.UserPassAuthType: 90 var err error 91 credentialAttributes := args.Credentials.Attributes() 92 cfg, err = cfg.Apply(map[string]interface{}{ 93 "username": credentialAttributes["username"], 94 "password": credentialAttributes["password"], 95 "region": args.CloudRegion, 96 "endpoint": args.CloudEndpoint, 97 }) 98 if err != nil { 99 return nil, errors.Trace(err) 100 } 101 default: 102 return nil, errors.NotSupportedf("%q auth-type", authType) 103 } 104 return cfg, nil 105 } 106 107 // PrepareForBootstrap is defined by EnvironProvider. 108 func (environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) { 109 logger.Infof("preparing model %q", cfg.Name()) 110 return providerInstance.Open(cfg) 111 } 112 113 // Validate ensures that config is a valid configuration for this 114 // provider, applying changes to it if necessary, and returns the 115 // validated configuration. 116 // If old is not nil, it holds the previous environment configuration 117 // for consideration when validating changes. 118 func (environProvider) Validate(cfg, old *config.Config) (*config.Config, error) { 119 logger.Infof("validating model %q", cfg.Name()) 120 121 // You should almost certainly not change this method; if you need to change 122 // how configs are validated, you should edit validateConfig itself, to ensure 123 // that your checks are always applied. 124 newEcfg, err := validateConfig(cfg, nil) 125 if err != nil { 126 return nil, errors.Errorf("invalid config: %v", err) 127 } 128 if old != nil { 129 oldEcfg, err := validateConfig(old, nil) 130 if err != nil { 131 return nil, errors.Errorf("invalid base config: %v", err) 132 } 133 if newEcfg, err = validateConfig(cfg, oldEcfg); err != nil { 134 return nil, errors.Errorf("invalid config change: %v", err) 135 } 136 } 137 138 return newEcfg.Config, nil 139 } 140 141 // SecretAttrs filters the supplied configuration returning only values 142 // which are considered sensitive. All of the values of these secret 143 // attributes need to be strings. 144 func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) { 145 logger.Infof("filtering secret attributes for model %q", cfg.Name()) 146 147 // If you keep configSecretFields up to date, this method should Just Work. 148 ecfg, err := validateConfig(cfg, nil) 149 if err != nil { 150 return nil, err 151 } 152 secretAttrs := map[string]string{} 153 for _, field := range configSecretFields { 154 if value, ok := ecfg.attrs[field]; ok { 155 if stringValue, ok := value.(string); ok { 156 secretAttrs[field] = stringValue 157 } else { 158 // All your secret attributes must be strings at the moment. Sorry. 159 // It's an expedient and hopefully temporary measure that helps us 160 // plug a security hole in the API. 161 return nil, errors.Errorf( 162 "secret %q field must have a string value; got %v", 163 field, value, 164 ) 165 } 166 } 167 } 168 169 return secretAttrs, nil 170 }