Skip to content

Commit

Permalink
Merge pull request #282 from NetApp/137-new-data-source-security_cert…
Browse files Browse the repository at this point in the history
…ificates

137 new data source security certificates
  • Loading branch information
carchi8py authored Oct 14, 2024
2 parents 4dce224 + d1a01b5 commit 497113f
Show file tree
Hide file tree
Showing 15 changed files with 802 additions and 17 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ FEATURES:
* **New Data Source:** `netapp-ontap_qtrees` ([#83](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/83))
* **New Data Source:** `netapp-ontap_volume_efficiency_policy` ([#81](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/81))
* **New Data Source:** `netapp-ontap_volume_efficiency_policies` ([#81](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/81))
* **New Data Source:** `netapp-ontap_security_certificate` ([#137](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/137))
* **New Data Source:** `netapp-ontap_security_certificates` ([#137](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/137))
* **New Resource:** `netapp-ontap_volume_efficiency_policy` ([#80](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/80))
* **New Resource:** `netapp-ontap_quota_rule` ([#136](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/136))
* **New Resource:** `netapp-ontap_volume_file` ([#5](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/5))
Expand Down
50 changes: 50 additions & 0 deletions docs/data-sources/security_certificate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "netapp-ontap_security_certificate Data Source - terraform-provider-netapp-ontap"
subcategory: "Security"
description: |-
Retrieve Security Certificate data source
---

# netapp-ontap_security_certificate (Data Source)

Retrieve Security Certificate data source

### Related ONTAP commands
* security certificate show

## Example Usage

```terraform
# retrieving a certificate using its unique name
data "netapp-ontap_security_certificate" "security_certificate1" {
# required to know which system to interface with
cx_profile_name = "cluster5"
name = "tfsvm_17B9B4C1696136FC"
}
```

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

### Required

- `cx_profile_name` (String) Connection profile name
- `name` (String) The unique name of the security certificate per SVM.

### Optional

- `svm_name` (String) SVM name in which the certificate is installed.

### Read-Only

- `common_name` (String) Common name of the certificate.
- `type` (String) Type of Certificate.
- `ca` (String) Certificate authority.
- `expiry_time` (String) Certificate expiration time, in ISO 8601 duration format or date and time format.
- `hash_function` (String) Hashing function.
- `id` (String) Certificate uuid.
- `key_size` (Number) Key size of the certificate in bits.
- `public_certificate` (String) Public key Certificate in PEM format.
- `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.
- `serial_number` (String) Serial number of certificate.
92 changes: 92 additions & 0 deletions docs/data-sources/security_certificates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "netapp-ontap_security_certificates Data Source - terraform-provider-netapp-ontap"
subcategory: "Security"
description: |-
Retrieve Security Certificates data source
---

# netapp-ontap_security_certificates (Data Source)

Retrieve Security Certificates data source

### Related ONTAP commands
* security certificate show

## Example Usage

```terraform
# retrieving certificates installed on a specific SVM
data "netapp-ontap_security_certificates" "security_certificates1" {
# required to know which system to interface with
cx_profile_name = "cluster5"
filter = {
scope = "svm"
svm_name = "tfsvm"
}
}
# retrieving all certificates installed at cluster-scope
data "netapp-ontap_security_certificates" "security_certificates2" {
# required to know which system to interface with
cx_profile_name = "cluster5"
filter = {
scope = "cluster"
}
}
# retrieving certificate using its common_name and type
data "netapp-ontap_security_certificates" "security_certificates3" {
# required to know which system to interface with
cx_profile_name = "cluster5"
filter = {
common_name = "tfsvm"
type = "server"
}
}
```

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

### Required

- `cx_profile_name` (String) Connection profile name

### Optional

- `filter` (Attributes) (see [below for nested schema](#nestedatt--filter))

### Read-Only

- `security_certificates` (Attributes List) (see [below for nested schema](#nestedatt--security_certificates))

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

Optional:

- `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.
- `svm_name` (String) SVM name in which the certificate is installed.
- `common_name` (String) Common name of the certificate.
- `type` (String) Type of certificate.


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

Read-Only:

- `cx_profile_name` (String) Connection profile name.
- `name` (String) The unique name of the security certificate per SVM.
- `common_name` (String) Common name of the certificate.
- `type` (String) Type of certificate.
- `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.
- `expiry_time` (String) Certificate expiration time, in ISO 8601 duration format or date and time format.
- `hash_function` (String) Hashing function.
- `key_size` (Number) Key size of the certificate in bits.
- `public_certificate` (String) Public key Certificate in PEM format.
- `ca` (String) Certificate authority.
- `serial_number` (String) Serial number of certificate.
- `svm_name` (String) SVM name in which the certificate is installed.
- `id` (String) Certificate uuid.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# retrieving a certificate using its unique name
data "netapp-ontap_security_certificate" "security_certificate1" {
# required to know which system to interface with
cx_profile_name = "cluster5"
name = "tfsvm_ca_cert1"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# retrieving certificates installed on a specific SVM
data "netapp-ontap_security_certificates" "security_certificates1" {
# required to know which system to interface with
cx_profile_name = "cluster5"
filter = {
scope = "svm"
svm_name = "tfsvm"
}
}

# retrieving all certificates installed at cluster-scope
data "netapp-ontap_security_certificates" "security_certificates2" {
# required to know which system to interface with
cx_profile_name = "cluster5"
filter = {
scope = "cluster"
}
}

# retrieving certificate using its common_name and type
data "netapp-ontap_security_certificates" "security_certificates3" {
# required to know which system to interface with
cx_profile_name = "cluster5"
filter = {
common_name = "tfsvm"
type = "server"
}
}
7 changes: 7 additions & 0 deletions examples/provider/provider.tf
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ provider "netapp-ontap" {
password = var.password
validate_certs = var.validate_certs
},
{
name = "cluster5"
hostname = "********2"
username = var.username
password = var.password
validate_certs = var.validate_certs
},
{
name = "clustercifs"
hostname = "********189"
Expand Down
168 changes: 168 additions & 0 deletions internal/interfaces/security_certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package interfaces

import (
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/mitchellh/mapstructure"
"github.com/netapp/terraform-provider-netapp-ontap/internal/restclient"
"github.com/netapp/terraform-provider-netapp-ontap/internal/utils"
)

// SecurityCertificateGetDataModelONTAP describes the GET record data model using go types for mapping.
type SecurityCertificateGetDataModelONTAP struct {
Name string `mapstructure:"name"`
UUID string `mapstructure:"uuid"`
CommonName string `mapstructure:"common_name"`
SVM svm `mapstructure:"svm"`
Scope string `mapstructure:"scope"`
Type string `mapstructure:"type"`
SerialNumber string `mapstructure:"serial_number"`
CA string `mapstructure:"ca"`
HashFunction string `mapstructure:"hash_function"`
KeySize int64 `mapstructure:"key_size"`
ExpiryTime string `mapstructure:"expiry_time"`
PublicCertificate string `mapstructure:"public_certificate"`
}

// SecurityCertificateDataSourceFilterModel describes the data source data model for queries.
type SecurityCertificateDataSourceFilterModel struct {
SVMName string `mapstructure:"svm.name"`
Scope string `mapstructure:"scope"`
CommonName string `mapstructure:"common_name"`
Type string `mapstructure:"type"`
}

// GetSecurityCertificate to get security_certificate info
// Retrieves the certificate with the given name and/or (common name & type)
func GetSecurityCertificate(errorHandler *utils.ErrorHandler, r restclient.RestClient, version versionModelONTAP, name string, common_name string, type_ string) (*SecurityCertificateGetDataModelONTAP, error) {
api := "security/certificates"
query := r.NewQuery()
if name != "" {
query.Set("name", name)
} else {
query.Set("common_name", common_name)
query.Set("type", type_)
}
var fields = []string{"uuid", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time", "public_certificate"}
if version.Generation == 9 && version.Major >= 8 {
fields = append(fields, "name")
}
query.Fields(fields)

statusCode, response, err := r.GetNilOrOneRecord(api, query, nil)
if err == nil && response == nil {
err = fmt.Errorf("no response for GET %s", api)
}
if err != nil {
if strings.Contains(err.Error(), "or more records when only one is expected") {
return nil, errorHandler.MakeAndReportError("error reading security_certificate info", "Duplicate records found with the same common_name.")
}
return nil, errorHandler.MakeAndReportError("error reading security_certificate info", fmt.Sprintf("error on GET %s: %s, statusCode %d", api, err, statusCode))
}

var dataONTAP SecurityCertificateGetDataModelONTAP
if err := mapstructure.Decode(response, &dataONTAP); err != nil {
return nil, errorHandler.MakeAndReportError(fmt.Sprintf("failed to decode response from GET %s", api),
fmt.Sprintf("error: %s, statusCode %d, response %#v", err, statusCode, response))
}
tflog.Debug(errorHandler.Ctx, fmt.Sprintf("Read security_certificate data source: %#v", dataONTAP))
return &dataONTAP, nil
}

// GetSecurityCertificateByName to get security_certificate info
// Retrieves the certificate using its unique name
func GetSecurityCertificateByName(errorHandler *utils.ErrorHandler, r restclient.RestClient, version versionModelONTAP, name string) (*SecurityCertificateGetDataModelONTAP, error) {
api := "security/certificates"
query := r.NewQuery()
if version.Generation == 9 && version.Major >= 8 {
query.Add("name", name)
} else {
return nil, errorHandler.MakeAndReportError("error reading security_certificate info", "Attribute 'name' requires ONTAP 9.8 or later.")
}
query.Fields([]string{"uuid", "name", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time", "public_certificate"})

statusCode, response, err := r.GetNilOrOneRecord(api, query, nil)
if err == nil && response == nil {
err = fmt.Errorf("no response for GET %s", api)
}
if err != nil {
return nil, errorHandler.MakeAndReportError("error reading security_certificate info", fmt.Sprintf("error on GET %s: %s, statusCode %d", api, err, statusCode))
}

var dataONTAP SecurityCertificateGetDataModelONTAP
if err := mapstructure.Decode(response, &dataONTAP); err != nil {
return nil, errorHandler.MakeAndReportError(fmt.Sprintf("failed to decode response from GET %s", api),
fmt.Sprintf("error: %s, statusCode %d, response %#v", err, statusCode, response))
}
tflog.Debug(errorHandler.Ctx, fmt.Sprintf("Read security_certificate data source: %#v", dataONTAP))
return &dataONTAP, nil
}

// GetSecurityCertificateByUUID to get security_certificate info
// Retrieves the certificate using its UUID
func GetSecurityCertificateByUUID(errorHandler *utils.ErrorHandler, r restclient.RestClient, version versionModelONTAP, uuid string) (*SecurityCertificateGetDataModelONTAP, error) {
api := "security/certificates/" + uuid
query := r.NewQuery()
var fields = []string{"uuid", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time", "public_certificate"}
if version.Generation == 9 && version.Major >= 8 {
fields = append(fields, "name")
}
query.Fields(fields)
statusCode, response, err := r.GetNilOrOneRecord(api, query, nil)
if err == nil && response == nil {
err = fmt.Errorf("no response for GET %s", api)
}
if err != nil {
return nil, errorHandler.MakeAndReportError("error reading security_certificate info", fmt.Sprintf("error on GET %s: %s, statusCode %d", api, err, statusCode))
}

var dataONTAP SecurityCertificateGetDataModelONTAP
if err := mapstructure.Decode(response, &dataONTAP); err != nil {
return nil, errorHandler.MakeAndReportError(fmt.Sprintf("failed to decode response from GET %s", api),
fmt.Sprintf("error: %s, statusCode %d, response %#v", err, statusCode, response))
}
tflog.Debug(errorHandler.Ctx, fmt.Sprintf("Read security_certificate data source: %#v", dataONTAP))
return &dataONTAP, nil
}

// GetSecurityCertificates to get security_certificate info for all resources matching a filter
func GetSecurityCertificates(errorHandler *utils.ErrorHandler, r restclient.RestClient, version versionModelONTAP, filter *SecurityCertificateDataSourceFilterModel) ([]SecurityCertificateGetDataModelONTAP, error) {
api := "security/certificates"
query := r.NewQuery()
var fields = []string{"uuid", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time", "public_certificate"}
if version.Generation == 9 && version.Major >= 8 {
fields = append(fields, "name")
}
query.Fields(fields)

if filter != nil {
var filterMap map[string]interface{}
if err := mapstructure.Decode(filter, &filterMap); err != nil {
return nil, errorHandler.MakeAndReportError("error encoding security_certificates filter info", fmt.Sprintf("error on filter %#v: %s", filter, err))
}
query.SetValues(filterMap)
}

tflog.Debug(errorHandler.Ctx, fmt.Sprintf("security certificates filter: %+v", query))
statusCode, response, err := r.GetZeroOrMoreRecords(api, query, nil)
if err == nil && response == nil {
err = fmt.Errorf("no response for GET %s", api)
}
if err != nil {
return nil, errorHandler.MakeAndReportError("error reading security_certificates info", fmt.Sprintf("error on GET %s: %s, statusCode %d", api, err, statusCode))
}

var dataONTAP []SecurityCertificateGetDataModelONTAP
for _, info := range response {
var record SecurityCertificateGetDataModelONTAP
if err := mapstructure.Decode(info, &record); err != nil {
return nil, errorHandler.MakeAndReportError(fmt.Sprintf("failed to decode response from GET %s", api),
fmt.Sprintf("error: %s, statusCode %d, info %#v", err, statusCode, info))
}
dataONTAP = append(dataONTAP, record)
}
tflog.Debug(errorHandler.Ctx, fmt.Sprintf("Read security_certificates data source: %#v", dataONTAP))
return dataONTAP, nil
}
2 changes: 2 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ func (p *ONTAPProvider) DataSources(ctx context.Context) []func() datasource.Dat
protocols.NewProtocolsSanLunMapsDataSource,
security.NewSecurityAccountDataSource,
security.NewSecurityAccountsDataSource,
security.NewSecurityCertificateDataSource,
security.NewSecurityCertificatesDataSource,
security.NewSecurityRoleDataSource,
security.NewSecurityRolesDataSource,
security.NewSecurityLoginMessageDataSource,
Expand Down
Loading

0 comments on commit 497113f

Please sign in to comment.