-
Notifications
You must be signed in to change notification settings - Fork 10k
f-aws-workmail-domain, f-aws-workmail-default-domain #46931
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c0791ea
ae04327
a659a4e
a49efa5
7d1a22a
e4cbf39
510b6e5
1c65df4
2c67370
db68fdf
950b0d1
d05c802
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| ```release-note:new-resource | ||
| aws_workmail_domain | ||
| ``` | ||
|
|
||
| ```release-note:new-resource | ||
| aws_workmail_default_domain | ||
| ``` | ||
|
|
||
| ```release-note:new-list-resource | ||
| aws_workmail_domain | ||
| ``` |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,183 @@ | ||||||||
| // Copyright IBM Corp. 2014, 2026 | ||||||||
| // SPDX-License-Identifier: MPL-2.0 | ||||||||
|
|
||||||||
| package workmail | ||||||||
|
|
||||||||
| import ( | ||||||||
| "context" | ||||||||
| "fmt" | ||||||||
|
|
||||||||
| "github.com/YakDriver/smarterr" | ||||||||
| "github.com/aws/aws-sdk-go-v2/aws" | ||||||||
| "github.com/aws/aws-sdk-go-v2/service/workmail" | ||||||||
| awstypes "github.com/aws/aws-sdk-go-v2/service/workmail/types" | ||||||||
| "github.com/hashicorp/terraform-plugin-framework/diag" | ||||||||
| "github.com/hashicorp/terraform-plugin-framework/path" | ||||||||
| "github.com/hashicorp/terraform-plugin-framework/resource" | ||||||||
| "github.com/hashicorp/terraform-plugin-framework/resource/schema" | ||||||||
| "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" | ||||||||
| "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" | ||||||||
| "github.com/hashicorp/terraform-plugin-framework/types" | ||||||||
| "github.com/hashicorp/terraform-provider-aws/internal/errs" | ||||||||
| "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" | ||||||||
| intflex "github.com/hashicorp/terraform-provider-aws/internal/flex" | ||||||||
| "github.com/hashicorp/terraform-provider-aws/internal/framework" | ||||||||
| "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" | ||||||||
| "github.com/hashicorp/terraform-provider-aws/internal/retry" | ||||||||
| "github.com/hashicorp/terraform-provider-aws/internal/smerr" | ||||||||
| "github.com/hashicorp/terraform-provider-aws/names" | ||||||||
| ) | ||||||||
|
|
||||||||
| // @FrameworkResource("aws_workmail_default_domain", name="Default Domain") | ||||||||
| func newDefaultDomainResource(_ context.Context) (resource.ResourceWithConfigure, error) { | ||||||||
| r := &defaultDomainResource{} | ||||||||
|
|
||||||||
| return r, nil | ||||||||
| } | ||||||||
|
|
||||||||
| const ( | ||||||||
| ResNameDefaultDomain = "Default Domain" | ||||||||
| ) | ||||||||
|
|
||||||||
| type defaultDomainResource struct { | ||||||||
| framework.ResourceWithModel[defaultDomainResourceModel] | ||||||||
| framework.WithNoOpDelete | ||||||||
| } | ||||||||
|
|
||||||||
| func (r *defaultDomainResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { | ||||||||
| resp.Schema = schema.Schema{ | ||||||||
| Attributes: map[string]schema.Attribute{ | ||||||||
| names.AttrDomainName: schema.StringAttribute{ | ||||||||
| Required: true, | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| }, | ||||||||
| "organization_id": schema.StringAttribute{ | ||||||||
| Required: true, | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| PlanModifiers: []planmodifier.String{ | ||||||||
| stringplanmodifier.RequiresReplace(), | ||||||||
| }, | ||||||||
| }, | ||||||||
| }, | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| func (r *defaultDomainResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { | ||||||||
| conn := r.Meta().WorkMailClient(ctx) | ||||||||
|
|
||||||||
| var plan defaultDomainResourceModel | ||||||||
| smerr.AddEnrich(ctx, &resp.Diagnostics, req.Plan.Get(ctx, &plan)) | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very nice! Use of smarterr |
||||||||
| if resp.Diagnostics.HasError() { | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| smerr.AddEnrich(ctx, &resp.Diagnostics, r.putDefaultMailDomain(ctx, conn, &plan)) | ||||||||
| if resp.Diagnostics.HasError() { | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| smerr.AddEnrich(ctx, &resp.Diagnostics, resp.State.Set(ctx, plan)) | ||||||||
| } | ||||||||
|
|
||||||||
| func (r *defaultDomainResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { | ||||||||
| conn := r.Meta().WorkMailClient(ctx) | ||||||||
|
|
||||||||
| var state defaultDomainResourceModel | ||||||||
| smerr.AddEnrich(ctx, &resp.Diagnostics, req.State.Get(ctx, &state)) | ||||||||
| if resp.Diagnostics.HasError() { | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| domainName, err := findDefaultDomainByOrgID(ctx, conn, state.OrganizationId.ValueString()) | ||||||||
| if retry.NotFound(err) { | ||||||||
| resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) | ||||||||
| resp.State.RemoveResource(ctx) | ||||||||
| return | ||||||||
| } | ||||||||
| if err != nil { | ||||||||
| smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, state.DomainName.String()) | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| state.DomainName = flex.StringValueToFramework(ctx, domainName) | ||||||||
|
|
||||||||
| smerr.AddEnrich(ctx, &resp.Diagnostics, resp.State.Set(ctx, &state)) | ||||||||
| } | ||||||||
|
|
||||||||
| func (r *defaultDomainResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { | ||||||||
| conn := r.Meta().WorkMailClient(ctx) | ||||||||
|
|
||||||||
| var plan defaultDomainResourceModel | ||||||||
| smerr.AddEnrich(ctx, &resp.Diagnostics, req.Plan.Get(ctx, &plan)) | ||||||||
| if resp.Diagnostics.HasError() { | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| smerr.AddEnrich(ctx, &resp.Diagnostics, r.putDefaultMailDomain(ctx, conn, &plan)) | ||||||||
| if resp.Diagnostics.HasError() { | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| smerr.AddEnrich(ctx, &resp.Diagnostics, resp.State.Set(ctx, plan)) | ||||||||
| } | ||||||||
|
|
||||||||
| func (r *defaultDomainResource) putDefaultMailDomain(ctx context.Context, conn *workmail.Client, plan *defaultDomainResourceModel) diag.Diagnostics { | ||||||||
| var diags diag.Diagnostics | ||||||||
|
|
||||||||
| var input workmail.UpdateDefaultMailDomainInput | ||||||||
| smerr.AddEnrich(ctx, &diags, flex.Expand(ctx, plan, &input)) | ||||||||
| if diags.HasError() { | ||||||||
| return diags | ||||||||
| } | ||||||||
|
|
||||||||
| _, err := conn.UpdateDefaultMailDomain(ctx, &input) | ||||||||
| if err != nil { | ||||||||
| smerr.AddError(ctx, &diags, err, smerr.ID, plan.DomainName.String()) | ||||||||
| } | ||||||||
|
|
||||||||
| return diags | ||||||||
| } | ||||||||
|
|
||||||||
| func (r *defaultDomainResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't need this with import by identity, similar to how you do with domain. |
||||||||
| parts, err := intflex.ExpandResourceId(req.ID, domainIDParts, false) | ||||||||
| if err != nil { | ||||||||
| resp.Diagnostics.Append(fwdiag.NewParsingResourceIDErrorDiagnostic(err)) | ||||||||
| return | ||||||||
| } | ||||||||
|
|
||||||||
| resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("organization_id"), parts[0])...) | ||||||||
| resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrDomainName), parts[1])...) | ||||||||
| } | ||||||||
|
|
||||||||
| func findDefaultDomainByOrgID(ctx context.Context, conn *workmail.Client, orgID string) (string, error) { | ||||||||
| input := workmail.ListMailDomainsInput{ | ||||||||
| OrganizationId: aws.String(orgID), | ||||||||
| } | ||||||||
|
|
||||||||
| pages := workmail.NewListMailDomainsPaginator(conn, &input) | ||||||||
| for pages.HasMorePages() { | ||||||||
| page, err := pages.NextPage(ctx) | ||||||||
| if err != nil { | ||||||||
| if errs.IsA[*awstypes.ResourceNotFoundException](err) { | ||||||||
| return "", smarterr.NewError(&retry.NotFoundError{ | ||||||||
| LastError: err, | ||||||||
| }) | ||||||||
| } | ||||||||
| return "", smarterr.NewError(err) | ||||||||
| } | ||||||||
|
|
||||||||
| for _, d := range page.MailDomains { | ||||||||
| if d.DefaultDomain { | ||||||||
| return aws.ToString(d.DomainName), nil | ||||||||
| } | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| return "", smarterr.NewError(&retry.NotFoundError{ | ||||||||
| Message: fmt.Sprintf("no default domain found for WorkMail organization %s", orgID), | ||||||||
| }) | ||||||||
| } | ||||||||
|
|
||||||||
| type defaultDomainResourceModel struct { | ||||||||
| framework.WithRegionModel | ||||||||
| OrganizationId types.String `tfsdk:"organization_id"` | ||||||||
| DomainName types.String `tfsdk:"domain_name"` | ||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| // Copyright IBM Corp. 2014, 2026 | ||
| // SPDX-License-Identifier: MPL-2.0 | ||
|
|
||
| package workmail_test | ||
|
|
||
| import ( | ||
| "context" | ||
| "errors" | ||
| "fmt" | ||
| "testing" | ||
|
|
||
| "github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
| "github.com/hashicorp/terraform-plugin-testing/terraform" | ||
| "github.com/hashicorp/terraform-provider-aws/internal/acctest" | ||
| "github.com/hashicorp/terraform-provider-aws/internal/create" | ||
| tfworkmail "github.com/hashicorp/terraform-provider-aws/internal/service/workmail" | ||
| "github.com/hashicorp/terraform-provider-aws/names" | ||
| ) | ||
|
|
||
| func TestAccWorkMailDefaultDomain_basic(t *testing.T) { | ||
| ctx := acctest.Context(t) | ||
|
|
||
| rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) | ||
| resourceName := "aws_workmail_default_domain.test" | ||
|
|
||
| acctest.ParallelTest(ctx, t, resource.TestCase{ | ||
| PreCheck: func() { | ||
| acctest.PreCheck(ctx, t) | ||
| acctest.PreCheckPartitionHasService(t, names.WorkMail) | ||
| }, | ||
| ErrorCheck: acctest.ErrorCheck(t, names.WorkMailServiceID), | ||
| ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, | ||
| CheckDestroy: acctest.CheckDestroyNoop, | ||
| Steps: []resource.TestStep{ | ||
| { | ||
| Config: testAccDefaultDomainConfig_basic(rName), | ||
| Check: resource.ComposeAggregateTestCheckFunc( | ||
| testAccCheckDefaultDomainExists(ctx, t, resourceName), | ||
| resource.TestCheckResourceAttrPair(resourceName, names.AttrDomainName, "aws_workmail_organization.test", "default_mail_domain"), | ||
| resource.TestCheckResourceAttrSet(resourceName, "organization_id"), | ||
| ), | ||
| }, | ||
| { | ||
| ResourceName: resourceName, | ||
| ImportState: true, | ||
| ImportStateIdFunc: testAccDefaultDomainImportStateIdFunc(resourceName), | ||
| ImportStateVerify: true, | ||
| ImportStateVerifyIdentifierAttribute: "organization_id", | ||
| }, | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| func testAccDefaultDomainImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { | ||
| return func(s *terraform.State) (string, error) { | ||
| rs, ok := s.RootModule().Resources[resourceName] | ||
| if !ok { | ||
| return "", fmt.Errorf("Not found: %s", resourceName) | ||
| } | ||
|
|
||
| return fmt.Sprintf("%s,%s", rs.Primary.Attributes["organization_id"], rs.Primary.Attributes[names.AttrDomainName]), nil | ||
| } | ||
| } | ||
|
|
||
| func testAccCheckDefaultDomainExists(ctx context.Context, t *testing.T, name string) resource.TestCheckFunc { | ||
| return func(s *terraform.State) error { | ||
| rs, ok := s.RootModule().Resources[name] | ||
| if !ok { | ||
| return create.Error(names.WorkMail, create.ErrActionCheckingExistence, tfworkmail.ResNameDefaultDomain, name, errors.New("not found")) | ||
| } | ||
|
|
||
| if rs.Primary.ID == "" { | ||
| return create.Error(names.WorkMail, create.ErrActionCheckingExistence, tfworkmail.ResNameDefaultDomain, name, errors.New("not set")) | ||
| } | ||
|
|
||
| orgID := rs.Primary.Attributes["organization_id"] | ||
|
|
||
| conn := acctest.ProviderMeta(ctx, t).WorkMailClient(ctx) | ||
|
|
||
| _, err := tfworkmail.FindDefaultDomainByOrgID(ctx, conn, orgID) | ||
| if err != nil { | ||
| return create.Error(names.WorkMail, create.ErrActionCheckingExistence, tfworkmail.ResNameDefaultDomain, rs.Primary.ID, err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
| } | ||
|
|
||
| func testAccDefaultDomainConfig_basic(rName string) string { | ||
| return fmt.Sprintf(` | ||
| resource "aws_workmail_organization" "test" { | ||
| organization_alias = %[1]q | ||
| delete_directory = true | ||
| } | ||
|
|
||
| resource "aws_workmail_default_domain" "test" { | ||
| organization_id = aws_workmail_organization.test.organization_id | ||
| domain_name = aws_workmail_organization.test.default_mail_domain | ||
| } | ||
| `, rName) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.