2019-03-07 11:31:36 +01:00
package oss
import (
"context"
2019-08-06 04:35:51 +02:00
"encoding/json"
2019-03-07 11:31:36 +01:00
"fmt"
2020-02-18 10:36:57 +01:00
"io/ioutil"
"log"
"net/http"
2020-10-07 17:00:06 +02:00
"net/url"
"os"
"regexp"
"runtime"
2020-02-18 10:36:57 +01:00
"strconv"
2020-10-07 17:00:06 +02:00
"strings"
2020-02-18 10:36:57 +01:00
"time"
2019-03-07 11:31:36 +01:00
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
2020-10-07 17:00:06 +02:00
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
2019-03-07 11:31:36 +01:00
"github.com/aliyun/alibaba-cloud-sdk-go/services/location"
2020-10-07 17:00:06 +02:00
"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
2019-04-11 01:11:10 +02:00
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
2019-03-07 11:31:36 +01:00
"github.com/hashicorp/go-cleanhttp"
2021-05-17 17:42:17 +02:00
"github.com/hashicorp/terraform/internal/backend"
2020-11-18 16:07:30 +01:00
"github.com/hashicorp/terraform/internal/legacy/helper/schema"
2019-03-07 11:31:36 +01:00
"github.com/hashicorp/terraform/version"
2020-10-07 17:00:06 +02:00
"github.com/jmespath/go-jmespath"
2019-11-01 17:09:30 +01:00
"github.com/mitchellh/go-homedir"
2019-03-07 11:31:36 +01:00
)
// New creates a new backend for OSS remote state.
func New ( ) backend . Backend {
s := & schema . Backend {
Schema : map [ string ] * schema . Schema {
"access_key" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
Description : "Alibaba Cloud Access Key ID" ,
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_ACCESS_KEY" , os . Getenv ( "ALICLOUD_ACCESS_KEY_ID" ) ) ,
} ,
"secret_key" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
Description : "Alibaba Cloud Access Secret Key" ,
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_SECRET_KEY" , os . Getenv ( "ALICLOUD_ACCESS_KEY_SECRET" ) ) ,
} ,
"security_token" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
Description : "Alibaba Cloud Security Token" ,
2019-04-11 01:11:10 +02:00
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_SECURITY_TOKEN" , "" ) ,
2019-03-07 11:31:36 +01:00
} ,
2019-11-01 17:09:30 +01:00
"ecs_role_name" : {
Type : schema . TypeString ,
Optional : true ,
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_ECS_ROLE_NAME" , os . Getenv ( "ALICLOUD_ECS_ROLE_NAME" ) ) ,
Description : "The RAM Role Name attached on a ECS instance for API operations. You can retrieve this from the 'Access Control' section of the Alibaba Cloud console." ,
} ,
2019-03-07 11:31:36 +01:00
"region" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
Description : "The region of the OSS bucket." ,
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_REGION" , os . Getenv ( "ALICLOUD_DEFAULT_REGION" ) ) ,
} ,
2019-04-11 01:11:10 +02:00
"tablestore_endpoint" : {
Type : schema . TypeString ,
Optional : true ,
Description : "A custom endpoint for the TableStore API" ,
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_TABLESTORE_ENDPOINT" , "" ) ,
} ,
2019-03-07 11:31:36 +01:00
"endpoint" : {
Type : schema . TypeString ,
Optional : true ,
Description : "A custom endpoint for the OSS API" ,
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_OSS_ENDPOINT" , os . Getenv ( "OSS_ENDPOINT" ) ) ,
} ,
"bucket" : & schema . Schema {
Type : schema . TypeString ,
Required : true ,
Description : "The name of the OSS bucket" ,
} ,
2019-04-11 01:11:10 +02:00
"prefix" : & schema . Schema {
2019-03-07 11:31:36 +01:00
Type : schema . TypeString ,
2019-04-11 01:11:10 +02:00
Optional : true ,
Description : "The directory where state files will be saved inside the bucket" ,
Default : "env:" ,
ValidateFunc : func ( v interface { } , s string ) ( [ ] string , [ ] error ) {
prefix := v . ( string )
if strings . HasPrefix ( prefix , "/" ) || strings . HasPrefix ( prefix , "./" ) {
return nil , [ ] error { fmt . Errorf ( "workspace_key_prefix must not start with '/' or './'" ) }
}
return nil , nil
} ,
2019-03-07 11:31:36 +01:00
} ,
2019-04-11 01:11:10 +02:00
"key" : & schema . Schema {
2019-03-07 11:31:36 +01:00
Type : schema . TypeString ,
Optional : true ,
2019-04-11 01:11:10 +02:00
Description : "The path of the state file inside the bucket" ,
2019-03-07 11:31:36 +01:00
ValidateFunc : func ( v interface { } , s string ) ( [ ] string , [ ] error ) {
if strings . HasPrefix ( v . ( string ) , "/" ) || strings . HasSuffix ( v . ( string ) , "/" ) {
2019-04-11 01:11:10 +02:00
return nil , [ ] error { fmt . Errorf ( "key can not start and end with '/'" ) }
2019-03-07 11:31:36 +01:00
}
return nil , nil
} ,
Default : "terraform.tfstate" ,
} ,
2019-04-11 01:11:10 +02:00
"tablestore_table" : {
Type : schema . TypeString ,
2019-03-07 11:31:36 +01:00
Optional : true ,
2019-04-11 01:11:10 +02:00
Description : "TableStore table for state locking and consistency" ,
Default : "" ,
2019-03-07 11:31:36 +01:00
} ,
"encrypt" : & schema . Schema {
Type : schema . TypeBool ,
Optional : true ,
Description : "Whether to enable server side encryption of the state file" ,
Default : false ,
} ,
"acl" : & schema . Schema {
Type : schema . TypeString ,
Optional : true ,
Description : "Object ACL to be applied to the state file" ,
Default : "" ,
ValidateFunc : func ( v interface { } , k string ) ( [ ] string , [ ] error ) {
if value := v . ( string ) ; value != "" {
acls := oss . ACLType ( value )
if acls != oss . ACLPrivate && acls != oss . ACLPublicRead && acls != oss . ACLPublicReadWrite {
return nil , [ ] error { fmt . Errorf (
"%q must be a valid ACL value , expected %s, %s or %s, got %q" ,
k , oss . ACLPrivate , oss . ACLPublicRead , oss . ACLPublicReadWrite , acls ) }
}
}
return nil , nil
} ,
} ,
2019-07-30 17:26:51 +02:00
"assume_role" : assumeRoleSchema ( ) ,
2019-08-06 04:35:51 +02:00
"shared_credentials_file" : {
Type : schema . TypeString ,
Optional : true ,
2019-11-01 17:09:30 +01:00
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_SHARED_CREDENTIALS_FILE" , "" ) ,
2019-08-06 04:35:51 +02:00
Description : "This is the path to the shared credentials file. If this is not set and a profile is specified, `~/.aliyun/config.json` will be used." ,
} ,
"profile" : {
Type : schema . TypeString ,
Optional : true ,
Description : "This is the Alibaba Cloud profile name as set in the shared credentials file. It can also be sourced from the `ALICLOUD_PROFILE` environment variable." ,
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_PROFILE" , "" ) ,
} ,
2019-03-07 11:31:36 +01:00
} ,
}
result := & Backend { Backend : s }
result . Backend . ConfigureFunc = result . configure
return result
}
2019-07-30 17:26:51 +02:00
func assumeRoleSchema ( ) * schema . Schema {
return & schema . Schema {
Type : schema . TypeSet ,
Optional : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"role_arn" : {
Type : schema . TypeString ,
Required : true ,
Description : "The ARN of a RAM role to assume prior to making API calls." ,
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_ASSUME_ROLE_ARN" , "" ) ,
} ,
"session_name" : {
Type : schema . TypeString ,
Optional : true ,
Description : "The session name to use when assuming the role." ,
2019-08-06 04:35:51 +02:00
DefaultFunc : schema . EnvDefaultFunc ( "ALICLOUD_ASSUME_ROLE_SESSION_NAME" , "" ) ,
2019-07-30 17:26:51 +02:00
} ,
"policy" : {
Type : schema . TypeString ,
Optional : true ,
Description : "The permissions applied when assuming a role. You cannot use this policy to grant permissions which exceed those of the role that is being assumed." ,
} ,
"session_expiration" : {
2020-10-07 17:00:06 +02:00
Type : schema . TypeInt ,
Optional : true ,
Description : "The time after which the established session for assuming role expires." ,
ValidateFunc : func ( v interface { } , k string ) ( [ ] string , [ ] error ) {
min := 900
max := 3600
value , ok := v . ( int )
if ! ok {
return nil , [ ] error { fmt . Errorf ( "expected type of %s to be int" , k ) }
}
if value < min || value > max {
return nil , [ ] error { fmt . Errorf ( "expected %s to be in the range (%d - %d), got %d" , k , min , max , v ) }
}
return nil , nil
} ,
2019-07-30 17:26:51 +02:00
} ,
} ,
} ,
}
}
2019-03-07 11:31:36 +01:00
type Backend struct {
* schema . Backend
// The fields below are set from configure
ossClient * oss . Client
2019-04-11 01:11:10 +02:00
otsClient * tablestore . TableStoreClient
2019-03-07 11:31:36 +01:00
bucketName string
2019-04-11 01:11:10 +02:00
statePrefix string
stateKey string
2019-03-07 11:31:36 +01:00
serverSideEncryption bool
acl string
endpoint string
2019-04-11 01:11:10 +02:00
otsEndpoint string
otsTable string
2019-03-07 11:31:36 +01:00
}
func ( b * Backend ) configure ( ctx context . Context ) error {
if b . ossClient != nil {
return nil
}
// Grab the resource data
d := schema . FromContextBackendConfig ( ctx )
b . bucketName = d . Get ( "bucket" ) . ( string )
2019-04-11 01:11:10 +02:00
b . statePrefix = strings . TrimPrefix ( strings . Trim ( d . Get ( "prefix" ) . ( string ) , "/" ) , "./" )
b . stateKey = d . Get ( "key" ) . ( string )
2019-03-07 11:31:36 +01:00
b . serverSideEncryption = d . Get ( "encrypt" ) . ( bool )
b . acl = d . Get ( "acl" ) . ( string )
2019-08-06 04:35:51 +02:00
var getBackendConfig = func ( str string , key string ) string {
if str == "" {
value , err := getConfigFromProfile ( d , key )
if err == nil && value != nil {
str = value . ( string )
}
}
return str
}
accessKey := getBackendConfig ( d . Get ( "access_key" ) . ( string ) , "access_key_id" )
secretKey := getBackendConfig ( d . Get ( "secret_key" ) . ( string ) , "access_key_secret" )
securityToken := getBackendConfig ( d . Get ( "security_token" ) . ( string ) , "sts_token" )
region := getBackendConfig ( d . Get ( "region" ) . ( string ) , "region_id" )
2019-03-07 11:31:36 +01:00
endpoint := d . Get ( "endpoint" ) . ( string )
schma := "https"
2019-08-06 04:35:51 +02:00
roleArn := getBackendConfig ( "" , "ram_role_arn" )
sessionName := getBackendConfig ( "" , "ram_session_name" )
var policy string
var sessionExpiration int
expiredSeconds , err := getConfigFromProfile ( d , "expired_seconds" )
if err == nil && expiredSeconds != nil {
sessionExpiration = ( int ) ( expiredSeconds . ( float64 ) )
}
2019-07-30 17:26:51 +02:00
if v , ok := d . GetOk ( "assume_role" ) ; ok {
for _ , v := range v . ( * schema . Set ) . List ( ) {
assumeRole := v . ( map [ string ] interface { } )
2019-08-06 04:35:51 +02:00
if assumeRole [ "role_arn" ] . ( string ) != "" {
roleArn = assumeRole [ "role_arn" ] . ( string )
}
if assumeRole [ "session_name" ] . ( string ) != "" {
sessionName = assumeRole [ "session_name" ] . ( string )
}
if sessionName == "" {
sessionName = "terraform"
}
policy = assumeRole [ "policy" ] . ( string )
sessionExpiration = assumeRole [ "session_expiration" ] . ( int )
if sessionExpiration == 0 {
if v := os . Getenv ( "ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION" ) ; v != "" {
if expiredSeconds , err := strconv . Atoi ( v ) ; err == nil {
sessionExpiration = expiredSeconds
}
}
if sessionExpiration == 0 {
sessionExpiration = 3600
}
2019-07-30 17:26:51 +02:00
}
}
}
2019-11-01 17:09:30 +01:00
if accessKey == "" {
ecsRoleName := getBackendConfig ( d . Get ( "ecs_role_name" ) . ( string ) , "ram_role_name" )
subAccessKeyId , subAccessKeySecret , subSecurityToken , err := getAuthCredentialByEcsRoleName ( ecsRoleName )
if err != nil {
return err
}
accessKey , secretKey , securityToken = subAccessKeyId , subAccessKeySecret , subSecurityToken
}
2019-08-06 04:35:51 +02:00
if roleArn != "" {
2019-11-01 17:09:30 +01:00
subAccessKeyId , subAccessKeySecret , subSecurityToken , err := getAssumeRoleAK ( accessKey , secretKey , securityToken , region , roleArn , sessionName , policy , sessionExpiration )
2019-08-06 04:35:51 +02:00
if err != nil {
return err
}
accessKey , secretKey , securityToken = subAccessKeyId , subAccessKeySecret , subSecurityToken
}
2019-03-07 11:31:36 +01:00
if endpoint == "" {
2021-07-15 10:07:18 +02:00
endpointsResponse , _ := b . getOSSEndpointByRegion ( accessKey , secretKey , securityToken , region )
for _ , endpointItem := range endpointsResponse . Endpoints . Endpoint {
if endpointItem . Type == "openAPI" {
endpoint = endpointItem . Endpoint
break
2019-03-07 11:31:36 +01:00
}
2021-07-15 10:07:18 +02:00
}
if endpoint == "" {
2019-03-07 11:31:36 +01:00
endpoint = fmt . Sprintf ( "oss-%s.aliyuncs.com" , region )
}
}
if ! strings . HasPrefix ( endpoint , "http" ) {
endpoint = fmt . Sprintf ( "%s://%s" , schma , endpoint )
}
log . Printf ( "[DEBUG] Instantiate OSS client using endpoint: %#v" , endpoint )
var options [ ] oss . ClientOption
2019-04-11 01:11:10 +02:00
if securityToken != "" {
options = append ( options , oss . SecurityToken ( securityToken ) )
2019-03-07 11:31:36 +01:00
}
options = append ( options , oss . UserAgent ( fmt . Sprintf ( "%s/%s" , TerraformUA , TerraformVersion ) ) )
2020-06-05 08:48:58 +02:00
proxyUrl := getHttpProxyUrl ( )
if proxyUrl != nil {
options = append ( options , oss . Proxy ( proxyUrl . String ( ) ) )
}
2019-04-11 01:11:10 +02:00
client , err := oss . New ( endpoint , accessKey , secretKey , options ... )
2019-03-07 11:31:36 +01:00
b . ossClient = client
2019-04-11 01:11:10 +02:00
otsEndpoint := d . Get ( "tablestore_endpoint" ) . ( string )
if otsEndpoint != "" {
if ! strings . HasPrefix ( otsEndpoint , "http" ) {
otsEndpoint = fmt . Sprintf ( "%s://%s" , schma , otsEndpoint )
}
b . otsEndpoint = otsEndpoint
parts := strings . Split ( strings . TrimPrefix ( strings . TrimPrefix ( otsEndpoint , "https://" ) , "http://" ) , "." )
b . otsClient = tablestore . NewClientWithConfig ( otsEndpoint , parts [ 0 ] , accessKey , secretKey , securityToken , tablestore . NewDefaultTableStoreConfig ( ) )
}
b . otsTable = d . Get ( "tablestore_table" ) . ( string )
2019-03-07 11:31:36 +01:00
return err
}
2021-07-15 10:07:18 +02:00
func ( b * Backend ) getOSSEndpointByRegion ( access_key , secret_key , security_token , region string ) ( * location . DescribeEndpointsResponse , error ) {
args := location . CreateDescribeEndpointsRequest ( )
2019-03-07 11:31:36 +01:00
args . ServiceCode = "oss"
args . Id = region
args . Domain = "location-readonly.aliyuncs.com"
locationClient , err := location . NewClientWithOptions ( region , getSdkConfig ( ) , credentials . NewStsTokenCredential ( access_key , secret_key , security_token ) )
if err != nil {
return nil , fmt . Errorf ( "Unable to initialize the location client: %#v" , err )
}
locationClient . AppendUserAgent ( TerraformUA , TerraformVersion )
2021-07-15 10:07:18 +02:00
endpointsResponse , err := locationClient . DescribeEndpoints ( args )
2019-03-07 11:31:36 +01:00
if err != nil {
return nil , fmt . Errorf ( "Describe oss endpoint using region: %#v got an error: %#v." , region , err )
}
return endpointsResponse , nil
}
2019-11-01 17:09:30 +01:00
func getAssumeRoleAK ( accessKey , secretKey , stsToken , region , roleArn , sessionName , policy string , sessionExpiration int ) ( string , string , string , error ) {
2019-07-30 17:26:51 +02:00
request := sts . CreateAssumeRoleRequest ( )
request . RoleArn = roleArn
request . RoleSessionName = sessionName
request . DurationSeconds = requests . NewInteger ( sessionExpiration )
request . Policy = policy
request . Scheme = "https"
2019-11-01 17:09:30 +01:00
var client * sts . Client
var err error
if stsToken == "" {
client , err = sts . NewClientWithAccessKey ( region , accessKey , secretKey )
} else {
client , err = sts . NewClientWithStsToken ( region , accessKey , secretKey , stsToken )
}
2019-07-30 17:26:51 +02:00
if err != nil {
return "" , "" , "" , err
}
response , err := client . AssumeRole ( request )
if err != nil {
return "" , "" , "" , err
}
return response . Credentials . AccessKeyId , response . Credentials . AccessKeySecret , response . Credentials . SecurityToken , nil
}
2019-03-07 11:31:36 +01:00
func getSdkConfig ( ) * sdk . Config {
return sdk . NewConfig ( ) .
WithMaxRetryTime ( 5 ) .
WithTimeout ( time . Duration ( 30 ) * time . Second ) .
WithGoRoutinePoolSize ( 10 ) .
WithDebug ( false ) .
WithHttpTransport ( getTransport ( ) ) .
WithScheme ( "HTTPS" )
}
func getTransport ( ) * http . Transport {
handshakeTimeout , err := strconv . Atoi ( os . Getenv ( "TLSHandshakeTimeout" ) )
if err != nil {
handshakeTimeout = 120
}
transport := cleanhttp . DefaultTransport ( )
transport . TLSHandshakeTimeout = time . Duration ( handshakeTimeout ) * time . Second
transport . Proxy = http . ProxyFromEnvironment
return transport
}
type Invoker struct {
catchers [ ] * Catcher
}
type Catcher struct {
Reason string
RetryCount int
RetryWaitSeconds int
}
const TerraformUA = "HashiCorp-Terraform"
var TerraformVersion = strings . TrimSuffix ( version . String ( ) , "-dev" )
var ClientErrorCatcher = Catcher { "AliyunGoClientFailure" , 10 , 3 }
var ServiceBusyCatcher = Catcher { "ServiceUnavailable" , 10 , 3 }
func NewInvoker ( ) Invoker {
i := Invoker { }
i . AddCatcher ( ClientErrorCatcher )
i . AddCatcher ( ServiceBusyCatcher )
return i
}
func ( a * Invoker ) AddCatcher ( catcher Catcher ) {
a . catchers = append ( a . catchers , & catcher )
}
func ( a * Invoker ) Run ( f func ( ) error ) error {
err := f ( )
if err == nil {
return nil
}
for _ , catcher := range a . catchers {
if strings . Contains ( err . Error ( ) , catcher . Reason ) {
catcher . RetryCount --
if catcher . RetryCount <= 0 {
return fmt . Errorf ( "Retry timeout and got an error: %#v." , err )
} else {
time . Sleep ( time . Duration ( catcher . RetryWaitSeconds ) * time . Second )
return a . Run ( f )
}
}
}
return err
}
2019-08-06 04:35:51 +02:00
var providerConfig map [ string ] interface { }
func getConfigFromProfile ( d * schema . ResourceData , ProfileKey string ) ( interface { } , error ) {
if providerConfig == nil {
if v , ok := d . GetOk ( "profile" ) ; ! ok || v . ( string ) == "" {
return nil , nil
}
current := d . Get ( "profile" ) . ( string )
2019-11-01 17:09:30 +01:00
// Set CredsFilename, expanding home directory
profilePath , err := homedir . Expand ( d . Get ( "shared_credentials_file" ) . ( string ) )
if err != nil {
return nil , err
}
2019-08-06 04:35:51 +02:00
if profilePath == "" {
profilePath = fmt . Sprintf ( "%s/.aliyun/config.json" , os . Getenv ( "HOME" ) )
if runtime . GOOS == "windows" {
profilePath = fmt . Sprintf ( "%s/.aliyun/config.json" , os . Getenv ( "USERPROFILE" ) )
}
}
providerConfig = make ( map [ string ] interface { } )
2019-11-01 17:09:30 +01:00
_ , err = os . Stat ( profilePath )
2019-08-06 04:35:51 +02:00
if ! os . IsNotExist ( err ) {
data , err := ioutil . ReadFile ( profilePath )
if err != nil {
return nil , err
}
config := map [ string ] interface { } { }
err = json . Unmarshal ( data , & config )
if err != nil {
return nil , err
}
for _ , v := range config [ "profiles" ] . ( [ ] interface { } ) {
if current == v . ( map [ string ] interface { } ) [ "name" ] {
providerConfig = v . ( map [ string ] interface { } )
}
}
}
}
mode := ""
if v , ok := providerConfig [ "mode" ] ; ok {
mode = v . ( string )
} else {
return v , nil
}
switch ProfileKey {
case "access_key_id" , "access_key_secret" :
if mode == "EcsRamRole" {
return "" , nil
}
case "ram_role_name" :
if mode != "EcsRamRole" {
return "" , nil
}
case "sts_token" :
if mode != "StsToken" {
return "" , nil
}
case "ram_role_arn" , "ram_session_name" :
if mode != "RamRoleArn" {
return "" , nil
}
case "expired_seconds" :
if mode != "RamRoleArn" {
return float64 ( 0 ) , nil
}
}
return providerConfig [ ProfileKey ] , nil
}
2019-11-01 17:09:30 +01:00
var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/"
// getAuthCredentialByEcsRoleName aims to access meta to get sts credential
// Actually, the job should be done by sdk, but currently not all resources and products support alibaba-cloud-sdk-go,
// and their go sdk does support ecs role name.
// This method is a temporary solution and it should be removed after all go sdk support ecs role name
// The related PR: https://github.com/terraform-providers/terraform-provider-alicloud/pull/731
func getAuthCredentialByEcsRoleName ( ecsRoleName string ) ( accessKey , secretKey , token string , err error ) {
if ecsRoleName == "" {
return
}
requestUrl := securityCredURL + ecsRoleName
httpRequest , err := http . NewRequest ( requests . GET , requestUrl , strings . NewReader ( "" ) )
if err != nil {
err = fmt . Errorf ( "build sts requests err: %s" , err . Error ( ) )
return
}
httpClient := & http . Client { }
httpResponse , err := httpClient . Do ( httpRequest )
if err != nil {
err = fmt . Errorf ( "get Ecs sts token err : %s" , err . Error ( ) )
return
}
response := responses . NewCommonResponse ( )
err = responses . Unmarshal ( response , httpResponse , "" )
if err != nil {
err = fmt . Errorf ( "Unmarshal Ecs sts token response err : %s" , err . Error ( ) )
return
}
if response . GetHttpStatus ( ) != http . StatusOK {
err = fmt . Errorf ( "get Ecs sts token err, httpStatus: %d, message = %s" , response . GetHttpStatus ( ) , response . GetHttpContentString ( ) )
return
}
var data interface { }
err = json . Unmarshal ( response . GetHttpContentBytes ( ) , & data )
if err != nil {
err = fmt . Errorf ( "refresh Ecs sts token err, json.Unmarshal fail: %s" , err . Error ( ) )
return
}
code , err := jmespath . Search ( "Code" , data )
if err != nil {
err = fmt . Errorf ( "refresh Ecs sts token err, fail to get Code: %s" , err . Error ( ) )
return
}
if code . ( string ) != "Success" {
err = fmt . Errorf ( "refresh Ecs sts token err, Code is not Success" )
return
}
accessKeyId , err := jmespath . Search ( "AccessKeyId" , data )
if err != nil {
err = fmt . Errorf ( "refresh Ecs sts token err, fail to get AccessKeyId: %s" , err . Error ( ) )
return
}
accessKeySecret , err := jmespath . Search ( "AccessKeySecret" , data )
if err != nil {
err = fmt . Errorf ( "refresh Ecs sts token err, fail to get AccessKeySecret: %s" , err . Error ( ) )
return
}
securityToken , err := jmespath . Search ( "SecurityToken" , data )
if err != nil {
err = fmt . Errorf ( "refresh Ecs sts token err, fail to get SecurityToken: %s" , err . Error ( ) )
return
}
if accessKeyId == nil || accessKeySecret == nil || securityToken == nil {
err = fmt . Errorf ( "there is no any available accesskey, secret and security token for Ecs role %s" , ecsRoleName )
return
}
return accessKeyId . ( string ) , accessKeySecret . ( string ) , securityToken . ( string ) , nil
}
2020-06-05 08:48:58 +02:00
func getHttpProxyUrl ( ) * url . URL {
for _ , v := range [ ] string { "HTTPS_PROXY" , "https_proxy" , "HTTP_PROXY" , "http_proxy" } {
value := strings . Trim ( os . Getenv ( v ) , " " )
if value != "" {
if ! regexp . MustCompile ( ` ^http(s)?:// ` ) . MatchString ( value ) {
value = fmt . Sprintf ( "https://%s" , value )
}
proxyUrl , err := url . Parse ( value )
if err == nil {
return proxyUrl
}
break
}
}
return nil
}