github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/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/eliastor/durgaform/internal/backend" 33 "github.com/eliastor/durgaform/internal/legacy/helper/schema" 34 "github.com/eliastor/durgaform/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: "durgaform.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 = "durgaform" 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 return err 384 } 385 for _, endpointItem := range endpointsResponse.Endpoints.Endpoint { 386 if endpointItem.Type == "openAPI" { 387 endpoint = endpointItem.Endpoint 388 break 389 } 390 } 391 if endpoint == "" { 392 endpoint = fmt.Sprintf("oss-%s.aliyuncs.com", region) 393 } 394 } 395 if !strings.HasPrefix(endpoint, "http") { 396 endpoint = fmt.Sprintf("%s://%s", schma, endpoint) 397 } 398 log.Printf("[DEBUG] Instantiate OSS client using endpoint: %#v", endpoint) 399 var options []oss.ClientOption 400 if securityToken != "" { 401 options = append(options, oss.SecurityToken(securityToken)) 402 } 403 options = append(options, oss.UserAgent(fmt.Sprintf("%s/%s", DurgaformUA, DurgaformVersion))) 404 405 proxyUrl := getHttpProxyUrl() 406 if proxyUrl != nil { 407 options = append(options, oss.Proxy(proxyUrl.String())) 408 } 409 410 client, err := oss.New(endpoint, accessKey, secretKey, options...) 411 b.ossClient = client 412 otsEndpoint := d.Get("tablestore_endpoint").(string) 413 if otsEndpoint != "" { 414 if !strings.HasPrefix(otsEndpoint, "http") { 415 otsEndpoint = fmt.Sprintf("%s://%s", schma, otsEndpoint) 416 } 417 b.otsEndpoint = otsEndpoint 418 parts := strings.Split(strings.TrimPrefix(strings.TrimPrefix(otsEndpoint, "https://"), "http://"), ".") 419 b.otsClient = tablestore.NewClientWithConfig(otsEndpoint, parts[0], accessKey, secretKey, securityToken, tablestore.NewDefaultTableStoreConfig()) 420 } 421 b.otsTable = d.Get("tablestore_table").(string) 422 423 return err 424 } 425 426 func (b *Backend) getOSSEndpointByRegion(access_key, secret_key, security_token, region string) (*location.DescribeEndpointsResponse, error) { 427 args := location.CreateDescribeEndpointsRequest() 428 args.ServiceCode = "oss" 429 args.Id = region 430 args.Domain = "location-readonly.aliyuncs.com" 431 432 locationClient, err := location.NewClientWithOptions(region, getSdkConfig(), credentials.NewStsTokenCredential(access_key, secret_key, security_token)) 433 if err != nil { 434 return nil, fmt.Errorf("unable to initialize the location client: %#v", err) 435 436 } 437 locationClient.AppendUserAgent(DurgaformUA, DurgaformVersion) 438 endpointsResponse, err := locationClient.DescribeEndpoints(args) 439 if err != nil { 440 return nil, fmt.Errorf("describe oss endpoint using region: %#v got an error: %#v", region, err) 441 } 442 return endpointsResponse, nil 443 } 444 445 func getAssumeRoleAK(accessKey, secretKey, stsToken, region, roleArn, sessionName, policy, stsEndpoint string, sessionExpiration int) (string, string, string, error) { 446 request := sts.CreateAssumeRoleRequest() 447 request.RoleArn = roleArn 448 request.RoleSessionName = sessionName 449 request.DurationSeconds = requests.NewInteger(sessionExpiration) 450 request.Policy = policy 451 request.Scheme = "https" 452 453 var client *sts.Client 454 var err error 455 if stsToken == "" { 456 client, err = sts.NewClientWithAccessKey(region, accessKey, secretKey) 457 } else { 458 client, err = sts.NewClientWithStsToken(region, accessKey, secretKey, stsToken) 459 } 460 if err != nil { 461 return "", "", "", err 462 } 463 if stsEndpoint != "" { 464 endpoints.AddEndpointMapping(region, "STS", stsEndpoint) 465 } 466 response, err := client.AssumeRole(request) 467 if err != nil { 468 return "", "", "", err 469 } 470 return response.Credentials.AccessKeyId, response.Credentials.AccessKeySecret, response.Credentials.SecurityToken, nil 471 } 472 473 func getSdkConfig() *sdk.Config { 474 return sdk.NewConfig(). 475 WithMaxRetryTime(5). 476 WithTimeout(time.Duration(30) * time.Second). 477 WithGoRoutinePoolSize(10). 478 WithDebug(false). 479 WithHttpTransport(getTransport()). 480 WithScheme("HTTPS") 481 } 482 483 func getTransport() *http.Transport { 484 handshakeTimeout, err := strconv.Atoi(os.Getenv("TLSHandshakeTimeout")) 485 if err != nil { 486 handshakeTimeout = 120 487 } 488 transport := cleanhttp.DefaultTransport() 489 transport.TLSHandshakeTimeout = time.Duration(handshakeTimeout) * time.Second 490 transport.Proxy = http.ProxyFromEnvironment 491 return transport 492 } 493 494 type Invoker struct { 495 catchers []*Catcher 496 } 497 498 type Catcher struct { 499 Reason string 500 RetryCount int 501 RetryWaitSeconds int 502 } 503 504 const DurgaformUA = "HashiCorp-Terraform" 505 506 var DurgaformVersion = strings.TrimSuffix(version.String(), "-dev") 507 var ClientErrorCatcher = Catcher{"AliyunGoClientFailure", 10, 3} 508 var ServiceBusyCatcher = Catcher{"ServiceUnavailable", 10, 3} 509 510 func NewInvoker() Invoker { 511 i := Invoker{} 512 i.AddCatcher(ClientErrorCatcher) 513 i.AddCatcher(ServiceBusyCatcher) 514 return i 515 } 516 517 func (a *Invoker) AddCatcher(catcher Catcher) { 518 a.catchers = append(a.catchers, &catcher) 519 } 520 521 func (a *Invoker) Run(f func() error) error { 522 err := f() 523 524 if err == nil { 525 return nil 526 } 527 528 for _, catcher := range a.catchers { 529 if strings.Contains(err.Error(), catcher.Reason) { 530 catcher.RetryCount-- 531 532 if catcher.RetryCount <= 0 { 533 return fmt.Errorf("retry timeout and got an error: %#v", err) 534 } else { 535 time.Sleep(time.Duration(catcher.RetryWaitSeconds) * time.Second) 536 return a.Run(f) 537 } 538 } 539 } 540 return err 541 } 542 543 var providerConfig map[string]interface{} 544 545 func getConfigFromProfile(d *schema.ResourceData, ProfileKey string) (interface{}, error) { 546 547 if providerConfig == nil { 548 if v, ok := d.GetOk("profile"); !ok || v.(string) == "" { 549 return nil, nil 550 } 551 current := d.Get("profile").(string) 552 // Set CredsFilename, expanding home directory 553 profilePath, err := homedir.Expand(d.Get("shared_credentials_file").(string)) 554 if err != nil { 555 return nil, err 556 } 557 if profilePath == "" { 558 profilePath = fmt.Sprintf("%s/.aliyun/config.json", os.Getenv("HOME")) 559 if runtime.GOOS == "windows" { 560 profilePath = fmt.Sprintf("%s/.aliyun/config.json", os.Getenv("USERPROFILE")) 561 } 562 } 563 providerConfig = make(map[string]interface{}) 564 _, err = os.Stat(profilePath) 565 if !os.IsNotExist(err) { 566 data, err := ioutil.ReadFile(profilePath) 567 if err != nil { 568 return nil, err 569 } 570 config := map[string]interface{}{} 571 err = json.Unmarshal(data, &config) 572 if err != nil { 573 return nil, err 574 } 575 for _, v := range config["profiles"].([]interface{}) { 576 if current == v.(map[string]interface{})["name"] { 577 providerConfig = v.(map[string]interface{}) 578 } 579 } 580 } 581 } 582 583 mode := "" 584 if v, ok := providerConfig["mode"]; ok { 585 mode = v.(string) 586 } else { 587 return v, nil 588 } 589 switch ProfileKey { 590 case "access_key_id", "access_key_secret": 591 if mode == "EcsRamRole" { 592 return "", nil 593 } 594 case "ram_role_name": 595 if mode != "EcsRamRole" { 596 return "", nil 597 } 598 case "sts_token": 599 if mode != "StsToken" { 600 return "", nil 601 } 602 case "ram_role_arn", "ram_session_name": 603 if mode != "RamRoleArn" { 604 return "", nil 605 } 606 case "expired_seconds": 607 if mode != "RamRoleArn" { 608 return float64(0), nil 609 } 610 } 611 612 return providerConfig[ProfileKey], nil 613 } 614 615 var securityCredURL = "http://100.100.100.200/latest/meta-data/ram/security-credentials/" 616 617 // getAuthCredentialByEcsRoleName aims to access meta to get sts credential 618 // Actually, the job should be done by sdk, but currently not all resources and products support alibaba-cloud-sdk-go, 619 // and their go sdk does support ecs role name. 620 // This method is a temporary solution and it should be removed after all go sdk support ecs role name 621 // The related PR: https://github.com/durgaform-providers/terraform-provider-alicloud/pull/731 622 func getAuthCredentialByEcsRoleName(ecsRoleName string) (accessKey, secretKey, token string, err error) { 623 624 if ecsRoleName == "" { 625 return 626 } 627 requestUrl := securityCredURL + ecsRoleName 628 httpRequest, err := http.NewRequest(requests.GET, requestUrl, strings.NewReader("")) 629 if err != nil { 630 err = fmt.Errorf("build sts requests err: %s", err.Error()) 631 return 632 } 633 httpClient := &http.Client{} 634 httpResponse, err := httpClient.Do(httpRequest) 635 if err != nil { 636 err = fmt.Errorf("get Ecs sts token err : %s", err.Error()) 637 return 638 } 639 640 response := responses.NewCommonResponse() 641 err = responses.Unmarshal(response, httpResponse, "") 642 if err != nil { 643 err = fmt.Errorf("unmarshal Ecs sts token response err : %s", err.Error()) 644 return 645 } 646 647 if response.GetHttpStatus() != http.StatusOK { 648 err = fmt.Errorf("get Ecs sts token err, httpStatus: %d, message = %s", response.GetHttpStatus(), response.GetHttpContentString()) 649 return 650 } 651 var data interface{} 652 err = json.Unmarshal(response.GetHttpContentBytes(), &data) 653 if err != nil { 654 err = fmt.Errorf("refresh Ecs sts token err, json.Unmarshal fail: %s", err.Error()) 655 return 656 } 657 code, err := jmespath.Search("Code", data) 658 if err != nil { 659 err = fmt.Errorf("refresh Ecs sts token err, fail to get Code: %s", err.Error()) 660 return 661 } 662 if code.(string) != "Success" { 663 err = fmt.Errorf("refresh Ecs sts token err, Code is not Success") 664 return 665 } 666 accessKeyId, err := jmespath.Search("AccessKeyId", data) 667 if err != nil { 668 err = fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeyId: %s", err.Error()) 669 return 670 } 671 accessKeySecret, err := jmespath.Search("AccessKeySecret", data) 672 if err != nil { 673 err = fmt.Errorf("refresh Ecs sts token err, fail to get AccessKeySecret: %s", err.Error()) 674 return 675 } 676 securityToken, err := jmespath.Search("SecurityToken", data) 677 if err != nil { 678 err = fmt.Errorf("refresh Ecs sts token err, fail to get SecurityToken: %s", err.Error()) 679 return 680 } 681 682 if accessKeyId == nil || accessKeySecret == nil || securityToken == nil { 683 err = fmt.Errorf("there is no any available accesskey, secret and security token for Ecs role %s", ecsRoleName) 684 return 685 } 686 687 return accessKeyId.(string), accessKeySecret.(string), securityToken.(string), nil 688 } 689 690 func getHttpProxyUrl() *url.URL { 691 for _, v := range []string{"HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"} { 692 value := strings.Trim(os.Getenv(v), " ") 693 if value != "" { 694 if !regexp.MustCompile(`^http(s)?://`).MatchString(value) { 695 value = fmt.Sprintf("https://%s", value) 696 } 697 proxyUrl, err := url.Parse(value) 698 if err == nil { 699 return proxyUrl 700 } 701 break 702 } 703 } 704 return nil 705 }