Skip to content

Commit

Permalink
feat: add new data source for marking ext identities (#1853)
Browse files Browse the repository at this point in the history
  • Loading branch information
roope-kar authored Sep 30, 2024
1 parent cf8ce32 commit 4307b4f
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ nav_order: 1
- Remove `aiven_valkey` from beta resources
- Remove `aiven_valkey_user` from beta resources
- Adds`aiven_organization_permission` example
- Add capability to map external service user with internal aiven user with external_identity data source

## [4.25.0] - 2024-09-17

Expand Down
23 changes: 23 additions & 0 deletions docs/data-sources/external_identity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "aiven_external_identity Data Source - terraform-provider-aiven"
subcategory: ""
description: |-
Maps an external service user to an Aiven user.
---

# aiven_external_identity (Data Source)

Maps an external service user to an Aiven user.



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `external_service_name` (String) The name of the external service. The possible values are `github`.
- `external_user_id` (String) The user's ID on the external service.
- `internal_user_id` (String) The Aiven user ID.
- `organization_id` (String) The ID of the Aiven organization that the user is part of.
5 changes: 4 additions & 1 deletion internal/plugin/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/aiven/terraform-provider-aiven/internal/common"
"github.com/aiven/terraform-provider-aiven/internal/plugin/errmsg"
"github.com/aiven/terraform-provider-aiven/internal/plugin/service/externalidentity"
"github.com/aiven/terraform-provider-aiven/internal/plugin/service/organization"
"github.com/aiven/terraform-provider-aiven/internal/plugin/util"
)
Expand Down Expand Up @@ -138,7 +139,9 @@ func (p *AivenProvider) DataSources(context.Context) []func() datasource.DataSou

// Add to a list of data sources that are currently in beta.
if util.IsBeta() {
var betaDataSources []func() datasource.DataSource
betaDataSources := []func() datasource.DataSource{
externalidentity.NewExternalIdentityDataSource,
}
dataSources = append(dataSources, betaDataSources...)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package externalidentity

import (
"context"
"fmt"

"github.com/aiven/aiven-go-client/v2"
"github.com/aiven/terraform-provider-aiven/internal/schemautil/userconfig"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"

"github.com/aiven/terraform-provider-aiven/internal/plugin/util"
)

var (
_ datasource.DataSource = &externalIdentityDataSource{}
_ datasource.DataSourceWithConfigure = &externalIdentityDataSource{}
_ util.TypeNameable = &externalIdentityDataSource{}
)

func NewExternalIdentityDataSource() datasource.DataSource {
return &externalIdentityDataSource{}
}

type externalIdentityDataSource struct {
client *aiven.Client
typeName string
}

// externalIdentityDataSourceModel is the model for the external_identity data source.
type externalIdentityDataSourceModel struct {
OrganizationID types.String `tfsdk:"organization_id"`
InternalUserID types.String `tfsdk:"internal_user_id"`
ExternalUserID types.String `tfsdk:"external_user_id"`
ExternalServiceName types.String `tfsdk:"external_service_name"`
}

// Metadata returns the metadata for the external_identity data source.
func (r *externalIdentityDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_external_identity"
r.typeName = resp.TypeName
}

// TypeName returns the data source type name for the external_identity data source.
func (r *externalIdentityDataSource) TypeName() string {
return r.typeName
}

// Schema defines the schema for the external_identity data source.
func (r *externalIdentityDataSource) Schema(
_ context.Context,
_ datasource.SchemaRequest,
resp *datasource.SchemaResponse,
) {
resp.Schema = schema.Schema{
Description: "Maps an external service user to an Aiven user.",
Attributes: map[string]schema.Attribute{
"organization_id": schema.StringAttribute{
Description: "The ID of the Aiven organization that the user is part of.",
Required: true,
},
"internal_user_id": schema.StringAttribute{
Description: "The Aiven user ID.",
Required: true,
},
"external_user_id": schema.StringAttribute{
Description: "The user's ID on the external service.",
Required: true,
},
"external_service_name": schema.StringAttribute{
Description: userconfig.Desc("The name of the external service.").PossibleValuesString("github").Build(),
Required: true,
},
},
}
}

// Configure sets up the external_identity data source.
func (r *externalIdentityDataSource) Configure(
_ context.Context,
req datasource.ConfigureRequest,
resp *datasource.ConfigureResponse,
) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*aiven.Client)
if !ok {
resp.Diagnostics = util.DiagErrorUnexpectedProviderDataType(resp.Diagnostics, req.ProviderData)

return
}

