diff --git a/Makefile b/Makefile index 28535b27..2a07f600 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ build: go build -v -o examples/terraform-provider-alks -mod=vendor . test: - go test -v . + go test -timeout 1200s -v . plan: @terraform plan diff --git a/assume_role_policy_test.go b/assume_role_policy_test.go index f5c9fb3a..94eab302 100644 --- a/assume_role_policy_test.go +++ b/assume_role_policy_test.go @@ -15,8 +15,8 @@ func TestSuppressEquivalentTrustPolicyDiffs(t *testing.T) { { policy1: string(` { - "Version": "1234", - "Id": "Something", + "Version": "1234", + "Id": "Something", "Statement": [ { "Action": "sts:AssumeRole", @@ -34,7 +34,7 @@ func TestSuppressEquivalentTrustPolicyDiffs(t *testing.T) { policy2: string(` { "Id": "Something", - "Version": "1234", + "Version": "1234", "Statement": [ { "Action": "sts:AssumeRole", @@ -54,8 +54,8 @@ func TestSuppressEquivalentTrustPolicyDiffs(t *testing.T) { { policy1: string(` { - "Version": "1234", - "Id": "Something", + "Version": "1234", + "Id": "Something", "Statement": [ { "Action": "sts:AssumeRole", @@ -73,7 +73,7 @@ func TestSuppressEquivalentTrustPolicyDiffs(t *testing.T) { policy2: string(` { "Id": "Something", - "Version": "1234", + "Version": "1234", "Statement": [ { "Action": "sts:AssumeRole", diff --git a/docs/guides/local_installation.md b/docs/guides/local_installation.md index 7099d5cb..7cb4d46a 100644 --- a/docs/guides/local_installation.md +++ b/docs/guides/local_installation.md @@ -47,11 +47,11 @@ mkdir -p ~/.terraform.d/plugins && **One-liner download for macOS / Linux:** ```sh -mkdir -p ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.6.1/darwin_amd64 && - curl -Ls https://api.github.com/repos/Cox-Automotive/terraform-provider-alks/releases | jq -r --arg release "v2.6.1" --arg arch "$(uname -s | tr A-Z a-z)" '.[] | select(.tag_name | contains($release)) | .assets[]| select(.browser_download_url | contains($arch)) | select(.browser_download_url | contains("amd64")) | .browser_download_url' | - xargs -n 1 curl -Lo ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.6.1/darwin_amd64/terraform-provider-alks.zip && - pushd ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.6.1/darwin_amd64 && - unzip ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.6.1/darwin_amd64/terraform-provider-alks.zip -d terraform-provider-alks-tmp && +mkdir -p ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.7.0/darwin_amd64 && + curl -Ls https://api.github.com/repos/Cox-Automotive/terraform-provider-alks/releases | jq -r --arg release "v2.7.0" --arg arch "$(uname -s | tr A-Z a-z)" '.[] | select(.tag_name | contains($release)) | .assets[]| select(.browser_download_url | contains($arch)) | select(.browser_download_url | contains("amd64")) | .browser_download_url' | + xargs -n 1 curl -Lo ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.7.0/darwin_amd64/terraform-provider-alks.zip && + pushd ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.7.0/darwin_amd64 && + unzip ~/.terraform.d/plugins/Cox-Automotive/engineering-enablement/alks/2.7.0/darwin_amd64/terraform-provider-alks.zip -d terraform-provider-alks-tmp && mv terraform-provider-alks-tmp/terraform-provider-alks* . && chmod +x terraform-provider-alks* && rm -rf terraform-provider-alks-tmp && diff --git a/docs/resources/alks_ltk.md b/docs/resources/alks_ltk.md index 4d469b27..c194af07 100644 --- a/docs/resources/alks_ltk.md +++ b/docs/resources/alks_ltk.md @@ -11,10 +11,21 @@ resource "alks_ltk" "test_ltk_user" { } ``` +### ALKS IAM Role Creation With Tags +```hcl +resource "alks_ltk" "test_ltk_user" { + iam_username = "My_LTK_User_Name" + tags = { + "tagKey" = "tagValue" + } +} +``` + ## Argument Reference The following arguments are supported: * `iam_username` - (Required) The name of the IAM user to create. This parameter allows a string of characters consisting of upper and lowercase alphanumeric characters with no spaces. You can also include any of the following characters: =,.@-. User names are not distinguished by case. +* `tags` - (Optional) If present, will add specified tags onto role. * `iam_user_arn` - (Computed) The ARN associated with the LTK user. * `access_key` - (Computed) Generated access key for the LTK user. Note: This is saved in the state file, so please be aware of this. * `secret_key` - (Computed) Generated secret key for the LTK user. Note: This is saved in the state file, so please be aware of this. diff --git a/examples/alks.tf b/examples/alks.tf index c64fd143..e829f4d6 100644 --- a/examples/alks.tf +++ b/examples/alks.tf @@ -102,4 +102,7 @@ resource "aws_iam_role_policy_attachment" "sr-attach" { # CREATE LTK USER resource "alks_ltk" "ltk" { iam_username = "TEST-LTK-USER" + tags = { + TagKey = "TagValue" + } } diff --git a/go.mod b/go.mod index 9be141db..a0e36d66 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/Cox-Automotive/terraform-provider-alks go 1.18 require ( - github.com/Cox-Automotive/alks-go v0.0.0-20221010204605-136b6e9b6530 + github.com/Cox-Automotive/alks-go v0.0.0-20221019181202-84b27abafb6b github.com/aws/aws-sdk-go v1.31.15 github.com/hashicorp/terraform-plugin-sdk/v2 v2.21.0 github.com/mitchellh/go-homedir v1.1.0 @@ -57,4 +57,3 @@ require ( google.golang.org/grpc v1.48.0 // indirect google.golang.org/protobuf v1.28.1 // indirect ) - diff --git a/go.sum b/go.sum index 8945acc9..d4f2c6c1 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/Cox-Automotive/alks-go v0.0.0-20221004204541-a25fb5c4f655 h1:akQkFItS github.com/Cox-Automotive/alks-go v0.0.0-20221004204541-a25fb5c4f655/go.mod h1:jJNgXthl59Vt2tJHSC3WZ0vlopV9xqdclfQuLgwHjOw= github.com/Cox-Automotive/alks-go v0.0.0-20221010204605-136b6e9b6530 h1:8j3NYoLnFy2PGw+UX47C8jC2j3CCkFeXqlaMfKu9Bh8= github.com/Cox-Automotive/alks-go v0.0.0-20221010204605-136b6e9b6530/go.mod h1:jJNgXthl59Vt2tJHSC3WZ0vlopV9xqdclfQuLgwHjOw= +github.com/Cox-Automotive/alks-go v0.0.0-20221019181202-84b27abafb6b h1:9Ey7kdUL+/f5EY2KOpTawWMw4P7fhZxNmo8gXIuBQzw= +github.com/Cox-Automotive/alks-go v0.0.0-20221019181202-84b27abafb6b/go.mod h1:jJNgXthl59Vt2tJHSC3WZ0vlopV9xqdclfQuLgwHjOw= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= diff --git a/resource_alks_iamrole.go b/resource_alks_iamrole.go index b6f17f79..8feb7b07 100644 --- a/resource_alks_iamrole.go +++ b/resource_alks_iamrole.go @@ -76,6 +76,7 @@ func resourceAlksIamRole() *schema.Resource { Type: schema.TypeBool, Default: false, Optional: true, + ForceNew: true, }, "template_fields": { Type: schema.TypeMap, @@ -260,7 +261,7 @@ func resourceAlksIamRoleUpdate(ctx context.Context, d *schema.ResourceData, meta if d.HasChange("tags_all") { // try updating enable_alks_access - if err := updateIamTags(d, meta); err != nil { + if err := updateIamRoleTags(d, meta); err != nil { return diag.FromErr(err) } } @@ -294,7 +295,7 @@ func updateAlksAccess(d *schema.ResourceData, meta interface{}) error { return nil } -func updateIamTags(d *schema.ResourceData, meta interface{}) error { +func updateIamRoleTags(d *schema.ResourceData, meta interface{}) error { providerStruct := meta.(*AlksClient) client := providerStruct.client diff --git a/resource_alks_ltk.go b/resource_alks_ltk.go index e4767530..13095b7e 100644 --- a/resource_alks_ltk.go +++ b/resource_alks_ltk.go @@ -4,9 +4,9 @@ import ( "context" "log" + "github.com/Cox-Automotive/alks-go" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - - // "github.com/Cox-Automotive/alks-go" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -14,6 +14,7 @@ func resourceAlksLtk() *schema.Resource { return &schema.Resource{ CreateContext: resourceAlksLtkCreate, ReadContext: resourceAlksLtkRead, + UpdateContext: resourceAlksLtkUpdate, DeleteContext: resourceAlksLtkDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -39,7 +40,12 @@ func resourceAlksLtk() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "tags": TagsSchema(), + "tags_all": TagsSchemaComputed(), }, + CustomizeDiff: customdiff.All( + SetTagsDiff, + ), } } @@ -47,16 +53,24 @@ func resourceAlksLtkCreate(ctx context.Context, d *schema.ResourceData, meta int log.Printf("[INFO] ALKS LTK User Create") var iamUsername = d.Get("iam_username").(string) + var tags = d.Get("tags").(map[string]interface{}) providerStruct := meta.(*AlksClient) client := providerStruct.client + + allTags := tagMapToSlice(combineTagMaps(providerStruct.defaultTags, tags)) + + options := &alks.IamUserOptions{ + IamUserName: &iamUsername, + Tags: &allTags, + } if err := validateIAMEnabled(client); err != nil { return diag.FromErr(err) } - resp, err := client.CreateLongTermKey(iamUsername) + resp, err := client.CreateIamUser(options) if err != nil { - return diag.FromErr(err) + return diag.FromErr(err.Err) } d.SetId(iamUsername) @@ -75,26 +89,66 @@ func resourceAlksLtkRead(ctx context.Context, d *schema.ResourceData, meta inter providerStruct := meta.(*AlksClient) client := providerStruct.client + defaultTags := providerStruct.defaultTags + ignoreTags := providerStruct.ignoreTags + // Check if role exists. if d.Id() == "" || d.Id() == "none" { return nil } - resp, err := client.GetLongTermKey(d.Id()) + resp, err := client.GetIamUser(d.Id()) if err != nil { - d.SetId("") - return nil + //If error is 404, UserNotFound, we log it and let terraform decide how to handle it. + //All other errors cause a failure + if err.StatusCode == 404 { + log.Printf("[Error] %s", err.Err) + d.SetId("") + return nil + } + return diag.FromErr(err.Err) } log.Printf("[INFO] alks_ltk.id: %v", d.Id()) - _ = d.Set("iam_username", resp.UserName) - _ = d.Set("access_key", resp.AccessKeyID) + _ = d.Set("iam_username", resp.User.UserName) + _ = d.Set("access_key", resp.User.AccessKey) + + allTags := tagSliceToMap(resp.User.Tags) + localTags := removeIgnoredTags(allTags, *ignoreTags) + + if err := d.Set("tags_all", localTags); err != nil { + return diag.FromErr(err) + } + + userSpecificTags := removeDefaultTags(localTags, defaultTags) + + if err := d.Set("tags", userSpecificTags); err != nil { + return diag.FromErr(err) + } return nil } +func resourceAlksLtkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + log.Printf("[INFO] ALKS LTK Update") + + // enable partial state mode + d.Partial(true) + + if d.HasChange("tags_all") { + // try updating enable_alks_access + if err := updateUserTags(d, meta); err != nil { + return diag.FromErr(err) + } + } + + d.Partial(false) + + return resourceAlksLtkRead(ctx, d, meta) +} + func resourceAlksLtkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { log.Printf("[INFO] ALKS LTK User Delete") @@ -104,9 +158,43 @@ func resourceAlksLtkDelete(ctx context.Context, d *schema.ResourceData, meta int return diag.FromErr(err) } - if _, err := client.DeleteLongTermKey(d.Id()); err != nil { - return diag.FromErr(err) + if _, err := client.DeleteIamUser(d.Id()); err != nil { + return diag.FromErr(err.Err) } return nil } + +func updateUserTags(d *schema.ResourceData, meta interface{}) error { + providerStruct := meta.(*AlksClient) + client := providerStruct.client + + if err := validateIAMEnabled(client); err != nil { + return err + } + + //Do a read to get existing tags. If any of those are in ignore_tags, then they are externally managed + //and they should be included in the update so they don't get removed. + resp, err := client.GetIamUser(d.Id()) + + if err != nil { + return err + } + + existingTags := tagSliceToMap(resp.User.Tags) + externalTags := getExternalyManagedTags(existingTags, *providerStruct.ignoreTags) + internalTags := d.Get("tags_all").(map[string]interface{}) + + //Tags includes default tags, role specific tags, and tags that exist externally on the role itself and are specified in ignored_tags + tags := tagMapToSlice(combineTagMaps(internalTags, externalTags)) + + options := alks.IamUserOptions{ + IamUserName: &resp.User.UserName, + Tags: &tags, + } + + if _, err := client.UpdateIamUser(&options); err != nil { + return err.Err + } + return nil +} diff --git a/resource_alks_ltk_test.go b/resource_alks_ltk_test.go index e135592f..567566f0 100644 --- a/resource_alks_ltk_test.go +++ b/resource_alks_ltk_test.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log" "testing" "github.com/Cox-Automotive/alks-go" @@ -10,7 +11,7 @@ import ( ) func TestAlksLTKCreate(t *testing.T) { - var resp alks.CreateLongTermKeyResponse + var resp alks.CreateIamUserResponse resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -22,16 +23,172 @@ func TestAlksLTKCreate(t *testing.T) { Config: testAlksLTKCreateConfig, Check: resource.ComposeTestCheckFunc(resource.TestCheckResourceAttr("alks_ltk.foo", "iam_username", "TEST_LTK_USER")), }, - // Update the resource + }, + }) +} + +func TestAlksLTKCreateWithTags(t *testing.T) { + var resp alks.CreateIamUserResponse + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAlksLtkDestroy(&resp), + Steps: []resource.TestStep{ + // Create the resource + { + Config: testAlksLTKCreateWithTagsConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("alks_ltk.foo", "iam_username", "TEST_LTK_USER"), + resource.TestCheckResourceAttr("alks_ltk.foo", "tags.foo", "bar"), + resource.TestCheckResourceAttr("alks_ltk.foo", "tags.cloud", "railway"), + ), + }, + }, + }) +} + +func TestAlksLTKCreateWithTagsEmptyList(t *testing.T) { + var resp alks.CreateIamUserResponse + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAlksLtkDestroy(&resp), + Steps: []resource.TestStep{ + // Create the resource + { + Config: testAlksLTKCreateWithTagsEmptyListConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("alks_ltk.foo", "iam_username", "TEST_LTK_USER"), + resource.TestCheckResourceAttr("alks_ltk.foo", "tags_all.%", "0"), + ), + }, + }, + }) +} + +func TestAccAlksLTKCreate_DefaultTags(t *testing.T) { + var resp alks.CreateIamUserResponse + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAlksLtkDestroy(&resp), + Steps: []resource.TestStep{ + { + // create resource with tags + Config: testAccCheckAlksLtkCreateWithDefaultTags, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags.cloud", "railway"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.cloud", "railway"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.defaultTagKey1", "defaultTagValue1"), + ), + }, + }, + }) +} + +func TestAccAlksLTKUpdate_DefaultTags(t *testing.T) { + var resp alks.CreateIamUserResponse + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAlksLtkDestroy(&resp), + Steps: []resource.TestStep{ { - Config: testAlksLTKUpdateConfig, - Check: resource.ComposeTestCheckFunc(resource.TestCheckResourceAttr("alks_ltk.foo", "iam_username", "TEST_LTK_USER_2")), + // create resource with tags + Config: testAccCheckAlksLtkCreateWithDefaultTags, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags.cloud", "railway"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.cloud", "railway"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.defaultTagKey1", "defaultTagValue1"), + ), + }, + { + // update resource with new tags + Config: testAccCheckAlksLtkUpdateWithDefaultTags, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags.cloud2", "railway2"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.cloud2", "railway2"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.%", "1"), + ), }, }, }) } -func testAlksLtkDestroy(ltk *alks.CreateLongTermKeyResponse) resource.TestCheckFunc { +func TestAccAlksLTK_IgnoreTags(t *testing.T) { + var resp alks.CreateIamUserResponse + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAlksLtkDestroy(&resp), + Steps: []resource.TestStep{ + { + // create resource with tags + Config: testAccCheckAlksLtkCreateWithDefaultTags, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags.cloud", "railway"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.cloud", "railway"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.defaultTagKey1", "defaultTagValue1"), + ), + }, + { + //Add tags externally. These should not trigger an update because they are excluded by ignore_tags + PreConfig: func() { + client := testAccProvider.Meta().(*AlksClient).client + tags := TagMap{ + "defaultTagKey1": "defaultTagValue1", + "cloud": "railway", + "ignorePrefix:testKey1": "testValue1", + "ignoreFullKey": "testValue1", + } + userName := "TEST_LTK_USER" + + tagSlice := tagMapToSlice(tags) + options := alks.IamUserOptions{ + IamUserName: &userName, + Tags: &tagSlice, + } + + if _, err := client.UpdateIamUser(&options); err != nil { + log.Printf("[INFO] Error in UpdateRole from test") + return + } + }, + Config: testAccCheckAlksLtkUpdateWithTagsWithIgnoredTags, + PlanOnly: true, //This PlanOnly ensures there are no changes happening on this step. Any changes will cause the test to error out because of uncompleted plan + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.defaultTagKey1", "defaultTagValue1"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags.cloud", "railway"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.cloud", "railway"), + resource.TestCheckResourceAttr( + "alks_ltk.foo", "tags_all.%", "2"), + ), + }, + }, + }) +} + +func testAlksLtkDestroy(ltk *alks.CreateIamUserResponse) resource.TestCheckFunc { return func(s *terraform.State) error { providerStruct := testAccProvider.Meta().(*AlksClient) client := providerStruct.client @@ -41,9 +198,9 @@ func testAlksLtkDestroy(ltk *alks.CreateLongTermKeyResponse) resource.TestCheckF continue } - resp, err := client.GetLongTermKey(rs.Primary.ID) + resp, err := client.GetIamUser(rs.Primary.ID) if resp != nil { - return fmt.Errorf("long term key still exists: %#v (%v)", resp, err) + return fmt.Errorf("Iam User still exists: %#v (%v)", resp, err) } } @@ -57,8 +214,66 @@ const testAlksLTKCreateConfig = ` } ` -const testAlksLTKUpdateConfig = ` +const testAlksLTKCreateWithTagsConfig = ` resource "alks_ltk" "foo" { - iam_username = "TEST_LTK_USER_2" + iam_username = "TEST_LTK_USER" + tags = { + foo = "bar" + cloud = "railway" + } } ` + +const testAlksLTKCreateWithTagsEmptyListConfig = ` + resource "alks_ltk" "foo" { + iam_username = "TEST_LTK_USER" + tags = {} + } +` + +const testAccCheckAlksLtkCreateWithDefaultTags = ` + provider "alks" { + default_tags { + tags = { + defaultTagKey1 = "defaultTagValue1" + } + } + } + resource "alks_ltk" "foo" { + iam_username = "TEST_LTK_USER" + tags = { + cloud = "railway" + } + } +` + +const testAccCheckAlksLtkUpdateWithDefaultTags = ` + provider "alks" { + } + resource "alks_ltk" "foo" { + iam_username = "TEST_LTK_USER" + tags = { + cloud2 = "railway2" + } + } +` + +const testAccCheckAlksLtkUpdateWithTagsWithIgnoredTags = ` + provider "alks" { + default_tags { + tags = { + defaultTagKey1 = "defaultTagValue1" + } + } + ignore_tags { + keys = ["ignoreFullKey"] + key_prefixes = ["ignorePrefix"] + } + } + resource "alks_ltk" "foo" { + iam_username = "TEST_LTK_USER" + tags = { + cloud = "railway" + } + } +` diff --git a/vendor/github.com/Cox-Automotive/alks-go/iam_ltk.go b/vendor/github.com/Cox-Automotive/alks-go/iam_ltk.go deleted file mode 100644 index 38f146c2..00000000 --- a/vendor/github.com/Cox-Automotive/alks-go/iam_ltk.go +++ /dev/null @@ -1,350 +0,0 @@ -package alks - -import ( - "encoding/json" - "fmt" - "log" - "net/http" - "strings" -) - -// LongTermKey represents a long term key -type LongTermKey struct { - UserName string `json:"userName"` - AccessKeyID string `json:"accessKeyId"` - Status string `json:"status"` - CreateDate string `json:"createDate"` -} - -// GetLongTermKeysResponse is used to represent the list of long term keys -type GetLongTermKeysResponse struct { - BaseResponse - LongTermKeys []LongTermKey `json:"longTermKeys"` -} - -// GetLongTermKeyResponse is used to represent a single long term key. -type GetLongTermKeyResponse struct { - BaseResponse - LongTermKey `json:"longTermKey"` -} - -// BaseLongTermKeyResponse encapsulates shared response fields -type BaseLongTermKeyResponse struct { - Action string `json:"action,omitempty"` - AddedIAMUserToGroup bool `json:"addedIAMUserToGroup,omitempty"` - PartialError bool `json:"partialError,omitempty"` -} - -// CreateLongTermKey represents the response from API -type CreateLongTermKey struct { - IAMUserName string `json:"iamUserName"` - IAMUserArn string `json:"iamUserArn"` - AccessKey string `json:"accessKey"` - SecretKey string `json:"secretKey"` -} - -// LongTermKeyRequest is used to represent the request body to create or delete LTKs -type LongTermKeyRequest struct { - AccountDetails - IamUserName string `json:"iamUserName"` -} - -// CreateLongTermKeyResponse is the response to the CLI client -type CreateLongTermKeyResponse struct { - AccountDetails - BaseResponse - BaseLongTermKeyResponse - CreateLongTermKey -} - -// DeleteLongTermKeyResponse is the response to the CLI client -type DeleteLongTermKeyResponse struct { - AccountDetails - BaseResponse - BaseLongTermKeyResponse -} - -// GetLongTermKeys gets the LTKs for an account -// If no error is returned then you will receive a list of LTKs -func (c *Client) GetLongTermKeys() (*GetLongTermKeysResponse, error) { - log.Printf("[INFO] Getting long term keys") - - accountID, err := c.AccountDetails.GetAccountNumber() - if err != nil { - return nil, fmt.Errorf("Error reading Account value: %s", err) - } - - roleName, err := c.AccountDetails.GetRoleName(false) - if err != nil { - return nil, fmt.Errorf("Error reading Role value: %s", err) - } - - req, err := c.NewRequest(nil, "GET", "/ltks/"+accountID+"/"+roleName) - if err != nil { - return nil, err - } - - resp, err := c.http.Do(req) - if err != nil { - return nil, err - } - - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - keyErr := new(AlksResponseError) - err = decodeBody(resp, &keyErr) - if err != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ParseErrorReqId, reqID, err) - } - - return nil, fmt.Errorf(ParseError, err) - } - - if keyErr.Errors != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ErrorStringFull, reqID, resp.StatusCode, keyErr.Errors) - } - - return nil, fmt.Errorf(ErrorStringNoReqId, resp.StatusCode, keyErr.Errors) - } - - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode) - } - - return nil, fmt.Errorf(ErrorStringOnlyCode, resp.StatusCode) - } - - cr := new(GetLongTermKeysResponse) - err = decodeBody(resp, &cr) - - if err != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf("Error parsing GetLongTermKeysResponse: [%s] %s", reqID, err) - } - - return nil, fmt.Errorf("Error parsing GetLongTermKeysResponse: %s", err) - } - - if cr.RequestFailed() { - return nil, fmt.Errorf("Error getting long term keys: [%s] %s", cr.BaseResponse.RequestID, strings.Join(cr.GetErrors(), ", ")) - } - - return cr, nil -} - -// GetLongTermKey gets a single LTK for an account -// If no error is returned, then you will receive an LTK for the given account. -func (c *Client) GetLongTermKey(iamUsername string) (*GetLongTermKeyResponse, error) { - log.Printf("[INFO] Getting long term key") - - var req *http.Request - var err error - - if c.IsUsingSTSCredentials() { - req, err = c.NewRequest(nil, "GET", "/ltk/search/"+iamUsername) - } else { - accountID, err := c.AccountDetails.GetAccountNumber() - if err != nil { - return nil, fmt.Errorf("error reading Account value: %s", err) - } - - roleName, err := c.AccountDetails.GetRoleName(false) - if err != nil { - return nil, fmt.Errorf("error reading Role value: %s", err) - } - - req, err = c.NewRequest(nil, "GET", "/ltk/"+accountID+"/"+roleName+"/search/"+iamUsername) - } - - if err != nil { - return nil, err - } - - resp, err := c.http.Do(req) - if err != nil { - return nil, err - } - - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - keyErr := new(AlksResponseError) - err = decodeBody(resp, &keyErr) - if err != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ParseErrorReqId, reqID, err) - } - - return nil, fmt.Errorf(ParseError, err) - } - - if keyErr.Errors != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ErrorStringFull, reqID, resp.StatusCode, keyErr.Errors) - } - - return nil, fmt.Errorf(ErrorStringNoReqId, resp.StatusCode, keyErr.Errors) - } - - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode) - } - - return nil, fmt.Errorf(ErrorStringOnlyCode, resp.StatusCode) - } - - cr := new(GetLongTermKeyResponse) - err = decodeBody(resp, &cr) - - if err != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf("error parsing GetLongTermKeyResponse: [%s] %s", reqID, err) - } - } - - if cr.RequestFailed() { - return nil, fmt.Errorf("error getting long term keys: [%s] %s", cr.BaseResponse.RequestID, strings.Join(cr.GetErrors(), ", ")) - } - - return cr, nil -} - -// CreateLongTermKey creates an LTK user for an account. -// If no error is returned, then you will receive an appropriate success message. -func (c *Client) CreateLongTermKey(iamUsername string) (*CreateLongTermKeyResponse, error) { - log.Printf("[INFO] Creating long term key: %s", iamUsername) - - request := LongTermKeyRequest{ - AccountDetails: c.AccountDetails, - IamUserName: iamUsername, - } - - reqBody, err := json.Marshal(request) - - if err != nil { - return nil, fmt.Errorf("error encoding LTK create JSON: %s", err) - } - - req, err := c.NewRequest(reqBody, "POST", "/accessKeys") - if err != nil { - return nil, err - } - - resp, err := c.http.Do(req) - if err != nil { - return nil, err - } - - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - keyErr := new(AlksResponseError) - err = decodeBody(resp, &keyErr) - if err != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ParseErrorReqId, reqID, err) - } - - return nil, fmt.Errorf(ParseError, err) - } - - if keyErr.Errors != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ErrorStringFull, reqID, resp.StatusCode, keyErr.Errors) - } - - return nil, fmt.Errorf(ErrorStringNoReqId, resp.StatusCode, keyErr.Errors) - } - - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode) - } - - return nil, fmt.Errorf(ErrorStringOnlyCode, resp.StatusCode) - } - - cr := new(CreateLongTermKeyResponse) - err = decodeBody(resp, &cr) - - if err != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf("error parsing CreateLongTermKeyResponse: [%s] %s", reqID, err) - } - - return nil, fmt.Errorf("error parsing CreateLongTermKeyResponse: %s", err) - } - - if cr.RequestFailed() { - return nil, fmt.Errorf("error creating long term key: [%s] %s", cr.BaseResponse.RequestID, strings.Join(cr.GetErrors(), ", ")) - } - - return cr, nil -} - -// DeleteLongTermKey deletes an LTK user for an account. -// If no error is returned, then you will receive an appropriate success message. -func (c *Client) DeleteLongTermKey(iamUsername string) (*DeleteLongTermKeyResponse, error) { - log.Printf("[INFO] Deleting long term key: %s", iamUsername) - - request := LongTermKeyRequest{ - AccountDetails: c.AccountDetails, - IamUserName: iamUsername, - } - - reqBody, err := json.Marshal(request) - - if err != nil { - return nil, fmt.Errorf("error encoding LTK delete JSON: %s", err) - } - - req, err := c.NewRequest(reqBody, "DELETE", "/IAMUser") - if err != nil { - return nil, err - } - - resp, err := c.http.Do(req) - if err != nil { - return nil, err - } - - if resp.StatusCode < 200 || resp.StatusCode >= 300 { - keyErr := new(AlksResponseError) - err = decodeBody(resp, &keyErr) - if err != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ParseErrorReqId, reqID, err) - } - - return nil, fmt.Errorf(ParseError, err) - } - - if keyErr.Errors != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ErrorStringFull, reqID, resp.StatusCode, keyErr.Errors) - } - - return nil, fmt.Errorf(ErrorStringNoReqId, resp.StatusCode, keyErr.Errors) - } - - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode) - } - - return nil, fmt.Errorf(ErrorStringOnlyCode, resp.StatusCode) - } - - cr := new(DeleteLongTermKeyResponse) - err = decodeBody(resp, &cr) - - if err != nil { - if reqID := GetRequestID(resp); reqID != "" { - return nil, fmt.Errorf("error parsing DeleteLongTermKeyResponse: [%s] %s", reqID, err) - } - - return nil, fmt.Errorf("error parsing DeleteLongTermKeyResponse: %s", err) - } - - if cr.RequestFailed() { - return nil, fmt.Errorf("error deleting long term key: [%s] %s", cr.BaseResponse.RequestID, strings.Join(cr.GetErrors(), ", ")) - } - - return cr, nil - -} diff --git a/vendor/github.com/Cox-Automotive/alks-go/iam_role.go b/vendor/github.com/Cox-Automotive/alks-go/iam_role.go index 7efe3dbe..1585193c 100644 --- a/vendor/github.com/Cox-Automotive/alks-go/iam_role.go +++ b/vendor/github.com/Cox-Automotive/alks-go/iam_role.go @@ -380,7 +380,9 @@ type UpdateIamRoleResponse struct { func (c *Client) UpdateIamRole(options *UpdateIamRoleRequest) (*UpdateIamRoleResponse, *AlksError) { if err := options.updateIamRoleValidate(); err != nil { return nil, &AlksError{ - Err: err, + StatusCode: 0, + RequestId: "", + Err: err, } } log.Printf("[INFO] update IAM role %s with Tags: %v", *options.RoleName, *options.Tags) diff --git a/vendor/github.com/Cox-Automotive/alks-go/iam_user.go b/vendor/github.com/Cox-Automotive/alks-go/iam_user.go new file mode 100644 index 00000000..79e00c2d --- /dev/null +++ b/vendor/github.com/Cox-Automotive/alks-go/iam_user.go @@ -0,0 +1,558 @@ +package alks + +import ( + "encoding/json" + "fmt" + "log" + + // "net/http" + "strings" +) + +//Represents iamUser returned by iam-user endpoint +type IamUser struct { + ARN string `json:"arn"` + AccountId string `json:"accountId"` + UserName string `json:"userName"` + AccessKey string `json:"accessKey"` + Tags []Tag `json:"tags"` +} + +// AllIamUsersResponseType represents iamUser returned by ltks endpoint +type AllIamUsersResponseType struct { + UserName string `json:"userName"` + AccessKeyID string `json:"accessKeyId"` + Status string `json:"status"` + CreateDate string `json:"createDate"` +} + +// GetIamUsersResponse is used to represent the list of long term keys +type GetIamUsersResponse struct { + BaseResponse + IamUsers []AllIamUsersResponseType `json:"longTermKeys"` +} + +// GetIamUserResponse is used to represent a single long term key. +type GetIamUserResponse struct { + BaseResponse + User IamUser `json:"item"` +} + +// BaseIamUserResponse encapsulates shared response fields +type BaseIamUserResponse struct { + Action string `json:"action,omitempty"` + AddedIAMUserToGroup bool `json:"addedIAMUserToGroup,omitempty"` + PartialError bool `json:"partialError,omitempty"` +} + +// CreateIamUserApiResponse represents the response from API +type CreateIamUserApiResponse struct { + IAMUserName string `json:"iamUserName"` + IAMUserArn string `json:"iamUserArn"` + AccessKey string `json:"accessKey"` + SecretKey string `json:"secretKey"` +} + +type CreateIamUserRequest struct { + AccountDetails + IamUserName string `json:"iamUserName"` + Tags []Tag `json:"tags,omitempty"` +} + +// CreateIamUserResponse is the response to the CLI client +type CreateIamUserResponse struct { + AccountDetails + BaseResponse + BaseIamUserResponse + CreateIamUserApiResponse +} + +//Used as options for create and update iamUser +type IamUserOptions struct { + IamUserName *string + Tags *[]Tag +} + +// DeleteIamUserRequest is used to represent the request body to delete LTKs +type DeleteIamUserRequest struct { + AccountDetails + IamUserName string `json:"iamUserName"` +} + +type DeleteIamUserResponse struct { + AccountDetails + BaseResponse + BaseIamUserResponse +} + +type UpdateIamUserRequest struct { + User struct { + Tags []Tag `json:"tags"` + } `json:"user"` +} + +type UpdateIamUserResponse struct { + BaseResponse + User IamUser `json:"item"` +} + +// GetIamUsers gets the LTKs for an account +// If no error is returned then you will receive a list of LTKs +func (c *Client) GetIamUsers() (*GetIamUsersResponse, *AlksError) { + log.Printf("[INFO] Getting long term keys") + + accountID, err := c.AccountDetails.GetAccountNumber() + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: fmt.Errorf("Error reading Account value: %s", err), + } + } + + roleName, err := c.AccountDetails.GetRoleName(false) + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: fmt.Errorf("Error reading Role value: %s", err), + } + } + + req, err := c.NewRequest(nil, "GET", "/ltks/"+accountID+"/"+roleName) + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + + resp, err := c.http.Do(req) + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + + reqID := GetRequestID(resp) + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + keyErr := new(AlksResponseError) + err = decodeBody(resp, &keyErr) + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ParseErrorReqId, reqID, err), + } + } + + if keyErr.Errors != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringFull, reqID, resp.StatusCode, strings.Join(keyErr.Errors, ", ")), + } + } + + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode), + } + } + + cr := new(GetIamUsersResponse) + err = decodeBody(resp, &cr) + + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf("Error parsing GetLongTermKeysResponse: [%s] %s", reqID, err), + } + } + + return cr, nil +} + +// GetIamUser gets a single LTK for an account +// If no error is returned, then you will receive an LTK for the given account. +func (c *Client) GetIamUser(iamUsername string) (*GetIamUserResponse, *AlksError) { + log.Printf("[INFO] Getting long term key") + + accountID, err := c.AccountDetails.GetAccountNumber() + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: fmt.Errorf("Error reading Account value: %s", err), + } + } + + req, err := c.NewRequest(nil, "GET", "/iam-users/id/"+accountID+"/"+iamUsername) + + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: fmt.Errorf("Error creating request object: %s", err), + } + } + + resp, err := c.http.Do(req) + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: fmt.Errorf("Error during request: %s", err), + } + } + + reqID := GetRequestID(resp) + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + keyErr := new(AlksResponseError) + err = decodeBody(resp, &keyErr) + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ParseErrorReqId, reqID, err), + } + } + + if keyErr.Errors != nil { + if reqID := GetRequestID(resp); reqID != "" { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringFull, reqID, resp.StatusCode, keyErr.Errors), + } + } + } + + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode), + } + } + + cr := new(GetIamUserResponse) + err = decodeBody(resp, &cr) + + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf("error parsing GetLongTermKeyResponse: [%s] %s", reqID, err), + } + } + + return cr, nil +} + +func NewCreateIamUserRequest(options *IamUserOptions) (*CreateIamUserRequest, error) { + if options.IamUserName == nil { + return nil, fmt.Errorf("IamUserName option must not be nil") + } + + iamUser := &CreateIamUserRequest{} + iamUser.IamUserName = *options.IamUserName + + if options.Tags != nil { + iamUser.Tags = *options.Tags + } else { + iamUser.Tags = nil + } + + return iamUser, nil +} + +// CreateIamUser creates an iamUser and secret key for an account. +// If no error is returned, then you will receive an appropriate success message. +func (c *Client) CreateIamUser(options *IamUserOptions) (*CreateIamUserResponse, *AlksError) { + request, err := NewCreateIamUserRequest(options) + + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + log.Printf("[INFO] Creating long term key: %s", *options.IamUserName) + + request.AccountDetails = c.AccountDetails + + log.Printf("[INFO] The request body is %v", *request) + + b, err := json.Marshal(struct { + CreateIamUserRequest + }{*request}) + + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: fmt.Errorf("error encoding LTK create JSON: %s", err), + } + } + + log.Printf("[INFO] Request Body: %v", string(b)) + + req, err := c.NewRequest(b, "POST", "/accessKeys") + + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + + resp, err := c.http.Do(req) + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + + reqID := GetRequestID(resp) + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + keyErr := new(AlksResponseError) + err = decodeBody(resp, &keyErr) + + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ParseErrorReqId, reqID, err), + } + } + + if keyErr.Errors != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringFull, reqID, resp.StatusCode, keyErr.Errors), + } + } + + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode), + } + } + + cr := new(CreateIamUserResponse) + err = decodeBody(resp, &cr) + + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf("error parsing CreateLongTermKeyResponse: [%s] %s", reqID, err), + } + } + return cr, nil +} + +// DeleteIamUser deletes an LTK user for an account. +// If no error is returned, then you will receive an appropriate success message. +func (c *Client) DeleteIamUser(iamUsername string) (*DeleteIamUserResponse, *AlksError) { + log.Printf("[INFO] Deleting long term key: %s", iamUsername) + + request := DeleteIamUserRequest{ + AccountDetails: c.AccountDetails, + IamUserName: iamUsername, + } + + reqBody, err := json.Marshal(request) + + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: fmt.Errorf("error encoding iamUser delete JSON: %s", err), + } + } + + req, err := c.NewRequest(reqBody, "DELETE", "/IAMUser") + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + + resp, err := c.http.Do(req) + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + + reqID := GetRequestID(resp) + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + keyErr := new(AlksResponseError) + err = decodeBody(resp, &keyErr) + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ParseErrorReqId, reqID, err), + } + } + + if keyErr.Errors != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringNoReqId, resp.StatusCode, keyErr.Errors), + } + } + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode), + } + } + + cr := new(DeleteIamUserResponse) + err = decodeBody(resp, &cr) + + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf("error parsing DeleteLongTermKeyResponse: [%s] %s", reqID, err), + } + } + return cr, nil +} + +func NewUpdateIamUserRequest(options *IamUserOptions) (*UpdateIamUserRequest, error) { + if options.IamUserName == nil { + return nil, fmt.Errorf("IamUserName option must not be nil") + } else if *options.IamUserName == "" { + return nil, fmt.Errorf("IamUserName must contain a value") + } + + iamUser := &UpdateIamUserRequest{} + + if options.Tags != nil { + iamUser.User.Tags = *options.Tags + } else { + return nil, fmt.Errorf("Tags must not be nil on update request, include empty list to remove all non-protected tags") + } + + return iamUser, nil +} + +func (c *Client) UpdateIamUser(options *IamUserOptions) (*UpdateIamUserResponse, *AlksError) { + request, err := NewUpdateIamUserRequest(options) + + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + + log.Printf("[INFO] update IamUser %s with Tags: %v", *options.IamUserName, *options.Tags) + + accountID, err := c.AccountDetails.GetAccountNumber() + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: fmt.Errorf("Error reading Account value: %s", err), + } + } + + b, err := json.Marshal(struct { + UpdateIamUserRequest + }{*request}) + + log.Printf("[INFO] Request Body %v:\n", string(b)) + + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + req, err := c.NewRequest(b, "PATCH", "/iam-users/id/"+accountID+"/"+*options.IamUserName) + + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + resp, err := c.http.Do(req) + if err != nil { + return nil, &AlksError{ + StatusCode: 0, + RequestId: "", + Err: err, + } + } + + reqID := GetRequestID(resp) + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + updateErr := new(AlksResponseError) + err = decodeBody(resp, &updateErr) + + if err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ParseErrorReqId, reqID, err), + } + } + + if updateErr.Errors != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringNoReqId, resp.StatusCode, updateErr.Errors), + } + } + + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf(ErrorStringOnlyCodeAndReqId, reqID, resp.StatusCode), + } + + } + + respObj := &UpdateIamUserResponse{} + if err = decodeBody(resp, respObj); err != nil { + return nil, &AlksError{ + StatusCode: resp.StatusCode, + RequestId: reqID, + Err: fmt.Errorf("error parsing update ltk response: %s", err), + } + } + + return respObj, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 8b793da8..568b3d13 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/Cox-Automotive/alks-go v0.0.0-20221010204605-136b6e9b6530 +# github.com/Cox-Automotive/alks-go v0.0.0-20221019181202-84b27abafb6b ## explicit; go 1.16 github.com/Cox-Automotive/alks-go # github.com/agext/levenshtein v1.2.2