github.com/hugorut/terraform@v1.1.3/src/backend/remote-state/oss/backend.go (about) 1 package oss 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints" 8 "io/ioutil" 9 "log" 10 "net/http" 11 "net/url" 12 "os" 13 "regexp" 14 "runtime" 15 "strconv" 16 "strings" 17 "time" 18 19 "github.com/aliyun/alibaba-cloud-sdk-go/sdk" 20 "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials" 21 "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" 22 "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" 23 "github.com/aliyun/alibaba-cloud-sdk-go/services/location" 24 "github.com/aliyun/alibaba-cloud-sdk-go/services/sts" 25 "github.com/aliyun/aliyun-oss-go-sdk/oss" 26 "github.com/aliyun/aliyun-tablestore-go-sdk/tablestore" 27 "github.com/hashicorp/go-cleanhttp" 28 "github.com/jmespath/go-jmespath" 29 "github.com/mitchellh/go-homedir" 30 31 "github.com/hugorut/terraform/src/backend" 32 "github.com/hugorut/terraform/src/legacy/helper/schema" 33 "github.com/hugorut/terraform/version" 34 ) 35 36 // Deprecated in favor of flattening assume_role_* options 37 func deprecatedAssumeRoleSchema() *schema.Schema { 38 return &schema.Schema{ 39 Type: schema.TypeSet, 40 Optional: true, 41 MaxItems: 1, 42 Deprecated: "use assume_role_* options instead", 43 Elem: &schema.Resource{ 44 Schema: map[string]*schema.Schema{ 45 "role_arn": { 46 Type: schema.TypeString, 47 Required: true, 48 Description: "The ARN of a RAM role to assume prior to making API calls.", 49 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_ARN", ""), 50 }, 51 "session_name": { 52 Type: schema.TypeString, 53 Optional: true, 54 Description: "The session name to use when assuming the role.", 55 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_SESSION_NAME", ""), 56 }, 57 "policy": { 58 Type: schema.TypeString, 59 Optional: true, 60 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.", 61 }, 62 "session_expiration": { 63 Type: schema.TypeInt, 64 Optional: true, 65 Description: "The time after which the established session for assuming role expires.", 66 ValidateFunc: func(v interface{}, k string) ([]string, []error) { 67 min := 900 68 max := 3600 69 value, ok := v.(int) 70 if !ok { 71 return nil, []error{fmt.Errorf("expected type of %s to be int", k)} 72 } 73 74 if value < min || value > max { 75 return nil, []error{fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)} 76 } 77 78 return nil, nil 79 }, 80 }, 81 }, 82 }, 83 } 84 } 85 86 // New creates a new backend for OSS remote state. 87 func New() backend.Backend { 88 s := &schema.Backend{ 89 Schema: map[string]*schema.Schema{ 90 "access_key": { 91 Type: schema.TypeString, 92 Optional: true, 93 Description: "Alibaba Cloud Access Key ID", 94 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ACCESS_KEY", os.Getenv("ALICLOUD_ACCESS_KEY_ID")), 95 }, 96 97 "secret_key": { 98 Type: schema.TypeString, 99 Optional: true, 100 Description: "Alibaba Cloud Access Secret Key", 101 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECRET_KEY", os.Getenv("ALICLOUD_ACCESS_KEY_SECRET")), 102 }, 103 104 "security_token": { 105 Type: schema.TypeString, 106 Optional: true, 107 Description: "Alibaba Cloud Security Token", 108 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SECURITY_TOKEN", ""), 109 }, 110 111 "ecs_role_name": { 112 Type: schema.TypeString, 113 Optional: true, 114 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ECS_ROLE_NAME", os.Getenv("ALICLOUD_ECS_ROLE_NAME")), 115 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.", 116 }, 117 118 "region": { 119 Type: schema.TypeString, 120 Optional: true, 121 Description: "The region of the OSS bucket.", 122 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_REGION", os.Getenv("ALICLOUD_DEFAULT_REGION")), 123 }, 124 "sts_endpoint": { 125 Type: schema.TypeString, 126 Optional: true, 127 Description: "A custom endpoint for the STS API", 128 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_STS_ENDPOINT", ""), 129 }, 130 "tablestore_endpoint": { 131 Type: schema.TypeString, 132 Optional: true, 133 Description: "A custom endpoint for the TableStore API", 134 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_TABLESTORE_ENDPOINT", ""), 135 }, 136 "endpoint": { 137 Type: schema.TypeString, 138 Optional: true, 139 Description: "A custom endpoint for the OSS API", 140 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_OSS_ENDPOINT", os.Getenv("OSS_ENDPOINT")), 141 }, 142 143 "bucket": { 144 Type: schema.TypeString, 145 Required: true, 146 Description: "The name of the OSS bucket", 147 }, 148 149 "prefix": { 150 Type: schema.TypeString, 151 Optional: true, 152 Description: "The directory where state files will be saved inside the bucket", 153 Default: "env:", 154 ValidateFunc: func(v interface{}, s string) ([]string, []error) { 155 prefix := v.(string) 156 if strings.HasPrefix(prefix, "/") || strings.HasPrefix(prefix, "./") { 157 return nil, []error{fmt.Errorf("workspace_key_prefix must not start with '/' or './'")} 158 } 159 return nil, nil 160 }, 161 }, 162 163 "key": { 164 Type: schema.TypeString, 165 Optional: true, 166 Description: "The path of the state file inside the bucket", 167 ValidateFunc: func(v interface{}, s string) ([]string, []error) { 168 if strings.HasPrefix(v.(string), "/") || strings.HasSuffix(v.(string), "/") { 169 return nil, []error{fmt.Errorf("key can not start and end with '/'")} 170 } 171 return nil, nil 172 }, 173 Default: "terraform.tfstate", 174 }, 175 176 "tablestore_table": { 177 Type: schema.TypeString, 178 Optional: true, 179 Description: "TableStore table for state locking and consistency", 180 Default: "", 181 }, 182 183 "encrypt": { 184 Type: schema.TypeBool, 185 Optional: true, 186 Description: "Whether to enable server side encryption of the state file", 187 Default: false, 188 }, 189 190 "acl": { 191 Type: schema.TypeString, 192 Optional: true, 193 Description: "Object ACL to be applied to the state file", 194 Default: "", 195 ValidateFunc: func(v interface{}, k string) ([]string, []error) { 196 if value := v.(string); value != "" { 197 acls := oss.ACLType(value) 198 if acls != oss.ACLPrivate && acls != oss.ACLPublicRead && acls != oss.ACLPublicReadWrite { 199 return nil, []error{fmt.Errorf( 200 "%q must be a valid ACL value , expected %s, %s or %s, got %q", 201 k, oss.ACLPrivate, oss.ACLPublicRead, oss.ACLPublicReadWrite, acls)} 202 } 203 } 204 return nil, nil 205 }, 206 }, 207 "shared_credentials_file": { 208 Type: schema.TypeString, 209 Optional: true, 210 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_SHARED_CREDENTIALS_FILE", ""), 211 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.", 212 }, 213 "profile": { 214 Type: schema.TypeString, 215 Optional: true, 216 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.", 217 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_PROFILE", ""), 218 }, 219 "assume_role": deprecatedAssumeRoleSchema(), 220 "assume_role_role_arn": { 221 Type: schema.TypeString, 222 Optional: true, 223 Description: "The ARN of a RAM role to assume prior to making API calls.", 224 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_ARN", ""), 225 }, 226 "assume_role_session_name": { 227 Type: schema.TypeString, 228 Optional: true, 229 Description: "The session name to use when assuming the role.", 230 DefaultFunc: schema.EnvDefaultFunc("ALICLOUD_ASSUME_ROLE_SESSION_NAME", ""), 231 }, 232 "assume_role_policy": { 233 Type: schema.TypeString, 234 Optional: true, 235 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.", 236 }, 237 "assume_role_session_expiration": { 238 Type: schema.TypeInt, 239 Optional: true, 240 Description: "The time after which the established session for assuming role expires.", 241 ValidateFunc: func(v interface{}, k string) ([]string, []error) { 242 min := 900 243 max := 3600 244 value, ok := v.(int) 245 if !ok { 246 return nil, []error{fmt.Errorf("expected type of %s to be int", k)} 247 } 248 249 if value < min || value > max { 250 return nil, []error{fmt.Errorf("expected %s to be in the range (%d - %d), got %d", k, min, max, v)} 251 } 252 253 return nil, nil 254 }, 255 }, 256 }, 257 } 258 259 result := &Backend{Backend: s} 260 result.Backend.ConfigureFunc = result.configure 261 return result 262 } 263 264 type Backend struct { 265 *schema.Backend 266 267 // The fields below are set from configure 268 ossClient *oss.Client 269 otsClient *tablestore.TableStoreClient 270 271 bucketName string 272 statePrefix string 273 stateKey string 274 serverSideEncryption bool 275 acl string 276 otsEndpoint string 277 otsTable string 278 } 279 280 func (b *Backend) configure(ctx context.Context) error { 281 if b.ossClient != nil { 282 return nil 283 } 284 285 // Grab the resource data 286 d := schema.FromContextBackendConfig(ctx) 287 288 b.bucketName = d.Get("bucket").(string) 289 b.statePrefix = strings.TrimPrefix(strings.Trim(d.Get("prefix").(string), "/"), "./") 290 b.stateKey = d.Get("key").(string) 291 b.serverSideEncryption = d.Get("encrypt").(bool) 292 b.acl = d.Get("acl").(string) 293 294 var getBackendConfig = func(str string, key string) string { 295 if str == "" { 296 value, err := getConfigFromProfile(d, key) 297 if err == nil && value != nil { 298 str = value.(string) 299 } 300 } 301 return str 302 } 303 304 accessKey := getBackendConfig(d.Get("access_key").(string), "access_key_id") 305 secretKey := getBackendConfig(d.Get("secret_key").(string), "access_key_secret") 306 securityToken := getBackendConfig(d.Get("security_token").(string), "sts_token") 307 region := getBackendConfig(d.Get("region").(string), "region_id") 308 309 stsEndpoint := d.Get("sts_endpoint").(string) 310 endpoint := d.Get("endpoint").(string) 311 schma := "https" 312 313 roleArn := getBackendConfig("", "ram_role_arn") 314 sessionName := getBackendConfig("", "ram_session_name") 315 var policy string 316 var sessionExpiration int 317 expiredSeconds, err := getConfigFromProfile(d, "expired_seconds") 318 if err == nil && expiredSeconds != nil { 319 sessionExpiration = (int)(expiredSeconds.(float64)) 320 } 321 322 if v, ok := d.GetOk("assume_role_role_arn"); ok && v.(string) != "" { 323 roleArn = v.(string) 324 if v, ok := d.GetOk("assume_role_session_name"); ok { 325 sessionName = v.(string) 326 } 327 if v, ok := d.GetOk("assume_role_policy"); ok { 328 policy = v.(string) 329 } 330 if v, ok := d.GetOk("assume_role_session_expiration"); ok { 331 sessionExpiration = v.(int) 332 } 333 } else if v, ok := d.GetOk("assume_role"); ok { 334 // deprecated assume_role block 335 for _, v := range v.(*schema.Set).List() { 336 assumeRole := v.(map[string]interface{}) 337 if assumeRole["role_arn"].(string) != "" { 338 roleArn = assumeRole["role_arn"].(string) 339 } 340 if assumeRole["session_name"].(string) != "" { 341 sessionName = assumeRole["session_name"].(string) 342 } 343 policy = assumeRole["policy"].(string) 344 sessionExpiration = assumeRole["session_expiration"].(int) 345 } 346 } 347 348 if sessionName == "" { 349 sessionName = "terraform" 350 } 351 if sessionExpiration == 0 { 352 if v := os.Getenv("ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION"); v != "" { 353 if expiredSeconds, err := strconv.Atoi(v); err == nil { 354 sessionExpiration = expiredSeconds 355 } 356 } 357 if sessionExpiration == 0 { 358 sessionExpiration = 3600 359 } 360 } 361 362 if accessKey == "" { 363 ecsRoleName := getBackendConfig(d.Get("ecs_role_name").(string), "ram_role_name") 364 subAccessKeyId, subAccessKeySecret, subSecurityToken, err := getAuthCredentialByEcsRoleName(ecsRoleName) 365 if err != nil { 366 return err 367 } 368 accessKey, secretKey, securityToken = subAccessKeyId, subAccessKeySecret, subSecurityToken 369 } 370 371 if roleArn != "" { 372 subAccessKeyId, subAccessKeySecret, subSecurityToken, err := getAssumeRoleAK(accessKey, secretKey, securityToken, region, roleArn, sessionName, policy, stsEndpoint, sessionExpiration) 373 if err != nil { 374 return err 375 } 376 accessKey, secretKey, securityToken = subAccessKeyId, subAccessKeySecret, subSecurityToken 377 } 378 379 if endpoint == "" { 380 endpointsResponse, err := b.getOSSEndpointByRegion(accessKey, secretKey, securityToken, region) 381 if err != nil { 382 return err 383 } 384 for _, endpointItem := range endpointsResponse.Endpoints.Endpoint { 385 if endpointItem.Type == "openAPI" { 386 endpoint = endpointItem.Endpoint 387 break 388 } 389 } 390 if endpoint == "" { 391 endpoint = fmt.Sprintf("oss-%s.aliyuncs.com", region) 392 } 393 } 394 if !strings.HasPrefix(endpoint, "http") { 395 endpoint = fmt.Sprintf("%s://%s", schma, endpoint) 396 } 397 log.Printf("[DEBUG] Instantiate OSS client using endpoint: %#v", endpoint) 398 var options []oss.ClientOption 399 if securityToken != "" { 400 options = append(options, oss.SecurityToken(securityToken)) 401 } 402 options = append(options, oss.UserAgent(fmt.Sprintf("%s/%s", TerraformUA, TerraformVersion))) 403 404 proxyUrl := getHttpProxyUrl() 405 if proxyUrl != nil { 406 options = append(options, oss.Proxy(proxyUrl.String())) 407 } 408 409 client, err := oss.New(endpoint, accessKey, secretKey, options...) 410 b.ossClient = client 411 otsEndpoint := d.Get("tablestore_endpoint").(string) 412 if otsEndpoint != "" { 413 if !strings.HasPrefix(otsEndpoint, "http") { 414 otsEndpoint = fmt.Sprintf("%s://%s", schma, otsEndpoint) 415 } 416 b.otsEndpoint = otsEndpoint 417 parts := strings.Split(strings.TrimPrefix(strings.TrimPrefix(otsEndpoint, "https://"), "http://"), ".") 418 b.otsClient = tablestore.NewClientWithConfig(otsEndpoint, parts[0], accessKey, secretKey, securityToken, tablestore.NewDefaultTableStoreConfig()) 419 } 420 b.otsTable = d.Get("tablestore_table").(string) 421 422 return err 423 } 424 425 func (b *Backend) getOSSEndpointByRegion(access_key, secret_key, security_token, region string) (*location.DescribeEndpointsResponse, error) { 426 args := location.CreateDescribeEndpointsRequest() 427 args.ServiceCode = "oss" 428 args.Id = region 429 args.Domain = "location-readonly.aliyuncs.com" 430 431 locationClient, err := location.NewClientWithOptions(region, getSdkConfig(), credentials.NewStsTokenCredential(access_key, secret_key, security_token)) 432 if err != nil { 433 return nil, fmt.Errorf("unable to initialize the location client: %#v", err) 434 435 } 436 locationClient.AppendUserAgent(TerraformUA, TerraformVersion) 437 endpointsResponse, err := locationClient.DescribeEndpoints(args) 438 if err != nil { 439 return nil, fmt.Errorf("describe oss endpoint using region: %#v got an error: %#v", region, err) 440 } 441 return endpointsResponse, nil 442 } 443 444 func getAssumeRoleAK(accessKey, secretKey, stsToken, region, roleArn, sessionName, policy, stsEndpoint string, sessionExpiration int) (string, string, string, error) { 445 request := sts.CreateAssumeRoleRequest() 446 request.RoleArn = roleArn 447 request.RoleSessionName = sessionName 448 request.DurationSeconds = requests.NewInteger(sessionExpiration) 449 request.Policy = policy 450 request.Scheme = "https" 451 452 var client *sts.Client 453 var err error 454 if stsToken == "" { 455 client, err = sts.NewClientWithAccessKey(region, accessKey, secretKey) 456 } else { 457 client, err = sts.NewClientWithStsToken(region, accessKey, secretKey, stsToken) 458 } 459 if err != nil { 460 return "", "", "", err 461 } 462 if stsEndpoint != "" { 463 endpoints.AddEndpointMapping(region, "STS", stsEndpoint) 464 } 465 response, err := client.AssumeRole(request) 466 if err != nil { 467 return "", "", "", err 468 } 469 return response.Credentials.AccessKeyId, response.Credentials.AccessKeySecret, response.Credentials.SecurityToken, nil 470 } 471 472 func getSdkConfig() *sdk.Config { 473 return sdk.NewConfig(). 474 WithMaxRetryTime(5). 475 WithTimeout(time.Duration(30) * time.Second). 476 WithGoRoutinePoolSize(10). 477 WithDebug(false). 478 WithHttpTransport(getTransport()). 479 WithScheme("HTTPS") 480 } 481 482 func getTransport() *http.Transport { 483 handshakeTimeout, err := strconv.Atoi(os.Getenv("TLSHandshakeTimeout")) 484 if err != nil { 485 handshakeTimeout = 120 486 } 487 transport := cleanhttp.DefaultTransport() 488 transport.TLSHandshakeTimeout = time.Duration(handshakeTimeout) * time.Second 489 transport.Proxy = http.ProxyFromEnvironment 490 return transport 491 } 492 493 type Invoker struct { 494 catchers []*Catcher 495 } 496 497 type Catcher struct { 498 Reason string 499 RetryCount int 500 RetryWaitSeconds int 501 } 502 503 const TerraformUA = "HashiCorp-Terraform" 504 505 var TerraformVersion = strings.TrimSuffix(version.String(), "-dev") 506 var ClientErrorCatcher = Catcher{"AliyunGoClientFailure", 10, 3} 507 var ServiceBusyCatcher = Catcher{"ServiceUnavailable", 10, 3} 508 509 func NewInvoker() Invoker { 510 i := Invoker{} 511 i.AddCatcher(ClientErrorCatcher) 512 i.AddCatcher(ServiceBusyCatcher) 513 return i 514 } 515 516 func (a *Invoker) AddCatcher(catcher Catcher) { 517 a.catchers = append(a.catchers, &catcher) 518 } 519 520 func (a *Invoker) Run(f func() error) error { 521 err := f() 522 523 if err == nil { 524 return nil 525 } 526 527 for _, catcher := range a.catchers { 528 if strings.Contains(err.Error(), catcher.Reason) { 529 catcher.RetryCount-- 530 531 if catcher.RetryCount <= 0 { 532 return fmt.Errorf("retry timeout and got an error: %#v", err) 533 } else { 534 time.Sleep(time.Duration(catcher.RetryWaitSeconds) * time.Second) 535 return a.Run(f) 536 } 537 } 538 } 539 return err 540 } 541 542 var providerConfig map[string]interface{} 543 544 func getConfigFromProfile(d *schema.ResourceData, ProfileKey string) (interface{}, error) { 545 546 if providerConfig == nil { 547 if v, ok := d.GetOk("profile"); !ok || v.(string) == "" { 548 return nil, nil 549 } 550 current := d.Get("profile").(string) 551 // Set CredsFilename, expanding home directory 552 profilePath, err := homedir.Expand(d.Get("shared_credentials_file").(string)) 553 if err != nil { 554 return nil, err 555 } 556 if profilePath == "" { 557 profilePath = fmt.Sprintf("%s/.aliyun/config.json", os.Getenv("HOME")) 558 if runtime.GOOS == "windows" { 559 profilePath = fmt.Sprintf("%s/.aliyun/config.json", os.Getenv("USERPROFILE")) 560 } 561 } 562 providerConfig = make(map[string]interface{}) 563 _, err = os.Stat(profilePath) 564 if !os.IsNotExist(err) { 565 data, err := ioutil.ReadFile(profilePath) 566 if err != nil { 567 return nil, err 568 } 569 config := map[string]interface{}{} 570 err = json.Unmarshal(data, &config) 571 if err != nil { 572 return nil, err 573 } 574 for _, v := range config["profiles"].([]interface{}) { 575 if current == v.(map[string]interface{})["name"] { 576 providerConfig = v.(map[string]interface{}) 577 } 578 } 579 } 580 } 581 582 mode := "" 583 if v, ok := providerConfig["mode"]; ok { 584 mode = v.(string) 585 } else { 586 return v, nil 587 } 588 switch ProfileKey { 589 case "access_key_id", "access_key_secret": 590 if mode == "EcsRamRole" { 591 return "", nil 592 } 593 case "ram_role_name": 594 if mode != "EcsRamRole" { 595 return "", nil 596 } 597 case "sts_token": 598 if mode != "StsToken" { 599 return "", nil 600 } 601 case "ram_role_arn", "ram_session_name": 602 if mode != "RamRoleArn" { 603 return "", nil 604 } 605 case "expired_seconds": 606 if mode != "RamRoleArn" { 607 return float64(0), nil 608 } 609 } 610 611 return providerConfig[ProfileKey], nil 612 } 613 614 var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/" 615 616 // getAuthCredentialByEcsRoleName aims to access meta to get sts credential 617 // Actually, the job should be done by sdk, but currently not all resources and products support alibaba-cloud-sdk-go, 618 // and their go sdk does support ecs role name. 619 // This method is a temporary solution and it should be removed after all go sdk support ecs role name 620 // The related PR: https://github.com/terraform-providers/terraform-provider-alicloud/pull/731 621 func getAuthCredentialByEcsRoleName(ecsRoleName string) (accessKey, secretKey, token string, err error) { 622 623 if ecsRoleName == "" { 624 return 625 } 626 requestUrl := securityCredURL + ecsRoleName 627 httpRequest, err := http.NewRequest(requests.GET, requestUrl, strings.NewReader("")) 628 if err != nil { 629 err = fmt.Errorf("build sts requests err: %s", err.Error()) 630 return 631 } 632 httpClient := &http.Client{} 633 httpResponse, err := httpClient.Do(httpRequest) 634 if err != nil { 635 err = fmt.Errorf("get Ecs sts token err : %s", err.Error()) 636 return 637 } 638 639 response := responses.NewCommonResponse() 640 err = responses.Unmarshal(response, httpResponse, "") 641 if err != nil { 642 err = fmt.Errorf("unmarshal Ecs sts token response err : %s", err.Error()) 643 return 644 } 645 646 if response.GetHttpStatus() != http.StatusOK { 647 err = fmt.Errorf("get Ecs sts token err, httpStatus: %d, message = %s", response.GetHttpStatus(), response.GetHttpContentString()) 648 return 649 } 650 var data interface{} 651 err = json.Unmarshal(response.GetHttpContentBytes(), &data) 652 if err != nil { 653 err = fmt.Errorf("refresh Ecs sts token err, json.Unmarshal fail: %s", err.Error()) 654 return 655 } 656 code, err := jmespath.Search("Code", data) 657 if err != nil { 658 err = fmt.Errorf("refresh Ecs sts token err, fail to get Code: %s", err.Error()) 659 return 660 } 661 if code.(string) != "Success" { 662 err = fmt.Errorf("refresh Ecs sts token err, Code is not Success") 663 return 664 } 665 accessKeyId, err := jmespath.Search("AccessKeyId", data) 666 if err != nil { 667 err = fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeyId: %s", err.Error()) 668 return 669 } 670 accessKeySecret, err := jmespath.Search("AccessKeySecret", data) 671 if err != nil { 672 err = fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeySecret: %s", err.Error()) 673 return 674 } 675 securityToken, err := jmespath.Search("SecurityToken", data) 676 if err != nil { 677 err = fmt.Errorf("refresh Ecs sts token err, fail to get SecurityToken: %s", err.Error()) 678 return 679 } 680 681 if accessKeyId == nil || accessKeySecret == nil || securityToken == nil { 682 err = fmt.Errorf("there is no any available accesskey, secret and security token for Ecs role %s", ecsRoleName) 683 return 684 } 685 686 return accessKeyId.(string), accessKeySecret.(string), securityToken.(string), nil 687 } 688 689 func getHttpProxyUrl() *url.URL { 690 for _, v := range []string{"HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"} { 691 value := strings.Trim(os.Getenv(v), " ") 692 if value != "" { 693 if !regexp.MustCompile(`^http(s)?://`).MatchString(value) { 694 value = fmt.Sprintf("https://%s", value) 695 } 696 proxyUrl, err := url.Parse(value) 697 if err == nil { 698 return proxyUrl 699 } 700 break 701 } 702 } 703 return nil 704 }