diff --git a/CHANGELOG.md b/CHANGELOG.md index 336ae4f..55294c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ FEATURES: * **New Data Source:** `netapp-ontap_volumes_files` ([#8](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/8)) +ENHANCEMENTS: +* **netapp-ontap_lun**: added `size_unit` option. ([#227](https://github.com/NetApp/terraform-provider-netapp-ontap/issues/227)) + ## 1.1.2 (2024-06-03) ENHANCEMENTS: diff --git a/docs/resources/storage_lun_resource.md b/docs/resources/storage_lun_resource.md index 2712b63..48d8351 100644 --- a/docs/resources/storage_lun_resource.md +++ b/docs/resources/storage_lun_resource.md @@ -46,13 +46,14 @@ resource "netapp-ontap_lun" "storage_lun" { - `cx_profile_name` (String) Connection profile name - `name` (String) Lun name or location.logical_unit - `os_type` (String) OS type -- `size` (Number) Size of the lun +- `size` (Number) Size of the lun in byte if size_unit is not provided, otherwise size in the specified `size_unit` - `svm_name` (String) SVM name - `volume_name` (String) Volume name ### Optional - `qos_policy_name` (String) QoS policy name +- `size_unit` (String) The unit used to interpret the size parameter ### Read-Only diff --git a/internal/provider/storage/storage_lun_resource.go b/internal/provider/storage/storage_lun_resource.go index d4b20c0..cef10d7 100644 --- a/internal/provider/storage/storage_lun_resource.go +++ b/internal/provider/storage/storage_lun_resource.go @@ -44,6 +44,7 @@ type StorageLunResourceModel struct { VolumeName types.String `tfsdk:"volume_name"` OSType types.String `tfsdk:"os_type"` Size types.Int64 `tfsdk:"size"` + SizeUnit types.String `tfsdk:"size_unit"` QoSPolicyName types.String `tfsdk:"qos_policy_name"` SerialNumber types.String `tfsdk:"serial_number"` LogicalUnit types.String `tfsdk:"logical_unit"` @@ -95,9 +96,13 @@ func (r *StorageLunResource) Schema(ctx context.Context, req resource.SchemaRequ Required: true, }, "size": schema.Int64Attribute{ - MarkdownDescription: "Size of the lun", + MarkdownDescription: "Size of the lun in byte if size_unit is not provided, otherwise size in the specified unit", Required: true, }, + "size_unit": schema.StringAttribute{ + MarkdownDescription: "The unit used to interpret the size parameter", + Optional: true, + }, "qos_policy_name": schema.StringAttribute{ MarkdownDescription: "QoS policy name", Optional: true, @@ -182,7 +187,15 @@ func (r *StorageLunResource) Read(ctx context.Context, req resource.ReadRequest, data.VolumeName = types.StringValue(restInfo.Location.Volume.Name) data.OSType = types.StringValue(restInfo.OSType) data.SerialNumber = types.StringValue(restInfo.SerialNumber) - data.Size = types.Int64Value(restInfo.Space.Size) + if !data.SizeUnit.IsNull() { + var sizeUnit string + var size int64 + size, sizeUnit = interfaces.ByteFormat(int64(restInfo.Space.Size)) + data.Size = types.Int64Value(size) + data.SizeUnit = types.StringValue(sizeUnit) + } else { + data.Size = types.Int64Value(restInfo.Space.Size) + } if restInfo.QoSPolicy.Name != "" { data.QoSPolicyName = types.StringValue(restInfo.QoSPolicy.Name) } @@ -218,7 +231,16 @@ func (r *StorageLunResource) Create(ctx context.Context, req resource.CreateRequ body.Locations.Volume.Name = data.VolumeName.ValueString() body.SVM.Name = data.SVMName.ValueString() body.OsType = data.OSType.ValueString() - body.Space.Size = data.Size.ValueInt64() + if !data.SizeUnit.IsNull() { + if _, ok := interfaces.POW2BYTEMAP[data.SizeUnit.ValueString()]; !ok { + errorHandler.MakeAndReportError("error creating flexcache", fmt.Sprintf("invalid input for size_unit: %s, required one of: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb", data.SizeUnit.ValueString())) + return + } + body.Space.Size = data.Size.ValueInt64() * int64(interfaces.POW2BYTEMAP[data.SizeUnit.ValueString()]) + } else { + body.Space.Size = data.Size.ValueInt64() + } + if !data.QoSPolicyName.IsNull() { body.QosPolicy = data.QoSPolicyName.ValueString() } @@ -279,9 +301,16 @@ func (r *StorageLunResource) Update(ctx context.Context, req resource.UpdateRequ if !plan.OSType.Equal(state.OSType) { request.OsType = plan.OSType.ValueString() } - if !plan.Size.Equal(state.Size) { - request.Space.Size = plan.Size.ValueInt64() + baseUnit := int64(1) + if !plan.SizeUnit.IsNull() { + if _, ok := interfaces.POW2BYTEMAP[plan.SizeUnit.ValueString()]; !ok { + errorHandler.MakeAndReportError("error updating lun", fmt.Sprintf("invalid input for size_unit: %s, required one of: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb", plan.SizeUnit.ValueString())) + return + } + baseUnit = int64(interfaces.POW2BYTEMAP[plan.SizeUnit.ValueString()]) } + request.Space.Size = plan.Size.ValueInt64() * baseUnit + if !plan.QoSPolicyName.Equal(state.QoSPolicyName) { request.QosPolicy = plan.QoSPolicyName.ValueString() } diff --git a/internal/provider/storage/storage_lun_resource_test.go b/internal/provider/storage/storage_lun_resource_test.go index 82baf8e..886b147 100644 --- a/internal/provider/storage/storage_lun_resource_test.go +++ b/internal/provider/storage/storage_lun_resource_test.go @@ -25,7 +25,7 @@ func TestAccStorageLunResouce(t *testing.T) { Config: testAccStorageLunResourceConfig("ACC-lun", "carchi-test", "unnownsvm", "linux", 1048576), ExpectError: regexp.MustCompile("917927"), }, - // Create storage lun and read + // Create storage lun and read without size_unit { Config: testAccStorageLunResourceConfig("ACC-lun", "carchi-test", "lunTest", "linux", 1048576), Check: resource.ComposeTestCheckFunc( @@ -58,6 +58,42 @@ func TestAccStorageLunResouce(t *testing.T) { resource.TestCheckResourceAttr("netapp-ontap_lun.example", "size", "1048576"), ), }, + // create storage lun with size_unit + { + Config: testAccStorageLunResourceWithSizeUnitConfig("ACC-lun-size", "carchi-test", "lunTest", "linux", 4, "kb"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "name", "/vol/lunTest/ACC-lun-size"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "svm_name", "carchi-test"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "volume_name", "lunTest"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "os_type", "linux"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "size", "4"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "size_unit", "kb"), + ), + }, + // update storage lun with size_unit + { + Config: testAccStorageLunResourceWithSizeUnitConfig("ACC-lun-size", "carchi-test", "lunTest", "linux", 5, "kb"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "name", "/vol/lunTest/ACC-lun-size"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "svm_name", "carchi-test"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "volume_name", "lunTest"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "os_type", "linux"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "size", "5"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "size_unit", "kb"), + ), + }, + // update storage lun size_unit + { + Config: testAccStorageLunResourceWithSizeUnitConfig("ACC-lun-size", "carchi-test", "lunTest", "linux", 5, "mb"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "name", "/vol/lunTest/ACC-lun-size"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "svm_name", "carchi-test"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "volume_name", "lunTest"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "os_type", "linux"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "size", "5"), + resource.TestCheckResourceAttr("netapp-ontap_lun.example_size", "size_unit", "mb"), + ), + }, }, }) } @@ -93,3 +129,36 @@ resource "netapp-ontap_lun" "example" { size = "%d" }`, host, admin, password, logicalUnit, svmname, volumeName, osType, size) } + +func testAccStorageLunResourceWithSizeUnitConfig(logicalUnit string, svmname string, volumeName string, osType string, size int64, size_unit string) string { + host := os.Getenv("TF_ACC_NETAPP_HOST") + admin := os.Getenv("TF_ACC_NETAPP_USER") + password := os.Getenv("TF_ACC_NETAPP_PASS") + if host == "" || admin == "" || password == "" { + fmt.Println("TF_ACC_NETAPP_HOST, TF_ACC_NETAPP_USER, and TF_ACC_NETAPP_PASS must be set for acceptance tests") + os.Exit(1) + } + return fmt.Sprintf(` +provider "netapp-ontap" { + connection_profiles = [ + { + name = "cluster4" + hostname = "%s" + username = "%s" + password = "%s" + validate_certs = false + }, + ] +} + +resource "netapp-ontap_lun" "example_size" { + # required to know which system to interface with + cx_profile_name = "cluster4" + logical_unit = "%s" + svm_name = "%s" + volume_name = "%s" + os_type = "%s" + size = "%d" + size_unit = "%s" +}`, host, admin, password, logicalUnit, svmname, volumeName, osType, size, size_unit) +} diff --git a/internal/provider/storage/storage_volume_resource.go b/internal/provider/storage/storage_volume_resource.go index c9fe8f1..cb6ef53 100644 --- a/internal/provider/storage/storage_volume_resource.go +++ b/internal/provider/storage/storage_volume_resource.go @@ -3,10 +3,11 @@ package storage import ( "context" "fmt" + "strings" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/mitchellh/mapstructure" "github.com/netapp/terraform-provider-netapp-ontap/internal/provider/connection" - "strings" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" @@ -944,7 +945,7 @@ func (r *StorageVolumeResource) Update(ctx context.Context, req resource.UpdateR return } if _, ok := interfaces.POW2BYTEMAP[space.SizeUnit.ValueString()]; !ok { - errorHandler.MakeAndReportError("error creating volume", fmt.Sprintf("invalid input for size_unit: %s, required one of: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb", space.SizeUnit.ValueString())) + errorHandler.MakeAndReportError("error updating volume", fmt.Sprintf("invalid input for size_unit: %s, required one of: bytes, b, kb, mb, gb, tb, pb, eb, zb, yb", space.SizeUnit.ValueString())) return } if !plan.Space.Equal(state.Space) {