Skip to content

Commit

Permalink
feat(aiven_organization_user_list): add datasource
Browse files Browse the repository at this point in the history
  • Loading branch information
byashimov committed Oct 16, 2024
1 parent b61f67c commit 8cd9e1e
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 6 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ nav_order: 1
<!-- Always keep the following header in place: -->
<!-- ## [MAJOR.MINOR.PATCH] - YYYY-MM-DD -->

## [MAJOR.MINOR.PATCH] - YYYY-MM-DD

- Add `aiven_organization_user_list` resource
- Run client-side validation for `aiven_kafka_schema` AVRO type schema

## [4.27.0] - 2024-10-09

- Remove `aiven_thanos` from beta resources
- Removes `receiver_ingesting_remote_write_uri` and `store_uri` Thanos connection info fields
- Adds `stringtype` to `flink_external_postgresql_user_config` service integration
- Fix `terraform import` for services with additional disk space or read replica service integration
- Run client-side validation for `aiven_kafka_schema` AVRO type schema

## [4.26.0] - 2024-09-25

Expand Down
53 changes: 53 additions & 0 deletions docs/data-sources/organization_user_list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "aiven_organization_user_list Data Source - terraform-provider-aiven"
subcategory: ""
description: |-
List of users of the organization
---

# aiven_organization_user_list (Data Source)

List of users of the organization



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

### Required

- `name` (String) Account ID. Example `a`

### Read-Only

