Skip to content

Commit

Permalink
Merge pull request #275 from NetApp/140-new-resource-securityroles-1
Browse files Browse the repository at this point in the history
140 new resource securityroles 1
  • Loading branch information
wenjun666 authored Sep 16, 2024
2 parents 813ccca + 2767dd0 commit 57eed30
Show file tree
Hide file tree
Showing 13 changed files with 978 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ FEATURES:
* **New Resource:** `netapp-ontap_volume_efficiency_policies` ([#80](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/80))
* **New Resource:** `netapp-ontap_quota_rules` ([#136](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/136))
* **New Resource:** `netapp-ontap_volumes_files` ([#5](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/5))
* **New Resource:** `netapp-ontap_security_roles` ([#140](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/140))
* **New Resource:** `netapp-ontap_storage_qtrees` ([#82](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/82))
* **New Resource:** `netapp-ontap_qos_policies` ([#76](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/76))
* **New Resource:** `netapp-security_login_messages` ([#18](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/18))
Expand Down
16 changes: 11 additions & 5 deletions docs/data-sources/security_role.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "netapp-ontap_security_role Data Source - terraform-provider-netapp-ontap"
subcategory: "Security"
subcategory: ""
description: |-
Retrieves a Security role
SecurityRole data source
---

# netapp-ontap_security_role (Data Source)

SecurityRole data source
Retrieve a security role

### Related ONTAP commands
```commandline
* security login role show
```

## Example Usage

```terraform
data "netapp-ontap_security_role" "security_role" {
# required to know which system to interface with
Expand All @@ -29,7 +35,7 @@ data "netapp-ontap_security_role" "security_role" {
- `name` (String) SecurityRole name
- `svm_name` (String) IPInterface svm name

### Optional
### Read-Only

- `builtin` (Boolean) Indicates if this is a built-in (pre-defined) role which cannot be modified or deleted.
- `privileges` (Attributes Set) The list of privileges that this role has been granted. (see [below for nested schema](#nestedatt--privileges))
Expand All @@ -38,7 +44,7 @@ data "netapp-ontap_security_role" "security_role" {
<a id="nestedatt--privileges"></a>
### Nested Schema for `privileges`

Optional:
Read-Only:

- `access` (String) Access level for the REST endpoint or command/command directory path. If it denotes the access level for a command/command directory path, the only supported enum values are 'none','readonly' and 'all'.
- `path` (String) Either of REST URI/endpoint OR command/command directory path.
25 changes: 17 additions & 8 deletions docs/data-sources/security_roles.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,33 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "netapp-ontap_security_roles Data Source - terraform-provider-netapp-ontap"
subcategory: "Security"
subcategory: ""
description: |-
Retrieves Security Rules
SecurityRules data source
---

# netapp-ontap_security_roles (Data Source)

SecurityRules data source
Retreive one or more security roles by filter

### Related ONTAP commands
```commandline
* security login role show
```


## Example Usage

```terraform
data "netapp-ontap_security_roles" "security_roles" {
# required to know which system to interface with
cx_profile_name = "cluster4"
filter = {
svm_name = "svm_1"
scope = "svm"
svm_name = "acc_test"
scope = "cluster"
}
}

```

<!-- schema generated by tfplugindocs -->
## Schema
Expand Down Expand Up @@ -54,7 +63,7 @@ Required:
- `name` (String) SecurityRule name
- `svm_name` (String) IPInterface svm name

Optional:
Read-Only:

- `builtin` (Boolean) Indicates if this is a built-in (pre-defined) role which cannot be modified or deleted.
- `privileges` (Attributes Set) The list of privileges that this role has been granted. (see [below for nested schema](#nestedatt--security_roles--privileges))
Expand All @@ -63,7 +72,7 @@ Optional:
<a id="nestedatt--security_roles--privileges"></a>
### Nested Schema for `security_roles.privileges`

Optional:
Read-Only:

- `access` (String) Access level for the REST endpoint or command/command directory path. If it denotes the access level for a command/command directory path, the only supported enum values are 'none','readonly' and 'all'.
- `path` (String) Either of REST URI/endpoint OR command/command directory path.
104 changes: 104 additions & 0 deletions docs/resources/security_roles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "netapp-ontap_security_roles Resource - terraform-provider-netapp-ontap"
subcategory: "Security"
description: |-
SecurityRoles resource
---

# netapp-ontap_security_roles (Resource)

Create/Modify/Delete a Security role

## Supported Platforms
* On-perm ONTAP system 9.6 or higher

## Example Usage

```terraform
resource "netapp-ontap_security_roles" "security_role" {
# required to know which system to interface with
cx_profile_name = "cluster3"
name = "testme"
svm_name = "temp"
privileges = [
{
access = "all"
path = "lun"
},
{
access = "all"
path = "vserver"
query = "-vserver acc_test"
}
]
}
```

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

### Required

- `cx_profile_name` (String) Connection profile name
- `name` (String) SecurityRole name

### Optional

- `privileges` (Attributes Set) The list of privileges that this role has been granted. (see [below for nested schema](#nestedatt--privileges))
- `svm_name` (String) SecurityRole svm name

### Read-Only

- `builtin` (Boolean) Indicates if this is a built-in (pre-defined) role which cannot be modified or deleted.
- `id` (String) The unique identifier of the security role.
- `scope` (String) Scope of the entity. Set to 'cluster' for cluster owned objects and to 'svm' for SVM owned objects.

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

Optional:

- `access` (String) Access level for the REST endpoint or command/command directory path. If it denotes the access level for a command/command directory path, the only supported enum values are 'none','readonly' and 'all'.
- `path` (String) Either of REST URI/endpoint OR command/command directory path.
- `query` (String) Requires 9.11 system or above. Optional attribute that can be specified only if the 'path' attribute refers to a command/command directory path. The privilege tuple implicitly defines a set of objects the role can or cannot access at the specified access level. The query further reduces this set of objects to a subset of objects that the role is allowed to access. The query attribute must be applicable to the command/command directory specified by the 'path' attribute. It is defined using one or more parameters of the command/command directory path specified by the 'path' attribute.

## Import
This Resource supports import, which allows you to import existing security role into the state of this resoruce.
Import require a unique ID composed of the role name, svm_name and cx_profile_name, separated by a comma.
id = `name`,`svm_name`,`cx_profile_name`

### Terraform Import
For example
```shell
terraform import netapp-ontap_security_roles.example role1,svm1,cluster1
```

!> The terraform import CLI command can only import resources into the state. Importing via the CLI does not generate configuration. If you want to generate the accompanying configuration for imported resources, use the import block instead.

### Terraform Import Block
This requires Terraform 1.5 or higher, and will auto create the configuration for you

First create the block
```terraform
import {
to = netapp-ontap_security_roles.role_import
id = "role1,svm1,cluster1"
}
```
Next run, this will auto create the configuration for you
```shell
terraform plan -generate-config-out=generated.tf
```
This will generate a file called generated.tf, which will contain the configuration for the imported resource
```terraform
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
# __generated__ by Terraform from "role1,svm1,cluster1"
resource "netapp-ontap_security_roles" "role1_import" {
cx_profile_name = "cluster1"
name = "role1"
svm_name = "svm1"
...
}
```
1 change: 1 addition & 0 deletions examples/resources/netapp-ontap_security_roles/provider.tf
17 changes: 17 additions & 0 deletions examples/resources/netapp-ontap_security_roles/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
resource "netapp-ontap_security_roles" "security_role" {
# required to know which system to interface with
cx_profile_name = "cluster3"
name = "testme"
svm_name = "temp"
privileges = [
{
access = "all"
path = "lun"
},
{
access = "all"
path = "vserver"
query = "-vserver acc_test"
}
]
}
107 changes: 98 additions & 9 deletions internal/interfaces/security_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package interfaces

import (
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/mitchellh/mapstructure"
Expand All @@ -14,14 +15,15 @@ type SecurityRoleGetDataModelONTAP struct {
Name string `mapstructure:"name"`
UUID string `mapstructure:"uuid"`
Owner SecurityRoleOwner `mapstructure:"owner"`
Privileges []SecurityRolePrivileges `mapstructure:"privileges"`
Privileges []SecurityRolePrivileges `mapstructure:"privileges,omitempty"`
Scope string `mapstructure:"scope"`
Builtin bool `mapstructure:"builtin"`
}

type SecurityRolePrivileges struct {
Access string `mapstructure:"access"`
Path string `mapstructure:"path"`
Access string `mapstructure:"access,omitempty"`
Path string `mapstructure:"path,omitempty"`
Query string `mapstructure:"query,omitempty"`
}

type SecurityRoleOwner struct {
Expand All @@ -31,8 +33,21 @@ type SecurityRoleOwner struct {

// SecurityRoleResourceBodyDataModelONTAP describes the body data model using go types for mapping.
type SecurityRoleResourceBodyDataModelONTAP struct {
Name string `mapstructure:"name"`
SVM svm `mapstructure:"svm"`
Name string `mapstructure:"name"`
Owner svm `mapstructure:"owner"`
Privileges []SecurityRolePrivilegesListBodyDataModelONTAP `mapstructure:"privileges"`
}

type SecurityRolePrivilegesListBodyDataModelONTAP struct {
Access string `json:"access,omitempty"`
Path string `json:"path,omitempty"`
Query string `json:"query,omitempty"`
}

type SecurityRolePrivilegesBodyDataModelONTAP struct {
Access string `mapstructure:"access,omitempty"`
Path string `mapstructure:"path,omitempty"`
Query string `mapstructure:"query,omitempty"`
}

// SecurityRoleDataSourceFilterModel describes the data source data model for queries.
Expand Down Expand Up @@ -100,11 +115,12 @@ func GetSecurityRoles(errorHandler *utils.ErrorHandler, r restclient.RestClient,

// CreateSecurityRole to create security_role
func CreateSecurityRole(errorHandler *utils.ErrorHandler, r restclient.RestClient, body SecurityRoleResourceBodyDataModelONTAP) (*SecurityRoleGetDataModelONTAP, error) {
api := "api_url"
api := "security/roles"
var bodyMap map[string]interface{}
if err := mapstructure.Decode(body, &bodyMap); err != nil {
return nil, errorHandler.MakeAndReportError("error encoding security_role body", fmt.Sprintf("error on encoding %s body: %s, body: %#v", api, err, body))
}
log.Printf("body body!! %#v", bodyMap)
query := r.NewQuery()
query.Add("return_records", "true")
statusCode, response, err := r.CallCreateMethod(api, query, bodyMap)
Expand All @@ -120,12 +136,85 @@ func CreateSecurityRole(errorHandler *utils.ErrorHandler, r restclient.RestClien
return &dataONTAP, nil
}

// UpdateSecurityRole to update security_role
// Only privileges can be updated
func UpdateSecurityRole(errorHandler *utils.ErrorHandler, r restclient.RestClient, body SecurityRoleResourceBodyDataModelONTAP, name string, svmUUID string) error {
api := "security/roles/" + svmUUID + "/" + name
var bodyMap map[string]interface{}
if err := mapstructure.Decode(body, &bodyMap); err != nil {
return errorHandler.MakeAndReportError("error encoding security_role body", fmt.Sprintf("error on encoding %s body: %s, body: %#v", api, err, body))
}
statusCode, _, err := r.CallCreateMethod(api, nil, bodyMap)
if err != nil {
return errorHandler.MakeAndReportError("error creating security_role", fmt.Sprintf("error on POST %s: %s, statusCode %d", api, err, statusCode))
}

return nil
}

func CreateSecurityRolePrivileges(errorHandler *utils.ErrorHandler, r restclient.RestClient, privileges SecurityRolePrivilegesBodyDataModelONTAP, name string, svmUUID string) error {
api := "security/roles/" + svmUUID + "/" + name + "/privileges"
var bodyMap map[string]interface{}
if err := mapstructure.Decode(privileges, &bodyMap); err != nil {
return errorHandler.MakeAndReportError("error encoding security_role privileges body", fmt.Sprintf("error on encoding %s body: %s, body: %#v", api, err, privileges))
}
statusCode, _, err := r.CallCreateMethod(api, nil, bodyMap)
if err != nil {
return errorHandler.MakeAndReportError("error creating security_role privileges", fmt.Sprintf("error on POST %s: %s, statusCode %d", api, err, statusCode))
}

return nil
}

func UpdateSecurityRolePrivileges(errorHandler *utils.ErrorHandler, r restclient.RestClient, privileges SecurityRolePrivilegesBodyDataModelONTAP, name string, svmUUID string) error {
api := "security/roles/" + svmUUID + "/" + name + "/privileges/" + privileges.Path
var bodyMap map[string]interface{}
if err := mapstructure.Decode(privileges, &bodyMap); err != nil {
return errorHandler.MakeAndReportError("error encoding security_role privileges body", fmt.Sprintf("error on encoding %s body: %s, body: %#v", api, err, privileges))
}
// path is not supported in the body of a PATCH
delete(bodyMap, "path")
statusCode, _, err := r.CallUpdateMethod(api, nil, bodyMap)
if err != nil {
return errorHandler.MakeAndReportError("error updating security_role privileges", fmt.Sprintf("error on POST %s: %s, statusCode %d", api, err, statusCode))
}

return nil
}

func DeleteSecurityRolePrivileges(errorHandler *utils.ErrorHandler, r restclient.RestClient, path string, name string, svmUUID string) error {
api := "security/roles/" + svmUUID + "/" + name + "/privileges/" + path
statusCode, _, err := r.CallDeleteMethod(api, nil, nil)
if err != nil {
return errorHandler.MakeAndReportError("error deleting security_role privileges", fmt.Sprintf("error on POST %s: %s, statusCode %d", api, err, statusCode))
}

return nil
}

// DeleteSecurityRole to delete security_role
func DeleteSecurityRole(errorHandler *utils.ErrorHandler, r restclient.RestClient, uuid string) error {
api := "api_url"
statusCode, _, err := r.CallDeleteMethod(api+"/"+uuid, nil, nil)
func DeleteSecurityRole(errorHandler *utils.ErrorHandler, r restclient.RestClient, name string, svmUUID string) error {
api := "security/roles/" + svmUUID + "/" + name
statusCode, _, err := r.CallDeleteMethod(api, nil, nil)
if err != nil {
return errorHandler.MakeAndReportError("error deleting security_role", fmt.Sprintf("error on DELETE %s: %s, statusCode %d", api, err, statusCode))
}
return nil
}

// Difference returns the difference between two slices of SecurityRolePrivileges.
// It returns a slice containing all the elements in b that are not present in a.
func Difference(a, b []SecurityRolePrivileges) (diff []SecurityRolePrivileges) {
m := make(map[SecurityRolePrivileges]bool)

for _, s1Val := range a {
m[s1Val] = true
}

for _, s2Val := range b {
if _, ok := m[s2Val]; !ok {
diff = append(diff, s2Val)
}
}
return diff
}
Loading

0 comments on commit 57eed30

Please sign in to comment.