github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/provider/ec2/config.go (about)

     1  // Copyright 2011, 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ec2
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/juju/schema"
    11  	"gopkg.in/amz.v3/aws"
    12  	"gopkg.in/juju/environschema.v1"
    13  
    14  	"github.com/juju/juju/environs/config"
    15  )
    16  
    17  var configSchema = environschema.Fields{
    18  	"access-key": {
    19  		Description: "The EC2 access key",
    20  		EnvVar:      "AWS_ACCESS_KEY_ID",
    21  		Type:        environschema.Tstring,
    22  		Mandatory:   true,
    23  		Group:       environschema.AccountGroup,
    24  	},
    25  	"secret-key": {
    26  		Description: "The EC2 secret key",
    27  		EnvVar:      "AWS_SECRET_ACCESS_KEY",
    28  		Type:        environschema.Tstring,
    29  		Mandatory:   true,
    30  		Secret:      true,
    31  		Group:       environschema.AccountGroup,
    32  	},
    33  	"region": {
    34  		Description: "The EC2 region to use",
    35  		Type:        environschema.Tstring,
    36  	},
    37  	"vpc-id": {
    38  		Description: "Use a specific AWS VPC ID (optional). When not specified, Juju requires a default VPC to exist the chosen EC2 account/region.",
    39  		Example:     "vpc-a1b2c3d4",
    40  		Type:        environschema.Tstring,
    41  		Group:       environschema.AccountGroup,
    42  		Immutable:   true,
    43  	},
    44  	"vpc-id-force": {
    45  		Description: "Force Juju to use the AWS VPC ID specified with vpc-id, when it fails the minimum validation criteria. Not accepted without vpc-id",
    46  		Type:        environschema.Tbool,
    47  		Group:       environschema.AccountGroup,
    48  		Immutable:   true,
    49  	},
    50  }
    51  
    52  var configFields = func() schema.Fields {
    53  	fs, _, err := configSchema.ValidationSchema()
    54  	if err != nil {
    55  		panic(err)
    56  	}
    57  	return fs
    58  }()
    59  
    60  var configDefaults = schema.Defaults{
    61  	"access-key":   "",
    62  	"secret-key":   "",
    63  	"region":       "us-east-1",
    64  	"vpc-id":       "",
    65  	"vpc-id-force": false,
    66  }
    67  
    68  type environConfig struct {
    69  	*config.Config
    70  	attrs map[string]interface{}
    71  }
    72  
    73  func (c *environConfig) region() string {
    74  	return c.attrs["region"].(string)
    75  }
    76  
    77  func (c *environConfig) accessKey() string {
    78  	return c.attrs["access-key"].(string)
    79  }
    80  
    81  func (c *environConfig) secretKey() string {
    82  	return c.attrs["secret-key"].(string)
    83  }
    84  
    85  func (c *environConfig) vpcID() string {
    86  	return c.attrs["vpc-id"].(string)
    87  }
    88  
    89  func (c *environConfig) forceVPCID() bool {
    90  	return c.attrs["vpc-id-force"].(bool)
    91  }
    92  
    93  func (p environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
    94  	valid, err := p.Validate(cfg, nil)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	return &environConfig{valid, valid.UnknownAttrs()}, nil
    99  }
   100  
   101  // Schema returns the configuration schema for an environment.
   102  func (environProvider) Schema() environschema.Fields {
   103  	fields, err := config.Schema(configSchema)
   104  	if err != nil {
   105  		panic(err)
   106  	}
   107  	return fields
   108  }
   109  
   110  func validateConfig(cfg, old *config.Config) (*environConfig, error) {
   111  	// Check for valid changes for the base config values.
   112  	if err := config.Validate(cfg, old); err != nil {
   113  		return nil, err
   114  	}
   115  	validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	ecfg := &environConfig{cfg, validated}
   120  
   121  	if ecfg.accessKey() == "" || ecfg.secretKey() == "" {
   122  		auth, err := aws.EnvAuth()
   123  		if err != nil || ecfg.accessKey() != "" || ecfg.secretKey() != "" {
   124  			return nil, fmt.Errorf("model has no access-key or secret-key")
   125  		}
   126  		ecfg.attrs["access-key"] = auth.AccessKey
   127  		ecfg.attrs["secret-key"] = auth.SecretKey
   128  	}
   129  
   130  	if _, ok := aws.Regions[ecfg.region()]; !ok {
   131  		return nil, fmt.Errorf("invalid region name %q", ecfg.region())
   132  	}
   133  
   134  	if vpcID := ecfg.vpcID(); vpcID != "" && !strings.HasPrefix(vpcID, "vpc-") {
   135  		return nil, fmt.Errorf("vpc-id: %q is not a valid AWS VPC ID", vpcID)
   136  	} else if vpcID == "" && ecfg.forceVPCID() {
   137  		return nil, fmt.Errorf("cannot use vpc-id-force without specifying vpc-id as well")
   138  	}
   139  
   140  	if old != nil {
   141  		attrs := old.UnknownAttrs()
   142  		if region, _ := attrs["region"].(string); ecfg.region() != region {
   143  			return nil, fmt.Errorf("cannot change region from %q to %q", region, ecfg.region())
   144  		}
   145  
   146  		if vpcID, _ := attrs["vpc-id"].(string); vpcID != ecfg.vpcID() {
   147  			return nil, fmt.Errorf("cannot change vpc-id from %q to %q", vpcID, ecfg.vpcID())
   148  		}
   149  
   150  		if forceVPCID, _ := attrs["vpc-id-force"].(bool); forceVPCID != ecfg.forceVPCID() {
   151  			return nil, fmt.Errorf("cannot change vpc-id-force from %v to %v", forceVPCID, ecfg.forceVPCID())
   152  		}
   153  	}
   154  
   155  	// ssl-hostname-verification cannot be disabled
   156  	if !ecfg.SSLHostnameVerification() {
   157  		return nil, fmt.Errorf("disabling ssh-hostname-verification is not supported")
   158  	}
   159  	return ecfg, nil
   160  }