Skip to content

Commit

Permalink
Merge branch 'integration/main' into 50-new-data-source-clusterpeers
Browse files Browse the repository at this point in the history
  • Loading branch information
carchi8py committed Dec 7, 2023
2 parents 27c04b9 + e50f989 commit 298dfb7
Show file tree
Hide file tree
Showing 15 changed files with 345 additions and 40 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/blackduck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Blackduck Scan

on:
push:
branches:
- integration/main

jobs:
build:

runs-on: self-hosted
steps:
- uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options
java-version: '17'
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.19.3'
- uses: actions/checkout@v3

- name: Build
env:
BLACKDUCK_URL: ${{ secrets.BLACKDUCK_URL }}
BLACKDUCK_API_TOKEN: ${{ secrets.BLACKDUCK_API_TOKEN }}

run: |
bash scripts/bd_scan.bash $BLACKDUCK_URL $BLACKDUCK_API_TOKEN
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ ENHANCEMENTS:
* **netapp-ontap_svm_resource**: Add support for import ([#6](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/6))
* **netapp-ontap_storage_volume_snapshot_resource**: Add support for import ([#42](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/42))
* **netapp-ontap_cluster_schedule_resource**: Add support for import ([#31](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/31))
* **netapp-ontap_snapmiror_policy**: Add support for import ([#38](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/38))
* **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))


## 1.0.2 (2023-11-17)
Expand Down
37 changes: 36 additions & 1 deletion docs/resources/networking_ip_interface_resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,39 @@ Required:
- `home_port` (String) IPInterface home port

## Import
Import is currently not support for this Resource.
This Resource supports import, which allows you to import existing network ip interface into the state of this resoruce.
Import require a unique ID composed of the interface name, svm_name and cx_profile_name, separated by a comma.
id = `name`,`svm_name`,`cx_profile_name`
### Terraform Import
For example
```shell
terraform import netapp-ontap_networking_ip_interface_resource.example if1,svm1,cluster4
```

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

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

First create the block
```terraform
import {
to = netapp-ontap_networking_ip_interface_resource.if_import
id = "if1,svm1,cluster4"
}
```
Next run, this will auto create the configuration for you
```shell
terraform plan -generate-config-out=generated.tf
```
This will generate a file called generated.tf, which will contain the configuration for the imported resource
```terraform
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
# __generated__ by Terraform from "if1,svm1,cluster4"
resource "netapp-ontap_networking_ip_interface_resource" "if1_import" {
cx_profile_name = "cluster4"
name = "if1"
svm_name = "svm1"
}
```
36 changes: 35 additions & 1 deletion docs/resources/protocols_nfs_export_policy_rule_resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,39 @@ resource "netapp-ontap_protocols_nfs_export_policy_rule_resource" "example" {
- `index` (Number) rule index

## Import
Import is currently not support for this Resource.
This Resource supports import, which allows you to import existing nfs export policy rule into the state of this resoruce.
Import require a unique ID composed of the rule index, export policy name, svm_name and cx_profile_name, separated by a comma.
id = `index`,`export_policy_name`,`svm_name`,`cx_profile_name`
### Terraform Import
For example
```shell
terraform import netapp-ontap_protocols_nfs_export_policy_rule_resource.rule_import index1,exp1,svm1,cluster4
```

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

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

First create the block
```terraform
import {
to = netapp-ontap_protocols_nfs_export_policy_rule_resource.rule_import
id = "index1,exp1,svm1,cluster4"
}
```
Next run, this will auto create the configuration for you
```shell
terraform plan -generate-config-out=generated.tf
```
This will generate a file called generated.tf, which will contain the configuration for the imported resource
```terraform
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
# __generated__ by Terraform from "index1,exp1,svm1,cluster4"
resource "netapp-ontap_protocols_nfs_export_policy_rule_resource" "rule_import" {
cx_profile_name = "cluster4"
export_policy_name = "exp1"
svm_name = "svm1"
}
```
56 changes: 55 additions & 1 deletion docs/resources/snapmirror_policy_resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,58 @@ Optional:
- `prefix` (String) Specifies the prefix for the Snapshot copy name to be created as per the schedule

## Import
Import is currently not support for this Resource.
This resource supports import, which allows you to import existing snapmirror policy into the state of this resource.
Import require a unique ID composed of the snapmirror policy name, svm name and connection profile, separated by a comma.

id = `name`,`svm_name`,`cx_profile_name`

### Terraform Import

For example
```shell
terraform import netapp-ontap_snapmirror_policy_resource.example test_name,svm1,cluster5
```
!> The terraform import CLI command can only import resources into the state. Importing via the CLI does not generate configuration. If you want to generate the accompanying configuration for imported resources, use the import block instead.

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

First create the block
```terraform
import {
to = netapp-ontap_snapmirror_policy_resource.snapmirror_policy_import
id = "test_name,svm1,cluster4"
}
```
Next run, this will auto create the configuration for you
```shell
terraform plan -generate-config-out=generated.tf
```
This will generate a file called generated.tf, which will contain the configuration for the imported resource
```terraform
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
# __generated__ by Terraform from "svm1_root,svm1,cluster4"
resource "netapp-ontap_snapmirror_policy_resource" "svm_import" {
comment = "testing import"
cx_profile_name = "cluster4"
name = "testImport"
copy_all_source_snapshots = false
copy_latest_source_snapshot = false
create_snapshot_on_source = false
identity_preservation = full
network_compression_enabled = false
retention = [
{
count = 4
creation_schedule_name = null
label = hi
prefix = null
}
]
svm_name = ansibleSVM
sync_type = null
transfer_schedule_name = null
type = async
}
```
30 changes: 29 additions & 1 deletion internal/interfaces/networking_ip_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,35 @@ type IPInterfaceDataSourceFilterModel struct {
}

// GetIPInterface to get ip_interface info
func GetIPInterface(errorHandler *utils.ErrorHandler, r restclient.RestClient, name string, svmName string) (*IPInterfaceGetDataModelONTAP, error) {
func GetIPInterface(errorHandler *utils.ErrorHandler, r restclient.RestClient, id string) (*IPInterfaceGetDataModelONTAP, error) {
api := "network/ip/interfaces" + "/" + id
query := r.NewQuery()
// if svmName == "" {
// query.Set("scope", "cluster")
// } else {
// query.Set("svm.name", svmName)
// query.Set("scope", "svm")
// }
query.Fields([]string{"name", "svm.name", "ip", "scope", "location"})
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 ip_interface info", fmt.Sprintf("error on GET %s: %s, statusCode %d", api, err, statusCode))
}

var dataONTAP IPInterfaceGetDataModelONTAP
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 ip_interface data source: %#v", dataONTAP))
return &dataONTAP, nil
}

// GetIPInterfaceByName to get ip_interface info
func GetIPInterfaceByName(errorHandler *utils.ErrorHandler, r restclient.RestClient, name string, svmName string) (*IPInterfaceGetDataModelONTAP, error) {
api := "network/ip/interfaces"
query := r.NewQuery()
query.Set("name", name)
Expand Down
2 changes: 1 addition & 1 deletion internal/interfaces/networking_ip_interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func TestGetIPInterface(t *testing.T) {
if err != nil {
panic(err)
}
got, err := GetIPInterface(errorHandler, *r, "name", "svmName")
got, err := GetIPInterfaceByName(errorHandler, *r, "name", "svmName")
if err != nil {
fmt.Printf("err: %s\n", err)
}
Expand Down
6 changes: 3 additions & 3 deletions internal/interfaces/snapmirror_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func GetSnapmirrorPolicy(errorHandler *utils.ErrorHandler, r restclient.RestClie
}

// GetSnapmirrorPolicyByName to get snapmirror policy info
func GetSnapmirrorPolicyByName(errorHandler *utils.ErrorHandler, r restclient.RestClient, name string, svmName string) (*SnapmirrorPolicyGetDataModelONTAP, error) {
func GetSnapmirrorPolicyByName(errorHandler *utils.ErrorHandler, r restclient.RestClient, name string, svmName string) (*SnapmirrorPolicyGetRawDataModelONTAP, error) {
api := "snapmirror/policies"
query := r.NewQuery()
query.Set("name", name)
Expand All @@ -141,7 +141,7 @@ func GetSnapmirrorPolicyByName(errorHandler *utils.ErrorHandler, r restclient.Re
query.Set("scope", "svm")
}
// TODO: copy_all_source_snapshots is 9.10 and up
query.Fields(([]string{"name", "svm.name", "type", "comment", "transfer_schedule", "network_compression_enabled", "retention", "identity_preservation", "copy_all_source_snapshots", "uuid"}))
query.Fields(([]string{"name", "svm.name", "type", "sync_type", "comment", "transfer_schedule", "network_compression_enabled", "retention", "identity_preservation", "copy_all_source_snapshots", "uuid"}))
statusCode, response, err := r.GetNilOrOneRecord(api, query, nil)
if err == nil && response == nil {
err = fmt.Errorf("no response for GET %s", api)
Expand All @@ -150,7 +150,7 @@ func GetSnapmirrorPolicyByName(errorHandler *utils.ErrorHandler, r restclient.Re
return nil, errorHandler.MakeAndReportError("error reading snapmirror/policies info", fmt.Sprintf("error on GET %s: %s, statusCode %d", api, err, statusCode))
}

var dataONTAP SnapmirrorPolicyGetDataModelONTAP
var dataONTAP SnapmirrorPolicyGetRawDataModelONTAP
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))
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/networking_ip_interface_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (d *IPInterfaceDataSource) Read(ctx context.Context, req datasource.ReadReq
return
}

restInfo, err := interfaces.GetIPInterface(errorHandler, *client, data.Name.ValueString(), data.SVMName.ValueString())
restInfo, err := interfaces.GetIPInterfaceByName(errorHandler, *client, data.Name.ValueString(), data.SVMName.ValueString())
if err != nil {
// error reporting done inside GetIPInterface
return
Expand Down
47 changes: 37 additions & 10 deletions internal/provider/networking_ip_interface_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"strconv"
"strings"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
Expand Down Expand Up @@ -162,26 +163,41 @@ func (r *IPInterfaceResource) Read(ctx context.Context, req resource.ReadRequest
return
}

restInfo, err := interfaces.GetIPInterface(errorHandler, *client, data.Name.ValueString(), data.SVMName.ValueString())
if err != nil {
// error reporting done inside GetIPInterface
return
var restInfo *interfaces.IPInterfaceGetDataModelONTAP
if data.UUID.IsNull() {
restInfo, err = interfaces.GetIPInterfaceByName(errorHandler, *client, data.Name.ValueString(), data.SVMName.ValueString())
if err != nil {
// error reporting done inside GetIPInterfaceByName
return
}
} else {
restInfo, err = interfaces.GetIPInterface(errorHandler, *client, data.UUID.ValueString())
if err != nil {
// error reporting done inside GetIPInterface
return
}
}
if restInfo == nil {
errorHandler.MakeAndReportError("No Interface found", fmt.Sprintf("NO interface, %s found.", data.Name.ValueString()))
return
}
data.Name = types.StringValue(restInfo.Name)
data.UUID = types.StringValue(restInfo.UUID)
data.Location.HomeNode = types.StringValue(restInfo.Location.HomeNode.Name)
data.IP.Address = types.StringValue(restInfo.IP.Address)

var location IPInterfaceResourceLocation
location.HomeNode = types.StringValue(restInfo.Location.HomeNode.Name)
location.HomePort = types.StringValue(restInfo.Location.HomePort.Name)
data.Location = &location

var ip IPInterfaceResourceIP
ip.Address = types.StringValue(restInfo.IP.Address)
intValue, err := strconv.Atoi(restInfo.IP.Netmask)
if err != nil {
errorHandler.MakeAndReportError("Failed to read ip interface", fmt.Sprintf("Error: failed to convert string value '%s' to int for net mask.", restInfo.IP.Netmask))
return
}
data.IP.Netmask = types.Int64Value(int64(intValue))

ip.Netmask = types.Int64Value(int64(intValue))
data.IP = &ip
// Write logs using the tflog package
// Documentation: https://terraform.io/plugin/log
tflog.Debug(ctx, fmt.Sprintf("read a resource: %#v", data))
Expand Down Expand Up @@ -300,7 +316,7 @@ func (r *IPInterfaceResource) Delete(ctx context.Context, req resource.DeleteReq
}

if data.UUID.IsNull() {
errorHandler.MakeAndReportError("UUID is null", "ip_interface UUID is null")
errorHandler.MakeAndReportError("UUID is null", "ip_interface ID is null")
return
}

Expand All @@ -313,5 +329,16 @@ func (r *IPInterfaceResource) Delete(ctx context.Context, req resource.DeleteReq

// ImportState imports a resource using ID from terraform import command by calling the Read method.
func (r *IPInterfaceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
tflog.Debug(ctx, fmt.Sprintf("import req a network ip interface resource: %#v", req))
idParts := strings.Split(req.ID, ",")
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
resp.Diagnostics.AddError(
"Unexpected Import Identifier",
fmt.Sprintf("Expected import identifier with format: name,svm_name,cx_profile_name. Got: %q", req.ID),
)
return
}
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("name"), idParts[0])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("svm_name"), idParts[1])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("cx_profile_name"), idParts[2])...)
}
10 changes: 10 additions & 0 deletions internal/provider/networking_ip_interface_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ func TestAccNetworkingIpInterfaceResource(t *testing.T) {
resource.TestCheckResourceAttr("netapp-ontap_networking_ip_interface_resource.example", "ip.address", "10.10.10.20"),
),
},
// Test importing a resource
{
ResourceName: "netapp-ontap_networking_ip_interface_resource.example",
ImportState: true,
ImportStateId: fmt.Sprintf("%s,%s,%s", "test-interface", "svm0", "cluster4"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("netapp-ontap_networking_ip_interface_resource.example", "name", "test-interface"),
resource.TestCheckResourceAttr("netapp-ontap_networking_ip_interface_resource.example", "ip.address", "10.10.10.20"),
),
},
},
})
}
Expand Down
Loading

0 comments on commit 298dfb7

Please sign in to comment.