Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLT-1483: Added role management support in terraform #540

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions docs/resources/role.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
page_title: "spectrocloud_role Resource - terraform-provider-spectrocloud"
subcategory: ""
description: |-
The role resource allows you to manage roles in Palette.
---

# spectrocloud_role (Resource)

The role resource allows you to manage roles in Palette.

You can learn more about managing roles in Palette by reviewing the [Roles](https://docs.spectrocloud.com/glossary-all/#role) guide.

## Example Usage

```terraform
variable "roles" {
type = list(string)
default = ["Cluster Admin", "Cluster Profile Editor"]
}

# Data source loop to retrieve multiple roles
data "spectrocloud_role" "roles" {
for_each = toset(var.roles)
name = each.key
}

resource "spectrocloud_role" "custom_role" {
name = "Test Cluster Role"
type = "project"
permissions = flatten([for role in data.spectrocloud_role.roles : role.permissions])
}
```


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

### Required

- `name` (String) The name of the role.
- `permissions` (Set of String) The permission's assigned to the role.

### Optional

- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
- `type` (String) The role type. Allowed values are `project` or `tenant` or `project`

### Read-Only

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

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

Optional:

- `create` (String)
- `delete` (String)
- `update` (String)
28 changes: 28 additions & 0 deletions examples/resources/spectrocloud_role/providers.tf
Original file line number Diff line number Diff line change
@@ -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
}
16 changes: 16 additions & 0 deletions examples/resources/spectrocloud_role/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
variable "roles" {
type = list(string)
default = ["Cluster Admin", "Cluster Profile Editor"]
}

# Data source loop to retrieve multiple roles
data "spectrocloud_role" "roles" {
for_each = toset(var.roles)
name = each.key
}

resource "spectrocloud_role" "custom_role" {
name = "Test Cluster Role"
type = "project"
permissions = flatten([for role in data.spectrocloud_role.roles : role.permissions])
}
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/robfig/cron v1.2.0
github.com/spectrocloud/gomi v1.14.1-0.20240214074114-c19394812368
github.com/spectrocloud/hapi v1.14.1-0.20240214071352-81f589b1d86d
github.com/spectrocloud/palette-sdk-go v0.0.0-20241113133445-a5e87250e68d
github.com/spectrocloud/palette-sdk-go v0.0.0-20241113152438-58866fb1d5b7
github.com/stretchr/testify v1.9.0
gotest.tools v2.2.0+incompatible
k8s.io/api v0.23.5
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -600,8 +600,8 @@ github.com/spectrocloud/gomi v1.14.1-0.20240214074114-c19394812368 h1:eY0BOyEbGu
github.com/spectrocloud/gomi v1.14.1-0.20240214074114-c19394812368/go.mod h1:LlZ9We4kDaELYi7Is0SVmnySuDhwphJLS6ZT4wXxFIk=
github.com/spectrocloud/hapi v1.14.1-0.20240214071352-81f589b1d86d h1:OMRbHxMJ1a+G1BYzvUYuMM0wLkYJPdnEOFx16faQ/UY=
github.com/spectrocloud/hapi v1.14.1-0.20240214071352-81f589b1d86d/go.mod h1:MktpRPnSXDTHsQrFSD+daJFQ1zMLSR+1gWOL31jVvWE=
github.com/spectrocloud/palette-sdk-go v0.0.0-20241113133445-a5e87250e68d h1:RkU8p4K15zpH1FB2roV3yrpLiKn+/FcRxuxyJrXmtsk=
github.com/spectrocloud/palette-sdk-go v0.0.0-20241113133445-a5e87250e68d/go.mod h1:dSlNvDS0qwUWTbrYI6P8x981mcbbRHFrBg67v5zl81U=
github.com/spectrocloud/palette-sdk-go v0.0.0-20241113152438-58866fb1d5b7 h1:6qWLXVkq5Ry4tOt1pALAlEz4no8i5XS4SxB8IZEYq6k=
github.com/spectrocloud/palette-sdk-go v0.0.0-20241113152438-58866fb1d5b7/go.mod h1:dSlNvDS0qwUWTbrYI6P8x981mcbbRHFrBg67v5zl81U=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
Expand Down
1 change: 1 addition & 0 deletions spectrocloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ func New(_ string) func() *schema.Provider {
"spectrocloud_workspace": resourceWorkspace(),
"spectrocloud_alert": resourceAlert(),
"spectrocloud_ssh_key": resourceSSHKey(),
"spectrocloud_role": resourceRole(),
},
DataSourcesMap: map[string]*schema.Resource{
"spectrocloud_user": dataSourceUser(),
Expand Down
148 changes: 148 additions & 0 deletions spectrocloud/resource_role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package spectrocloud

import (
"context"
"fmt"
"github.com/spectrocloud/palette-sdk-go/api/models"
"time"

"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"
)

func resourceRole() *schema.Resource {
return &schema.Resource{
CreateContext: resourceRoleCreate,
ReadContext: resourceRoleRead,
UpdateContext: resourceRoleUpdate,
DeleteContext: resourceRoleDelete,
Description: "The role resource allows you to manage roles 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{
"name": {
Type: schema.TypeString,
Required: true,
Description: "The name of the role.",
},
"type": {
Type: schema.TypeString,
Optional: true,
Default: "project",
ValidateFunc: validation.StringInSlice([]string{"project", "tenant", "resource"}, false),
Description: "The role type. Allowed values are `project` or `tenant` or `project`",
},
"permissions": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "The permission's assigned to the role.",
},
},
}
}

