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