Skip to content

Commit

Permalink
feat: add support for user group resources
Browse files Browse the repository at this point in the history
Signed-off-by: Michal Wasilewski <[email protected]>
  • Loading branch information
mwasilew2 committed Oct 4, 2023
1 parent 0d9812b commit 30b32bc
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 0 deletions.
47 changes: 47 additions & 0 deletions docs/resources/user_group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "spacelift_user_group Resource - terraform-provider-spacelift"
subcategory: ""
description: |-
spacelift_user_group represents a Spacelift user group - a collection of users as provided by your Identity Provider (IdP). If you assign permissions to a user group, all users in the group will have those permissions, unless the user's permissions are higher than the group's permissions.
---

# spacelift_user_group (Resource)

`spacelift_user_group` represents a Spacelift **user group** - a collection of users as provided by your Identity Provider (IdP). If you assign permissions to a user group, all users in the group will have those permissions, unless the user's permissions are higher than the group's permissions.

## Example Usage

```terraform
resource "spacelift_user_group" "test" {
name = "test"
access {
space_id = "root"
level = "ADMIN"
}
access {
space_id = "legacy"
level = "ADMIN"
}
}
```

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

### Required

- `access` (Block List, Min: 1) (see [below for nested schema](#nestedblock--access))
- `name` (String)

### Read-Only

- `id` (String) The ID of this resource.

<a id="nestedblock--access"></a>
### Nested Schema for `access`

Required:

- `level` (String)
- `space_id` (String)
11 changes: 11 additions & 0 deletions examples/resources/spacelift_user_group/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
resource "spacelift_user_group" "test" {
name = "test"
access {
space_id = "root"
level = "ADMIN"
}
access {
space_id = "legacy"
level = "ADMIN"
}
}
12 changes: 12 additions & 0 deletions spacelift/internal/structs/user_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package structs

type SpaceAccessRule struct {
Space string `graphql:"space"`
SpaceAccessLevel string `graphql:"spaceAccessLevel"`
}

type UserGroup struct {
ID string `graphql:"id"`
Name string `graphql:"groupName"`
AccessRules []SpaceAccessRule `graphql:"accessRules"`
}
20 changes: 20 additions & 0 deletions spacelift/internal/structs/user_group_input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package structs

import "github.com/shurcooL/graphql"

type SpaceAccessLevel string

type SpaceAccessRuleInput struct {
Space graphql.ID `json:"space"`
SpaceAccessLevel SpaceAccessLevel `json:"spaceAccessLevel"`
}

type ManagedUserGroupCreateInput struct {
Name graphql.String `json:"groupName"`
AccessRules []SpaceAccessRuleInput `json:"accessRules"`
}

type ManagedUserGroupUpdateInput struct {
ID graphql.ID `json:"id"`
AccessRules []SpaceAccessRuleInput `json:"accessRules"`
}
1 change: 1 addition & 0 deletions spacelift/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ func Provider(commit, version string) plugin.ProviderFunc {
"spacelift_stack_aws_role": resourceStackAWSRole(), // deprecated
"spacelift_stack_gcp_service_account": resourceStackGCPServiceAccount(), // deprecated
"spacelift_terraform_provider": resourceTerraformProvider(),
"spacelift_user_group": resourceUserGroup(),
"spacelift_vcs_agent_pool": resourceVCSAgentPool(),
"spacelift_webhook": resourceWebhook(),
"spacelift_named_webhook": resourceNamedWebhook(),
Expand Down
173 changes: 173 additions & 0 deletions spacelift/resource_user_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package spacelift

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/shurcooL/graphql"

"github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal"
"github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal/structs"
"github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal/validations"
)

var validAccessLevels = []string{
"READ",
"WRITE",
"ADMIN",
}

func resourceUserGroup() *schema.Resource {
return &schema.Resource{
Description: "" +
"`spacelift_user_group` represents a Spacelift **user group** - " +
"a collection of users as provided by your Identity Provider (IdP). " +
"If you assign permissions to a user group, all users in the group " +
"will have those permissions, unless the user's permissions are higher than " +
"the group's permissions.",
CreateContext: resourceUserGroupCreate,
ReadContext: resourceUserGroupRead,
UpdateContext: resourceUserGroupUpdate,
DeleteContext: resourceUserGroupDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateDiagFunc: validations.DisallowEmptyString,
},
"access": {

Type: schema.TypeList,
MinItems: 1,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"space_id": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validations.DisallowEmptyString,
},
"level": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(validAccessLevels, false),
},
},
},
},
},
}
}

func resourceUserGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var mutation struct {
UserGroup *structs.UserGroup `graphql:"managedUserGroupCreate(input: $input)"`
}

variables := map[string]interface{}{
"input": structs.ManagedUserGroupCreateInput{
Name: toString(d.Get("name")),
AccessRules: getAccessRules(d),
},
}

if err := meta.(*internal.Client).Mutate(ctx, "ManagedUserGroupCreate", &mutation, variables); err != nil {
return diag.Errorf("could not create user group %v: %v", toString(d.Get("name")), internal.FromSpaceliftError(err))
}

d.SetId(mutation.UserGroup.ID)

return resourceUserGroupRead(ctx, d, meta)
}

func resourceUserGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var query struct {
UserGroup *structs.UserGroup `graphql:"managedUserGroup(id: $id)"`
}

variables := map[string]interface{}{"id": graphql.ID(d.Id())}
if err := meta.(*internal.Client).Query(ctx, "ManagedUserGroupRead", &query, variables); err != nil {
return diag.Errorf("could not query for user group: %v", err)
}

userGroup := query.UserGroup
if userGroup == nil {
d.SetId("")
return nil
}

d.Set("name", userGroup.Name)

var accessList []interface{}

for _, a := range userGroup.AccessRules {
accessList = append(accessList, map[string]interface{}{
"space_id": a.Space,
"level": a.SpaceAccessLevel,
})
}

d.Set("access", accessList)

return nil

}

func resourceUserGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var mutation struct {
UserGroup *structs.UserGroup `graphql:"managedUserGroupUpdate(input: $input)"`
}

variables := map[string]interface{}{
"input": structs.ManagedUserGroupUpdateInput{
ID: toID(d.Id()),
AccessRules: getAccessRules(d),
},
}

var ret diag.Diagnostics

if err := meta.(*internal.Client).Mutate(ctx, "ManagedUserGroupUpdate", &mutation, variables); err != nil {
ret = append(ret, diag.Errorf("could not update user group: %v", internal.FromSpaceliftError(err))...)
}

ret = append(ret, resourceUserGroupRead(ctx, d, meta)...)

return ret
}

func resourceUserGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var mutation struct {
UserGroup *structs.UserGroup `graphql:"managedUserGroupDelete(id: $id)"`
}

variables := map[string]interface{}{"id": toID(d.Id())}

if err := meta.(*internal.Client).Mutate(ctx, "ManagedUserGroupDelete", &mutation, variables); err != nil {
return diag.Errorf("could not delete user group: %v", internal.FromSpaceliftError(err))
}

d.SetId("")

return nil
}

func getAccessRules(d *schema.ResourceData) []structs.SpaceAccessRuleInput {
var accessRules []structs.SpaceAccessRuleInput
for _, a := range d.Get("access").([]interface{}) {
access := a.(map[string]interface{})
accessRules = append(accessRules, structs.SpaceAccessRuleInput{
Space: toID(access["space_id"]),
SpaceAccessLevel: structs.SpaceAccessLevel(access["level"].(string)),
})
}
return accessRules
}

0 comments on commit 30b32bc

Please sign in to comment.