-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: service account OIDC Identity resource (#821)
- Loading branch information
1 parent
e688aa7
commit 39fe8de
Showing
9 changed files
with
418 additions
and
3 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,32 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "octopusdeploy_service_account_oidc_identity Data Source - terraform-provider-octopusdeploy" | ||
subcategory: "" | ||
description: |- | ||
--- | ||
|
||
# octopusdeploy_service_account_oidc_identity (Data Source) | ||
|
||
|
||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `service_account_id` (String) ID of the user associated to this identity | ||
|
||
### Optional | ||
|
||
- `id` (String) The unique ID for this resource. | ||
|
||
### Read-Only | ||
|
||
- `issuer` (String) OIDC issuer url | ||
- `name` (String) Name of the user associated to this identity | ||
- `subject` (String) OIDC subject claims | ||
|
||
|
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,29 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "octopusdeploy_service_account_oidc_identity Resource - terraform-provider-octopusdeploy" | ||
subcategory: "" | ||
description: |- | ||
This resource manages manages OIDC service account for the associated user | ||
--- | ||
|
||
# octopusdeploy_service_account_oidc_identity (Resource) | ||
|
||
This resource manages manages OIDC service account for the associated user | ||
|
||
|
||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `issuer` (String) OIDC issuer url | ||
- `name` (String) The name of this resource. | ||
- `service_account_id` (String) ID of the user to associate this identity to | ||
- `subject` (String) OIDC subject claims | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The unique ID for this resource. | ||
|
||
|
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
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
57 changes: 57 additions & 0 deletions
57
octopusdeploy_framework/datasource_service_account_oidc_identity.go
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,57 @@ | ||
package octopusdeploy_framework | ||
|
||
import ( | ||
"context" | ||
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/serviceaccounts" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util" | ||
"github.com/hashicorp/terraform-plugin-framework/datasource" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
type serviceAccountOIDCIdentityDataSource struct { | ||
*Config | ||
} | ||
|
||
func NewServiceAccountOIDCIdentityDataSource() datasource.DataSource { | ||
return &serviceAccountOIDCIdentityDataSource{} | ||
} | ||
|
||
func (*serviceAccountOIDCIdentityDataSource) Metadata(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { | ||
resp.TypeName = util.GetTypeName(schemas.ServiceAccountOIDCIdentityDatasourceName) | ||
} | ||
|
||
func (s *serviceAccountOIDCIdentityDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { | ||
s.Config = DataSourceConfiguration(req, resp) | ||
} | ||
|
||
func (*serviceAccountOIDCIdentityDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { | ||
resp.Schema = schemas.ServiceAccountOIDCIdentitySchema{}.GetDatasourceSchema() | ||
} | ||
|
||
func (s *serviceAccountOIDCIdentityDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { | ||
var err error | ||
var data schemas.OIDCServiceAccountDatasourceSchemaModel | ||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
oidcIdentity, err := serviceaccounts.GetOIDCIdentityByID(s.Client, data.ServiceAccountID.ValueString(), data.ID.ValueString()) | ||
if err != nil { | ||
resp.Diagnostics.AddError("unable to load service account OIDC Identity", err.Error()) | ||
return | ||
} | ||
|
||
updateServiceAccountOIDCDataModel(oidcIdentity, &data) | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) | ||
} | ||
|
||
func updateServiceAccountOIDCDataModel(request *serviceaccounts.OIDCIdentity, model *schemas.OIDCServiceAccountDatasourceSchemaModel) { | ||
model.Name = types.StringValue(request.Name) | ||
model.Issuer = types.StringValue(request.Issuer) | ||
model.Subject = types.StringValue(request.Subject) | ||
model.ID = types.StringValue(request.ID) | ||
model.ServiceAccountID = types.StringValue(request.ServiceAccountID) | ||
} |
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
127 changes: 127 additions & 0 deletions
127
octopusdeploy_framework/resource_service_account_oidc_identity.go
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,127 @@ | ||
package octopusdeploy_framework | ||
|
||
import ( | ||
"context" | ||
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/serviceaccounts" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas" | ||
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util" | ||
"github.com/hashicorp/terraform-plugin-framework/resource" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
var _ resource.Resource = &ServiceAccountOIDCIdentity{} | ||
|
||
type ServiceAccountOIDCIdentity struct { | ||
*Config | ||
} | ||
|
||
func NewServiceAccountOIDCIdentity() resource.Resource { | ||
return &ServiceAccountOIDCIdentity{} | ||
} | ||
|
||
func (s *ServiceAccountOIDCIdentity) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { | ||
resp.TypeName = util.GetTypeName(schemas.ServiceAccountOIDCIdentityResourceName) | ||
} | ||
|
||
func (s *ServiceAccountOIDCIdentity) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { | ||
resp.Schema = schemas.ServiceAccountOIDCIdentitySchema{}.GetResourceSchema() | ||
} | ||
|
||
func (s *ServiceAccountOIDCIdentity) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { | ||
s.Config = ResourceConfiguration(req, resp) | ||
} | ||
func (s *ServiceAccountOIDCIdentity) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { | ||
var plan schemas.OIDCServiceAccountSchemaModel | ||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
identityRequest := mapServiceAccountOIDCModelToRequest(&plan) | ||
identityCreateResponse, err := serviceaccounts.AddOIDCIdentity(s.Client, identityRequest) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error creating OIDC identity", err.Error()) | ||
return | ||
} | ||
identityResponse, err := serviceaccounts.GetOIDCIdentityByID(s.Client, identityRequest.ServiceAccountID, identityCreateResponse.ID) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error creating OIDC identity", err.Error()) | ||
return | ||
} | ||
|
||
updateServiceAccountOIDCModel(identityResponse, &plan) | ||
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) | ||
} | ||
|
||
func (s *ServiceAccountOIDCIdentity) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { | ||
var state schemas.OIDCServiceAccountSchemaModel | ||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
identityResponse, err := serviceaccounts.GetOIDCIdentityByID(s.Client, state.ServiceAccountID.ValueString(), state.ID.ValueString()) | ||
if err != nil { | ||
if err := errors.ProcessApiErrorV2(ctx, resp, state, err, "service account OIDC identity"); err != nil { | ||
resp.Diagnostics.AddError("Error reading service account OIDC identity", err.Error()) | ||
} | ||
return | ||
} | ||
|
||
updateServiceAccountOIDCModel(identityResponse, &state) | ||
resp.Diagnostics.Append(resp.State.Set(ctx, state)...) | ||
} | ||
|
||
func (s *ServiceAccountOIDCIdentity) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { | ||
var plan schemas.OIDCServiceAccountSchemaModel | ||
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
identityRequest := mapServiceAccountOIDCModelToRequest(&plan) | ||
|
||
err := serviceaccounts.UpdateOIDCIdentity(s.Client, identityRequest) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error updating service account OIDC identity", err.Error()) | ||
return | ||
} | ||
identityResponse, err := serviceaccounts.GetOIDCIdentityByID(s.Client, identityRequest.ServiceAccountID, identityRequest.ID) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error creating OIDC identity", err.Error()) | ||
return | ||
} | ||
|
||
updateServiceAccountOIDCModel(identityResponse, &plan) | ||
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) | ||
} | ||
|
||
func (s *ServiceAccountOIDCIdentity) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { | ||
var state schemas.OIDCServiceAccountSchemaModel | ||
resp.Diagnostics.Append(req.State.Get(ctx, &state)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
err := serviceaccounts.DeleteOIDCIdentityByID(s.Client, state.ServiceAccountID.ValueString(), state.ID.ValueString()) | ||
if err != nil { | ||
resp.Diagnostics.AddError("Error deleting service account OIDC identity", err.Error()) | ||
return | ||
} | ||
} | ||
|
||
func mapServiceAccountOIDCModelToRequest(model *schemas.OIDCServiceAccountSchemaModel) *serviceaccounts.OIDCIdentity { | ||
identity := serviceaccounts.NewOIDCIdentity(model.ServiceAccountID.ValueString(), model.Name.ValueString(), model.Issuer.ValueString(), model.Subject.ValueString()) | ||
identity.ID = model.ID.ValueString() | ||
identity.Name = model.Name.ValueString() | ||
|
||
return identity | ||
} | ||
|
||
func updateServiceAccountOIDCModel(request *serviceaccounts.OIDCIdentity, model *schemas.OIDCServiceAccountSchemaModel) { | ||
model.Name = types.StringValue(request.Name) | ||
model.Issuer = types.StringValue(request.Issuer) | ||
model.Subject = types.StringValue(request.Subject) | ||
model.ID = types.StringValue(request.ID) | ||
model.ServiceAccountID = types.StringValue(request.ServiceAccountID) | ||
} |
87 changes: 87 additions & 0 deletions
87
octopusdeploy_framework/resource_service_account_oidc_identity_test.go
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,87 @@ | ||
package octopusdeploy_framework | ||
|
||
import ( | ||
"fmt" | ||
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/serviceaccounts" | ||
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/users" | ||
"github.com/hashicorp/terraform-plugin-testing/helper/acctest" | ||
"github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
"testing" | ||
) | ||
|
||
func TestAccOctopusDeployServiceAccountOIDCIdentity(t *testing.T) { | ||
localName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha) | ||
prefix := "octopusdeploy_service_account_oidc_identity." + localName | ||
|
||
localUserName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha) | ||
userPrefix := " octopusdeploy_user." + localUserName | ||
|
||
userData := users.User{ | ||
DisplayName: acctest.RandStringFromCharSet(20, acctest.CharSetAlpha), | ||
EmailAddress: acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) + "@test.com", | ||
Username: acctest.RandStringFromCharSet(20, acctest.CharSetAlpha), | ||
} | ||
|
||
data := serviceaccounts.OIDCIdentity{ | ||
Name: acctest.RandStringFromCharSet(20, acctest.CharSetAlpha), | ||
ServiceAccountID: userPrefix + ".id", | ||
Issuer: "https://token.actions.githubusercontent.com", | ||
Subject: "repo:test/test:environment:test", | ||
} | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { TestAccPreCheck(t) }, | ||
ProtoV6ProviderFactories: ProtoV6ProviderFactories(), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testServiceAccountIdentityConfig(localName, localUserName, data, userData), | ||
Check: resource.ComposeTestCheckFunc( | ||
testScriptModuleExists(prefix), | ||
resource.TestCheckResourceAttr(prefix, "name", data.Name), | ||
resource.TestCheckResourceAttr(prefix, "issuer", data.Issuer), | ||
resource.TestCheckResourceAttr(prefix, "subject", data.Subject), | ||
), | ||
}, | ||
{ | ||
Config: testServiceAccountIdentityUpdate(localName, localUserName, data, userData), | ||
Check: resource.ComposeTestCheckFunc( | ||
testScriptModuleExists(prefix), | ||
resource.TestCheckResourceAttr(prefix, "name", data.Name+"-updated"), | ||
resource.TestCheckResourceAttr(prefix, "issuer", data.Issuer), | ||
resource.TestCheckResourceAttr(prefix, "subject", data.Subject), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testServiceAccountIdentityConfig(localName string, localUserName string, data serviceaccounts.OIDCIdentity, userData users.User) string { | ||
return fmt.Sprintf(` | ||
resource "octopusdeploy_user" "%s" { | ||
display_name = "%s" | ||
email_address = "%s" | ||
is_active = true | ||
is_service = true | ||
username = "%s" | ||
} | ||
resource "octopusdeploy_service_account_oidc_identity" "%s" { | ||
name = "%s" | ||
service_account_id = %s | ||
issuer = "%s" | ||
subject = "%s" | ||
}`, | ||
localUserName, | ||
userData.DisplayName, | ||
userData.EmailAddress, | ||
userData.Username, | ||
localName, | ||
data.Name, | ||
data.ServiceAccountID, | ||
data.Issuer, | ||
data.Subject) | ||
} | ||
|
||
func testServiceAccountIdentityUpdate(localName string, localUserName string, data serviceaccounts.OIDCIdentity, userData users.User) string { | ||
data.Name = data.Name + "-updated" | ||
return testServiceAccountIdentityConfig(localName, localUserName, data, userData) | ||
} |
Oops, something went wrong.