github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/provider/joyent/config.go (about) 1 // Copyright 2013 Joyent Inc. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package joyent 5 6 import ( 7 "fmt" 8 "net/url" 9 "os" 10 "strings" 11 12 "github.com/juju/errors" 13 "github.com/juju/schema" 14 15 "github.com/juju/juju/environs/config" 16 ) 17 18 const ( 19 SdcAccount = "SDC_ACCOUNT" 20 SdcKeyId = "SDC_KEY_ID" 21 SdcUrl = "SDC_URL" 22 23 sdcUser = "sdc-user" 24 sdcKeyId = "sdc-key-id" 25 sdcUrl = "sdc-url" 26 privateKeyPath = "private-key-path" 27 algorithm = "algorithm" 28 privateKey = "private-key" 29 ) 30 31 var environmentVariables = map[string]string{ 32 sdcUser: SdcAccount, 33 sdcKeyId: SdcKeyId, 34 sdcUrl: SdcUrl, 35 } 36 37 var configFields = schema.Fields{ 38 sdcUser: schema.String(), 39 sdcKeyId: schema.String(), 40 sdcUrl: schema.String(), 41 algorithm: schema.String(), 42 privateKey: schema.String(), 43 } 44 45 var configDefaults = schema.Defaults{ 46 sdcUrl: "https://us-west-1.api.joyentcloud.com", 47 algorithm: "rsa-sha256", 48 sdcUser: schema.Omit, 49 sdcKeyId: schema.Omit, 50 privateKey: schema.Omit, 51 } 52 53 var requiredFields = []string{ 54 sdcUrl, 55 algorithm, 56 sdcUser, 57 sdcKeyId, 58 // privatekey and privatekeypath are handled separately 59 } 60 61 var configSecretFields = []string{ 62 sdcUser, 63 sdcKeyId, 64 privateKey, 65 } 66 67 var configImmutableFields = []string{ 68 sdcUrl, 69 privateKey, 70 algorithm, 71 } 72 73 func validateConfig(cfg, old *config.Config) (*environConfig, error) { 74 // Check for valid changes for the base config values. 75 if err := config.Validate(cfg, old); err != nil { 76 return nil, err 77 } 78 79 newAttrs, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) 80 if err != nil { 81 return nil, err 82 } 83 envConfig := &environConfig{cfg, newAttrs} 84 // If an old config was supplied, check any immutable fields have not changed. 85 if old != nil { 86 oldEnvConfig, err := validateConfig(old, nil) 87 if err != nil { 88 return nil, err 89 } 90 for _, field := range configImmutableFields { 91 if oldEnvConfig.attrs[field] != envConfig.attrs[field] { 92 return nil, fmt.Errorf( 93 "%s: cannot change from %v to %v", 94 field, oldEnvConfig.attrs[field], envConfig.attrs[field], 95 ) 96 } 97 } 98 } 99 100 // Read env variables to fill in any missing fields. 101 for field, envVar := range environmentVariables { 102 // If field is not set, get it from env variables 103 if nilOrEmptyString(envConfig.attrs[field]) { 104 localEnvVariable := os.Getenv(envVar) 105 if localEnvVariable != "" { 106 envConfig.attrs[field] = localEnvVariable 107 } else { 108 return nil, fmt.Errorf("cannot get %s value from environment variable %s", field, envVar) 109 } 110 } 111 } 112 113 if err := ensurePrivateKey(envConfig); err != nil { 114 return nil, err 115 } 116 117 // Check for missing fields. 118 for _, field := range requiredFields { 119 if nilOrEmptyString(envConfig.attrs[field]) { 120 return nil, fmt.Errorf("%s: must not be empty", field) 121 } 122 } 123 return envConfig, nil 124 } 125 126 // Ensure private-key is set. 127 func ensurePrivateKey(envConfig *environConfig) error { 128 if !nilOrEmptyString(envConfig.attrs[privateKey]) { 129 return nil 130 } 131 return errors.New("no ssh private key specified in joyent configuration") 132 } 133 134 type environConfig struct { 135 *config.Config 136 attrs map[string]interface{} 137 } 138 139 func (ecfg *environConfig) GetAttrs() map[string]interface{} { 140 return ecfg.attrs 141 } 142 143 func (ecfg *environConfig) sdcUrl() string { 144 return ecfg.attrs[sdcUrl].(string) 145 } 146 147 func (ecfg *environConfig) sdcUser() string { 148 return ecfg.attrs[sdcUser].(string) 149 } 150 151 func (ecfg *environConfig) sdcKeyId() string { 152 return ecfg.attrs[sdcKeyId].(string) 153 } 154 155 func (ecfg *environConfig) privateKey() string { 156 if v, ok := ecfg.attrs[privateKey]; ok { 157 return v.(string) 158 } 159 return "" 160 } 161 162 func (ecfg *environConfig) algorithm() string { 163 return ecfg.attrs[algorithm].(string) 164 } 165 166 func (ecfg *environConfig) SdcUrl() string { 167 return ecfg.sdcUrl() 168 } 169 170 func (ecfg *environConfig) Region() string { 171 sdcUrl := ecfg.sdcUrl() 172 // Check if running against local services 173 if isLocalhost(sdcUrl) { 174 return "some-region" 175 } 176 return sdcUrl[strings.LastIndex(sdcUrl, "/")+1 : strings.Index(sdcUrl, ".")] 177 } 178 179 func isLocalhost(u string) bool { 180 parsedUrl, err := url.Parse(u) 181 if err != nil { 182 return false 183 } 184 if strings.HasPrefix(parsedUrl.Host, "localhost") || strings.HasPrefix(parsedUrl.Host, "127.0.0.") { 185 return true 186 } 187 188 return false 189 } 190 191 func nilOrEmptyString(i interface{}) bool { 192 return i == nil || i == "" 193 }