Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement]: Add interface service_policy parameter #332

Open
wants to merge 6 commits into
base: integration/main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/data-sources/networking_ip_interface_data_source.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ data "netapp-ontap_network_ip_interface" "ip_interface" {
- `ip` (Attributes) (see [below for nested schema](#nestedatt--ip))
- `location` (Attributes) (see [below for nested schema](#nestedatt--location))
- `scope` (String) IPInterface scope
- `service_policy` (String) IPInterface service policy

<a id="nestedatt--ip"></a>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Read-Only:
- `name` (String) IPInterface name
- `scope` (String) IPInterface scope
- `svm_name` (String) IPInterface svm name. Applies only to SVM-scoped objects
- `service_policy` (String) IPInterface service policy

<a id="nestedatt--ip_interfaces--ip"></a>

Expand Down
5 changes: 5 additions & 0 deletions docs/resources/network_ip_interface_resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ resource "netapp-ontap_network_ip_interface" "example" {
home_port = "e0d"
home_node = "ontap_cluster_1-01"
}
service_policy = "default-management"
}
```

Expand All @@ -52,6 +53,10 @@ resource "netapp-ontap_network_ip_interface" "example" {
- `name` (String) IPInterface name
- `svm_name` (String) IPInterface svm name

### Optional

- `service_policy` (String) IPInterface service policy

### Read-Only

- `id` (String) IPInterface UUID
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
resource "netapp-ontap_network_ip_interface" "ip_interface" {
# required to know which system to interface with
cx_profile_name = "cluster4"
name = "testme"
svm_name = "ansibleSVM"
name = "testme"
svm_name = "ansibleSVM"
ip = {
address = "10.10.10.10"
netmask = 20
}
}
location = {
home_port = "e0c"
home_node = "ontap_cluster_1-01"
}
service_policy = "default-management"
}
54 changes: 41 additions & 13 deletions internal/interfaces/networking_ip_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import (

// IPInterfaceGetDataModelONTAP describes the GET record data model using go types for mapping.
type IPInterfaceGetDataModelONTAP struct {
Name string `mapstructure:"name"`
Scope string `mapstructure:"scope"`
SVM IPInterfaceSvmName `mapstructure:"svm"`
UUID string `mapstructure:"uuid"`
IP IPInterfaceGetIP `mapstructure:"ip"`
Location IPInterfaceResourceLocation `mapstructure:"location"`
IP IPInterfaceGetIP `mapstructure:"ip"`
Location IPInterfaceResourceLocation `mapstructure:"location"`
Name string `mapstructure:"name"`
Scope string `mapstructure:"scope"`
ServicePolicy IPInterfaceServicePolicy `mapstructure:"service_policy"`
SVM IPInterfaceSvmName `mapstructure:"svm"`
UUID string `mapstructure:"uuid"`
}

// IPInterfaceGetIP describes the GET record data for IP.
Expand All @@ -27,10 +28,11 @@ type IPInterfaceGetIP struct {

// IPInterfaceResourceBodyDataModelONTAP describes the body data model using go types for mapping.
type IPInterfaceResourceBodyDataModelONTAP struct {
Name string `mapstructure:"name"`
SVM IPInterfaceSvmName `mapstructure:"svm,omitempty"` // API errors if body contains svm name when updating. can not use universal 'svm struct'
IP IPInterfaceResourceIP `mapstructure:"ip"`
Location IPInterfaceResourceLocation `mapstructure:"location"`
IP IPInterfaceResourceIP `mapstructure:"ip"`
Location IPInterfaceResourceLocation `mapstructure:"location"`
Name string `mapstructure:"name"`
ServicePolicy IPInterfaceServicePolicy `mapstructure:"service_policy"`
SVM IPInterfaceSvmName `mapstructure:"svm,omitempty"` // API errors if body contains svm name when updating. can not use universal 'svm struct'
}

// IPInterfaceSvmName describes the svm name specifcally for network ip interface.
Expand Down Expand Up @@ -61,6 +63,11 @@ type IPInterfaceResourceHomePort struct {
Node IPInterfaceResourceHomeNode `mapstructure:"node"`
}

// IPInterfaceServicePolicy is the body data model for the service_policy field
type IPInterfaceServicePolicy struct {
Name string `mapstructure:"name,omitempty"`
}

// IPInterfaceDataSourceFilterModel describes filter model.
type IPInterfaceDataSourceFilterModel struct {
Name string `tfsdk:"name"`
Expand All @@ -78,7 +85,14 @@ func GetIPInterface(errorHandler *utils.ErrorHandler, r restclient.RestClient, i
// query.Set("svm.name", svmName)
// query.Set("scope", "svm")
// }
query.Fields([]string{"name", "svm.name", "ip", "scope", "location"})
query.Fields([]string{
"name",
"svm.name",
"ip",
"scope",
"location",
"service_policy",
})
statusCode, response, err := r.GetNilOrOneRecord(api, query, nil)
if err == nil && response == nil {
err = fmt.Errorf("no response for GET %s", api)
Expand Down Expand Up @@ -107,7 +121,14 @@ func GetIPInterfaceByName(errorHandler *utils.ErrorHandler, r restclient.RestCli
query.Set("svm.name", svmName)
query.Set("scope", "svm")
}
query.Fields([]string{"name", "svm.name", "ip", "scope", "location"})
query.Fields([]string{
"name",
"svm.name",
"ip",
"scope",
"location",
"service_policy",
})
statusCode, response, err := r.GetNilOrOneRecord(api, query, nil)
if err == nil && response == nil {
err = fmt.Errorf("no response for GET %s", api)
Expand All @@ -129,7 +150,14 @@ func GetIPInterfaceByName(errorHandler *utils.ErrorHandler, r restclient.RestCli
func GetListIPInterfaces(errorHandler *utils.ErrorHandler, r restclient.RestClient, filter *IPInterfaceDataSourceFilterModel) ([]IPInterfaceGetDataModelONTAP, error) {
api := "network/ip/interfaces"
query := r.NewQuery()
query.Fields([]string{"name", "svm.name", "ip", "scope", "location"})
query.Fields([]string{
"name",
"svm.name",
"ip",
"scope",
"location",
"service_policy",
})

if filter != nil {
if filter.Name != "" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import (
"fmt"
"strconv"

"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/provider/connection"
"github.com/netapp/terraform-provider-netapp-ontap/internal/utils"
)

Expand Down Expand Up @@ -49,6 +48,7 @@ type IPInterfaceDataSourceModel struct {
Scope types.String `tfsdk:"scope"`
IP *IPDataSourceModel `tfsdk:"ip"`
Location *LocationDataSourceModel `tfsdk:"location"`
ServicePolicy types.String `tfsdk:"service_policy"`
}

// IPDataSourceModel describes the data source model for IP address and mask.
Expand Down Expand Up @@ -117,6 +117,10 @@ func (d *IPInterfaceDataSource) Schema(ctx context.Context, req datasource.Schem
},
Computed: true,
},
"service_policy": schema.StringAttribute{
Computed: true,
MarkdownDescription: "IPInterface service policy",
},
},
}
}
Expand Down Expand Up @@ -182,6 +186,7 @@ func (d *IPInterfaceDataSource) Read(ctx context.Context, req datasource.ReadReq
HomeNode: types.StringValue(restInfo.Location.HomeNode.Name),
HomePort: types.StringValue(restInfo.Location.HomePort.Name),
}
data.ServicePolicy = types.StringValue(restInfo.ServicePolicy.Name)

// Write logs using the tflog package
// Documentation: https://terraform.io/plugin/log
Expand Down
27 changes: 25 additions & 2 deletions internal/provider/networking/network_ip_interface_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"strconv"
"strings"

"github.com/netapp/terraform-provider-netapp-ontap/internal/provider/connection"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
Expand All @@ -16,6 +14,7 @@ import (
"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/provider/connection"
"github.com/netapp/terraform-provider-netapp-ontap/internal/utils"
)

Expand Down Expand Up @@ -65,6 +64,7 @@ type IPInterfaceResourceModel struct {
SVMName types.String `tfsdk:"svm_name"`
IP *IPInterfaceResourceIP `tfsdk:"ip"`
Location *IPInterfaceResourceLocation `tfsdk:"location"`
ServicePolicy types.String `tfsdk:"service_policy"`
UUID types.String `tfsdk:"id"`
}

Expand Down Expand Up @@ -121,6 +121,14 @@ func (r *IPInterfaceResource) Schema(ctx context.Context, req resource.SchemaReq
},
Required: true,
},
"service_policy": schema.StringAttribute{
MarkdownDescription: "IPInterface service policy",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"id": schema.StringAttribute{
MarkdownDescription: "IPInterface UUID",
Computed: true,
Expand Down Expand Up @@ -202,6 +210,9 @@ func (r *IPInterfaceResource) Read(ctx context.Context, req resource.ReadRequest
}
ip.Netmask = types.Int64Value(int64(intValue))
data.IP = &ip

data.ServicePolicy = types.StringValue(restInfo.ServicePolicy.Name)

// 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 @@ -238,6 +249,7 @@ func (r *IPInterfaceResource) Create(ctx context.Context, req resource.CreateReq
body.Location.HomeNode = interfaces.IPInterfaceResourceHomeNode{
Name: data.Location.HomeNode.ValueString(),
}
body.ServicePolicy.Name = data.ServicePolicy.ValueString()

client, err := connection.GetRestClient(errorHandler, r.config, data.CxProfileName)
if err != nil {
Expand All @@ -254,6 +266,16 @@ func (r *IPInterfaceResource) Create(ctx context.Context, req resource.CreateReq

tflog.Trace(ctx, fmt.Sprintf("created a resource, UUID=%s", data.UUID))

if data.ServicePolicy.IsUnknown() {
// read newly created interface to populate service policy (not fetched by CreateIPInterface)
restInfo, err := interfaces.GetIPInterface(errorHandler, *client, data.UUID.ValueString())
if err != nil {
// error reporting done inside GetIPInterface
return
}
data.ServicePolicy = types.StringValue(restInfo.ServicePolicy.Name)
}

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
Expand Down Expand Up @@ -284,6 +306,7 @@ func (r *IPInterfaceResource) Update(ctx context.Context, req resource.UpdateReq
body.Location.HomeNode = interfaces.IPInterfaceResourceHomeNode{
Name: data.Location.HomeNode.ValueString(),
}
body.ServicePolicy.Name = data.ServicePolicy.ValueString()

client, err := connection.GetRestClient(errorHandler, r.config, data.CxProfileName)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,30 @@ func TestAccNetworkIpInterfaceResourceAlias(t *testing.T) {
Steps: []resource.TestStep{
// non-existant SVM return code 2621462. Must happen before create/read
{
Config: testAccNetworkIPInterfaceResourceConfigAlias("non-existant", "10.10.10.10", "ontap_cluster_1-01"),
Config: testAccNetworkIPInterfaceResourceConfigAlias("non-existant", "10.10.10.10", "ontap_cluster_1-01", "default-data-files"),
ExpectError: regexp.MustCompile("2621462"),
},
// non-existant home node
{
Config: testAccNetworkIPInterfaceResourceConfigAlias("terraform", "10.10.10.10", "non-existant_home_node"),
ExpectError: regexp.MustCompile("393271"),
Config: testAccNetworkIPInterfaceResourceConfigAlias("terraform", "10.10.10.10", "non-existant_home_node", "default-data-files"),
ExpectError: regexp.MustCompile("53281680"),
},
// Create and Read
// {
// Config: testAccNetworkIPInterfaceResourceConfigAlias("terraform", "10.10.10.10", "ontap_cluster_1-01"),
// Config: testAccNetworkIPInterfaceResourceConfigAlias("terraform", "10.10.10.10", "ontap_cluster_1-01", "default-data-files"),
// Check: resource.ComposeTestCheckFunc(
// resource.TestCheckResourceAttr("netapp-ontap_networking_ip_interface_resource.example", "name", "test-interface"),
// resource.TestCheckResourceAttr("netapp-ontap_networking_ip_interface_resource.example", "svm_name", "terraform"),
// resource.TestCheckResourceAttr("netapp-ontap_networking_ip_interface_resource.example", "service_policy", "default-data-files"),
// ),
// },
// // Update and Read
// {
// Config: testAccNetworkIPInterfaceResourceConfigAlias("terraform", "10.10.10.20", "ontap_cluster_1-01"),
// Config: testAccNetworkIPInterfaceResourceConfigAlias("terraform", "10.10.10.20", "ontap_cluster_1-01", "default-data-iscsi"),
// 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"),
// resource.TestCheckResourceAttr("netapp-ontap_networking_ip_interface_resource.example", "service_policy", "default-data-iscsi"),
// ),
// },
// Test importing a resource
Expand All @@ -56,7 +58,7 @@ func TestAccNetworkIpInterfaceResourceAlias(t *testing.T) {
})
}

func testAccNetworkIPInterfaceResourceConfigAlias(svmName, address, homeNode string) string {
func testAccNetworkIPInterfaceResourceConfigAlias(svmName, address, homeNode, servicePolicy string) string {
host := os.Getenv("TF_ACC_NETAPP_HOST5")
admin := os.Getenv("TF_ACC_NETAPP_USER")
password := os.Getenv("TF_ACC_NETAPP_PASS2")
Expand Down Expand Up @@ -89,6 +91,7 @@ resource "netapp-ontap_networking_ip_interface_resource" "example" {
home_port = "e0d"
home_node = "%s"
}
service_policy = "%s"
}
`, host, admin, password, svmName, address, homeNode)
`, host, admin, password, svmName, address, homeNode, servicePolicy)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,30 @@ func TestAccNetworkIpInterfaceResource(t *testing.T) {
Steps: []resource.TestStep{
// non-existant SVM return code 2621462. Must happen before create/read
{
Config: testAccNetworkIPInterfaceResourceConfig("non-existant", "10.10.10.10", "ontap_cluster_1-01"),
Config: testAccNetworkIPInterfaceResourceConfig("non-existant", "10.10.10.10", "ontap_cluster_1-01", "default-data-files"),
ExpectError: regexp.MustCompile("2621462"),
},
// non-existant home node
{
Config: testAccNetworkIPInterfaceResourceConfig("terraform", "10.10.10.10", "non-existant_home_node"),
ExpectError: regexp.MustCompile("393271"),
Config: testAccNetworkIPInterfaceResourceConfig("terraform", "10.10.10.10", "non-existant_home_node", "default-data-files"),
ExpectError: regexp.MustCompile("53281680"),
},
// Create and Read
// {
// Config: testAccNetworkIPInterfaceResourceConfig("svm0", "10.10.10.10", "ontap_cluster_1-01"),
// Config: testAccNetworkIPInterfaceResourceConfig("svm0", "10.10.10.10", "ontap_cluster_1-01", "default-data-files"),
// Check: resource.ComposeTestCheckFunc(
// resource.TestCheckResourceAttr("netapp-ontap_network_ip_interface.example", "name", "test-interface"),
// resource.TestCheckResourceAttr("netapp-ontap_network_ip_interface.example", "svm_name", "svm0"),
// resource.TestCheckResourceAttr("netapp-ontap_network_ip_interface.example", "service_policy", "default-data-files"),
// ),
// },
// // Update and Read
// {
// Config: testAccNetworkIPInterfaceResourceConfig("svm0", "10.10.10.20", "ontap_cluster_1-01"),
// Config: testAccNetworkIPInterfaceResourceConfig("svm0", "10.10.10.20", "ontap_cluster_1-01", "default-data-iscsi"),
// Check: resource.ComposeTestCheckFunc(
// resource.TestCheckResourceAttr("netapp-ontap_network_ip_interface.example", "name", "test-interface"),
// resource.TestCheckResourceAttr("netapp-ontap_network_ip_interface.example", "ip.address", "10.10.10.20"),
// resource.TestCheckResourceAttr("netapp-ontap_network_ip_interface.example", "service_policy", "default-data-iscsi"),
// ),
// },
// // Test importing a resource
Expand All @@ -56,7 +58,7 @@ func TestAccNetworkIpInterfaceResource(t *testing.T) {
})
}

func testAccNetworkIPInterfaceResourceConfig(svmName, address, homeNode string) string {
func testAccNetworkIPInterfaceResourceConfig(svmName, address, homeNode, servicePolicy string) string {
host := os.Getenv("TF_ACC_NETAPP_HOST5")
admin := os.Getenv("TF_ACC_NETAPP_USER")
password := os.Getenv("TF_ACC_NETAPP_PASS2")
Expand Down Expand Up @@ -89,6 +91,7 @@ resource "netapp-ontap_network_ip_interface" "example" {
home_port = "e0d"
home_node = "%s"
}
service_policy = "%s"
}
`, host, admin, password, svmName, address, homeNode)
`, host, admin, password, svmName, address, homeNode, servicePolicy)
}
Loading