- `id` (String) The ID of this resource.
- `users` (List of Object) List of users of the organization (see [below for nested schema](#nestedatt--users))

<a id="nestedatt--users"></a>
### Nested Schema for `users`

Read-Only:

- `is_super_admin` (Boolean)
- `join_time` (String)
- `last_activity_time` (String)
- `user_id` (String)
- `user_info` (List of Object) (see [below for nested schema](#nestedobjatt--users--user_info))

<a id="nestedobjatt--users--user_info"></a>
### Nested Schema for `users.user_info`

Read-Only:

- `city` (String)
- `country` (String)
- `create_time` (String)
- `department` (String)
- `is_application_user` (Boolean)
- `job_title` (String)
- `managed_by_scim` (Boolean)
- `managing_organization_id` (String)
- `real_name` (String)
- `state` (String)
- `user_email` (String)
41 changes: 36 additions & 5 deletions internal/schemautil/schemautil.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,24 +386,24 @@ func ResourceDataGet(d *schema.ResourceData, dto any, fns ...KVModifier) error {
k, value = f(k, value)
}

m[k] = serializeValue(value)
m[k] = serializeGet(value)
}

return Remarshal(&m, dto)
}

func serializeValue(value any) any {
func serializeGet(value any) any {
switch t := value.(type) {
case *schema.Set:
return serializeValue(t.List())
return serializeGet(t.List())
case []any:
for i, v := range t {
t[i] = serializeValue(v)
t[i] = serializeGet(v)
}
return t
case map[string]any:
for k, v := range t {
t[k] = serializeValue(v)
t[k] = serializeGet(v)
}
}
return value
Expand Down Expand Up @@ -442,6 +442,7 @@ func ResourceDataSet(s map[string]*schema.Schema, d *schema.ResourceData, dto an
}
}

m = serializeSet(s, m)
for k := range s {
if v, ok := m[k]; ok {
if err = d.Set(k, v); err != nil {
Expand All @@ -452,6 +453,36 @@ func ResourceDataSet(s map[string]*schema.Schema, d *schema.ResourceData, dto an
return nil
}

func serializeSet(s map[string]*schema.Schema, m map[string]any) map[string]any {
for k, prop := range s {
value, ok := m[k]
if !ok {
continue
}

res, ok := prop.Elem.(*schema.Resource)
if !ok {
continue
}

// When we have an object, we need to convert it to a list.
// So there is no difference between a single object and a list of objects.
var items []any
switch element := value.(type) {
case map[string]any:
items = append(items, serializeSet(res.Schema, element))
case []any:
for _, v := range element {
items = append(items, serializeSet(res.Schema, v.(map[string]any)))
}
}

m[k] = items
}

return m
}

// RenameAliases renames field names on object top level
func RenameAliases(aliases map[string]string) KVModifier {
return func(k string, v any) (string, any) {
Expand Down
1 change: 1 addition & 0 deletions internal/sdkprovider/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func Provider(version string) (*schema.Provider, error) {
// organization
"aiven_organizational_unit": organization.DatasourceOrganizationalUnit(),
"aiven_organization_user": organization.DatasourceOrganizationUser(),
"aiven_organization_user_list": organization.DatasourceOrganizationUserList(),
"aiven_organization_user_group": organization.DatasourceOrganizationUserGroup(),
"aiven_organization_application_user": organization.DatasourceOrganizationApplicationUser(),

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package organization

import (
"context"
"fmt"

avngen "github.com/aiven/go-client-codegen"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/aiven/terraform-provider-aiven/internal/common"
"github.com/aiven/terraform-provider-aiven/internal/schemautil"
)

func datasourceOrganizationUserListSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "Account ID. Example `a`",
},
"users": {
Type: schema.TypeList,
Computed: true,
Description: "List of users of the organization",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"is_super_admin": {
Type: schema.TypeBool,
Computed: true,
Description: "Super admin state of the organization user",
},
"join_time": {
Type: schema.TypeString,
Computed: true,
Description: "Join time",
},
"last_activity_time": {
Type: schema.TypeString,
Computed: true,
Description: "Last activity time",
},
"user_id": {
Type: schema.TypeString,
Computed: true,
Description: "User ID",
},
"user_info": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"city": {
Type: schema.TypeString,
Computed: true,
Description: "City",
},
"country": {
Type: schema.TypeString,
Computed: true,
Description: "Country",
},
"create_time": {
Type: schema.TypeString,
Computed: true,
Description: "Creation time",
},
"department": {
Type: schema.TypeString,
Computed: true,
Description: "Department",
},
"is_application_user": {
Type: schema.TypeBool,
Computed: true,
Description: "Is Application User",
},
"job_title": {
Type: schema.TypeString,
Computed: true,
Description: "Job Title",
},
"managed_by_scim": {
Type: schema.TypeBool,
Computed: true,
Description: "Managed By Scim",
},
"managing_organization_id": {
Type: schema.TypeString,
Computed: true,
Description: "Managing Organization ID",
},
"real_name": {
Type: schema.TypeString,
Computed: true,
Description: "Real Name",
},
"state": {
Type: schema.TypeString,
Computed: true,
Description: "State",
},
"user_email": {
Type: schema.TypeString,
Computed: true,
Description: "User Email",
},
},
},
},
},
},
},
}
}

func DatasourceOrganizationUserList() *schema.Resource {
return &schema.Resource{
ReadContext: common.WithGenClient(datasourceOrganizationUserListRead),
Description: "List of users of the organization",
Schema: datasourceOrganizationUserListSchema(),
}
}

func datasourceOrganizationUserListRead(ctx context.Context, d *schema.ResourceData, client avngen.Client) error {
orgs, err := client.UserOrganizationsList(ctx)
if err != nil {
return err
}

var organizationID string
name := d.Get("name").(string)
for _, o := range orgs {
if o.OrganizationName == name {
organizationID = o.OrganizationId
break
}
}

if organizationID == "" {
return fmt.Errorf("organization %q not found", name)
}

list, err := client.OrganizationUserList(ctx, organizationID)
if err != nil {
return fmt.Errorf("cannot get organization %q user list: %w", organizationID, err)
}

users := map[string]any{"users": list}
err = schemautil.ResourceDataSet(datasourceOrganizationUserListSchema(), d, users)
if err != nil {
return err
}

d.SetId(organizationID)
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package organization_test

import (
"fmt"
"os"
"regexp"
"testing"

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

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

func testAccAivenOrganizationUserList() string {
return fmt.Sprintf(`
data "aiven_organization_user_list" "org" {
name = "%s"
}
`, os.Getenv("AIVEN_ORGANIZATION_NAME"))
}

func TestAccAivenOrganizationUserList_basic(t *testing.T) {
resourceName := "data.aiven_organization_user_list.org"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acc.TestAccPreCheck(t) },
ProtoV6ProviderFactories: acc.TestProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccAivenOrganizationUserList(),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(resourceName, "users.#"),
resource.TestMatchResourceAttr(resourceName, "users.0.user_info.0.user_email", regexp.MustCompile(`.*@.*`)),
),
},
},
})
}

0 comments on commit 8cd9e1e

Please sign in to comment.