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  }