From ede403e92cd20dc0f1ac5ab78b3e5fcefb4210ec Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 5 Sep 2024 15:56:39 +0530 Subject: [PATCH 01/23] security certificate data source --- CHANGELOG.md | 6 + examples/provider/provider.tf | 7 + examples/provider/terraform.tfvars | 4 +- internal/interfaces/security_certificate.go | 121 ++++++++++++ internal/provider/provider.go | 2 + .../security_certificate_data_source.go | 172 ++++++++++++++++++ main.go | 2 +- 7 files changed, 311 insertions(+), 3 deletions(-) create mode 100644 internal/interfaces/security_certificate.go create mode 100644 internal/provider/security/security_certificate_data_source.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 505325d5..54b636c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 2.0.0 () + +FEATURES: +* **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)) + # 1.2.0 () FEATURES: diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index 3e684d4a..760dd81e 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -40,6 +40,13 @@ provider "netapp-ontap" { password = var.password validate_certs = var.validate_certs }, + { + name = "cluster5" + hostname = "10.193.73.2" + username = var.username + password = var.password + validate_certs = var.validate_certs + }, { name = "clustercifs" hostname = "********189" diff --git a/examples/provider/terraform.tfvars b/examples/provider/terraform.tfvars index d36beb44..37b13f0f 100644 --- a/examples/provider/terraform.tfvars +++ b/examples/provider/terraform.tfvars @@ -1,3 +1,3 @@ username = "admin" -password = "xxxxxxxxx" -validate_certs = true +password = "Netapp1!" +validate_certs = false diff --git a/internal/interfaces/security_certificate.go b/internal/interfaces/security_certificate.go new file mode 100644 index 00000000..0f78c457 --- /dev/null +++ b/internal/interfaces/security_certificate.go @@ -0,0 +1,121 @@ +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"` +} + +// SecurityCertificateDataSourceFilterModel describes the data source data model for queries. +type SecurityCertificateDataSourceFilterModel struct { + SVMName string `mapstructure:"svm.name"` + Scope string `mapstructure:"scope"` +} + +// GetSecurityCertificate to get security_certificate info +func GetSecurityCertificate(errorHandler *utils.ErrorHandler, r restclient.RestClient, name string, common_name string) (*SecurityCertificateGetDataModelONTAP, error) { + api := "security/certificates" + query := r.NewQuery() + if name != "" { + query.Set("name", name) + } else if common_name != "" { + query.Set("common_name", common_name) + } else { + return nil, errorHandler.MakeAndLogError("Error: 'name' or 'common_name' are required parameters.") + } + query.Fields([]string{"uuid", "name", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time"}) + + 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 +func GetSecurityCertificateByUUID(errorHandler *utils.ErrorHandler, r restclient.RestClient, uuid string) (*SecurityCertificateGetDataModelONTAP, error) { + api := "security/certificates/" + uuid + query := r.NewQuery() + query.Fields([]string{"uuid", "name", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time"}) + 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, filter *SecurityCertificateDataSourceFilterModel) ([]SecurityCertificateGetDataModelONTAP, error) { + api := "security/certificates" + query := r.NewQuery() + query.Fields([]string{"uuid", "name", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time"}) + if filter != nil { + if filter.SVMName != "" { + query.Add("svm.name", filter.SVMName) + query.Add("scope", "svm") + } else { + // set scope to cluster + query.Add("scope", strings.ToLower(filter.Scope)) + } + } + + tflog.Debug(errorHandler.Ctx, fmt.Sprintf("security account 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 +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 58ab741a..36b1851e 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -234,6 +234,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, diff --git a/internal/provider/security/security_certificate_data_source.go b/internal/provider/security/security_certificate_data_source.go new file mode 100644 index 00000000..c591d2a2 --- /dev/null +++ b/internal/provider/security/security_certificate_data_source.go @@ -0,0 +1,172 @@ +package security + +import ( + "context" + "fmt" + "github.com/netapp/terraform-provider-netapp-ontap/internal/provider/connection" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netapp/terraform-provider-netapp-ontap/internal/interfaces" + "github.com/netapp/terraform-provider-netapp-ontap/internal/utils" +) + +// Ensure provider defined types fully satisfy framework interfaces +var _ datasource.DataSource = &SecurityCertificateDataSource{} + +// NewSecurityCertificateDataSource is a helper function to simplify the provider implementation. +func NewSecurityCertificateDataSource() datasource.DataSource { + return &SecurityCertificateDataSource{ + config: connection.ResourceOrDataSourceConfig{ + Name: "security_certificate", + }, + } +} + +// SecurityCertificateDataSource defines the data source implementation. +type SecurityCertificateDataSource struct { + config connection.ResourceOrDataSourceConfig +} + +// SecurityCertificateDataSourceModel describes the data source data model. +type SecurityCertificateDataSourceModel struct { + CxProfileName types.String `tfsdk:"cx_profile_name"` + Name types.String `tfsdk:"name"` + CommonName types.String `tfsdk:"common_name"` + SVMName types.String `tfsdk:"svm_name"` + Scope types.String `tfsdk:"scope"` + Type types.String `tfsdk:"type"` + SerialNumber types.String `tfsdk:"serial_number"` + CA types.String `tfsdk:"ca"` + HashFunction types.String `tfsdk:"hash_function"` + KeySize types.Int64 `tfsdk:"key_size"` + ExpiryTime types.String `tfsdk:"expiry_time"` + ID types.String `tfsdk:"id"` +} + +// Metadata returns the data source type name. +func (d *SecurityCertificateDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_" + d.config.Name +} + +// Schema defines the schema for the data source. +func (d *SecurityCertificateDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "SecurityCertificate data source", + + Attributes: map[string]schema.Attribute{ + "cx_profile_name": schema.StringAttribute{ + MarkdownDescription: "Connection profile name", + Required: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "The unique name of the security certificate per SVM.", + Optional: true, + }, + "common_name": schema.StringAttribute{ + MarkdownDescription: "Common name of the certificate.", + Optional: true, + }, + "svm_name": schema.StringAttribute{ + MarkdownDescription: "SVM name in which the certificate is installed.", + Optional: true, + }, + "scope": schema.StringAttribute{ + MarkdownDescription: "Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.", + Computed: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of Certificate.", + Computed: true, + }, + "serial_number": schema.StringAttribute{ + MarkdownDescription: "Serial number of certificate.", + Computed: true, + }, + "ca": schema.StringAttribute{ + MarkdownDescription: "Certificate authority.", + Computed: true, + }, + "hash_function": schema.StringAttribute{ + MarkdownDescription: "Hashing function.", + Computed: true, + }, + "key_size": schema.Int64Attribute{ + MarkdownDescription: "Key size of the certificate in bits.", + Computed: true, + }, + "expiry_time": schema.StringAttribute{ + MarkdownDescription: "Certificate expiration time, in ISO 8601 duration format or date and time format.", + Computed: true, + }, + "id": schema.StringAttribute{ + MarkdownDescription: "Certificate uuid.", + Computed: true, + }, + }, + } +} + +// Configure adds the provider configured client to the data source. +func (d *SecurityCertificateDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + config, ok := req.ProviderData.(connection.Config) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + } + d.config.ProviderConfig = config +} + +// Read refreshes the Terraform state with the latest data. +func (d *SecurityCertificateDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data SecurityCertificateDataSourceModel + + // Read Terraform configuration data into the model + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + errorHandler := utils.NewErrorHandler(ctx, &resp.Diagnostics) + // we need to defer setting the client until we can read the connection profile name + client, err := connection.GetRestClient(errorHandler, d.config, data.CxProfileName) + if err != nil { + // error reporting done inside NewClient + return + } + + restInfo, err := interfaces.GetSecurityCertificate(errorHandler, *client, data.Name.ValueString(), data.CommonName.ValueString()) + if err != nil { + // error reporting done inside GetSecurityCertificate + return + } + + data.Name = types.StringValue(restInfo.Name) + data.CommonName = types.StringValue(restInfo.CommonName) + data.SVMName = types.StringValue(restInfo.SVM.Name) + data.Scope = types.StringValue(restInfo.Scope) + data.Type = types.StringValue(restInfo.Type) + data.SerialNumber = types.StringValue(restInfo.SerialNumber) + data.CA = types.StringValue(restInfo.CA) + data.HashFunction = types.StringValue(restInfo.HashFunction) + data.KeySize = types.Int64Value(restInfo.KeySize) + data.ExpiryTime = types.StringValue(restInfo.ExpiryTime) + data.ID = types.StringValue(restInfo.UUID) + + // Write logs using the tflog package + // Documentation: https://terraform.io/plugin/log + tflog.Debug(ctx, fmt.Sprintf("read a data source: %#v", data)) + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/main.go b/main.go index bf1d4ac8..e777665b 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,7 @@ import ( var ( // these will be set by the goreleaser configuration // to appropriate values for the compiled binary - version string = "1.2.0" + version string = "2.0.0" // goreleaser can also pass the specific commit if you want // commit string = "" From 79ffd5557b82825435d6fba52133ae1d2ce00cd0 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 5 Sep 2024 16:10:57 +0530 Subject: [PATCH 02/23] security certificates data source --- .../security_certificates_data_source.go | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 internal/provider/security/security_certificates_data_source.go diff --git a/internal/provider/security/security_certificates_data_source.go b/internal/provider/security/security_certificates_data_source.go new file mode 100644 index 00000000..23550f5d --- /dev/null +++ b/internal/provider/security/security_certificates_data_source.go @@ -0,0 +1,207 @@ +package security + +import ( + "context" + "fmt" + "github.com/netapp/terraform-provider-netapp-ontap/internal/provider/connection" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/netapp/terraform-provider-netapp-ontap/internal/interfaces" + "github.com/netapp/terraform-provider-netapp-ontap/internal/utils" +) + +// Ensure provider defined types fully satisfy framework interfaces +var _ datasource.DataSource = &SecurityCertificatesDataSource{} + +// NewSecurityCertificatesDataSource is a helper function to simplify the provider implementation. +func NewSecurityCertificatesDataSource() datasource.DataSource { + return &SecurityCertificatesDataSource{ + config: connection.ResourceOrDataSourceConfig{ + Name: "security_certificates", + }, + } +} + +// SecurityCertificatesDataSource defines the data source implementation. +type SecurityCertificatesDataSource struct { + config connection.ResourceOrDataSourceConfig +} + +// SecurityCertificatesDataSourceModel describes the data source data model. +type SecurityCertificatesDataSourceModel struct { + CxProfileName types.String `tfsdk:"cx_profile_name"` + SecurityCertificates []SecurityCertificateDataSourceModel `tfsdk:"security_certificates"` + Filter *SecurityCertificatesDataSourceFilterModel `tfsdk:"filter"` +} + +// SecurityCertificatesDataSourceFilterModel describes the data source data model for queries. +type SecurityCertificatesDataSourceFilterModel struct { + SVMName types.String `tfsdk:"svm_name"` + Scope types.String `tfsdk:"scope"` +} + +// Metadata returns the data source type name. +func (d *SecurityCertificatesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_" + d.config.Name +} + +// Schema defines the schema for the data source. +func (d *SecurityCertificatesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + // This description is used by the documentation generator and the language server. + MarkdownDescription: "SecurityCertificates data source", + + Attributes: map[string]schema.Attribute{ + "cx_profile_name": schema.StringAttribute{ + MarkdownDescription: "Connection profile name", + Required: true, + }, + "filter": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "svm_name": schema.StringAttribute{ + MarkdownDescription: "SVM name in which the certificate is installed.", + Optional: true, + }, + "scope": schema.StringAttribute{ + MarkdownDescription: "Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.", + Optional: true, + }, + }, + Optional: true, + }, + "security_certificates": schema.ListNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "cx_profile_name": schema.StringAttribute{ + MarkdownDescription: "Connection profile name", + Required: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "The unique name of the security certificate per SVM.", + Optional: true, + }, + "common_name": schema.StringAttribute{ + MarkdownDescription: "Common name of the certificate.", + Optional: true, + }, + "svm_name": schema.StringAttribute{ + MarkdownDescription: "SVM name in which the certificate is installed.", + Optional: true, + }, + "scope": schema.StringAttribute{ + MarkdownDescription: "Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.", + Computed: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of Certificate.", + Computed: true, + }, + "serial_number": schema.StringAttribute{ + MarkdownDescription: "Serial number of certificate.", + Computed: true, + }, + "ca": schema.StringAttribute{ + MarkdownDescription: "Certificate authority.", + Computed: true, + }, + "hash_function": schema.StringAttribute{ + MarkdownDescription: "Hashing function.", + Computed: true, + }, + "key_size": schema.Int64Attribute{ + MarkdownDescription: "Key size of the certificate in bits.", + Computed: true, + }, + "expiry_time": schema.StringAttribute{ + MarkdownDescription: "Certificate expiration time, in ISO 8601 duration format or date and time format.", + Computed: true, + }, + "id": schema.StringAttribute{ + MarkdownDescription: "Certificate uuid.", + Computed: true, + }, + }, + }, + Computed: true, + MarkdownDescription: "", + }, + }, + } +} + +// Configure adds the provider configured client to the data source. +func (d *SecurityCertificatesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + config, ok := req.ProviderData.(connection.Config) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + } + d.config.ProviderConfig = config +} + +// Read refreshes the Terraform state with the latest data. +func (d *SecurityCertificatesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data SecurityCertificatesDataSourceModel + + // Read Terraform configuration data into the model + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + errorHandler := utils.NewErrorHandler(ctx, &resp.Diagnostics) + // we need to defer setting the client until we can read the connection profile name + client, err := connection.GetRestClient(errorHandler, d.config, data.CxProfileName) + if err != nil { + // error reporting done inside NewClient + return + } + + var filter *interfaces.SecurityCertificateDataSourceFilterModel = nil + if data.Filter != nil { + filter = &interfaces.SecurityCertificateDataSourceFilterModel{ + SVMName: data.Filter.SVMName.ValueString(), + Scope: data.Filter.Scope.ValueString(), + } + } + restInfo, err := interfaces.GetSecurityCertificates(errorHandler, *client, filter) + if err != nil { + // error reporting done inside GetSecurityCertificates + return + } + + data.SecurityCertificates = make([]SecurityCertificateDataSourceModel, len(restInfo)) + for index, record := range restInfo { + data.SecurityCertificates[index] = SecurityCertificateDataSourceModel{ + CxProfileName: types.String(data.CxProfileName), + Name: types.StringValue(record.Name), + CommonName: types.StringValue(record.CommonName), + SVMName: types.StringValue(record.SVM.Name), + Scope: types.StringValue(record.Scope), + Type: types.StringValue(record.Type), + SerialNumber: types.StringValue(record.SerialNumber), + CA: types.StringValue(record.CA), + HashFunction: types.StringValue(record.HashFunction), + KeySize: types.Int64Value(record.KeySize), + ExpiryTime: types.StringValue(record.ExpiryTime), + ID: types.StringValue(record.UUID), + } + } + + // Write logs using the tflog package + // Documentation: https://terraform.io/plugin/log + tflog.Debug(ctx, fmt.Sprintf("read a data source: %#v", data)) + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} From 6c6996448fcbe0635b28f4ccc5017bc31b60e26a Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 5 Sep 2024 16:18:55 +0530 Subject: [PATCH 03/23] security certificate data source --- .../data-source.tf | 11 +++++++++++ .../provider.tf | 1 + .../variables.tf | 1 + .../data-source.tf | 16 ++++++++++++++++ .../provider.tf | 1 + .../variables.tf | 1 + 6 files changed, 31 insertions(+) create mode 100644 examples/data-sources/netapp-ontap_security_certificate/data-source.tf create mode 120000 examples/data-sources/netapp-ontap_security_certificate/provider.tf create mode 120000 examples/data-sources/netapp-ontap_security_certificate/variables.tf create mode 100644 examples/data-sources/netapp-ontap_security_certificates/data-source.tf create mode 120000 examples/data-sources/netapp-ontap_security_certificates/provider.tf create mode 120000 examples/data-sources/netapp-ontap_security_certificates/variables.tf diff --git a/examples/data-sources/netapp-ontap_security_certificate/data-source.tf b/examples/data-sources/netapp-ontap_security_certificate/data-source.tf new file mode 100644 index 00000000..0a1ba671 --- /dev/null +++ b/examples/data-sources/netapp-ontap_security_certificate/data-source.tf @@ -0,0 +1,11 @@ +data "netapp-ontap_security_certificate" "security_certificate1" { + # required to know which system to interface with + cx_profile_name = "cluster5" + name = "tfsvm_17B9B4C1696136FC" +} + +data "netapp-ontap_security_certificate" "security_certificate2" { + # required to know which system to interface with + cx_profile_name = "cluster5" + common_name = "tfsvm" +} \ No newline at end of file diff --git a/examples/data-sources/netapp-ontap_security_certificate/provider.tf b/examples/data-sources/netapp-ontap_security_certificate/provider.tf new file mode 120000 index 00000000..c6b7138f --- /dev/null +++ b/examples/data-sources/netapp-ontap_security_certificate/provider.tf @@ -0,0 +1 @@ +../../provider/provider.tf \ No newline at end of file diff --git a/examples/data-sources/netapp-ontap_security_certificate/variables.tf b/examples/data-sources/netapp-ontap_security_certificate/variables.tf new file mode 120000 index 00000000..395ce618 --- /dev/null +++ b/examples/data-sources/netapp-ontap_security_certificate/variables.tf @@ -0,0 +1 @@ +../../provider/variables.tf \ No newline at end of file diff --git a/examples/data-sources/netapp-ontap_security_certificates/data-source.tf b/examples/data-sources/netapp-ontap_security_certificates/data-source.tf new file mode 100644 index 00000000..b74860bf --- /dev/null +++ b/examples/data-sources/netapp-ontap_security_certificates/data-source.tf @@ -0,0 +1,16 @@ +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" + } +} + +data "netapp-ontap_security_certificates" "security_certificates2" { + # required to know which system to interface with + cx_profile_name = "cluster5" + filter = { + scope = "cluster" + } +} diff --git a/examples/data-sources/netapp-ontap_security_certificates/provider.tf b/examples/data-sources/netapp-ontap_security_certificates/provider.tf new file mode 120000 index 00000000..c6b7138f --- /dev/null +++ b/examples/data-sources/netapp-ontap_security_certificates/provider.tf @@ -0,0 +1 @@ +../../provider/provider.tf \ No newline at end of file diff --git a/examples/data-sources/netapp-ontap_security_certificates/variables.tf b/examples/data-sources/netapp-ontap_security_certificates/variables.tf new file mode 120000 index 00000000..395ce618 --- /dev/null +++ b/examples/data-sources/netapp-ontap_security_certificates/variables.tf @@ -0,0 +1 @@ +../../provider/variables.tf \ No newline at end of file From faf75ca183528362524a06f0624b02b503dfcf2a Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 5 Sep 2024 16:34:18 +0530 Subject: [PATCH 04/23] new data source security certificate --- CHANGELOG.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54b636c6..feb68c7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,3 @@ -# 2.0.0 () - -FEATURES: -* **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)) - # 1.2.0 () FEATURES: @@ -16,6 +10,8 @@ FEATURES: * **New Data Source:** `netapp-ontap_security_roles` ([#139](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/139)) * **New Data Source:** `netapp-ontap_security_login_message` ([#17](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/17)) * **New Data Source:** `netapp-ontap_security_login_messages` ([#17](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/17)) +* **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_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)) From 589855ec38de166f9b5ed420dc445266f004cc49 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Mon, 9 Sep 2024 10:16:36 +0530 Subject: [PATCH 05/23] added connection profile --- examples/provider/provider.tf | 2 +- examples/provider/terraform.tfvars | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index 760dd81e..354f521f 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -42,7 +42,7 @@ provider "netapp-ontap" { }, { name = "cluster5" - hostname = "10.193.73.2" + hostname = "********2" username = var.username password = var.password validate_certs = var.validate_certs diff --git a/examples/provider/terraform.tfvars b/examples/provider/terraform.tfvars index 37b13f0f..d36beb44 100644 --- a/examples/provider/terraform.tfvars +++ b/examples/provider/terraform.tfvars @@ -1,3 +1,3 @@ username = "admin" -password = "Netapp1!" -validate_certs = false +password = "xxxxxxxxx" +validate_certs = true From 0ec63851b8f31efd87e26b7fea4f1652f9b25f24 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Mon, 9 Sep 2024 15:38:05 +0530 Subject: [PATCH 06/23] add docs --- docs/data-sources/security_certificate.md | 54 ++++++++++++++ docs/data-sources/security_certificates.md | 83 ++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 docs/data-sources/security_certificate.md create mode 100644 docs/data-sources/security_certificates.md diff --git a/docs/data-sources/security_certificate.md b/docs/data-sources/security_certificate.md new file mode 100644 index 00000000..72598cb6 --- /dev/null +++ b/docs/data-sources/security_certificate.md @@ -0,0 +1,54 @@ +--- +# 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 +data "netapp-ontap_security_certificate" "security_certificate1" { + # required to know which system to interface with + cx_profile_name = "cluster5" + name = "tfsvm_17B9B4C1696136FC" +} + +data "netapp-ontap_security_certificate" "security_certificate2" { + # required to know which system to interface with + cx_profile_name = "cluster5" + common_name = "tfsvm" +} +``` + + +## Schema + +### Required + +- `cx_profile_name` (String) Connection profile name + +### Optional + +- `common_name` (String) Common name of the certificate. +- `name` (String) The unique name of the security certificate per SVM. This parameter is supported with ONTAP 9.8 or later. +- `svm_name` (String) SVM name in which the certificate is installed. + +### Read-Only + +- `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. +- `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'. +- `serial_number` (String) Serial number of certificate. +- `type` (String) Type of Certificate. diff --git a/docs/data-sources/security_certificates.md b/docs/data-sources/security_certificates.md new file mode 100644 index 00000000..ed129dc9 --- /dev/null +++ b/docs/data-sources/security_certificates.md @@ -0,0 +1,83 @@ +--- +# 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 Login Certificates data source +--- + +# netapp-ontap_security_certificates (Data Source) + +Retrieve Security Login Certificates data source + +### Related ONTAP commands +* security certificate show + +## Example Usage + +```terraform +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" + } +} + +data "netapp-ontap_security_certificates" "security_certificates2" { + # required to know which system to interface with + cx_profile_name = "cluster5" + filter = { + scope = "cluster" + } +} +``` + + +## 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)) + + +### 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. + + + +### Nested Schema for `security_certificates` + +Required: + +- `cx_profile_name` (String) Connection profile name + +Optional: + +- `common_name` (String) Common name of the certificate. +- `name` (String) The unique name of the security certificate per SVM. This parameter is supported with ONTAP 9.8 or later. +- `svm_name` (String) SVM name in which the certificate is installed. + +Read-Only: + +- `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. +- `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'. +- `serial_number` (String) Serial number of certificate. +- `type` (String) Type of Certificate. From 6649db87aac7a4fc69c430cdd47ef5265a040de2 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Mon, 9 Sep 2024 15:43:28 +0530 Subject: [PATCH 07/23] add docs --- scripts/generate_docs.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/scripts/generate_docs.py b/scripts/generate_docs.py index 98ac6719..20d6d5ba 100755 --- a/scripts/generate_docs.py +++ b/scripts/generate_docs.py @@ -2,9 +2,9 @@ import os import sys -# TO find the correct Catagory, check REST API to see what main header this API lives under +# TO find the correct Category, check REST API to see what main header this API lives under -CATAGORYS = { +CATEGORIES = { 'application': [], 'cloud': [], 'cluster': [ @@ -80,6 +80,8 @@ "security_login_message_data_source.md", "security_login_messages_data_source.md", "security_login_message_resource.md", + "security_certificate_data_source.md", + "security_certificates_data_source.md", ], 'snaplock': [], 'snapmirror': [ @@ -122,12 +124,12 @@ def main(): print("===== Generating docs =====") generate_doc() remove_example() - print("===== Adding Catagories =====") + print("===== Adding Categories =====") add_catagories() print("===== Validate =====") validate() print("===== Errors =====") - issue = warn_missing_catagory(["docs/data-sources/", "docs/resources/"]) + issue = warn_missing_category(["docs/data-sources/", "docs/resources/"]) if issue: sys.exit(1) @@ -150,25 +152,25 @@ def remove_example(): def add_catagories(): - for catagory in CATAGORYS: - for page in CATAGORYS[catagory]: + for category in CATEGORIES: + for page in CATEGORIES[category]: if 'data_source' in page: - update_datasource(page, catagory) + update_datasource(page, category) if 'resource' in page: - update_resouces(page, catagory) + update_resouces(page, category) -def update_datasource(page, catagory): +def update_datasource(page, category): path = "docs/data-sources/" + page - update_md_file(path, catagory) + update_md_file(path, category) -def update_resouces(page, catagory): +def update_resouces(page, category): path = "docs/resources/" + page - update_md_file(path, catagory) + update_md_file(path, category) -def update_md_file(path, catagory): +def update_md_file(path, category): print("Updating %s" % path) try: with open(path) as f: @@ -176,7 +178,7 @@ def update_md_file(path, catagory): for i, line in enumerate(lines): if line.startswith('subcategory: "'): split_line = line.split('subcategory: "') - new_line = split_line[0] + 'subcategory: "' + catagory + split_line[1] + new_line = split_line[0] + 'subcategory: "' + category + split_line[1] lines[i] = new_line break with open(path, 'w') as f: @@ -184,7 +186,7 @@ def update_md_file(path, catagory): except: return -def warn_missing_catagory(directory_paths): +def warn_missing_category(directory_paths): issue = False for directory_path in directory_paths: full_path = os.path.join(os.getcwd(), directory_path) @@ -193,7 +195,7 @@ def warn_missing_catagory(directory_paths): with open(os.path.join(full_path, filename), 'r') as f: file_content = f.read() if 'subcategory: ""' in file_content: - print('%s is missing a catagory' % filename) + print('%s is missing a category' % filename) issue = True return issue From 9b4b8ff9d3ebba31e03a26f7fe78c51b6a9db89c Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Mon, 9 Sep 2024 15:49:49 +0530 Subject: [PATCH 08/23] revert change in main.go --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index e777665b..bf1d4ac8 100644 --- a/main.go +++ b/main.go @@ -22,7 +22,7 @@ import ( var ( // these will be set by the goreleaser configuration // to appropriate values for the compiled binary - version string = "2.0.0" + version string = "1.2.0" // goreleaser can also pass the specific commit if you want // commit string = "" From c4c13d77a8c5e6a79bfc2ef8c26d7fe7314c92f3 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Tue, 10 Sep 2024 15:20:03 +0530 Subject: [PATCH 09/23] update docs --- docs/data-sources/security_certificate.md | 3 ++- docs/data-sources/security_certificates.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/data-sources/security_certificate.md b/docs/data-sources/security_certificate.md index 72598cb6..71926257 100644 --- a/docs/data-sources/security_certificate.md +++ b/docs/data-sources/security_certificate.md @@ -26,6 +26,7 @@ data "netapp-ontap_security_certificate" "security_certificate2" { # required to know which system to interface with cx_profile_name = "cluster5" common_name = "tfsvm" + type = "server" } ``` @@ -40,6 +41,7 @@ data "netapp-ontap_security_certificate" "security_certificate2" { - `common_name` (String) Common name of the certificate. - `name` (String) The unique name of the security certificate per SVM. This parameter is supported with ONTAP 9.8 or later. +- `type` (String) Type of Certificate. - `svm_name` (String) SVM name in which the certificate is installed. ### Read-Only @@ -51,4 +53,3 @@ data "netapp-ontap_security_certificate" "security_certificate2" { - `key_size` (Number) Key size of the certificate in bits. - `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'. - `serial_number` (String) Serial number of certificate. -- `type` (String) Type of Certificate. diff --git a/docs/data-sources/security_certificates.md b/docs/data-sources/security_certificates.md index ed129dc9..e5c4f9cb 100644 --- a/docs/data-sources/security_certificates.md +++ b/docs/data-sources/security_certificates.md @@ -69,6 +69,7 @@ Optional: - `common_name` (String) Common name of the certificate. - `name` (String) The unique name of the security certificate per SVM. This parameter is supported with ONTAP 9.8 or later. +- `type` (String) Type of Certificate. - `svm_name` (String) SVM name in which the certificate is installed. Read-Only: @@ -80,4 +81,3 @@ Read-Only: - `key_size` (Number) Key size of the certificate in bits. - `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'. - `serial_number` (String) Serial number of certificate. -- `type` (String) Type of Certificate. From 8641c98ee3ff5104fc236a20d50734c1d3ea1066 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Tue, 10 Sep 2024 15:21:14 +0530 Subject: [PATCH 10/23] update example --- .../netapp-ontap_security_certificate/data-source.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/data-sources/netapp-ontap_security_certificate/data-source.tf b/examples/data-sources/netapp-ontap_security_certificate/data-source.tf index 0a1ba671..bc7a547f 100644 --- a/examples/data-sources/netapp-ontap_security_certificate/data-source.tf +++ b/examples/data-sources/netapp-ontap_security_certificate/data-source.tf @@ -8,4 +8,5 @@ data "netapp-ontap_security_certificate" "security_certificate2" { # required to know which system to interface with cx_profile_name = "cluster5" common_name = "tfsvm" + type = "server" } \ No newline at end of file From 24eeb1a685867d449849be024ef9a14a18c462ea Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Tue, 10 Sep 2024 15:22:30 +0530 Subject: [PATCH 11/23] update version constraints --- internal/interfaces/security_certificate.go | 32 +++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/internal/interfaces/security_certificate.go b/internal/interfaces/security_certificate.go index 0f78c457..06746390 100644 --- a/internal/interfaces/security_certificate.go +++ b/internal/interfaces/security_certificate.go @@ -32,23 +32,29 @@ type SecurityCertificateDataSourceFilterModel struct { } // GetSecurityCertificate to get security_certificate info -func GetSecurityCertificate(errorHandler *utils.ErrorHandler, r restclient.RestClient, name string, common_name string) (*SecurityCertificateGetDataModelONTAP, error) { +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 if common_name != "" { - query.Set("common_name", common_name) } else { - return nil, errorHandler.MakeAndLogError("Error: 'name' or 'common_name' are required parameters.") + 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"} + if version.Generation == 9 && version.Major >= 8 { + fields = append(fields, "name") } - query.Fields([]string{"uuid", "name", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time"}) + 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)) } @@ -62,10 +68,14 @@ func GetSecurityCertificate(errorHandler *utils.ErrorHandler, r restclient.RestC } // GetSecurityCertificateByUUID to get security_certificate info -func GetSecurityCertificateByUUID(errorHandler *utils.ErrorHandler, r restclient.RestClient, uuid string) (*SecurityCertificateGetDataModelONTAP, error) { +func GetSecurityCertificateByUUID(errorHandler *utils.ErrorHandler, r restclient.RestClient, version versionModelONTAP, uuid string) (*SecurityCertificateGetDataModelONTAP, error) { api := "security/certificates/" + uuid query := r.NewQuery() - query.Fields([]string{"uuid", "name", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time"}) + var fields = []string{"uuid", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time"} + 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) @@ -84,10 +94,14 @@ func GetSecurityCertificateByUUID(errorHandler *utils.ErrorHandler, r restclient } // GetSecurityCertificates to get security_certificate info for all resources matching a filter -func GetSecurityCertificates(errorHandler *utils.ErrorHandler, r restclient.RestClient, filter *SecurityCertificateDataSourceFilterModel) ([]SecurityCertificateGetDataModelONTAP, error) { +func GetSecurityCertificates(errorHandler *utils.ErrorHandler, r restclient.RestClient, version versionModelONTAP, filter *SecurityCertificateDataSourceFilterModel) ([]SecurityCertificateGetDataModelONTAP, error) { api := "security/certificates" query := r.NewQuery() - query.Fields([]string{"uuid", "name", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time"}) + var fields = []string{"uuid", "common_name", "svm.name", "scope", "type", "serial_number", "ca", "hash_function", "key_size", "expiry_time"} + if version.Generation == 9 && version.Major >= 8 { + fields = append(fields, "name") + } + query.Fields(fields) if filter != nil { if filter.SVMName != "" { query.Add("svm.name", filter.SVMName) From 53c18330783d8a8dd8aae9febe8506612fcc4aa3 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Tue, 10 Sep 2024 15:23:20 +0530 Subject: [PATCH 12/23] add data source config validators --- .../security_certificate_data_source.go | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/internal/provider/security/security_certificate_data_source.go b/internal/provider/security/security_certificate_data_source.go index c591d2a2..cfc71477 100644 --- a/internal/provider/security/security_certificate_data_source.go +++ b/internal/provider/security/security_certificate_data_source.go @@ -8,6 +8,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/netapp/terraform-provider-netapp-ontap/internal/interfaces" "github.com/netapp/terraform-provider-netapp-ontap/internal/utils" @@ -70,6 +72,10 @@ func (d *SecurityCertificateDataSource) Schema(ctx context.Context, req datasour MarkdownDescription: "Common name of the certificate.", Optional: true, }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of Certificate.", + Optional: true, + }, "svm_name": schema.StringAttribute{ MarkdownDescription: "SVM name in which the certificate is installed.", Optional: true, @@ -78,10 +84,6 @@ func (d *SecurityCertificateDataSource) Schema(ctx context.Context, req datasour MarkdownDescription: "Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.", Computed: true, }, - "type": schema.StringAttribute{ - MarkdownDescription: "Type of Certificate.", - Computed: true, - }, "serial_number": schema.StringAttribute{ MarkdownDescription: "Serial number of certificate.", Computed: true, @@ -126,6 +128,20 @@ func (d *SecurityCertificateDataSource) Configure(ctx context.Context, req datas d.config.ProviderConfig = config } +// ConfigValidators validates entire data source configurations +func (d *SecurityCertificateDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { + return []datasource.ConfigValidator{ + datasourcevalidator.AtLeastOneOf( + path.MatchRoot("name"), + path.MatchRoot("common_name"), + ), + datasourcevalidator.RequiredTogether( + path.MatchRoot("common_name"), + path.MatchRoot("type"), + ), + } +} + // Read refreshes the Terraform state with the latest data. func (d *SecurityCertificateDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var data SecurityCertificateDataSourceModel @@ -145,7 +161,17 @@ func (d *SecurityCertificateDataSource) Read(ctx context.Context, req datasource return } - restInfo, err := interfaces.GetSecurityCertificate(errorHandler, *client, data.Name.ValueString(), data.CommonName.ValueString()) + cluster, err := interfaces.GetCluster(errorHandler, *client) + if err != nil { + // error reporting done inside GetCluster + return + } + if cluster == nil { + errorHandler.MakeAndReportError("No cluster found", "cluster not found") + return + } + + restInfo, err := interfaces.GetSecurityCertificate(errorHandler, *client, cluster.Version, data.Name.ValueString(), data.CommonName.ValueString(), data.Type.ValueString()) if err != nil { // error reporting done inside GetSecurityCertificate return From ce9e152ba1e56a7d586ec464da97fe03cdb1fb3f Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Tue, 10 Sep 2024 15:23:48 +0530 Subject: [PATCH 13/23] update schema --- .../security_certificates_data_source.go | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/internal/provider/security/security_certificates_data_source.go b/internal/provider/security/security_certificates_data_source.go index 23550f5d..42c3d28b 100644 --- a/internal/provider/security/security_certificates_data_source.go +++ b/internal/provider/security/security_certificates_data_source.go @@ -87,6 +87,10 @@ func (d *SecurityCertificatesDataSource) Schema(ctx context.Context, req datasou MarkdownDescription: "Common name of the certificate.", Optional: true, }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of Certificate.", + Optional: true, + }, "svm_name": schema.StringAttribute{ MarkdownDescription: "SVM name in which the certificate is installed.", Optional: true, @@ -95,10 +99,6 @@ func (d *SecurityCertificatesDataSource) Schema(ctx context.Context, req datasou MarkdownDescription: "Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.", Computed: true, }, - "type": schema.StringAttribute{ - MarkdownDescription: "Type of Certificate.", - Computed: true, - }, "serial_number": schema.StringAttribute{ MarkdownDescription: "Serial number of certificate.", Computed: true, @@ -167,6 +167,16 @@ func (d *SecurityCertificatesDataSource) Read(ctx context.Context, req datasourc return } + cluster, err := interfaces.GetCluster(errorHandler, *client) + if err != nil { + // error reporting done inside GetCluster + return + } + if cluster == nil { + errorHandler.MakeAndReportError("No cluster found", "cluster not found") + return + } + var filter *interfaces.SecurityCertificateDataSourceFilterModel = nil if data.Filter != nil { filter = &interfaces.SecurityCertificateDataSourceFilterModel{ @@ -174,7 +184,7 @@ func (d *SecurityCertificatesDataSource) Read(ctx context.Context, req datasourc Scope: data.Filter.Scope.ValueString(), } } - restInfo, err := interfaces.GetSecurityCertificates(errorHandler, *client, filter) + restInfo, err := interfaces.GetSecurityCertificates(errorHandler, *client, cluster.Version, filter) if err != nil { // error reporting done inside GetSecurityCertificates return From e3ff775d2a1c1a9d529da9b21d8baf4384ce154c Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 12 Sep 2024 17:49:57 +0530 Subject: [PATCH 14/23] add parameter public_certificate --- internal/interfaces/security_certificate.go | 27 +++++++++-------- .../security_certificate_data_source.go | 30 +++++++++++-------- .../security_certificates_data_source.go | 29 ++++++++++-------- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/internal/interfaces/security_certificate.go b/internal/interfaces/security_certificate.go index 06746390..9e6d01cb 100644 --- a/internal/interfaces/security_certificate.go +++ b/internal/interfaces/security_certificate.go @@ -12,17 +12,18 @@ import ( // 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"` + 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. @@ -41,7 +42,7 @@ func GetSecurityCertificate(errorHandler *utils.ErrorHandler, r restclient.RestC 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"} + 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") } @@ -97,7 +98,7 @@ func GetSecurityCertificateByUUID(errorHandler *utils.ErrorHandler, r restclient 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"} + 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") } diff --git a/internal/provider/security/security_certificate_data_source.go b/internal/provider/security/security_certificate_data_source.go index cfc71477..f04145e8 100644 --- a/internal/provider/security/security_certificate_data_source.go +++ b/internal/provider/security/security_certificate_data_source.go @@ -34,18 +34,19 @@ type SecurityCertificateDataSource struct { // SecurityCertificateDataSourceModel describes the data source data model. type SecurityCertificateDataSourceModel struct { - CxProfileName types.String `tfsdk:"cx_profile_name"` - Name types.String `tfsdk:"name"` - CommonName types.String `tfsdk:"common_name"` - SVMName types.String `tfsdk:"svm_name"` - Scope types.String `tfsdk:"scope"` - Type types.String `tfsdk:"type"` - SerialNumber types.String `tfsdk:"serial_number"` - CA types.String `tfsdk:"ca"` - HashFunction types.String `tfsdk:"hash_function"` - KeySize types.Int64 `tfsdk:"key_size"` - ExpiryTime types.String `tfsdk:"expiry_time"` - ID types.String `tfsdk:"id"` + CxProfileName types.String `tfsdk:"cx_profile_name"` + Name types.String `tfsdk:"name"` + CommonName types.String `tfsdk:"common_name"` + SVMName types.String `tfsdk:"svm_name"` + Scope types.String `tfsdk:"scope"` + Type types.String `tfsdk:"type"` + SerialNumber types.String `tfsdk:"serial_number"` + CA types.String `tfsdk:"ca"` + HashFunction types.String `tfsdk:"hash_function"` + KeySize types.Int64 `tfsdk:"key_size"` + ExpiryTime types.String `tfsdk:"expiry_time"` + PublicCertificate types.String `tfsdk:"public_certificate"` + ID types.String `tfsdk:"id"` } // Metadata returns the data source type name. @@ -104,6 +105,10 @@ func (d *SecurityCertificateDataSource) Schema(ctx context.Context, req datasour MarkdownDescription: "Certificate expiration time, in ISO 8601 duration format or date and time format.", Computed: true, }, + "public_certificate": schema.StringAttribute{ + MarkdownDescription: "Public key Certificate in PEM format.", + Computed: true, + }, "id": schema.StringAttribute{ MarkdownDescription: "Certificate uuid.", Computed: true, @@ -187,6 +192,7 @@ func (d *SecurityCertificateDataSource) Read(ctx context.Context, req datasource data.HashFunction = types.StringValue(restInfo.HashFunction) data.KeySize = types.Int64Value(restInfo.KeySize) data.ExpiryTime = types.StringValue(restInfo.ExpiryTime) + data.PublicCertificate = types.StringValue(restInfo.PublicCertificate) data.ID = types.StringValue(restInfo.UUID) // Write logs using the tflog package diff --git a/internal/provider/security/security_certificates_data_source.go b/internal/provider/security/security_certificates_data_source.go index 42c3d28b..45af7d90 100644 --- a/internal/provider/security/security_certificates_data_source.go +++ b/internal/provider/security/security_certificates_data_source.go @@ -119,6 +119,10 @@ func (d *SecurityCertificatesDataSource) Schema(ctx context.Context, req datasou MarkdownDescription: "Certificate expiration time, in ISO 8601 duration format or date and time format.", Computed: true, }, + "public_certificate": schema.StringAttribute{ + MarkdownDescription: "Public key Certificate in PEM format.", + Computed: true, + }, "id": schema.StringAttribute{ MarkdownDescription: "Certificate uuid.", Computed: true, @@ -193,18 +197,19 @@ func (d *SecurityCertificatesDataSource) Read(ctx context.Context, req datasourc data.SecurityCertificates = make([]SecurityCertificateDataSourceModel, len(restInfo)) for index, record := range restInfo { data.SecurityCertificates[index] = SecurityCertificateDataSourceModel{ - CxProfileName: types.String(data.CxProfileName), - Name: types.StringValue(record.Name), - CommonName: types.StringValue(record.CommonName), - SVMName: types.StringValue(record.SVM.Name), - Scope: types.StringValue(record.Scope), - Type: types.StringValue(record.Type), - SerialNumber: types.StringValue(record.SerialNumber), - CA: types.StringValue(record.CA), - HashFunction: types.StringValue(record.HashFunction), - KeySize: types.Int64Value(record.KeySize), - ExpiryTime: types.StringValue(record.ExpiryTime), - ID: types.StringValue(record.UUID), + CxProfileName: types.String(data.CxProfileName), + Name: types.StringValue(record.Name), + CommonName: types.StringValue(record.CommonName), + SVMName: types.StringValue(record.SVM.Name), + Scope: types.StringValue(record.Scope), + Type: types.StringValue(record.Type), + SerialNumber: types.StringValue(record.SerialNumber), + CA: types.StringValue(record.CA), + HashFunction: types.StringValue(record.HashFunction), + KeySize: types.Int64Value(record.KeySize), + ExpiryTime: types.StringValue(record.ExpiryTime), + PublicCertificate: types.StringValue(record.PublicCertificate), + ID: types.StringValue(record.UUID), } } From b2843928282f656e32cfdbdee4d5a34837749bc4 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 12 Sep 2024 17:50:47 +0530 Subject: [PATCH 15/23] update docs --- docs/data-sources/security_certificate.md | 1 + docs/data-sources/security_certificates.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/data-sources/security_certificate.md b/docs/data-sources/security_certificate.md index 71926257..26b52c7c 100644 --- a/docs/data-sources/security_certificate.md +++ b/docs/data-sources/security_certificate.md @@ -53,3 +53,4 @@ data "netapp-ontap_security_certificate" "security_certificate2" { - `key_size` (Number) Key size of the certificate in bits. - `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'. - `serial_number` (String) Serial number of certificate. +- `public_certificate` (String) Public key Certificate in PEM format. diff --git a/docs/data-sources/security_certificates.md b/docs/data-sources/security_certificates.md index e5c4f9cb..234cf7c5 100644 --- a/docs/data-sources/security_certificates.md +++ b/docs/data-sources/security_certificates.md @@ -81,3 +81,4 @@ Read-Only: - `key_size` (Number) Key size of the certificate in bits. - `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'. - `serial_number` (String) Serial number of certificate. +- `public_certificate` (String) Public key Certificate in PEM format. From ab7894fd681472d3c96c3a7da8ac4069afe1a953 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 3 Oct 2024 12:34:58 +0530 Subject: [PATCH 16/23] updated Read --- .../security_certificate_data_source.go | 26 ++++--------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/internal/provider/security/security_certificate_data_source.go b/internal/provider/security/security_certificate_data_source.go index f04145e8..cd13982d 100644 --- a/internal/provider/security/security_certificate_data_source.go +++ b/internal/provider/security/security_certificate_data_source.go @@ -8,8 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/netapp/terraform-provider-netapp-ontap/internal/interfaces" "github.com/netapp/terraform-provider-netapp-ontap/internal/utils" @@ -67,15 +65,15 @@ func (d *SecurityCertificateDataSource) Schema(ctx context.Context, req datasour }, "name": schema.StringAttribute{ MarkdownDescription: "The unique name of the security certificate per SVM.", - Optional: true, + Required: true, }, "common_name": schema.StringAttribute{ MarkdownDescription: "Common name of the certificate.", - Optional: true, + Computed: true, }, "type": schema.StringAttribute{ MarkdownDescription: "Type of Certificate.", - Optional: true, + Computed: true, }, "svm_name": schema.StringAttribute{ MarkdownDescription: "SVM name in which the certificate is installed.", @@ -133,20 +131,6 @@ func (d *SecurityCertificateDataSource) Configure(ctx context.Context, req datas d.config.ProviderConfig = config } -// ConfigValidators validates entire data source configurations -func (d *SecurityCertificateDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator { - return []datasource.ConfigValidator{ - datasourcevalidator.AtLeastOneOf( - path.MatchRoot("name"), - path.MatchRoot("common_name"), - ), - datasourcevalidator.RequiredTogether( - path.MatchRoot("common_name"), - path.MatchRoot("type"), - ), - } -} - // Read refreshes the Terraform state with the latest data. func (d *SecurityCertificateDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var data SecurityCertificateDataSourceModel @@ -176,9 +160,9 @@ func (d *SecurityCertificateDataSource) Read(ctx context.Context, req datasource return } - restInfo, err := interfaces.GetSecurityCertificate(errorHandler, *client, cluster.Version, data.Name.ValueString(), data.CommonName.ValueString(), data.Type.ValueString()) + restInfo, err := interfaces.GetSecurityCertificateByName(errorHandler, *client, cluster.Version, data.Name.ValueString()) if err != nil { - // error reporting done inside GetSecurityCertificate + // error reporting done inside GetSecurityCertificateByName return } From a0cf226dc10ca137166b12f9256bfb2b702278a9 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 3 Oct 2024 12:35:36 +0530 Subject: [PATCH 17/23] updated filter --- internal/interfaces/security_certificate.go | 52 +++++++++++++++---- .../security_certificates_data_source.go | 32 ++++++++---- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/internal/interfaces/security_certificate.go b/internal/interfaces/security_certificate.go index 9e6d01cb..78951943 100644 --- a/internal/interfaces/security_certificate.go +++ b/internal/interfaces/security_certificate.go @@ -28,11 +28,14 @@ type SecurityCertificateGetDataModelONTAP struct { // SecurityCertificateDataSourceFilterModel describes the data source data model for queries. type SecurityCertificateDataSourceFilterModel struct { - SVMName string `mapstructure:"svm.name"` - Scope string `mapstructure:"scope"` + 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() @@ -68,11 +71,41 @@ func GetSecurityCertificate(errorHandler *utils.ErrorHandler, r restclient.RestC 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"} + 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") } @@ -103,17 +136,16 @@ func GetSecurityCertificates(errorHandler *utils.ErrorHandler, r restclient.Rest fields = append(fields, "name") } query.Fields(fields) + if filter != nil { - if filter.SVMName != "" { - query.Add("svm.name", filter.SVMName) - query.Add("scope", "svm") - } else { - // set scope to cluster - query.Add("scope", strings.ToLower(filter.Scope)) + 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 account filter: %+v", query)) + 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) diff --git a/internal/provider/security/security_certificates_data_source.go b/internal/provider/security/security_certificates_data_source.go index 45af7d90..690efeca 100644 --- a/internal/provider/security/security_certificates_data_source.go +++ b/internal/provider/security/security_certificates_data_source.go @@ -39,8 +39,10 @@ type SecurityCertificatesDataSourceModel struct { // SecurityCertificatesDataSourceFilterModel describes the data source data model for queries. type SecurityCertificatesDataSourceFilterModel struct { - SVMName types.String `tfsdk:"svm_name"` - Scope types.String `tfsdk:"scope"` + SVMName types.String `tfsdk:"svm_name"` + Scope types.String `tfsdk:"scope"` + CommonName types.String `tfsdk:"common_name"` + Type types.String `tfsdk:"type"` } // Metadata returns the data source type name. @@ -69,6 +71,14 @@ func (d *SecurityCertificatesDataSource) Schema(ctx context.Context, req datasou MarkdownDescription: "Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.", Optional: true, }, + "common_name": schema.StringAttribute{ + MarkdownDescription: "Common name of the certificate.", + Optional: true, + }, + "type": schema.StringAttribute{ + MarkdownDescription: "Type of certificate.", + Optional: true, + }, }, Optional: true, }, @@ -77,23 +87,23 @@ func (d *SecurityCertificatesDataSource) Schema(ctx context.Context, req datasou Attributes: map[string]schema.Attribute{ "cx_profile_name": schema.StringAttribute{ MarkdownDescription: "Connection profile name", - Required: true, + Computed: true, }, "name": schema.StringAttribute{ MarkdownDescription: "The unique name of the security certificate per SVM.", - Optional: true, + Computed: true, }, "common_name": schema.StringAttribute{ MarkdownDescription: "Common name of the certificate.", - Optional: true, + Computed: true, }, "type": schema.StringAttribute{ - MarkdownDescription: "Type of Certificate.", - Optional: true, + MarkdownDescription: "Type of certificate.", + Computed: true, }, "svm_name": schema.StringAttribute{ MarkdownDescription: "SVM name in which the certificate is installed.", - Optional: true, + Computed: true, }, "scope": schema.StringAttribute{ MarkdownDescription: "Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'.", @@ -184,8 +194,10 @@ func (d *SecurityCertificatesDataSource) Read(ctx context.Context, req datasourc var filter *interfaces.SecurityCertificateDataSourceFilterModel = nil if data.Filter != nil { filter = &interfaces.SecurityCertificateDataSourceFilterModel{ - SVMName: data.Filter.SVMName.ValueString(), - Scope: data.Filter.Scope.ValueString(), + SVMName: data.Filter.SVMName.ValueString(), + Scope: data.Filter.Scope.ValueString(), + CommonName: data.Filter.CommonName.ValueString(), + Type: data.Filter.Type.ValueString(), } } restInfo, err := interfaces.GetSecurityCertificates(errorHandler, *client, cluster.Version, filter) From 02d2644ce781c9287fdcaae47516c697e81c821c Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 3 Oct 2024 12:36:09 +0530 Subject: [PATCH 18/23] updated examples --- .../data-source.tf | 10 ++-------- .../data-source.tf | 14 +++++++++++++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/examples/data-sources/netapp-ontap_security_certificate/data-source.tf b/examples/data-sources/netapp-ontap_security_certificate/data-source.tf index bc7a547f..5ace7893 100644 --- a/examples/data-sources/netapp-ontap_security_certificate/data-source.tf +++ b/examples/data-sources/netapp-ontap_security_certificate/data-source.tf @@ -1,12 +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_17B9B4C1696136FC" + name = "tfsvm_17B9B4C1696136FC" } - -data "netapp-ontap_security_certificate" "security_certificate2" { - # required to know which system to interface with - cx_profile_name = "cluster5" - common_name = "tfsvm" - type = "server" -} \ No newline at end of file diff --git a/examples/data-sources/netapp-ontap_security_certificates/data-source.tf b/examples/data-sources/netapp-ontap_security_certificates/data-source.tf index b74860bf..2b755222 100644 --- a/examples/data-sources/netapp-ontap_security_certificates/data-source.tf +++ b/examples/data-sources/netapp-ontap_security_certificates/data-source.tf @@ -1,12 +1,14 @@ +# 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" + 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" @@ -14,3 +16,13 @@ data "netapp-ontap_security_certificates" "security_certificates2" { 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" + } +} \ No newline at end of file From 4e3a3fb3b94d9fd5eeb22d6c0c05624c35797d2e Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 3 Oct 2024 13:06:18 +0530 Subject: [PATCH 19/23] update docs --- docs/data-sources/security_certificate.md | 21 +++------- docs/data-sources/security_certificates.md | 47 ++++++++++++---------- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/docs/data-sources/security_certificate.md b/docs/data-sources/security_certificate.md index 26b52c7c..17149084 100644 --- a/docs/data-sources/security_certificate.md +++ b/docs/data-sources/security_certificate.md @@ -10,23 +10,14 @@ description: |- 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" -} - -data "netapp-ontap_security_certificate" "security_certificate2" { - # required to know which system to interface with - cx_profile_name = "cluster5" - common_name = "tfsvm" - type = "server" + name = "tfsvm_17B9B4C1696136FC" } ``` @@ -36,21 +27,21 @@ data "netapp-ontap_security_certificate" "security_certificate2" { ### Required - `cx_profile_name` (String) Connection profile name +- `name` (String) The unique name of the security certificate per SVM. ### Optional -- `common_name` (String) Common name of the certificate. -- `name` (String) The unique name of the security certificate per SVM. This parameter is supported with ONTAP 9.8 or later. -- `type` (String) Type of Certificate. - `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. -- `public_certificate` (String) Public key Certificate in PEM format. diff --git a/docs/data-sources/security_certificates.md b/docs/data-sources/security_certificates.md index 234cf7c5..243e481b 100644 --- a/docs/data-sources/security_certificates.md +++ b/docs/data-sources/security_certificates.md @@ -3,28 +3,27 @@ page_title: "netapp-ontap_security_certificates Data Source - terraform-provider-netapp-ontap" subcategory: "Security" description: |- - Retrieve Security Login Certificates data source + Retrieve Security Certificates data source --- # netapp-ontap_security_certificates (Data Source) -Retrieve Security Login Certificates data source - -### Related ONTAP commands -* security certificate show +Retrieve Security Certificates data source ## 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" + 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" @@ -32,6 +31,16 @@ data "netapp-ontap_security_certificates" "security_certificates2" { 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" + } +} ``` @@ -56,29 +65,25 @@ 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. ### Nested Schema for `security_certificates` -Required: - -- `cx_profile_name` (String) Connection profile name - -Optional: - -- `common_name` (String) Common name of the certificate. -- `name` (String) The unique name of the security certificate per SVM. This parameter is supported with ONTAP 9.8 or later. -- `type` (String) Type of Certificate. -- `svm_name` (String) SVM name in which the certificate is installed. - Read-Only: -- `ca` (String) Certificate authority. +- `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. -- `id` (String) Certificate uuid. - `key_size` (Number) Key size of the certificate in bits. -- `scope` (String) Set to 'svm' for certificates installed in a SVM. Otherwise, set to 'cluster'. -- `serial_number` (String) Serial number of certificate. - `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. From 62a457018ed43a32ab9b5112fbb913567ccfa499 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 3 Oct 2024 13:16:27 +0530 Subject: [PATCH 20/23] update docs --- docs/data-sources/security_certificate.md | 3 +++ docs/data-sources/security_certificates.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/docs/data-sources/security_certificate.md b/docs/data-sources/security_certificate.md index 17149084..4dfa78bf 100644 --- a/docs/data-sources/security_certificate.md +++ b/docs/data-sources/security_certificate.md @@ -10,6 +10,9 @@ description: |- Retrieve Security Certificate data source +### Related ONTAP commands +* security certificate show + ## Example Usage ```terraform diff --git a/docs/data-sources/security_certificates.md b/docs/data-sources/security_certificates.md index 243e481b..eb45e364 100644 --- a/docs/data-sources/security_certificates.md +++ b/docs/data-sources/security_certificates.md @@ -10,6 +10,9 @@ description: |- Retrieve Security Certificates data source +### Related ONTAP commands +* security certificate show + ## Example Usage ```terraform From ad26a4dfcff31203b4dae757a95fdadc0e606d42 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 3 Oct 2024 13:34:45 +0530 Subject: [PATCH 21/23] update examples --- .../provider.tf | 1 + .../resource.tf | 26 +++++++++++++++++++ .../terraform.tfvars | 1 + .../variables.tf | 1 + 4 files changed, 29 insertions(+) create mode 120000 examples/resources/netapp-ontap_security_certificate/provider.tf create mode 100644 examples/resources/netapp-ontap_security_certificate/resource.tf create mode 120000 examples/resources/netapp-ontap_security_certificate/terraform.tfvars create mode 120000 examples/resources/netapp-ontap_security_certificate/variables.tf diff --git a/examples/resources/netapp-ontap_security_certificate/provider.tf b/examples/resources/netapp-ontap_security_certificate/provider.tf new file mode 120000 index 00000000..c6b7138f --- /dev/null +++ b/examples/resources/netapp-ontap_security_certificate/provider.tf @@ -0,0 +1 @@ +../../provider/provider.tf \ No newline at end of file diff --git a/examples/resources/netapp-ontap_security_certificate/resource.tf b/examples/resources/netapp-ontap_security_certificate/resource.tf new file mode 100644 index 00000000..233dee82 --- /dev/null +++ b/examples/resources/netapp-ontap_security_certificate/resource.tf @@ -0,0 +1,26 @@ +resource "netapp-ontap_security_certificate" "sign_certificate" { + cx_profile_name = "cluster5" + name = "svm2_ca_cert1_unique" + common_name = "svm2_ca_cert1" + type = "root_ca" + svm_name = "svm3" + expiry_time = "P90DT" + signing_request = <<-EOT +-----BEGIN CERTIFICATE REQUEST----- +MIICmjCCAYICAQAwFTETMBEGA1UEAxQKc3ZtM19jZXJ0MTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALR4afBcQLJ0iK041/5Kt1/X4KxKB2g50Ap3PNJw +aPx5KH/0PpxqLM8qqu5nsFVrjNnuUJ+1mnMsKVrVQHPXQqhJvlBmDh8PcR+snQhD +XqU1C/LOdsT1B2f6ezwHsQ0/s1yRXwRnYvbEpnNcq5xGRcwF4UeYZWjdhTDou9FL +qL9zJ0FeQZ/mt21yh9pe2NOtcawFfciljEOa3fEuZu2AMpNis53V3siQRcygBzmK +yC+OuoHIh7BO5Sac1wV6XZOANSGdqdQ+OJUSmh347ArEOBBTxDGPHrH0FFL0kSok +5sCO05eln/JErULyaySsjLW9dzSduZoIGEPweotVqKGGfDECAwEAAaBAMD4GCSqG +SIb3DQEJDjExMC8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMC +BggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEAMCmLaaAET6WrMBrXOsj1tfzi +5zFlSQXo72c2KgaIrYTJ/tDbXFGFpV4f7cKDI3CIBjh4GQ3cNtr9ktg6Aq4cZajr +2cSfIpwNIZZlU/UribZf3Y5F7zN6vxL/Kb31AjpSITyM+Q1hlK/1/w/DdMos7BBk +gGcgyIKyvvKkIea/ik8aJpLBuJIsQbdtQwl8KhgK+btFyOEPWw5BBTItyvYC5K24 +rA3/jvzFWCBU5nArNYhaCQSFd/270eVgYewhB7jKs6TX+38uANilF79qv1lnJIyg +43NyspLhk/mfjdZwvPBhRO1IyAcDwgw5X6NshnquxYCvtVHD4qfsS8oXw+D/OQ== +-----END CERTIFICATE REQUEST----- +EOT +} \ No newline at end of file diff --git a/examples/resources/netapp-ontap_security_certificate/terraform.tfvars b/examples/resources/netapp-ontap_security_certificate/terraform.tfvars new file mode 120000 index 00000000..8d9d1c96 --- /dev/null +++ b/examples/resources/netapp-ontap_security_certificate/terraform.tfvars @@ -0,0 +1 @@ +../../provider/terraform.tfvars \ No newline at end of file diff --git a/examples/resources/netapp-ontap_security_certificate/variables.tf b/examples/resources/netapp-ontap_security_certificate/variables.tf new file mode 120000 index 00000000..395ce618 --- /dev/null +++ b/examples/resources/netapp-ontap_security_certificate/variables.tf @@ -0,0 +1 @@ +../../provider/variables.tf \ No newline at end of file From d7b15c25ce1fb0e9f9adbe69bb78cca18efe4b14 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 3 Oct 2024 13:37:14 +0530 Subject: [PATCH 22/23] update exmaples --- .../netapp-ontap_security_certificate/data-source.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/data-sources/netapp-ontap_security_certificate/data-source.tf b/examples/data-sources/netapp-ontap_security_certificate/data-source.tf index 5ace7893..38c07eb4 100644 --- a/examples/data-sources/netapp-ontap_security_certificate/data-source.tf +++ b/examples/data-sources/netapp-ontap_security_certificate/data-source.tf @@ -2,5 +2,5 @@ data "netapp-ontap_security_certificate" "security_certificate1" { # required to know which system to interface with cx_profile_name = "cluster5" - name = "tfsvm_17B9B4C1696136FC" + name = "tfsvm_ca_cert1" } From 0ea7c7632d0492697708839db1037a095959f175 Mon Sep 17 00:00:00 2001 From: Chandrakanta Sahu Date: Thu, 3 Oct 2024 13:46:20 +0530 Subject: [PATCH 23/23] remove examples/resources/netapp-ontap_security_certificate --- .../provider.tf | 1 - .../resource.tf | 26 ------------------- .../terraform.tfvars | 1 - .../variables.tf | 1 - 4 files changed, 29 deletions(-) delete mode 120000 examples/resources/netapp-ontap_security_certificate/provider.tf delete mode 100644 examples/resources/netapp-ontap_security_certificate/resource.tf delete mode 120000 examples/resources/netapp-ontap_security_certificate/terraform.tfvars delete mode 120000 examples/resources/netapp-ontap_security_certificate/variables.tf diff --git a/examples/resources/netapp-ontap_security_certificate/provider.tf b/examples/resources/netapp-ontap_security_certificate/provider.tf deleted file mode 120000 index c6b7138f..00000000 --- a/examples/resources/netapp-ontap_security_certificate/provider.tf +++ /dev/null @@ -1 +0,0 @@ -../../provider/provider.tf \ No newline at end of file diff --git a/examples/resources/netapp-ontap_security_certificate/resource.tf b/examples/resources/netapp-ontap_security_certificate/resource.tf deleted file mode 100644 index 233dee82..00000000 --- a/examples/resources/netapp-ontap_security_certificate/resource.tf +++ /dev/null @@ -1,26 +0,0 @@ -resource "netapp-ontap_security_certificate" "sign_certificate" { - cx_profile_name = "cluster5" - name = "svm2_ca_cert1_unique" - common_name = "svm2_ca_cert1" - type = "root_ca" - svm_name = "svm3" - expiry_time = "P90DT" - signing_request = <<-EOT ------BEGIN CERTIFICATE REQUEST----- -MIICmjCCAYICAQAwFTETMBEGA1UEAxQKc3ZtM19jZXJ0MTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBALR4afBcQLJ0iK041/5Kt1/X4KxKB2g50Ap3PNJw -aPx5KH/0PpxqLM8qqu5nsFVrjNnuUJ+1mnMsKVrVQHPXQqhJvlBmDh8PcR+snQhD -XqU1C/LOdsT1B2f6ezwHsQ0/s1yRXwRnYvbEpnNcq5xGRcwF4UeYZWjdhTDou9FL -qL9zJ0FeQZ/mt21yh9pe2NOtcawFfciljEOa3fEuZu2AMpNis53V3siQRcygBzmK -yC+OuoHIh7BO5Sac1wV6XZOANSGdqdQ+OJUSmh347ArEOBBTxDGPHrH0FFL0kSok -5sCO05eln/JErULyaySsjLW9dzSduZoIGEPweotVqKGGfDECAwEAAaBAMD4GCSqG -SIb3DQEJDjExMC8wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMC -BggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEAMCmLaaAET6WrMBrXOsj1tfzi -5zFlSQXo72c2KgaIrYTJ/tDbXFGFpV4f7cKDI3CIBjh4GQ3cNtr9ktg6Aq4cZajr -2cSfIpwNIZZlU/UribZf3Y5F7zN6vxL/Kb31AjpSITyM+Q1hlK/1/w/DdMos7BBk -gGcgyIKyvvKkIea/ik8aJpLBuJIsQbdtQwl8KhgK+btFyOEPWw5BBTItyvYC5K24 -rA3/jvzFWCBU5nArNYhaCQSFd/270eVgYewhB7jKs6TX+38uANilF79qv1lnJIyg -43NyspLhk/mfjdZwvPBhRO1IyAcDwgw5X6NshnquxYCvtVHD4qfsS8oXw+D/OQ== ------END CERTIFICATE REQUEST----- -EOT -} \ No newline at end of file diff --git a/examples/resources/netapp-ontap_security_certificate/terraform.tfvars b/examples/resources/netapp-ontap_security_certificate/terraform.tfvars deleted file mode 120000 index 8d9d1c96..00000000 --- a/examples/resources/netapp-ontap_security_certificate/terraform.tfvars +++ /dev/null @@ -1 +0,0 @@ -../../provider/terraform.tfvars \ No newline at end of file diff --git a/examples/resources/netapp-ontap_security_certificate/variables.tf b/examples/resources/netapp-ontap_security_certificate/variables.tf deleted file mode 120000 index 395ce618..00000000 --- a/examples/resources/netapp-ontap_security_certificate/variables.tf +++ /dev/null @@ -1 +0,0 @@ -../../provider/variables.tf \ No newline at end of file