r.client = client
}

// Read reads an external_identity data source.
func (r *externalIdentityDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var state externalIdentityDataSourceModel

if !util.ConfigToModel(ctx, &req.Config, &state, &resp.Diagnostics) {
return
}

organizationID := state.OrganizationID.ValueString()
internalUserID := state.InternalUserID.ValueString()
externalUserID := state.ExternalUserID.ValueString()
externalServiceName := state.ExternalServiceName.ValueString()

responseData, err := r.client.OrganizationUser.List(ctx, organizationID)
if err != nil {
resp.Diagnostics = util.DiagErrorReadingDataSource(resp.Diagnostics, r, err)
return
}

var user *aiven.OrganizationMemberInfo
for _, member := range responseData.Users {
if member.UserID == internalUserID {
user = &member
break
}
}

if user == nil {
err := fmt.Errorf("organization user %s not found in organization %s", internalUserID, organizationID)
resp.Diagnostics = util.DiagErrorReadingDataSource(resp.Diagnostics, r, err)
return
}

state.OrganizationID = types.StringValue(organizationID)
state.InternalUserID = types.StringValue(internalUserID)
state.ExternalUserID = types.StringValue(externalUserID)
state.ExternalServiceName = types.StringValue(externalServiceName)

util.ModelToPlanState(ctx, state, &resp.State, &resp.Diagnostics)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package externalidentity_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"

acc "github.com/aiven/terraform-provider-aiven/internal/acctest"
)

// TestExternalIdentityDataSource tests the external_identity datasource.
func TestExternalIdentityDataSource(t *testing.T) {
deps := acc.CommonTestDependencies(t)

_ = deps.IsBeta(true)

organizationName := deps.OrganizationName()
userID := deps.OrganizationUserID(true)
prefix := acc.DefaultResourceNamePrefix
suffix := acctest.RandStringFromCharSet(acc.DefaultRandomSuffixLength, acctest.CharSetAlphaNum)
userGroupName := fmt.Sprintf("%s-usr-group-%s", prefix, suffix)
resourceName := "data.aiven_external_identity.foo"
externalUserID := "alice"

resource.ParallelTest(t, resource.TestCase{
ProtoV6ProviderFactories: acc.TestProtoV6ProviderFactories,
PreCheck: func() { acc.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testExternalIdentityDataSourceBasic(organizationName, userGroupName, *userID, externalUserID),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "external_user_id", "alice"),
resource.TestCheckResourceAttr(resourceName, "internal_user_id", *userID),
),
},
},
})
}

func testExternalIdentityDataSourceBasic(organizationName string, userGroupName string, userID string, externalUserID string) string {
return fmt.Sprintf(`
data "aiven_organization" "foo" {
name = "%s"
}
resource "aiven_organization_user_group" "foo" {
organization_id = data.aiven_organization.foo.id
name = "%s"
description = "Terraform acceptance tests"
}
resource "aiven_organization_user_group_member" "foo" {
organization_id = data.aiven_organization.foo.id
group_id = aiven_organization_user_group.foo.group_id
user_id = "%s"
}
data "aiven_external_identity" "foo" {
organization_id = data.aiven_organization.foo.id
internal_user_id = "%[3]s"
external_user_id = "%s"
external_service_name = "github"
}
`, organizationName, userGroupName, userID, externalUserID)
}

0 comments on commit 4307b4f

Please sign in to comment.