Skip to content

Commit

Permalink
feat: migrate users data source to tf framework (#795)
Browse files Browse the repository at this point in the history
* Add users datasource in framework

* Replace users datasource with framework version

* Remove password, make username not sensitive

* Remove comment

* Update descriptions and generated docs

* Migrate users datasource test

* Remove users datasource in SDK

* Add deprecation message to space id
  • Loading branch information
N-lson authored Oct 9, 2024
1 parent 6e97b3c commit 6c31839
Show file tree
Hide file tree
Showing 8 changed files with 360 additions and 79 deletions.
54 changes: 31 additions & 23 deletions docs/data-sources/users.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,48 +25,56 @@ data "octopusdeploy_users" "example" {

### Optional

- `filter` (String) A filter with which to search.
- `filter` (String) A filter search by username, display name or email
- `ids` (List of String) A filter to search by a list of IDs.
- `skip` (Number) A filter to specify the number of items to skip in the response.
- `space_id` (String) A Space ID to filter by. Will revert what is specified on the provider if not set.
- `space_id` (String, Deprecated) The space ID associated with this user.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.

### Read-Only

- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
- `users` (List of Object) A list of users that match the filter(s). (see [below for nested schema](#nestedatt--users))
- `id` (String) The unique ID for this resource.
- `users` (Attributes List) (see [below for nested schema](#nestedatt--users))

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

Required:

- `display_name` (String) The display name of this resource.
- `username` (String) The username associated with this resource.

Optional:

- `can_password_be_edited` (Boolean) Specifies whether or not the password can be edited.
- `email_address` (String) The email address of this resource.
- `identity` (Attributes Set) The identities associated with the user. (see [below for nested schema](#nestedatt--users--identity))
- `is_active` (Boolean) Specifies whether or not the user is active.
- `is_requestor` (Boolean) Specifies whether or not the user is the requestor.
- `is_service` (Boolean) Specifies whether or not the user is a service account.

Read-Only:

- `can_password_be_edited` (Boolean)
- `display_name` (String)
- `email_address` (String)
- `id` (String)
- `identity` (Set of Object) (see [below for nested schema](#nestedobjatt--users--identity))
- `is_active` (Boolean)
- `is_requestor` (Boolean)
- `is_service` (Boolean)
- `password` (String)
- `username` (String)

<a id="nestedobjatt--users--identity"></a>
- `id` (String) The unique ID for this resource.

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

Read-Only:

- `claim` (Set of Object) (see [below for nested schema](#nestedobjatt--users--identity--claim))
- `provider` (String)
- `claim` (Attributes Set) The claim associated with the identity. (see [below for nested schema](#nestedatt--users--identity--claim))
- `provider` (String) The identity provider.

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

Read-Only:
Required:

- `name` (String) The name of this resource.
- `value` (String) The value of this resource.

Optional:

- `is_identifying_claim` (Boolean)
- `name` (String)
- `value` (String)
- `is_identifying_claim` (Boolean) Specifies whether or not the claim is an identifying claim.


46 changes: 0 additions & 46 deletions octopusdeploy/data_source_users.go

This file was deleted.

1 change: 0 additions & 1 deletion octopusdeploy/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ func Provider() *schema.Provider {
"octopusdeploy_polling_tentacle_deployment_targets": dataSourcePollingTentacleDeploymentTargets(),
"octopusdeploy_ssh_connection_deployment_targets": dataSourceSSHConnectionDeploymentTargets(),
"octopusdeploy_teams": dataSourceTeams(),
"octopusdeploy_users": dataSourceUsers(),
"octopusdeploy_user_roles": dataSourceUserRoles(),
"octopusdeploy_worker_pools": dataSourceWorkerPools(),
},
Expand Down
80 changes: 80 additions & 0 deletions octopusdeploy_framework/datasource_users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package octopusdeploy_framework

import (
"context"
"fmt"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/users"
"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"
"github.com/hashicorp/terraform-plugin-log/tflog"
"time"
)

type userDataSource struct {
*Config
}

type usersDataSourceModel struct {
ID types.String `tfsdk:"id"`
SpaceID types.String `tfsdk:"space_id"`
IDs types.List `tfsdk:"ids"`
Filter types.String `tfsdk:"filter"`
Skip types.Int64 `tfsdk:"skip"`
Take types.Int64 `tfsdk:"take"`
Users types.List `tfsdk:"users"`
}

func NewUsersDataSource() datasource.DataSource {
return &userDataSource{}
}

func (u *userDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = util.GetTypeName("users")
}

func (u *userDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schemas.UserSchema{}.GetDatasourceSchema()
}

func (u *userDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
u.Config = DataSourceConfiguration(req, resp)
}

func (u *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var err error
var data usersDataSourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

query := users.UsersQuery{
IDs: util.GetIds(data.IDs),
Filter: data.Filter.ValueString(),
Skip: util.GetNumber(data.Skip),
Take: util.GetNumber(data.Take),
}

util.DatasourceReading(ctx, "users", query)

existingUsers, err := users.Get(u.Client, data.SpaceID.ValueString(), query)
if err != nil {
resp.Diagnostics.AddError("unable to load users", err.Error())
return
}

mappedUsers := []schemas.UserTypeResourceModel{}
tflog.Debug(ctx, fmt.Sprintf("users returned from API: %#v", existingUsers))
for _, user := range existingUsers.Items {
mappedUsers = append(mappedUsers, schemas.MapFromUser(user))
}

util.DatasourceResultCount(ctx, "users", len(mappedUsers))

data.Users, _ = types.ListValueFrom(ctx, types.ObjectType{AttrTypes: schemas.UserObjectType()}, mappedUsers)
data.ID = types.StringValue("Users " + time.Now().UTC().String())

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
package octopusdeploy
package octopusdeploy_framework

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

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccDataSourceUsers(t *testing.T) {
localName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
name := fmt.Sprintf("data.octopusdeploy_users.%s", localName)
username := "d"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
PreCheck: func() { TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testAccDataSourceUsersConfig(localName, username),
Check: resource.ComposeTestCheckFunc(
testAccCheckUsersDataSourceID(name),
resource.TestCheckResourceAttrSet(name, "users.#"),
)},
),
Config: testAccDataSourceUsersConfig(localName, username),
},
},
})
}
Expand Down
1 change: 1 addition & 0 deletions octopusdeploy_framework/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func (p *octopusDeployFrameworkProvider) DataSources(ctx context.Context) []func
NewTagSetsDataSource,
NewScriptModuleDataSource,
NewTenantProjectDataSource,
NewUsersDataSource,
}
}

Expand Down
34 changes: 34 additions & 0 deletions octopusdeploy_framework/schemas/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,40 @@ func GetReadonlyDescriptionDatasourceSchema(resourceDescription string) datasour
}
}

func GetUsernameDatasourceSchema(isRequired bool) datasourceSchema.Attribute {
s := datasourceSchema.StringAttribute{
Description: "The username associated with this resource.",
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
}

if isRequired {
s.Required = true
} else {
s.Optional = true
}

return s
}

func GetValueDatasourceSchema(isRequired bool) datasourceSchema.Attribute {
s := datasourceSchema.StringAttribute{
Description: "The value of this resource.",
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
}

if isRequired {
s.Required = true
} else {
s.Optional = true
}

return s
}

func GetIdResourceSchema() resourceSchema.Attribute {
return resourceSchema.StringAttribute{
Description: "The unique ID for this resource.",
Expand Down
Loading

0 comments on commit 6c31839

Please sign in to comment.