diff --git a/docs/data-sources/team.md b/docs/data-sources/team.md
new file mode 100644
index 00000000..bdeb3e36
--- /dev/null
+++ b/docs/data-sources/team.md
@@ -0,0 +1,42 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "spectrocloud_team Data Source - terraform-provider-spectrocloud"
+subcategory: ""
+description: |-
+
+---
+
+# spectrocloud_team (Data Source)
+
+
+
+## Example Usage
+
+```terraform
+data "spectrocloud_team" "team1" {
+ name = "team2"
+
+ # (alternatively)
+ # id = "5fd0ca727c411c71b55a359c"
+}
+
+output "team-id" {
+ value = data.spectrocloud_team.team1.id
+}
+
+output "team-role-ids" {
+ value = data.spectrocloud_team.team1.role_ids
+}
+```
+
+
+## Schema
+
+### Optional
+
+- `id` (String) The unique ID of the team. If provided, `name` cannot be used.
+- `name` (String) The name of the team. If provided, `id` cannot be used.
+
+### Read-Only
+
+- `role_ids` (List of String) The roles id's assigned to the team.
diff --git a/docs/resources/user.md b/docs/resources/user.md
new file mode 100644
index 00000000..aa97e7de
--- /dev/null
+++ b/docs/resources/user.md
@@ -0,0 +1,157 @@
+---
+page_title: "spectrocloud_user Resource - terraform-provider-spectrocloud"
+subcategory: ""
+description: |-
+ Create and manage projects in Palette.
+---
+
+# spectrocloud_user (Resource)
+
+ Create and manage projects in Palette.
+
+You can learn more about managing users in Palette by reviewing the [Users](https://docs.spectrocloud.com/user-management/) guide.
+
+## Example Usage
+
+An example of creating a user resource with assigned teams and custom roles in Palette.
+
+```hcl
+resource "spectrocloud_user" "user-test"{
+ first_name = "tf"
+ last_name = "test"
+ email = "test-tf@spectrocloud.com"
+ team_ids = [data.spectrocloud_team.team2.id]
+ project_role {
+ project_id = data.spectrocloud_project.default.id
+ role_ids = [for r in data.spectrocloud_role.app_roles : r.id]
+ }
+ project_role {
+ project_id = data.spectrocloud_project.ranjith.id
+ role_ids = [for r in data.spectrocloud_role.app_roles : r.id]
+ }
+
+ tenant_role = [for t in data.spectrocloud_role.tenant_roles : t.id]
+
+ workspace_role {
+ project_id = data.spectrocloud_project.default.id
+ workspace {
+ id = data.spectrocloud_workspace.workspace.id
+ role_ids = [for w in data.spectrocloud_role.workspace_roles : w.id]
+ }
+ workspace {
+ id = data.spectrocloud_workspace.workspace2.id
+ role_ids = ["66fbea622947f81fc26983e6"]
+ }
+ }
+
+ resource_role {
+ project_ids = [data.spectrocloud_project.default.id, data.spectrocloud_project.ranjith.id]
+ filter_ids = [data.spectrocloud_filter.filter.id]
+ role_ids = [for r in data.spectrocloud_role.resource_roles : r.id]
+ }
+
+ resource_role {
+ project_ids = [data.spectrocloud_project.ranjith.id]
+ filter_ids = [data.spectrocloud_filter.filter.id]
+ role_ids = [for re in data.spectrocloud_role.resource_roles_editor : re.id]
+ }
+
+}
+```
+
+The example below demonstrates how to create an user with only assigned teams.
+
+```hcl
+resource "spectrocloud_user" "user-test"{
+ first_name = "tf"
+ last_name = "test"
+ email = "test-tf@spectrocloud.com"
+ team_ids = [data.spectrocloud_team.team2.id]
+}
+
+
+```
+
+### Importing existing user states
+
+```hcl
+# import existing user example
+ import {
+ to = spectrocloud_user.test_user
+ id = "{userUID}"
+ }
+
+# To generate TF configuration.
+ terraform plan -generate-config-out=test_user.tf
+
+# To import State file
+ terraform import spectrocloud_user.test_user {userUID}
+```
+
+
+
+## Schema
+
+### Required
+
+- `email` (String) The email of the user.
+- `first_name` (String) The first name of the user.
+- `last_name` (String) The last name of the user.
+
+### Optional
+
+- `project_role` (Block Set) List of project roles to be associated with the user. (see [below for nested schema](#nestedblock--project_role))
+- `resource_role` (Block Set) (see [below for nested schema](#nestedblock--resource_role))
+- `team_ids` (List of String) The team id's assigned to the user.
+- `tenant_role` (Set of String) List of tenant role ids to be associated with the user.
+- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
+- `workspace_role` (Block Set) List of workspace roles to be associated with the user. (see [below for nested schema](#nestedblock--workspace_role))
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `project_role`
+
+Required:
+
+- `project_id` (String) Project id to be associated with the user.
+- `role_ids` (Set of String) List of project role ids to be associated with the user.
+
+
+
+### Nested Schema for `resource_role`
+
+Required:
+
+- `filter_ids` (Set of String) List of filter ids.
+- `project_ids` (Set of String) Project id's to be associated with the user.
+- `role_ids` (Set of String) List of resource role ids to be associated with the user.
+
+
+
+### Nested Schema for `timeouts`
+
+Optional:
+
+- `create` (String)
+- `delete` (String)
+- `update` (String)
+
+
+
+### Nested Schema for `workspace_role`
+
+Required:
+
+- `project_id` (String) Project id to be associated with the user.
+- `workspace` (Block Set, Min: 1) List of workspace roles to be associated with the user. (see [below for nested schema](#nestedblock--workspace_role--workspace))
+
+
+### Nested Schema for `workspace_role.workspace`
+
+Required:
+
+- `id` (String) Workspace id to be associated with the user.
+- `role_ids` (Set of String) List of workspace role ids to be associated with the user.
\ No newline at end of file
diff --git a/examples/data-sources/spectrocloud_team/data-source.tf b/examples/data-sources/spectrocloud_team/data-source.tf
new file mode 100644
index 00000000..e208a80f
--- /dev/null
+++ b/examples/data-sources/spectrocloud_team/data-source.tf
@@ -0,0 +1,14 @@
+data "spectrocloud_team" "team1" {
+ name = "team2"
+
+ # (alternatively)
+ # id = "5fd0ca727c411c71b55a359c"
+}
+
+output "team-id" {
+ value = data.spectrocloud_team.team1.id
+}
+
+output "team-role-ids" {
+ value = data.spectrocloud_team.team1.role_ids
+}
\ No newline at end of file
diff --git a/examples/data-sources/spectrocloud_team/providers.tf b/examples/data-sources/spectrocloud_team/providers.tf
new file mode 100644
index 00000000..f3bdb2e0
--- /dev/null
+++ b/examples/data-sources/spectrocloud_team/providers.tf
@@ -0,0 +1,28 @@
+terraform {
+ required_providers {
+ spectrocloud = {
+ version = ">= 0.1"
+ source = "spectrocloud/spectrocloud"
+ }
+ }
+}
+
+variable "sc_host" {
+ description = "Spectro Cloud Endpoint"
+ default = "api.spectrocloud.com"
+}
+
+variable "sc_api_key" {
+ description = "Spectro Cloud API key"
+}
+
+variable "sc_project_name" {
+ description = "Spectro Cloud Project (e.g: Default)"
+ default = "Default"
+}
+
+provider "spectrocloud" {
+ host = var.sc_host
+ api_key = var.sc_api_key
+ project_name = var.sc_project_name
+}
diff --git a/examples/data-sources/spectrocloud_team/terraform.template.tfvars b/examples/data-sources/spectrocloud_team/terraform.template.tfvars
new file mode 100644
index 00000000..c7e9d50b
--- /dev/null
+++ b/examples/data-sources/spectrocloud_team/terraform.template.tfvars
@@ -0,0 +1,4 @@
+# Spectro Cloud credentials
+sc_host = "{Enter Spectro Cloud API Host}" #e.g: api.spectrocloud.com (for SaaS)
+sc_api_key = "{Enter Spectro Cloud API Key}"
+sc_project_name = "{Enter Spectro Cloud Project Name}" #e.g: Default
\ No newline at end of file
diff --git a/examples/resources/spectrocloud_user/data_source.tf b/examples/resources/spectrocloud_user/data_source.tf
new file mode 100644
index 00000000..b0d50e68
--- /dev/null
+++ b/examples/resources/spectrocloud_user/data_source.tf
@@ -0,0 +1,49 @@
+
+data "spectrocloud_project" "default" {
+ name = "Default"
+}
+
+data "spectrocloud_project" "ranjith" {
+ name = "ranjith"
+}
+
+data "spectrocloud_role" "app_roles" {
+ for_each = toset(var.app_role_var)
+ name = each.key
+}
+
+data "spectrocloud_role" "tenant_roles" {
+ for_each = toset(var.tenant_role_var)
+ name = each.key
+}
+
+data "spectrocloud_workspace" "workspace" {
+ name = "test-ws-tf"
+}
+
+data "spectrocloud_workspace" "workspace2" {
+ name = "test-ws-2"
+}
+
+data "spectrocloud_role" "workspace_roles" {
+ for_each = toset(var.workspace_role_var)
+ name = each.key
+}
+
+data "spectrocloud_filter" "filter" {
+ name = "test-tf"
+}
+
+data "spectrocloud_role" "resource_roles" {
+ for_each = toset(var.resource_role_var)
+ name = each.key
+}
+
+data "spectrocloud_role" "resource_roles_editor" {
+ for_each = toset(var.resource_role_editor_var)
+ name = each.key
+}
+
+data "spectrocloud_team" "team2" {
+ name = "team2"
+}
\ No newline at end of file
diff --git a/examples/resources/spectrocloud_user/providers.tf b/examples/resources/spectrocloud_user/providers.tf
new file mode 100644
index 00000000..4c109161
--- /dev/null
+++ b/examples/resources/spectrocloud_user/providers.tf
@@ -0,0 +1,14 @@
+terraform {
+ required_providers {
+ spectrocloud = {
+ version = ">= 0.1"
+ source = "spectrocloud/spectrocloud"
+ }
+ }
+}
+
+provider "spectrocloud" {
+ host = var.sc_host
+ api_key = var.sc_api_key
+ project_name = var.sc_project_name
+}
diff --git a/examples/resources/spectrocloud_user/resource.tf b/examples/resources/spectrocloud_user/resource.tf
new file mode 100644
index 00000000..3e5ea1b2
--- /dev/null
+++ b/examples/resources/spectrocloud_user/resource.tf
@@ -0,0 +1,53 @@
+resource "spectrocloud_user" "user-test" {
+ first_name = "tf"
+ last_name = "test"
+ email = "test-tf@spectrocloud.com"
+ team_ids = [data.spectrocloud_team.team2.id]
+ project_role {
+ project_id = data.spectrocloud_project.default.id
+ role_ids = [for r in data.spectrocloud_role.app_roles : r.id]
+ }
+ project_role {
+ project_id = data.spectrocloud_project.ranjith.id
+ role_ids = [for r in data.spectrocloud_role.app_roles : r.id]
+ }
+
+ tenant_role = [for t in data.spectrocloud_role.tenant_roles : t.id]
+
+ workspace_role {
+ project_id = data.spectrocloud_project.default.id
+ workspace {
+ id = data.spectrocloud_workspace.workspace.id
+ role_ids = [for w in data.spectrocloud_role.workspace_roles : w.id]
+ }
+ workspace {
+ id = data.spectrocloud_workspace.workspace2.id
+ role_ids = ["66fbea622947f81fc26983e6"]
+ }
+ }
+
+ resource_role {
+ project_ids = [data.spectrocloud_project.default.id, data.spectrocloud_project.ranjith.id]
+ filter_ids = [data.spectrocloud_filter.filter.id]
+ role_ids = [for r in data.spectrocloud_role.resource_roles : r.id]
+ }
+
+ resource_role {
+ project_ids = [data.spectrocloud_project.ranjith.id]
+ filter_ids = [data.spectrocloud_filter.filter.id]
+ role_ids = [for re in data.spectrocloud_role.resource_roles_editor : re.id]
+ }
+
+}
+
+# import existing user example
+#import {
+# to = spectrocloud_user.test_user
+# id = "66fcb5fe19eb6dc880776d59"
+#}
+
+# To generate TF configuration.
+#terraform plan -generate-config-out=test_user.tf
+
+# To import State file
+#terraform import spectrocloud_user.test_user 672c5ae21adfa1c28c9e37c9
\ No newline at end of file
diff --git a/examples/resources/spectrocloud_user/terraform.template.tfvars b/examples/resources/spectrocloud_user/terraform.template.tfvars
new file mode 100644
index 00000000..c7e9d50b
--- /dev/null
+++ b/examples/resources/spectrocloud_user/terraform.template.tfvars
@@ -0,0 +1,4 @@
+# Spectro Cloud credentials
+sc_host = "{Enter Spectro Cloud API Host}" #e.g: api.spectrocloud.com (for SaaS)
+sc_api_key = "{Enter Spectro Cloud API Key}"
+sc_project_name = "{Enter Spectro Cloud Project Name}" #e.g: Default
\ No newline at end of file
diff --git a/examples/resources/spectrocloud_user/variables.tf b/examples/resources/spectrocloud_user/variables.tf
new file mode 100644
index 00000000..428b7837
--- /dev/null
+++ b/examples/resources/spectrocloud_user/variables.tf
@@ -0,0 +1,43 @@
+variable "sc_host" {
+ description = "Spectro Cloud Endpoint"
+ default = "api.spectrocloud.com"
+}
+
+variable "sc_api_key" {
+ description = "Spectro Cloud API key"
+}
+
+variable "sc_project_name" {
+ description = "Spectro Cloud Project (e.g: Default)"
+ default = "Default"
+}
+
+variable "ssh_key_value" {
+ description = "ssh key value"
+ default = "ssh-rsa ...... == test@test.com"
+}
+
+variable "tenant_role_var" {
+ type = list(string)
+ default = ["Tenant Admin", "Tenant User Admin"]
+}
+
+variable "app_role_var" {
+ type = list(string)
+ default = ["App Deployment Admin", "App Deployment Editor"]
+}
+
+variable "workspace_role_var" {
+ type = list(string)
+ default = ["Workspace Admin", "Workspace Operator"]
+}
+
+variable "resource_role_var" {
+ type = list(string)
+ default = ["Resource Cluster Admin", "Resource Cluster Profile Admin"]
+}
+
+variable "resource_role_editor_var" {
+ type = list(string)
+ default = ["Resource Cluster Editor", "Resource Cluster Profile Editor"]
+}
\ No newline at end of file
diff --git a/spectrocloud/data_source_team.go b/spectrocloud/data_source_team.go
new file mode 100644
index 00000000..a62c408d
--- /dev/null
+++ b/spectrocloud/data_source_team.go
@@ -0,0 +1,66 @@
+package spectrocloud
+
+import (
+ "context"
+ "github.com/spectrocloud/palette-sdk-go/api/models"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func dataSourceTeam() *schema.Resource {
+ return &schema.Resource{
+ ReadContext: dataSourceTeamRead,
+
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeString,
+ Computed: true,
+ Optional: true,
+ ConflictsWith: []string{"name"},
+ Description: "The unique ID of the team. If provided, `name` cannot be used.",
+ },
+ "name": {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: "The name of the team. If provided, `id` cannot be used.",
+ },
+ "role_ids": {
+ Type: schema.TypeList,
+ Computed: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Description: "The roles id's assigned to the team.",
+ },
+ },
+ }
+}
+
+func dataSourceTeamRead(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ c := getV1ClientWithResourceContext(m, "")
+ var diags diag.Diagnostics
+ var team *models.V1Team
+ var err error
+ if v, ok := d.GetOk("name"); ok {
+ team, err = c.GetTeamWithName(v.(string))
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ } else {
+ if val, okay := d.GetOk("id"); okay && val != "" {
+ team, err = c.GetTeam(val.(string))
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ }
+ }
+ if team != nil {
+ d.SetId(team.Metadata.UID)
+ if err := d.Set("name", team.Metadata.Name); err != nil {
+ return diag.FromErr(err)
+ }
+ if err := d.Set("role_ids", team.Spec.Roles); err != nil {
+ return diag.FromErr(err)
+ }
+ }
+ return diags
+}
diff --git a/spectrocloud/provider.go b/spectrocloud/provider.go
index 4925ab7d..029d7638 100644
--- a/spectrocloud/provider.go
+++ b/spectrocloud/provider.go
@@ -140,9 +140,12 @@ func New(_ string) func() *schema.Provider {
"spectrocloud_workspace": resourceWorkspace(),
"spectrocloud_alert": resourceAlert(),
"spectrocloud_ssh_key": resourceSSHKey(),
+ "spectrocloud_user": resourceUser(),
"spectrocloud_role": resourceRole(),
},
DataSourcesMap: map[string]*schema.Resource{
+ "spectrocloud_team": dataSourceTeam(),
+
"spectrocloud_user": dataSourceUser(),
"spectrocloud_project": dataSourceProject(),
diff --git a/spectrocloud/resource_user.go b/spectrocloud/resource_user.go
new file mode 100644
index 00000000..7813d742
--- /dev/null
+++ b/spectrocloud/resource_user.go
@@ -0,0 +1,721 @@
+package spectrocloud
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+ "github.com/spectrocloud/palette-sdk-go/client"
+ "regexp"
+ "sort"
+ "time"
+
+ "github.com/spectrocloud/palette-sdk-go/api/models"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceUser() *schema.Resource {
+ return &schema.Resource{
+ CreateContext: resourceUserCreate,
+ ReadContext: resourceUserRead,
+ UpdateContext: resourceUserUpdate,
+ DeleteContext: resourceUserDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceUserImport,
+ },
+
+ Description: "Create and manage projects in Palette.",
+
+ Timeouts: &schema.ResourceTimeout{
+ Create: schema.DefaultTimeout(10 * time.Minute),
+ Update: schema.DefaultTimeout(10 * time.Minute),
+ Delete: schema.DefaultTimeout(10 * time.Minute),
+ },
+
+ SchemaVersion: 2,
+ Schema: map[string]*schema.Schema{
+ "first_name": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "The first name of the user.",
+ },
+ "last_name": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "The last name of the user.",
+ },
+ "email": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ ValidateFunc: validation.StringMatch(
+ regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`),
+ "must be a valid email address",
+ ),
+ Description: "The email of the user.",
+ },
+ "team_ids": {
+ Type: schema.TypeList,
+ Optional: true,
+ ForceNew: true,
+ Elem: &schema.Schema{Type: schema.TypeString},
+ Description: "The team id's assigned to the user.",
+ },
+ "project_role": {
+ Type: schema.TypeSet,
+ Set: resourceUserProjectRoleMappingHash,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "project_id": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "Project id to be associated with the user.",
+ },
+ "role_ids": {
+ Type: schema.TypeSet,
+ Required: true,
+ Set: schema.HashString,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: "List of project role ids to be associated with the user. ",
+ },
+ },
+ },
+ Description: "List of project roles to be associated with the user. ",
+ },
+ "tenant_role": {
+ Type: schema.TypeSet,
+ Optional: true,
+ Set: schema.HashString,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: "List of tenant role ids to be associated with the user. ",
+ },
+ "workspace_role": {
+ Type: schema.TypeSet,
+ Set: resourceUserWorkspaceRoleMappingHash,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "project_id": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "Project id to be associated with the user.",
+ },
+ "workspace": {
+ Type: schema.TypeSet,
+ Set: resourceUserWorkspaceRoleMappingHashInternal,
+ Required: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "Workspace id to be associated with the user.",
+ },
+ "role_ids": {
+ Type: schema.TypeSet,
+ Set: schema.HashString,
+ Required: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: "List of workspace role ids to be associated with the user.",
+ },
+ },
+ },
+ Description: "List of workspace roles to be associated with the user. ",
+ },
+ },
+ },
+ Description: "List of workspace roles to be associated with the user. ",
+ },
+ "resource_role": {
+ Type: schema.TypeSet,
+ Set: resourceUserResourceRoleMappingHash,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "project_ids": {
+ Type: schema.TypeSet,
+ Set: schema.HashString,
+ Required: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: "Project id's to be associated with the user.",
+ },
+ "filter_ids": {
+ Type: schema.TypeSet,
+ Set: schema.HashString,
+ Required: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: "List of filter ids.",
+ },
+ "role_ids": {
+ Type: schema.TypeSet,
+ Set: schema.HashString,
+ Required: true,
+ Elem: &schema.Schema{
+ Type: schema.TypeString,
+ },
+ Description: "List of resource role ids to be associated with the user.",
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func resourceUserCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+
+ c := getV1ClientWithResourceContext(m, "tenant")
+ var diags diag.Diagnostics
+ user := toUser(d)
+ uid, err := c.CreateUser(user)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ d.SetId(uid)
+ //creating roles
+ if pRoles, ok := d.GetOk("project_role"); ok && pRoles != nil {
+ projectRole := toUserProjectRoleMapping(d)
+ err := c.AssociateUserProjectRole(uid, projectRole)
+ if err != nil {
+ _ = c.DeleteUser(uid)
+ return diag.FromErr(err)
+ }
+ }
+
+ if rRoles, ok := d.GetOk("tenant_role"); ok && rRoles != nil {
+ tenantRole := toUserTenantRoleMapping(d)
+ err := c.AssociateUserTenantRole(uid, tenantRole)
+ if err != nil {
+ _ = c.DeleteUser(uid)
+ return diag.FromErr(err)
+ }
+ }
+
+ if wRoles, ok := d.GetOk("workspace_role"); ok && wRoles != nil {
+ workspaceRole := toUserWorkspaceRoleMapping(d)
+ err := c.AssociateUserWorkspaceRole(uid, workspaceRole)
+ if err != nil {
+ _ = c.DeleteUser(uid)
+ return diag.FromErr(err)
+ }
+ }
+
+ if rRoles, ok := d.GetOk("resource_role"); ok && rRoles != nil {
+ resourceRoles := toUserResourceRoleMapping(d)
+ for _, role := range resourceRoles {
+ err := c.CreateUserResourceRole(uid, role)
+ if err != nil {
+ _ = c.DeleteUser(uid)
+ return diag.FromErr(err)
+ }
+ }
+ }
+
+ return diags
+}
+
+func resourceUserRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+
+ c := getV1ClientWithResourceContext(m, "tenant")
+ var diags diag.Diagnostics
+
+ email := d.Get("email").(string)
+ user, err := c.GetUserSummaryByEmail(email)
+ if err != nil {
+ return diag.FromErr(err)
+ } else if user == nil {
+ // Deleted - Terraform will recreate it
+ d.SetId("")
+ return diags
+ }
+ err = flattenUser(user, d, c)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ return diags
+}
+
+func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+
+ c := getV1ClientWithResourceContext(m, "tenant")
+ uid := d.Id()
+ var diags diag.Diagnostics
+
+ if d.HasChanges("project_role") {
+ ops, _ := d.GetChange("project_role")
+ if len(ops.(*schema.Set).List()) > 0 {
+ _ = deleteProjectResourceRoles(c, ops, uid)
+ }
+ projectRole := toUserProjectRoleMapping(d)
+ if projectRole != nil {
+ err := c.AssociateUserProjectRole(uid, projectRole)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ }
+ }
+ if d.HasChanges("tenant_role") {
+ tenantRole := toUserTenantRoleMapping(d)
+ err := c.AssociateUserTenantRole(uid, tenantRole)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ }
+ if d.HasChanges("workspace_role") {
+ ows, _ := d.GetChange("workspace_role")
+ if len(ows.(*schema.Set).List()) > 0 {
+ _ = deleteWorkspaceResourceRoles(c, ows, uid)
+ }
+ workspaceRole := toUserWorkspaceRoleMapping(d)
+ if len(workspaceRole.Workspaces) > 0 {
+ err := c.AssociateUserWorkspaceRole(uid, workspaceRole)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ }
+
+ }
+ if d.HasChanges("resource_role") {
+ err := deleteUserResourceRoles(c, uid)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ resourceRoles := toUserResourceRoleMapping(d)
+ for _, role := range resourceRoles {
+ err := c.CreateUserResourceRole(uid, role)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ }
+ }
+
+ return diags
+}
+
+func resourceUserDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+
+ c := getV1ClientWithResourceContext(m, "tenant")
+ var diags diag.Diagnostics
+
+ err := c.DeleteUser(d.Id())
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ return diags
+}
+
+func toUserResourceRoleMapping(d *schema.ResourceData) []*models.V1ResourceRolesUpdateEntity {
+ if resourceRoles, ok := d.GetOk("resource_role"); ok && resourceRoles != nil {
+ resourceRoleEntities := make([]*models.V1ResourceRolesUpdateEntity, 0)
+ for _, re := range d.Get("resource_role").(*schema.Set).List() {
+ resourceEntity := &models.V1ResourceRolesUpdateEntity{
+ FilterRefs: setToStringArray(re.(map[string]interface{})["filter_ids"]),
+ ProjectUids: setToStringArray(re.(map[string]interface{})["project_ids"]),
+ Roles: setToStringArray(re.(map[string]interface{})["role_ids"]),
+ }
+ resourceRoleEntities = append(resourceRoleEntities, resourceEntity)
+ }
+ return resourceRoleEntities
+ }
+ return nil
+}
+
+func toUserProjectRoleMapping(d *schema.ResourceData) *models.V1ProjectRolesPatch {
+ if projectRoles, ok := d.GetOk("project_role"); ok && projectRoles != nil {
+ //var role *models.V1ProjectRolesPatch
+ var projects []*models.V1ProjectRolesPatchProjectsItems0
+ for _, r := range projectRoles.(*schema.Set).List() {
+ projects = append(projects, &models.V1ProjectRolesPatchProjectsItems0{
+ ProjectUID: r.(map[string]interface{})["project_id"].(string),
+ Roles: setToStringArray(r.(map[string]interface{})["role_ids"]),
+ })
+ }
+ return &models.V1ProjectRolesPatch{
+ Projects: projects,
+ }
+ }
+
+ return nil
+}
+
+func toUserTenantRoleMapping(d *schema.ResourceData) *models.V1UserRoleUIDs {
+ roles := make([]string, 0)
+ if d.Get("tenant_role") != nil {
+ for _, role := range d.Get("tenant_role").(*schema.Set).List() {
+ roles = append(roles, role.(string))
+ }
+ }
+
+ return &models.V1UserRoleUIDs{
+ Roles: roles,
+ }
+}
+
+func toUserWorkspaceRoleMapping(d *schema.ResourceData) *models.V1WorkspacesRolesPatch {
+ workspaces := make([]*models.V1WorkspaceRolesPatch, 0)
+ workspaceRoleMappings := d.Get("workspace_role").(*schema.Set).List()
+
+ for _, mapping := range workspaceRoleMappings {
+ data := mapping.(map[string]interface{})
+
+ for _, workspace := range data["workspace"].(*schema.Set).List() {
+ workspaceData := workspace.(map[string]interface{})
+ roles := make([]string, 0)
+ if workspaceData["role_ids"] != nil {
+ for _, role := range workspaceData["role_ids"].(*schema.Set).List() {
+ roles = append(roles, role.(string))
+ }
+ }
+ workspaces = append(workspaces, &models.V1WorkspaceRolesPatch{
+ UID: workspaceData["id"].(string),
+ Roles: roles,
+ })
+ }
+
+ }
+
+ return &models.V1WorkspacesRolesPatch{
+ Workspaces: workspaces,
+ }
+}
+
+func setToStringArray(ids interface{}) []string {
+ idList := make([]string, 0)
+ for _, id := range ids.(*schema.Set).List() {
+ idList = append(idList, id.(string))
+ }
+ return idList
+}
+
+func deleteWorkspaceResourceRoles(c *client.V1Client, oldWs interface{}, userUID string) error {
+ oldWorkspaces := oldWs.(*schema.Set).List()
+ for _, p := range oldWorkspaces {
+
+ inWS := make([]*models.V1WorkspaceRolesPatch, 0)
+ for _, ws := range p.(map[string]interface{})["workspace"].(*schema.Set).List() {
+ inWS = append(inWS, &models.V1WorkspaceRolesPatch{
+ Roles: []string{},
+ UID: ws.(map[string]interface{})["id"].(string),
+ })
+ }
+ deleteWS := &models.V1WorkspacesRolesPatch{
+ Workspaces: inWS,
+ }
+ _ = c.AssociateUserWorkspaceRole(userUID, deleteWS)
+ }
+ return nil
+}
+
+func deleteProjectResourceRoles(c *client.V1Client, oldPs interface{}, userUID string) error {
+ oldProjectRoles := oldPs.(*schema.Set).List()
+
+ for _, p := range oldProjectRoles {
+ deletePR := &models.V1ProjectRolesPatch{
+ Projects: []*models.V1ProjectRolesPatchProjectsItems0{
+ {
+ ProjectUID: p.(map[string]interface{})["project_id"].(string),
+ Roles: []string{},
+ },
+ },
+ }
+ _ = c.AssociateUserProjectRole(userUID, deletePR)
+ }
+ return nil
+}
+
+func deleteUserResourceRoles(c *client.V1Client, userUID string) error {
+ resourceRoles, _ := c.GetUserResourceRoles(userUID)
+ for _, re := range resourceRoles {
+ err := c.DeleteUserResourceRoles(userUID, re.UID)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func flattenUser(user *models.V1UserSummary, d *schema.ResourceData, c *client.V1Client) error {
+ if user != nil {
+ if err := d.Set("first_name", user.Spec.FirstName); err != nil {
+ return err
+ }
+ if err := d.Set("last_name", user.Spec.LastName); err != nil {
+ return err
+ }
+ if err := d.Set("email", user.Spec.EmailID); err != nil {
+ return err
+ }
+
+ if user.Spec.Teams != nil {
+ var teamIds []string
+ for _, team := range user.Spec.Teams {
+ teamIds = append(teamIds, team.UID)
+ }
+ if err := d.Set("team_ids", teamIds); err != nil {
+ return err
+ }
+ }
+ if err := flattenUserProjectRoleMapping(d, c); err != nil {
+ return err
+ }
+ if err := flattenUserTenantRoleMapping(d, c); err != nil {
+ return err
+ }
+ if err := flattenUserWorkspaceRoleMapping(d, c); err != nil {
+ return err
+ }
+ if err := flattenUserResourceRoleMapping(d, c); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func flattenUserResourceRoleMapping(d *schema.ResourceData, c *client.V1Client) error {
+ userUID := d.Id()
+ resourceRoles, err := c.GetUserResourceRoles(userUID)
+ if err != nil {
+ return err
+ }
+ rRoles := make([]interface{}, 0)
+ for _, rr := range resourceRoles {
+ rRoles = append(rRoles, map[string]interface{}{
+ "project_ids": convertSummaryToIDS(rr.ProjectUids),
+ "filter_ids": convertSummaryToIDS(rr.FilterRefs),
+ "role_ids": convertSummaryToIDS(rr.Roles),
+ })
+ }
+ if err := d.Set("resource_role", rRoles); err != nil {
+ return err
+ }
+ return nil
+}
+
+func flattenUserWorkspaceRoleMapping(d *schema.ResourceData, c *client.V1Client) error {
+ userUID := d.Id()
+ workspaceRoles, err := c.GetUserWorkspaceRole(userUID)
+ if err != nil {
+ return err
+ }
+ wRoles := make([]interface{}, 0)
+ for _, w := range workspaceRoles.Projects {
+ wsRoles := make([]interface{}, 0)
+ for _, wr := range w.Workspaces {
+ wsIDS := make([]string, 0)
+ for _, ri := range wr.Roles {
+ wsIDS = append(wsIDS, ri.UID)
+ }
+ wsRoles = append(wsRoles, map[string]interface{}{
+ "id": wr.UID,
+ "role_ids": wsIDS,
+ })
+ }
+ wRoles = append(wRoles, map[interface{}]interface{}{
+ "project_id": w.UID,
+ "workspace": wsRoles,
+ })
+ }
+ if err := d.Set("workspace_role", wRoles); err != nil {
+ return err
+ }
+ return nil
+}
+
+func flattenUserTenantRoleMapping(d *schema.ResourceData, c *client.V1Client) error {
+ userUID := d.Id()
+ tenantRoles, err := c.GetUserTenantRole(userUID)
+ if err != nil {
+ return err
+ }
+ var tRoles []string
+ for _, t := range tenantRoles.Roles {
+ tRoles = append(tRoles, t.UID)
+ }
+ if err := d.Set("tenant_role", tRoles); err != nil {
+ return err
+ }
+ return nil
+}
+
+func flattenUserProjectRoleMapping(d *schema.ResourceData, c *client.V1Client) error {
+ userUID := d.Id()
+ projectRoles, err := c.GetUserProjectRole(userUID)
+ if err != nil {
+ return err
+ }
+ pRoles := make([]interface{}, 0)
+ for _, p := range projectRoles.Projects {
+ if len(p.Roles) > 0 {
+ roles := make([]string, 0)
+ for _, r := range p.Roles {
+ roles = append(roles, r.UID)
+ }
+ pRoles = append(pRoles, map[string]interface{}{
+ "project_id": p.UID,
+ "role_ids": roles,
+ })
+ }
+ }
+ if err := d.Set("project_role", pRoles); err != nil {
+ return err
+ }
+ return nil
+}
+
+func toUser(d *schema.ResourceData) *models.V1UserEntity {
+ fName := d.Get("first_name").(string)
+ lName := d.Get("last_name").(string)
+ user := &models.V1UserEntity{
+ Metadata: &models.V1ObjectMeta{
+ Name: fName + " " + lName,
+ },
+ Spec: &models.V1UserSpecEntity{
+ EmailID: d.Get("email").(string),
+ FirstName: fName,
+ LastName: lName,
+ },
+ }
+ if teams, ok := d.GetOk("team_ids"); ok && teams != nil {
+ user.Spec.Teams = convertToStrings(teams.([]interface{}))
+ }
+ return user
+}
+
+func convertToStrings(input []interface{}) []string {
+ var output []string
+ for _, v := range input {
+ if str, ok := v.(string); ok {
+ output = append(output, str)
+ }
+ }
+ return output
+}
+
+func convertSummaryToIDS(sum []*models.V1UIDSummary) []string {
+ var out []string
+ for _, v := range sum {
+ out = append(out, v.UID)
+ }
+ return out
+}
+
+func resourceUserResourceRoleMappingHash(i interface{}) int {
+ var buf bytes.Buffer
+ m := i.(map[string]interface{})
+
+ // Sort the roles to ensure order does not affect the hash
+ pids := make([]string, len(m["project_ids"].(*schema.Set).List()))
+ for i, pid := range m["project_ids"].(*schema.Set).List() {
+ pids[i] = pid.(string)
+ }
+ sort.Strings(pids)
+
+ fids := make([]string, len(m["filter_ids"].(*schema.Set).List()))
+ for i, fid := range m["filter_ids"].(*schema.Set).List() {
+ fids[i] = fid.(string)
+ }
+ sort.Strings(fids)
+
+ rids := make([]string, len(m["role_ids"].(*schema.Set).List()))
+ for i, rid := range m["role_ids"].(*schema.Set).List() {
+ rids[i] = rid.(string)
+ }
+ sort.Strings(rids)
+
+ //buf.WriteString(fmt.Sprintf("%s-", m["project_id"].(string)))
+
+ for _, id := range pids {
+ buf.WriteString(fmt.Sprintf("%s-", id))
+ }
+ for _, id := range fids {
+ buf.WriteString(fmt.Sprintf("%s-", id))
+ }
+ for _, id := range rids {
+ buf.WriteString(fmt.Sprintf("%s-", id))
+ }
+
+ return int(hash(buf.String()))
+}
+
+func resourceUserWorkspaceRoleMappingHash(i interface{}) int {
+ var buf bytes.Buffer
+ m := i.(map[string]interface{})
+
+ // Hash project id
+ if v, ok := m["project_id"].(string); ok {
+ h := schema.HashString(v)
+ buf.WriteString(fmt.Sprintf("%d-", h))
+ }
+
+ // Hash workspaces
+ if v, ok := m["workspace"].(*schema.Set); ok {
+ // Sort workspace hashes to ensure consistent ordering
+ workspaces := v.List()
+ hashes := make([]int, len(workspaces))
+ for i, workspaceInterface := range workspaces {
+ workspace := workspaceInterface.(map[string]interface{})
+ hashes[i] = resourceUserWorkspaceRoleMappingHashInternal(workspace)
+ }
+ sort.Ints(hashes)
+
+ for _, h := range hashes {
+ buf.WriteString(fmt.Sprintf("%d-", h))
+ }
+ }
+
+ return int(hash(buf.String()))
+}
+
+func resourceUserWorkspaceRoleMappingHashInternal(workspace interface{}) int {
+ var buf bytes.Buffer
+ m := workspace.(map[string]interface{})
+ // Sort the roles to ensure order does not affect the hash
+ roles := make([]string, len(m["role_ids"].(*schema.Set).List()))
+ for i, role := range m["role_ids"].(*schema.Set).List() {
+ roles[i] = role.(string)
+ }
+ sort.Strings(roles)
+
+ buf.WriteString(fmt.Sprintf("%s-", m["id"].(string)))
+
+ for _, role := range roles {
+ buf.WriteString(fmt.Sprintf("%s-", role))
+ }
+
+ return int(hash(buf.String()))
+}
+
+func resourceUserProjectRoleMappingHash(i interface{}) int {
+ var buf bytes.Buffer
+ m := i.(map[string]interface{})
+
+ // Sort the roles to ensure order does not affect the hash
+ roles := make([]string, len(m["role_ids"].(*schema.Set).List()))
+ for i, role := range m["role_ids"].(*schema.Set).List() {
+ roles[i] = role.(string)
+ }
+ sort.Strings(roles)
+
+ buf.WriteString(fmt.Sprintf("%s-", m["project_id"].(string)))
+
+ for _, role := range roles {
+ buf.WriteString(fmt.Sprintf("%s-", role))
+ }
+
+ return int(hash(buf.String()))
+}
diff --git a/spectrocloud/resource_user_import.go b/spectrocloud/resource_user_import.go
new file mode 100644
index 00000000..269fd54c
--- /dev/null
+++ b/spectrocloud/resource_user_import.go
@@ -0,0 +1,24 @@
+package spectrocloud
+
+import (
+ "context"
+ "fmt"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceUserImport(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
+ c := getV1ClientWithResourceContext(m, "tenant")
+ user, err := c.GetUserByID(d.Id())
+ if err != nil {
+ return nil, err
+ }
+ err = d.Set("email", user.Spec.EmailID)
+ if err != nil {
+ return nil, err
+ }
+ diags := resourceUserRead(ctx, d, m)
+ if diags.HasError() {
+ return nil, fmt.Errorf("could not read user for import: %v", diags)
+ }
+ return []*schema.ResourceData{d}, nil
+}
diff --git a/spectrocloud/resource_user_test.go b/spectrocloud/resource_user_test.go
new file mode 100644
index 00000000..8325771b
--- /dev/null
+++ b/spectrocloud/resource_user_test.go
@@ -0,0 +1,204 @@
+package spectrocloud
+
+import (
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/spectrocloud/palette-sdk-go/api/models"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestConvertSummaryToIDS(t *testing.T) {
+ tests := []struct {
+ name string
+ input []*models.V1UIDSummary
+ expected []string
+ }{
+ {
+ name: "Multiple UIDs",
+ input: []*models.V1UIDSummary{
+ {UID: "uid1"},
+ {UID: "uid2"},
+ {UID: "uid3"},
+ },
+ expected: []string{"uid1", "uid2", "uid3"},
+ },
+ {
+ name: "Empty input",
+ input: []*models.V1UIDSummary{},
+ expected: []string(nil),
+ },
+ {
+ name: "Single UID",
+ input: []*models.V1UIDSummary{
+ {UID: "singleUID"},
+ },
+ expected: []string{"singleUID"},
+ },
+ {
+ name: "Nil input",
+ input: nil,
+ expected: []string(nil),
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := convertSummaryToIDS(tt.input)
+ assert.Equal(t, tt.expected, result)
+ })
+ }
+}
+
+func TestConvertToStrings(t *testing.T) {
+ tests := []struct {
+ name string
+ input []interface{}
+ expected []string
+ }{
+ {
+ name: "All strings",
+ input: []interface{}{"one", "two", "three"},
+ expected: []string{"one", "two", "three"},
+ },
+ {
+ name: "Mixed types",
+ input: []interface{}{"one", 2, "three", 4.0, true},
+ expected: []string{"one", "three"},
+ },
+ {
+ name: "No strings",
+ input: []interface{}{1, 2, 3, 4.5, false},
+ expected: []string(nil),
+ },
+ {
+ name: "Empty input",
+ input: []interface{}{},
+ expected: []string(nil),
+ },
+ {
+ name: "Nil input",
+ input: nil,
+ expected: []string(nil),
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ result := convertToStrings(tt.input)
+ assert.Equal(t, tt.expected, result)
+ })
+ }
+}
+
+func TestToUser(t *testing.T) {
+ resourceData := schema.TestResourceDataRaw(t, map[string]*schema.Schema{
+ "first_name": {Type: schema.TypeString, Required: true},
+ "last_name": {Type: schema.TypeString, Required: true},
+ "email": {Type: schema.TypeString, Required: true},
+ "team_ids": {Type: schema.TypeList, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}},
+ }, map[string]interface{}{
+ "first_name": "John",
+ "last_name": "Doe",
+ "email": "johndoe@example.com",
+ "team_ids": []interface{}{"team1", "team2"},
+ })
+
+ user := toUser(resourceData)
+
+ expectedUser := &models.V1UserEntity{
+ Metadata: &models.V1ObjectMeta{
+ Name: "John Doe",
+ },
+ Spec: &models.V1UserSpecEntity{
+ EmailID: "johndoe@example.com",
+ FirstName: "John",
+ LastName: "Doe",
+ Teams: []string{"team1", "team2"},
+ },
+ }
+
+ assert.Equal(t, expectedUser, user)
+}
+
+func TestToUserNoTeams(t *testing.T) {
+ resourceData := schema.TestResourceDataRaw(t, map[string]*schema.Schema{
+ "first_name": {Type: schema.TypeString, Required: true},
+ "last_name": {Type: schema.TypeString, Required: true},
+ "email": {Type: schema.TypeString, Required: true},
+ "team_ids": {Type: schema.TypeList, Optional: true, Elem: &schema.Schema{Type: schema.TypeString}},
+ }, map[string]interface{}{
+ "first_name": "Alice",
+ "last_name": "Smith",
+ "email": "alice@example.com",
+ })
+
+ user := toUser(resourceData)
+
+ expectedUser := &models.V1UserEntity{
+ Metadata: &models.V1ObjectMeta{
+ Name: "Alice Smith",
+ },
+ Spec: &models.V1UserSpecEntity{
+ EmailID: "alice@example.com",
+ FirstName: "Alice",
+ LastName: "Smith",
+ Teams: nil,
+ },
+ }
+
+ assert.Equal(t, expectedUser, user)
+}
+
+func TestSetToStringArray(t *testing.T) {
+ // Create a schema.Set with some string values
+ input := schema.NewSet(schema.HashString, []interface{}{"id1", "id2", "id3"})
+
+ // Call the function with the set
+ result := setToStringArray(input)
+
+ // Define the expected output
+ expected := []string{"id1", "id2", "id3"}
+
+ // Assert that the result matches the expected output
+ assert.ElementsMatch(t, expected, result)
+}
+
+func TestSetToStringArrayEmptySet(t *testing.T) {
+ // Create an empty schema.Set
+ input := schema.NewSet(schema.HashString, []interface{}{})
+
+ // Call the function with the empty set
+ result := setToStringArray(input)
+
+ // Define the expected output for an empty set
+ expected := []string{}
+
+ // Assert that the result matches the expected output
+ assert.Equal(t, expected, result)
+}
+
+func TestToUserWorkspaceRoleMappingEmpty(t *testing.T) {
+ d := schema.TestResourceDataRaw(t, map[string]*schema.Schema{
+ "workspace_role": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "workspace": {
+ Type: schema.TypeSet,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id": {Type: schema.TypeString},
+ "role_ids": {Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}},
+ },
+ },
+ },
+ },
+ },
+ },
+ }, map[string]interface{}{"workspace_role": []interface{}{}})
+
+ result := toUserWorkspaceRoleMapping(d)
+ expected := &models.V1WorkspacesRolesPatch{Workspaces: []*models.V1WorkspaceRolesPatch{}}
+
+ assert.Equal(t, expected, result)
+}
diff --git a/templates/resources/user.md.tmpl b/templates/resources/user.md.tmpl
new file mode 100644
index 00000000..c399cc49
--- /dev/null
+++ b/templates/resources/user.md.tmpl
@@ -0,0 +1,92 @@
+---
+page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
+subcategory: ""
+description: |-
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+---
+
+# {{.Name}} ({{.Type}})
+
+{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
+
+You can learn more about managing users in Palette by reviewing the [Users](https://docs.spectrocloud.com/user-management/) guide.
+
+## Example Usage
+
+An example of creating a user resource with assigned teams and custom roles in Palette.
+
+```hcl
+resource "spectrocloud_user" "user-test"{
+ first_name = "tf"
+ last_name = "test"
+ email = "test-tf@spectrocloud.com"
+ team_ids = [data.spectrocloud_team.team2.id]
+ project_role {
+ project_id = data.spectrocloud_project.default.id
+ role_ids = [for r in data.spectrocloud_role.app_roles : r.id]
+ }
+ project_role {
+ project_id = data.spectrocloud_project.ranjith.id
+ role_ids = [for r in data.spectrocloud_role.app_roles : r.id]
+ }
+
+ tenant_role = [for t in data.spectrocloud_role.tenant_roles : t.id]
+
+ workspace_role {
+ project_id = data.spectrocloud_project.default.id
+ workspace {
+ id = data.spectrocloud_workspace.workspace.id
+ role_ids = [for w in data.spectrocloud_role.workspace_roles : w.id]
+ }
+ workspace {
+ id = data.spectrocloud_workspace.workspace2.id
+ role_ids = ["66fbea622947f81fc26983e6"]
+ }
+ }
+
+ resource_role {
+ project_ids = [data.spectrocloud_project.default.id, data.spectrocloud_project.ranjith.id]
+ filter_ids = [data.spectrocloud_filter.filter.id]
+ role_ids = [for r in data.spectrocloud_role.resource_roles : r.id]
+ }
+
+ resource_role {
+ project_ids = [data.spectrocloud_project.ranjith.id]
+ filter_ids = [data.spectrocloud_filter.filter.id]
+ role_ids = [for re in data.spectrocloud_role.resource_roles_editor : re.id]
+ }
+
+}
+```
+
+The example below demonstrates how to create an user with only assigned teams.
+
+```hcl
+resource "spectrocloud_user" "user-test"{
+ first_name = "tf"
+ last_name = "test"
+ email = "test-tf@spectrocloud.com"
+ team_ids = [data.spectrocloud_team.team2.id]
+}
+
+
+```
+
+### Importing existing user states
+
+```hcl
+# import existing user example
+ import {
+ to = spectrocloud_user.test_user
+ id = "{userUID}"
+ }
+
+# To generate TF configuration.
+ terraform plan -generate-config-out=test_user.tf
+
+# To import State file
+ terraform import spectrocloud_user.test_user {userUID}
+```
+
+
+{{ .SchemaMarkdown | trimspace }}
\ No newline at end of file