github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/provider/maas/environprovider.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package maas
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"net/url"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/gomaasapi"
    13  	"github.com/juju/loggo"
    14  
    15  	"github.com/juju/juju/cloud"
    16  	"github.com/juju/juju/environs"
    17  	"github.com/juju/juju/environs/config"
    18  )
    19  
    20  // Logger for the MAAS provider.
    21  var logger = loggo.GetLogger("juju.provider.maas")
    22  
    23  type maasEnvironProvider struct {
    24  	environProviderCredentials
    25  }
    26  
    27  var _ environs.EnvironProvider = (*maasEnvironProvider)(nil)
    28  
    29  var providerInstance maasEnvironProvider
    30  
    31  func (maasEnvironProvider) Open(args environs.OpenParams) (environs.Environ, error) {
    32  	logger.Debugf("opening model %q.", args.Config.Name())
    33  	if err := validateCloudSpec(args.Cloud); err != nil {
    34  		return nil, errors.Annotate(err, "validating cloud spec")
    35  	}
    36  	env, err := NewEnviron(args.Cloud, args.Config)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	return env, nil
    41  }
    42  
    43  var errAgentNameAlreadySet = errors.New(
    44  	"maas-agent-name is already set; this should not be set by hand")
    45  
    46  // PrepareConfig is specified in the EnvironProvider interface.
    47  func (p maasEnvironProvider) PrepareConfig(args environs.PrepareConfigParams) (*config.Config, error) {
    48  	if err := validateCloudSpec(args.Cloud); err != nil {
    49  		return nil, errors.Annotate(err, "validating cloud spec")
    50  	}
    51  	var attrs map[string]interface{}
    52  	if _, ok := args.Config.StorageDefaultBlockSource(); !ok {
    53  		attrs = map[string]interface{}{
    54  			config.StorageDefaultBlockSourceKey: maasStorageProviderType,
    55  		}
    56  	}
    57  	if len(attrs) == 0 {
    58  		return args.Config, nil
    59  	}
    60  	return args.Config.Apply(attrs)
    61  }
    62  
    63  func verifyCredentials(env *maasEnviron) error {
    64  	// Verify we can connect to the server and authenticate.
    65  	if env.usingMAAS2() {
    66  		// The maas2 controller verifies credentials at creation time.
    67  		return nil
    68  	}
    69  	_, err := env.getMAASClient().GetSubObject("maas").CallGet("get_config", nil)
    70  	if err, ok := errors.Cause(err).(gomaasapi.ServerError); ok && err.StatusCode == http.StatusUnauthorized {
    71  		logger.Debugf("authentication failed: %v", err)
    72  		return errors.New(`authentication failed.
    73  
    74  Please ensure the credentials are correct.`)
    75  	}
    76  	return nil
    77  }
    78  
    79  // DetectRegions is specified in the environs.CloudRegionDetector interface.
    80  func (p maasEnvironProvider) DetectRegions() ([]cloud.Region, error) {
    81  	return nil, errors.NotFoundf("regions")
    82  }
    83  
    84  func validateCloudSpec(spec environs.CloudSpec) error {
    85  	if err := spec.Validate(); err != nil {
    86  		return errors.Trace(err)
    87  	}
    88  	if _, err := parseCloudEndpoint(spec.Endpoint); err != nil {
    89  		return errors.Annotate(err, "validating endpoint")
    90  	}
    91  	if spec.Credential == nil {
    92  		return errors.NotValidf("missing credential")
    93  	}
    94  	if authType := spec.Credential.AuthType(); authType != cloud.OAuth1AuthType {
    95  		return errors.NotSupportedf("%q auth-type", authType)
    96  	}
    97  	if _, err := parseOAuthToken(*spec.Credential); err != nil {
    98  		return errors.Annotate(err, "validating MAAS OAuth token")
    99  	}
   100  	return nil
   101  }
   102  
   103  func parseCloudEndpoint(endpoint string) (server string, _ error) {
   104  	// For MAAS, the cloud endpoint may be either a full URL
   105  	// for the MAAS server, or just the IP/host.
   106  	if endpoint == "" {
   107  		return "", errors.New("MAAS server not specified")
   108  	}
   109  	server = endpoint
   110  	if url, err := url.Parse(server); err != nil || url.Scheme == "" {
   111  		server = fmt.Sprintf("http://%s/MAAS", endpoint)
   112  		if _, err := url.Parse(server); err != nil {
   113  			return "", errors.NotValidf("endpoint %q", endpoint)
   114  		}
   115  	}
   116  	return server, nil
   117  }