func convertInterfaceSliceToStringSlice(input []interface{}) ([]string, error) {
var output []string
for _, item := range input {
str, ok := item.(string)
if !ok {
return nil, fmt.Errorf("item %v is not a string", item)
}
output = append(output, str)
}
return output, nil
}

func toRole(d *schema.ResourceData) *models.V1Role {
name := d.Get("name").(string)
roleType := d.Get("type").(string)
permission, _ := convertInterfaceSliceToStringSlice(d.Get("permissions").(*schema.Set).List())
return &models.V1Role{
Metadata: &models.V1ObjectMeta{
Annotations: map[string]string{
"scope": roleType,
},
LastModifiedTimestamp: models.V1Time{},
Name: name,
},
Spec: &models.V1RoleSpec{
Permissions: permission,
Scope: models.V1Scope(roleType),
Type: "user",
},
Status: &models.V1RoleStatus{
IsEnabled: true,
},
}
}

func flattenRole(d *schema.ResourceData, role *models.V1Role) error {
var err error
err = d.Set("name", role.Metadata.Name)
if err != nil {
return err
}
err = d.Set("type", role.Spec.Scope)
if err != nil {
return err
}
err = d.Set("permissions", role.Spec.Permissions)
if err != nil {
return err
}
return nil
}

func resourceRoleCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := getV1ClientWithResourceContext(m, "tenant")
var diags diag.Diagnostics
role := toRole(d)
uid, err := c.CreateRole(role)
if err != nil {
return diag.FromErr(err)
}
d.SetId(uid)
return diags
}

func resourceRoleRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := getV1ClientWithResourceContext(m, "tenant")
var diags diag.Diagnostics
role, err := c.GetRoleByID(d.Id())
if err != nil {
return diag.FromErr(err)
}
err = flattenRole(d, role)
if err != nil {
return diag.FromErr(err)
}
return diags
}

func resourceRoleUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := getV1ClientWithResourceContext(m, "tenant")
var diags diag.Diagnostics
role := toRole(d)
err := c.UpdateRole(role, d.Id())
if err != nil {
return diag.FromErr(err)
}
return diags
}

func resourceRoleDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := getV1ClientWithResourceContext(m, "tenant")
var diags diag.Diagnostics
err := c.DeleteRole(d.Id())
if err != nil {
return diag.FromErr(err)
}
return diags
}
36 changes: 36 additions & 0 deletions templates/resources/role.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
subcategory: ""
description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---

# {{.Name}} ({{.Type}})

{{ .Description | plainmarkdown | trimspace | prefixlines " " }}

You can learn more about managing roles in Palette by reviewing the [Roles](https://docs.spectrocloud.com/glossary-all/#role) guide.

## Example Usage

```terraform
variable "roles" {
type = list(string)
default = ["Cluster Admin", "Cluster Profile Editor"]
}

# Data source loop to retrieve multiple roles
data "spectrocloud_role" "roles" {
for_each = toset(var.roles)
name = each.key
}

resource "spectrocloud_role" "custom_role" {
name = "Test Cluster Role"
type = "project"
permissions = flatten([for role in data.spectrocloud_role.roles : role.permissions])
}
```


{{ .SchemaMarkdown | trimspace }}
Loading