-
Notifications
You must be signed in to change notification settings - Fork 7
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
41 enhancement netapp ontap storage volume need to support import #91
Changes from 7 commits
a167926
0511c00
7f7520d
d5a7b67
d46c350
88db20d
65e631b
153f8bb
9df6464
471d8ac
03251af
51c78e4
ce97439
d939d60
ad68586
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -164,4 +164,86 @@ Optional: | |
- `policy_name` (String) The tiering policy that is to be associated with the volume | ||
|
||
## Import | ||
Import is currently not support for this Resource. | ||
This resource supports import, which allows you to import existing volumes into the state of this resource. | ||
Import require a unique ID composed of the volume name, the volume name, separated by a comma. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "the volume name, the volume name" ? |
||
|
||
id = `name`,`svm_name`,`cx_profile_name` | ||
|
||
### Terraform Import | ||
|
||
For example | ||
```shell | ||
terraform import netapp-ontap_storage_volume_resource.example vol1,svm2,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_storage_volume_resource.volume_import | ||
id = "svm1_root,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_storage_volume_resource" "volume_import" { | ||
aggregates = [ | ||
{ | ||
name = "aggr1" | ||
}, | ||
] | ||
analytics = { | ||
state = "off" | ||
} | ||
comment = null | ||
cx_profile_name = "cluster4" | ||
efficiency = { | ||
compression = "none" | ||
policy_name = "-" | ||
} | ||
encryption = false | ||
language = "c.utf_8" | ||
name = "svm1_root" | ||
nas = { | ||
export_policy_name = "default" | ||
group_id = 0 | ||
junction_path = "/" | ||
security_style = "unix" | ||
unix_permissions = 755 | ||
user_id = 0 | ||
} | ||
qos_policy_group = null | ||
snaplock = { | ||
type = "non_snaplock" | ||
} | ||
snapshot_policy = "default" | ||
space = { | ||
logical_space = { | ||
enforcement = false | ||
reporting = false | ||
} | ||
percent_snapshot_space = 5 | ||
size = 20 | ||
size_unit = "mb" | ||
} | ||
space_guarantee = "volume" | ||
state = "online" | ||
svm_name = "svm1" | ||
tiering = { | ||
minimum_cooling_days = 0 | ||
policy_name = "none" | ||
} | ||
type = "rw" | ||
} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,12 @@ | |
import ( | ||
"context" | ||
"fmt" | ||
"github.com/hashicorp/terraform-plugin-framework/path" | ||
"github.com/mitchellh/mapstructure" | ||
"strings" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/attr" | ||
"github.com/hashicorp/terraform-plugin-framework/diag" | ||
"github.com/hashicorp/terraform-plugin-framework/path" | ||
"github.com/hashicorp/terraform-plugin-framework/resource" | ||
"github.com/hashicorp/terraform-plugin-framework/resource/schema" | ||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" | ||
|
@@ -382,12 +383,21 @@ | |
// error reporting done inside NewClient | ||
return | ||
} | ||
// Import don't have id's so we need to get the id from the name | ||
var response *interfaces.StorageVolumeGetDataModelONTAP | ||
if data.ID.ValueString() == "" { | ||
response, err = interfaces.GetStorageVolumeByName(errorHandler, *client, data.Name.ValueString(), data.SVMName.ValueString()) | ||
data.ID = types.StringValue(response.UUID) | ||
|
||
} else { | ||
response, err = interfaces.GetStorageVolume(errorHandler, *client, data.ID.ValueString()) | ||
} | ||
|
||
response, err := interfaces.GetStorageVolume(errorHandler, *client, data.ID.ValueString()) | ||
if err != nil { | ||
return | ||
} | ||
|
||
tflog.Debug(ctx, fmt.Sprintf("read a volume resource: %#v", data)) | ||
|
||
data.Comment = types.StringValue(response.Comment) | ||
data.Encrypt = types.BoolValue(response.Encryption.Enabled) | ||
data.State = types.StringValue(response.State) | ||
|
@@ -414,20 +424,26 @@ | |
"logical_space": types.ObjectType{AttrTypes: nestedElementTypes}, | ||
} | ||
var sizeUnit string | ||
var size int64 | ||
var space StorageVolumeResourceSpace | ||
diags := data.Space.As(ctx, &space, basetypes.ObjectAsOptions{}) | ||
if diags.HasError() { | ||
resp.Diagnostics.Append(diags...) | ||
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())) | ||
return | ||
} | ||
sizeUnit = space.SizeUnit.ValueString() | ||
tflog.Debug(ctx, fmt.Sprintf("read a volume Space: %#v", space)) | ||
tflog.Debug(ctx, fmt.Sprintf("read a volume data.space: %#v", data.Space)) | ||
//diags := data.Space.As(ctx, &space, basetypes.ObjectAsOptions{}) | ||
//if diags.HasError() { | ||
// resp.Diagnostics.Append(diags...) | ||
// return | ||
//} | ||
tflog.Debug(ctx, fmt.Sprintf("read a volume Space3: %#v", space)) | ||
size, sizeUnit = interfaces.ByteFormat(int64(response.Space.Size)) | ||
//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())) | ||
// return | ||
//} | ||
tflog.Debug(ctx, fmt.Sprintf("read a volume Space size: %#v", space)) | ||
//sizeUnit = space.SizeUnit.ValueString() | ||
|
||
elements := map[string]attr.Value{ | ||
"size": types.Int64Value(int64(response.Space.Size / interfaces.POW2BYTEMAP[sizeUnit])), | ||
"size": types.Int64Value(size), | ||
"size_unit": types.StringValue(sizeUnit), | ||
"percent_snapshot_space": types.Int64Value(int64(response.Space.Snapshot.ReservePercent)), | ||
"logical_space": logicalObjectValue, | ||
|
@@ -518,6 +534,15 @@ | |
} | ||
data.Analytics = objectValue | ||
|
||
//Aggregates | ||
var aggregates []StorageVolumeResourceAggregates | ||
for _, v := range response.Aggregates { | ||
var aggregate StorageVolumeResourceAggregates | ||
aggregate.Name = types.StringValue(v.Name) | ||
aggregates = append(aggregates, aggregate) | ||
} | ||
data.Aggregates = aggregates | ||
|
||
// Save updated data into Terraform state | ||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) | ||
} | ||
|
@@ -1057,7 +1082,19 @@ | |
|
||
// ImportState imports a resource using ID from terraform import command by calling the Read method. | ||
func (r *StorageVolumeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { | ||
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) | ||
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: attr_one,attr_two,attr_three. Got: %q", req.ID), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we update the error message on attr_one,attr_two... with real parameter names? That will help the user know what need to put. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes we should do that. |
||
) | ||
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])...) | ||
} | ||
|
||
func readVolume(ctx context.Context, client *restclient.RestClient, data *StorageVolumeResourceModel) diag.Diagnostics { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this need to be 41