generated from hashicorp/terraform-provider-scaffolding
-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1dc1c26
commit 7b3c40b
Showing
7 changed files
with
465 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "hcp_group Data Source - terraform-provider-hcp" | ||
subcategory: "" | ||
description: |- | ||
The group data source retrieves the given group. | ||
--- | ||
|
||
# hcp_group (Data Source) | ||
|
||
The group data source retrieves the given group. | ||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `resource_name` (String) The group's resource name in format `iam/organization/<organization_id>/group/<resource_name>` or shortened `<resource_name>` | ||
|
||
### Read-Only | ||
|
||
- `description` (String) The group's description | ||
- `display_name` (String) The group's display name | ||
- `resource_id` (String) The group's unique identifier |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "hcp_group_members Resource - terraform-provider-hcp" | ||
subcategory: "" | ||
description: |- | ||
The group members resource manages the members of an HCP Group. | ||
The user or service account that is running Terraform when creating a hcp_service_principal resource must have roles/admin on the parent resource; either the project or organization. | ||
--- | ||
|
||
# hcp_group_members (Resource) | ||
|
||
The group members resource manages the members of an HCP Group. | ||
|
||
The user or service account that is running Terraform when creating a `hcp_service_principal` resource must have `roles/admin` on the parent resource; either the project or organization. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "hcp_group_members" "example" { | ||
group = hcp_group.example.id | ||
members = [ | ||
hcp_user_principal.example1.id, | ||
hcp_user_principal.example2.id, | ||
] | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `group` (String) The group's resource name in the format `iam/organization/<organization_id>/group/<name>` | ||
- `members` (List of String) A list of principal IDs to add to the group. | ||
|
||
## Import | ||
|
||
Import is supported using the following syntax: | ||
|
||
```shell | ||
# Group Members can be imported by specifying the group resource name | ||
terraform import hcp_group_members.example "iam/organization/org_id/group/group-name" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Group Members can be imported by specifying the group resource name | ||
terraform import hcp_group_members.example "iam/organization/org_id/group/group-name" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
resource "hcp_group_members" "example" { | ||
group = hcp_group.example.id | ||
members = [ | ||
hcp_user_principal.example1.id, | ||
hcp_user_principal.example2.id, | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package iam | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/hashicorp/hcp-sdk-go/clients/cloud-iam/stable/2019-12-10/client/groups_service" | ||
"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/types" | ||
|
||
"github.com/hashicorp/terraform-provider-hcp/internal/clients" | ||
) | ||
|
||
func NewGroupMembersResource() resource.Resource { | ||
return &resourceGroupMembers{} | ||
} | ||
|
||
type resourceGroupMembers struct { | ||
client *clients.Client | ||
} | ||
|
||
type GroupMembers struct { | ||
Group types.String `tfsdk:"group"` | ||
Members []types.String `tfsdk:"members"` | ||
} | ||
|
||
func (r *resourceGroupMembers) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { | ||
resp.TypeName = req.ProviderTypeName + "_group_members" | ||
} | ||
|
||
func (r *resourceGroupMembers) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { | ||
resp.Schema = schema.Schema{ | ||
MarkdownDescription: fmt.Sprintf(`The group members resource manages the members of an HCP Group. | ||
The user or service account that is running Terraform when creating a %s resource must have %s on the parent resource; either the project or organization.`, | ||
"`hcp_service_principal`", "`roles/admin`"), | ||
Attributes: map[string]schema.Attribute{ | ||
"group": schema.StringAttribute{ | ||
Required: true, | ||
Description: fmt.Sprintf("The group's resource name in the format `%s`", | ||
"iam/organization/<organization_id>/group/<name>"), | ||
}, | ||
"members": schema.ListAttribute{ | ||
ElementType: types.StringType, | ||
Required: true, | ||
Description: "A list of principal IDs to add to the group.", | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func (r *resourceGroupMembers) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { | ||
if req.ProviderData == nil { | ||
return | ||
} | ||
|
||
client, ok := req.ProviderData.(*clients.Client) | ||
if !ok { | ||
resp.Diagnostics.AddError( | ||
"Unexpected Data Source Configure Type", | ||
fmt.Sprintf("Expected *clients.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), | ||
) | ||
return | ||
} | ||
|
||
r.client = client | ||
} | ||
|
||
func (r *resourceGroupMembers) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { | ||
var plan GroupMembers | ||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
listParams := groups_service.NewGroupsServiceListGroupMembersParams().WithContext(ctx) | ||
listParams.SetResourceName(plan.Group.ValueString()) | ||
res, err := r.client.Groups.GroupsServiceListGroupMembers(listParams, nil) | ||
if err != nil { | ||
var listResp *groups_service.GroupsServiceListGroupMembersDefault | ||
if errors.As(err, &listResp) && !listResp.IsCode(http.StatusNotFound) { | ||
resp.Diagnostics.AddError("Failed to list group members", err.Error()) | ||
return | ||
} | ||
} else if len(res.GetPayload().Members) > 0 { | ||
resp.Diagnostics.AddError("Group already has members", "You need to import the resource first.") | ||
return | ||
} | ||
|
||
members := make([]string, len(plan.Members)) | ||
for i, member := range plan.Members { | ||
members[i] = member.ValueString() | ||
} | ||
|
||
updateParams := groups_service.NewGroupsServiceUpdateGroupMembersParams().WithContext(ctx) | ||
updateParams.SetResourceName(plan.Group.ValueString()) | ||
updateParams.SetBody(groups_service.GroupsServiceUpdateGroupMembersBody{ | ||
MemberPrincipalIdsToAdd: members, | ||
}) | ||
|
||
_, err = r.client.Groups.GroupsServiceUpdateGroupMembers(updateParams, nil) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Failed to update group members", err.Error()) | ||
return | ||
} | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) | ||
} | ||
|
||
func (r *resourceGroupMembers) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { | ||
var state GroupMembers | ||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
listParams := groups_service.NewGroupsServiceListGroupMembersParams().WithContext(ctx) | ||
listParams.SetResourceName(state.Group.ValueString()) | ||
res, err := r.client.Groups.GroupsServiceListGroupMembers(listParams, nil) | ||
if err != nil { | ||
var listResp *groups_service.GroupsServiceListGroupMembersDefault | ||
if errors.As(err, &listResp) && listResp.IsCode(http.StatusNotFound) { | ||
resp.State.RemoveResource(ctx) | ||
return | ||
} | ||
|
||
resp.Diagnostics.AddError("Failed to list group members", err.Error()) | ||
return | ||
} | ||
|
||
members := res.GetPayload().Members | ||
|
||
state.Members = make([]types.String, len(members)) | ||
for i, member := range members { | ||
state.Members[i] = types.StringValue(member.ID) | ||
} | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) | ||
} | ||
|
||
func (r *resourceGroupMembers) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { | ||
var plan, state GroupMembers | ||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) | ||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
planMembers := make(map[string]bool) | ||
for _, member := range plan.Members { | ||
planMembers[member.ValueString()] = true | ||
} | ||
|
||
stateMembers := make(map[string]bool) | ||
for _, member := range state.Members { | ||
stateMembers[member.ValueString()] = true | ||
} | ||
|
||
membersToAdd := make([]string, 0, len(plan.Members)) | ||
for _, member := range plan.Members { | ||
memberStr := member.ValueString() | ||
if _, ok := stateMembers[memberStr]; !ok { | ||
membersToAdd = append(membersToAdd, memberStr) | ||
} | ||
} | ||
|
||
membersToRemove := make([]string, 0, len(state.Members)) | ||
for _, member := range state.Members { | ||
memberStr := member.ValueString() | ||
if _, ok := planMembers[memberStr]; !ok { | ||
membersToRemove = append(membersToRemove, memberStr) | ||
} | ||
} | ||
|
||
if len(membersToAdd) > 0 || len(membersToRemove) > 0 { | ||
updateParams := groups_service.NewGroupsServiceUpdateGroupMembersParams().WithContext(ctx) | ||
updateParams.SetResourceName(plan.Group.ValueString()) | ||
updateParams.SetBody(groups_service.GroupsServiceUpdateGroupMembersBody{ | ||
MemberPrincipalIdsToAdd: membersToAdd, | ||
MemberPrincipalIdsToRemove: membersToRemove, | ||
}) | ||
|
||
_, err := r.client.Groups.GroupsServiceUpdateGroupMembers(updateParams, nil) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Failed to update group members", err.Error()) | ||
return | ||
} | ||
} | ||
|
||
// Store the updated values | ||
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) | ||
} | ||
|
||
func (r *resourceGroupMembers) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { | ||
var state GroupMembers | ||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
members := make([]string, len(state.Members)) | ||
for i, member := range state.Members { | ||
members[i] = member.ValueString() | ||
} | ||
|
||
updateParams := groups_service.NewGroupsServiceUpdateGroupMembersParams().WithContext(ctx) | ||
updateParams.SetResourceName(state.Group.ValueString()) | ||
updateParams.SetBody(groups_service.GroupsServiceUpdateGroupMembersBody{ | ||
MemberPrincipalIdsToRemove: members, | ||
}) | ||
|
||
_, err := r.client.Groups.GroupsServiceUpdateGroupMembers(updateParams, nil) | ||
if err != nil { | ||
var errResp *groups_service.GroupsServiceUpdateGroupMembersDefault | ||
if errors.As(err, &errResp) && !errResp.IsCode(http.StatusNotFound) { | ||
resp.Diagnostics.AddError("Failed to update group members", err.Error()) | ||
return | ||
} | ||
} | ||
} | ||
|
||
func (r *resourceGroupMembers) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { | ||
resource.ImportStatePassthroughID(ctx, path.Root("group"), req, resp) | ||
} |
Oops, something went wrong.