github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/openstack/credentials.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package openstack
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"regexp"
    11  
    12  	"github.com/juju/errors"
    13  	"github.com/juju/utils"
    14  	"gopkg.in/goose.v1/identity"
    15  	"gopkg.in/ini.v1"
    16  
    17  	"github.com/juju/juju/cloud"
    18  	"github.com/juju/juju/environs"
    19  )
    20  
    21  const (
    22  	CredAttrTenantName = "tenant-name"
    23  	CredAttrUserName   = "username"
    24  	CredAttrPassword   = "password"
    25  	CredAttrDomainName = "domain-name"
    26  	CredAttrAccessKey  = "access-key"
    27  	CredAttrSecretKey  = "secret-key"
    28  )
    29  
    30  type OpenstackCredentials struct{}
    31  
    32  // CredentialSchemas is part of the environs.ProviderCredentials interface.
    33  func (OpenstackCredentials) CredentialSchemas() map[cloud.AuthType]cloud.CredentialSchema {
    34  	return map[cloud.AuthType]cloud.CredentialSchema{
    35  		cloud.UserPassAuthType: {
    36  			{
    37  				CredAttrUserName, cloud.CredentialAttr{Description: "The username to authenticate with."},
    38  			}, {
    39  				CredAttrPassword, cloud.CredentialAttr{
    40  					Description: "The password for the specified username.",
    41  					Hidden:      true,
    42  				},
    43  			}, {
    44  				CredAttrTenantName, cloud.CredentialAttr{Description: "The OpenStack tenant name."},
    45  			}, {
    46  				CredAttrDomainName, cloud.CredentialAttr{
    47  					Description: "The OpenStack domain name.",
    48  					Optional:    true,
    49  				},
    50  			},
    51  		},
    52  		cloud.AccessKeyAuthType: {
    53  			{
    54  				CredAttrAccessKey, cloud.CredentialAttr{Description: "The access key to authenticate with."},
    55  			}, {
    56  				CredAttrSecretKey, cloud.CredentialAttr{
    57  					Description: "The secret key to authenticate with.",
    58  					Hidden:      true,
    59  				},
    60  			}, {
    61  				CredAttrTenantName, cloud.CredentialAttr{Description: "The OpenStack tenant name."},
    62  			},
    63  		},
    64  	}
    65  }
    66  
    67  // DetectCredentials is part of the environs.ProviderCredentials interface.
    68  func (c OpenstackCredentials) DetectCredentials() (*cloud.CloudCredential, error) {
    69  	result := cloud.CloudCredential{
    70  		AuthCredentials: make(map[string]cloud.Credential),
    71  	}
    72  
    73  	// Try just using environment variables
    74  	creds, user, region, err := c.detectCredential()
    75  	if err == nil {
    76  		result.DefaultRegion = region
    77  		result.AuthCredentials[user] = *creds
    78  	}
    79  
    80  	// Now look for .novarc file in home dir.
    81  	novarc := filepath.Join(utils.Home(), ".novarc")
    82  	novaInfo, err := ini.LooseLoad(novarc)
    83  	if err != nil {
    84  		return nil, errors.Annotate(err, "loading novarc file")
    85  	}
    86  	stripExport := regexp.MustCompile(`(?i)^\s*export\s*`)
    87  	keyValues := novaInfo.Section(ini.DEFAULT_SECTION).KeysHash()
    88  	if len(keyValues) > 0 {
    89  		for k, v := range keyValues {
    90  			k = stripExport.ReplaceAllString(k, "")
    91  			os.Setenv(k, v)
    92  		}
    93  		creds, user, region, err := c.detectCredential()
    94  		if err == nil {
    95  			result.DefaultRegion = region
    96  			result.AuthCredentials[user] = *creds
    97  		}
    98  	}
    99  	if len(result.AuthCredentials) == 0 {
   100  		return nil, errors.NotFoundf("openstack credentials")
   101  	}
   102  	return &result, nil
   103  }
   104  
   105  func (c OpenstackCredentials) detectCredential() (*cloud.Credential, string, string, error) {
   106  	creds := identity.CredentialsFromEnv()
   107  	if creds.TenantName == "" {
   108  		return nil, "", "", errors.NewNotFound(nil, "OS_TENANT_NAME environment variable not set")
   109  	}
   110  	if creds.User == "" {
   111  		return nil, "", "", errors.NewNotFound(nil, "neither OS_USERNAME nor OS_ACCESS_KEY environment variable not set")
   112  	}
   113  	if creds.Secrets == "" {
   114  		return nil, "", "", errors.NewNotFound(nil, "neither OS_PASSWORD nor OS_SECRET_KEY environment variable not set")
   115  	}
   116  
   117  	user, err := utils.LocalUsername()
   118  	if err != nil {
   119  		return nil, "", "", errors.Trace(err)
   120  	}
   121  
   122  	// If OS_USERNAME or NOVA_USERNAME is set, assume userpass.
   123  	var credential cloud.Credential
   124  	if os.Getenv("OS_USERNAME") != "" || os.Getenv("NOVA_USERNAME") != "" {
   125  		user = creds.User
   126  		credential = cloud.NewCredential(
   127  			cloud.UserPassAuthType,
   128  			map[string]string{
   129  				CredAttrUserName:   creds.User,
   130  				CredAttrPassword:   creds.Secrets,
   131  				CredAttrTenantName: creds.TenantName,
   132  				CredAttrDomainName: creds.DomainName,
   133  			},
   134  		)
   135  	} else {
   136  		credential = cloud.NewCredential(
   137  			cloud.AccessKeyAuthType,
   138  			map[string]string{
   139  				CredAttrAccessKey:  creds.User,
   140  				CredAttrSecretKey:  creds.Secrets,
   141  				CredAttrTenantName: creds.TenantName,
   142  			},
   143  		)
   144  	}
   145  	region := creds.Region
   146  	if region == "" {
   147  		region = "<unspecified>"
   148  	}
   149  	credential.Label = fmt.Sprintf("openstack region %q project %q user %q", region, creds.TenantName, user)
   150  	return &credential, user, creds.Region, nil
   151  }
   152  
   153  // FinalizeCredential is part of the environs.ProviderCredentials interface.
   154  func (OpenstackCredentials) FinalizeCredential(_ environs.FinalizeCredentialContext, args environs.FinalizeCredentialParams) (*cloud.Credential, error) {
   155  	return &args.Credential, nil
   156  }