Skip to content

Commit

Permalink
Merge pull request #166 from NetApp/16-new-data-source-cluster
Browse files Browse the repository at this point in the history
Edit cluster data source.
  • Loading branch information
carchi8py authored Apr 16, 2024
2 parents d2fabba + 31845ce commit 33b3bf4
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ ENHANCEMENTS:
* **netapp-ontap_networking_ip_interface_resource**: Add support for import ([#32](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/32))
* **netapp-ontap_protocols_nfs_export_policy_rule_resource**: Add support for import ([#35](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/35))
* **netapp-ontap_networking_ip_route_resource**: Add support for import ([#33](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/33))
* **netapp-ontap_cluster** Add contact, locaton, dns_domains, name_servers, timezone, certificate, ntp_servers, management_interfaces options ([#16](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/16))

BUG FIXES:
* **netapp-ontap_protocols_nfs_service**: Fixed issue with version check failing for minor versions
Expand Down
51 changes: 49 additions & 2 deletions docs/data-sources/cluster_data_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ description: |-

# netapp-ontap_cluster_data_source (Data Source)

Cluster data source
Retrieves the details of a cluster data source

### Related ONTAP commands
cluster show

## Example Usage
```terraform
data "netapp-ontap_cluster_data_source" "cluster" {
# required to know which system to interface with
cx_profile_name = "cluster2"
cx_profile_name = "cluster4"
}
```


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

Expand All @@ -26,10 +31,44 @@ data "netapp-ontap_cluster_data_source" "cluster" {

### Read-Only

- `certificate` (Attributes) Certificate (see [below for nested schema](#nestedatt--certificate))
- `contact` (String) Contact information. Example: support@company.com
- `dns_domains` (Set of String) A list of DNS domains.
- `location` (String) Location information
- `management_interfaces` (Attributes Set) A list of network interface (see [below for nested schema](#nestedatt--management_interfaces))
- `name` (String) Cluster name
- `name_servers` (Set of String) The list of IP addresses of the DNS servers. Addresses can be either IPv4 or IPv6 addresses.
- `nodes` (Attributes List) Cluster Nodes (see [below for nested schema](#nestedatt--nodes))
- `ntp_servers` (Set of String) Host name, IPv4 address, or IPv6 address for the external NTP time servers.
- `time_zone` (Attributes) Time zone (see [below for nested schema](#nestedatt--time_zone))
- `version` (Attributes) ONTAP software version (see [below for nested schema](#nestedatt--version))

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

Read-Only:

- `id` (String)


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

Read-Only:

- `id` (String) ID
- `ip` (Attributes) IP address (see [below for nested schema](#nestedatt--management_interfaces--ip))
- `name` (String) Name

<a id="nestedatt--management_interfaces--ip"></a>
### Nested Schema for `management_interfaces.ip`

Read-Only:

- `address` (String) IP address



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

Expand All @@ -39,6 +78,14 @@ Read-Only:
- `name` (String)


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

Read-Only:

- `name` (String) Time zone


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

Expand Down
33 changes: 29 additions & 4 deletions internal/interfaces/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,31 @@ import (
type ClusterGetDataModelONTAP struct {
// ConfigurableAttribute types.String `json:"configurable_attribute"`
// ID types.String `json:"id"`
Name string
Version versionModelONTAP
Name string
Version versionModelONTAP
Contact string
Location string
DNSDomains []string `mapstructure:"dns_domains"`
NameServers []string `mapstructure:"name_servers"`
NtpServers []string `mapstructure:"ntp_servers"`
TimeZone timeZone `mapstructure:"timezone"`
ClusterCertificate ClusterCertificate `mapstructure:"certificate"`
ManagementInterfaces []mgmtInterface `mapstructure:"management_interfaces"`
}

type timeZone struct {
Name string
}

type mgmtInterface struct {
IP ipAddress `mapstructure:"ip"`
Name string `mapstructure:"name"`
ID string `mapstructure:"uuid"`
}

// ClusterCertificate describes the GET record data model using go types for mapping.
type ClusterCertificate struct {
ID string `mapstructure:"uuid"`
}

type versionModelONTAP struct {
Expand All @@ -28,20 +51,22 @@ type ipAddress struct {
Address string
}

type mgmtInterface struct {
type noddMgmtInterface struct {
IP ipAddress
}

// ClusterNodeGetDataModelONTAP describes the GET record data model using go types for mapping.
type ClusterNodeGetDataModelONTAP struct {
Name string
ManagementInterfaces []mgmtInterface `mapstructure:"management_interfaces"`
ManagementInterfaces []noddMgmtInterface `mapstructure:"management_interfaces"`
// Version versionModelONTAP
}

// GetCluster to get cluster info
func GetCluster(errorHandler *utils.ErrorHandler, r restclient.RestClient) (*ClusterGetDataModelONTAP, error) {
statusCode, response, err := r.GetNilOrOneRecord("cluster", nil, nil)
query := r.NewQuery()
query.Fields([]string{"name", "location", "contact", "dns_domains", "name_servers", "ntp_servers", "management_interfaces", "timezone", "certificate"})
if err == nil && response == nil {
err = fmt.Errorf("no response for GET cluster")
}
Expand Down
2 changes: 1 addition & 1 deletion internal/interfaces/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestGetClusterNodes(t *testing.T) {
errorHandler := utils.NewErrorHandler(context.Background(), &diag.Diagnostics{})
record := ClusterNodeGetDataModelONTAP{
Name: "cluster1-01",
ManagementInterfaces: []mgmtInterface{
ManagementInterfaces: []noddMgmtInterface{
{ipAddress{"10.11.12.13"}},
{ipAddress{"10.11.12.14"}},
},
Expand Down
190 changes: 186 additions & 4 deletions internal/provider/cluster_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
Expand Down Expand Up @@ -33,10 +34,18 @@ type ClusterDataSource struct {
type ClusterDataSourceModel struct {
// ConfigurableAttribute types.String `tfsdk:"configurable_attribute"`
// ID types.String `tfsdk:"id"`
CxProfileName types.String `tfsdk:"cx_profile_name"`
Name types.String `tfsdk:"name"`
Version *versionModel `tfsdk:"version"`
Nodes []NodeDataSourceModel `tfsdk:"nodes"`
CxProfileName types.String `tfsdk:"cx_profile_name"`
Name types.String `tfsdk:"name"`
Version *versionModel `tfsdk:"version"`
Nodes []NodeDataSourceModel `tfsdk:"nodes"`
Contact types.String `tfsdk:"contact"`
Location types.String `tfsdk:"location"`
DNSDomains types.Set `tfsdk:"dns_domains"`
NameServers types.Set `tfsdk:"name_servers"`
TimeZone types.Object `tfsdk:"timezone"`
Certificate types.Object `tfsdk:"certificate"`
NtpServers types.Set `tfsdk:"ntp_servers"`
ManagementInterfaces types.Set `tfsdk:"management_interfaces"`
}

// NodeDataSourceModel describes the data source data model.
Expand Down Expand Up @@ -95,6 +104,74 @@ func (d *ClusterDataSource) Schema(ctx context.Context, req datasource.SchemaReq
},
},
},
"contact": schema.StringAttribute{
Computed: true,
MarkdownDescription: "Contact information. Example: support@company.com",
},
"location": schema.StringAttribute{
Computed: true,
MarkdownDescription: "Location information",
},
"dns_domains": schema.SetAttribute{
ElementType: types.StringType,
Computed: true,
MarkdownDescription: "A list of DNS domains.",
},
"name_servers": schema.SetAttribute{
ElementType: types.StringType,
Computed: true,
MarkdownDescription: "The list of IP addresses of the DNS servers. Addresses can be either IPv4 or IPv6 addresses.",
},
"timezone": schema.SingleNestedAttribute{
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Computed: true,
MarkdownDescription: "Time zone",
},
},
Computed: true,
MarkdownDescription: "Time zone",
},
"certificate": schema.SingleNestedAttribute{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
},
Computed: true,
MarkdownDescription: "Certificate",
},
"ntp_servers": schema.SetAttribute{
ElementType: types.StringType,
Computed: true,
MarkdownDescription: "Host name, IPv4 address, or IPv6 address for the external NTP time servers.",
},
"management_interfaces": schema.SetNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"ip": schema.SingleNestedAttribute{
Attributes: map[string]schema.Attribute{
"address": schema.StringAttribute{
Computed: true,
MarkdownDescription: "IP address",
},
},
Computed: true,
MarkdownDescription: "IP address",
},
"name": schema.StringAttribute{
Computed: true,
MarkdownDescription: "Name",
},
"id": schema.StringAttribute{
Computed: true,
MarkdownDescription: "ID",
},
},
},
Computed: true,
MarkdownDescription: "A list of network interface",
},
},
}
}
Expand Down Expand Up @@ -148,6 +225,111 @@ func (d *ClusterDataSource) Read(ctx context.Context, req datasource.ReadRequest
data.Version = &versionModel{
Full: types.StringValue(cluster.Version.Full),
}
data.Contact = types.StringValue(cluster.Contact)
data.Location = types.StringValue(cluster.Location)

// dns domains
elements := []attr.Value{}
for _, dnsDomain := range cluster.DNSDomains {
elements = append(elements, types.StringValue(dnsDomain))
}
setValue, diags := types.SetValue(types.StringType, elements)
resp.Diagnostics.Append(diags...)
data.DNSDomains = setValue

//name servers
elements = []attr.Value{}
for _, nameServer := range cluster.NameServers {
elements = append(elements, types.StringValue(nameServer))
}
setValue, diags = types.SetValue(types.StringType, elements)
resp.Diagnostics.Append(diags...)
data.NameServers = setValue
// time zone
elementTypes := map[string]attr.Type{
"name": types.StringType,
}
objectElements := map[string]attr.Value{
"name": types.StringValue(cluster.TimeZone.Name),
}
objectValue, diags := types.ObjectValue(elementTypes, objectElements)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}
data.TimeZone = objectValue

// certificate
elementTypes = map[string]attr.Type{
"id": types.StringType,
}
objectElements = map[string]attr.Value{
"id": types.StringValue(cluster.ClusterCertificate.ID),
}
objectValue, diags = types.ObjectValue(elementTypes, objectElements)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}
data.Certificate = objectValue

// ntp servers
elements = []attr.Value{}
for _, ntpServer := range cluster.NtpServers {
elements = append(elements, types.StringValue(ntpServer))
}
setValue, diags = types.SetValue(types.StringType, elements)
resp.Diagnostics.Append(diags...)
data.NtpServers = setValue

// management interfaces
setElements := []attr.Value{}
for _, mgmInterface := range cluster.ManagementInterfaces {
nestedElementTypes := map[string]attr.Type{
"address": types.StringType,
}
nestedVolumeElements := map[string]attr.Value{
"address": types.StringValue(mgmInterface.IP.Address),
}
originVolumeObjectValue, diags := types.ObjectValue(nestedElementTypes, nestedVolumeElements)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}

elementTypes := map[string]attr.Type{
"ip": types.ObjectType{AttrTypes: nestedElementTypes},
"name": types.StringType,
"id": types.StringType,
}
elements := map[string]attr.Value{
"ip": originVolumeObjectValue,
"name": types.StringValue(mgmInterface.Name),
"id": types.StringValue(mgmInterface.ID),
}
objectValue, diags := types.ObjectValue(elementTypes, elements)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}
setElements = append(setElements, objectValue)
}

setValue, diags = types.SetValue(types.ObjectType{
AttrTypes: map[string]attr.Type{
"ip": types.ObjectType{AttrTypes: map[string]attr.Type{
"address": types.StringType,
}},
"name": types.StringType,
"id": types.StringType,
},
}, setElements)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}

data.ManagementInterfaces = setValue

nodes, err := interfaces.GetClusterNodes(errorHandler, *client)
if err != nil {
Expand Down

0 comments on commit 33b3bf4

Please sign in to comment.