github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/provider/azure/config.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package azure 5 6 import ( 7 "encoding/pem" 8 "fmt" 9 "io" 10 "io/ioutil" 11 "os" 12 13 "github.com/juju/schema" 14 15 "github.com/juju/juju/environs/config" 16 ) 17 18 var configFields = schema.Fields{ 19 "location": schema.String(), 20 "management-subscription-id": schema.String(), 21 "management-certificate-path": schema.String(), 22 "management-certificate": schema.String(), 23 "storage-account-name": schema.String(), 24 "force-image-name": schema.String(), 25 "availability-sets-enabled": schema.Bool(), 26 } 27 var configDefaults = schema.Defaults{ 28 "location": "", 29 "management-certificate": "", 30 "management-certificate-path": "", 31 "force-image-name": "", 32 // availability-sets-enabled is set to Omit (equivalent 33 // to false) for backwards compatibility. 34 "availability-sets-enabled": schema.Omit, 35 } 36 37 type azureEnvironConfig struct { 38 *config.Config 39 attrs map[string]interface{} 40 } 41 42 func (cfg *azureEnvironConfig) location() string { 43 return cfg.attrs["location"].(string) 44 } 45 46 func (cfg *azureEnvironConfig) managementSubscriptionId() string { 47 return cfg.attrs["management-subscription-id"].(string) 48 } 49 50 func (cfg *azureEnvironConfig) managementCertificate() string { 51 return cfg.attrs["management-certificate"].(string) 52 } 53 54 func (cfg *azureEnvironConfig) storageAccountName() string { 55 return cfg.attrs["storage-account-name"].(string) 56 } 57 58 func (cfg *azureEnvironConfig) forceImageName() string { 59 return cfg.attrs["force-image-name"].(string) 60 } 61 62 func (cfg *azureEnvironConfig) availabilitySetsEnabled() bool { 63 enabled, _ := cfg.attrs["availability-sets-enabled"].(bool) 64 return enabled 65 } 66 67 func (prov azureEnvironProvider) newConfig(cfg *config.Config) (*azureEnvironConfig, error) { 68 validCfg, err := prov.Validate(cfg, nil) 69 if err != nil { 70 return nil, err 71 } 72 result := new(azureEnvironConfig) 73 result.Config = validCfg 74 result.attrs = validCfg.UnknownAttrs() 75 return result, nil 76 } 77 78 // Validate ensures that config is a valid configuration for this 79 // provider like specified in the EnvironProvider interface. 80 func (prov azureEnvironProvider) Validate(cfg, oldCfg *config.Config) (*config.Config, error) { 81 // Validate base configuration change before validating Azure specifics. 82 err := config.Validate(cfg, oldCfg) 83 if err != nil { 84 return nil, err 85 } 86 87 // User cannot change availability-sets-enabled after environment is prepared. 88 if oldCfg != nil { 89 if oldCfg.AllAttrs()["availability-sets-enabled"] != cfg.AllAttrs()["availability-sets-enabled"] { 90 return nil, fmt.Errorf("cannot change availability-sets-enabled") 91 } 92 } 93 94 validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) 95 if err != nil { 96 return nil, err 97 } 98 envCfg := new(azureEnvironConfig) 99 envCfg.Config = cfg 100 envCfg.attrs = validated 101 102 if _, ok := cfg.StorageDefaultBlockSource(); !ok { 103 // Default volume source not specified; set 104 // it to the azure storage provider. 105 envCfg.attrs[config.StorageDefaultBlockSourceKey] = storageProviderType 106 } 107 108 cert := envCfg.managementCertificate() 109 if cert == "" { 110 certPath := envCfg.attrs["management-certificate-path"].(string) 111 pemData, err := readPEMFile(certPath) 112 if err != nil { 113 return nil, fmt.Errorf("invalid management-certificate-path: %s", err) 114 } 115 envCfg.attrs["management-certificate"] = string(pemData) 116 } else { 117 if block, _ := pem.Decode([]byte(cert)); block == nil { 118 return nil, fmt.Errorf("invalid management-certificate: not a PEM encoded certificate") 119 } 120 } 121 delete(envCfg.attrs, "management-certificate-path") 122 123 if envCfg.location() == "" { 124 return nil, fmt.Errorf("environment has no location; you need to set one. E.g. 'West US'") 125 } 126 return cfg.Apply(envCfg.attrs) 127 } 128 129 func readPEMFile(path string) ([]byte, error) { 130 f, err := os.Open(path) 131 if err != nil { 132 return nil, err 133 } 134 defer f.Close() 135 136 // 640K ought to be enough for anybody. 137 data, err := ioutil.ReadAll(io.LimitReader(f, 1024*640)) 138 if err != nil { 139 return nil, err 140 } 141 block, _ := pem.Decode(data) 142 if block == nil { 143 return nil, fmt.Errorf("%q is not a PEM encoded certificate file", path) 144 } 145 return data, nil 146 } 147 148 var boilerplateYAML = ` 149 # https://juju.ubuntu.com/docs/config-azure.html 150 azure: 151 type: azure 152 153 # location specifies the place where instances will be started, 154 # for example: West US, North Europe. 155 # 156 location: West US 157 158 # The following attributes specify Windows Azure Management 159 # information. See: 160 # http://msdn.microsoft.com/en-us/library/windowsazure 161 # for details. 162 # 163 management-subscription-id: 00000000-0000-0000-0000-000000000000 164 management-certificate-path: /home/me/azure.pem 165 166 # storage-account-name holds Windows Azure Storage info. 167 # 168 storage-account-name: abcdefghijkl 169 170 # force-image-name overrides the OS image selection to use a fixed 171 # image for all deployments. Most useful for developers. 172 # 173 # force-image-name: b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-13_10-amd64-server-DEVELOPMENT-20130713-Juju_ALPHA-en-us-30GB 174 175 # image-stream chooses a simplestreams stream from which to select 176 # OS images, for example daily or released images (or any other stream 177 # available on simplestreams). 178 # 179 # image-stream: "released" 180 181 # agent-stream chooses a simplestreams stream from which to select tools, 182 # for example released or proposed tools (or any other stream available 183 # on simplestreams). 184 # 185 # agent-stream: "released" 186 187 # Whether or not to refresh the list of available updates for an 188 # OS. The default option of true is recommended for use in 189 # production systems, but disabling this can speed up local 190 # deployments for development or testing. 191 # 192 # enable-os-refresh-update: true 193 194 # Whether or not to perform OS upgrades when machines are 195 # provisioned. The default option of true is recommended for use 196 # in production systems, but disabling this can speed up local 197 # deployments for development or testing. 198 # 199 # enable-os-upgrade: true 200 201 `[1:] 202 203 func (prov azureEnvironProvider) BoilerplateConfig() string { 204 return boilerplateYAML 205 } 206 207 // SecretAttrs is specified in the EnvironProvider interface. 208 func (prov azureEnvironProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) { 209 secretAttrs := make(map[string]string) 210 azureCfg, err := prov.newConfig(cfg) 211 if err != nil { 212 return nil, err 213 } 214 secretAttrs["management-certificate"] = azureCfg.managementCertificate() 215 return secretAttrs, nil 216 }