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