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

snapshot import #102

Merged
Show file tree
Hide file tree
Changes from 2 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
41 changes: 40 additions & 1 deletion docs/resources/storage_volume_snapshot_resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,43 @@ resource "netapp-ontap_storage_volume_snapshot_resource" "example" {
- `id` (String) storage/volumes/snapshots identifier

## Import
Import is currently not support for this Resource.
This Resource supports import, which allows you to import existing snapshot into the state of this resoruce.
Import require a unique ID composed of the snapshot name, volume_name, svm_name and cx_profile_name, separated by a comma.

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

### Terraform Import

For example
```shell
terraform import netapp-ontap_storage_volume_snapshot_resource.example snapshotname,vol2,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_storage_volume_snapshot_resource.snapshot_import
id = "snapshot1,vol1,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 "snapshot1,vol1,svm1,cluster4"
resource "netapp-ontap_storage_volume_snapshot_resource" "snapshot_import" {
cx_profile_name = "cluster4"
name = "snapshot1"
volume_name = "vol1"
svm_name = "svm1"
}
```
3 changes: 2 additions & 1 deletion internal/interfaces/storage_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ func GetUUIDVolumeByName(errorHandler *utils.ErrorHandler, r restclient.RestClie

if response == nil {
tflog.Debug(errorHandler.Ctx, fmt.Sprintf("Volume %s not found", name))
return nil, nil
return nil, errorHandler.MakeAndReportError("error reading volume info",
fmt.Sprintf("error on Get %s: volume %s is not found, statusCode %d", api, name, statusCode))
}
var dataONTAP NameDataModel
if err := mapstructure.Decode(response, &dataONTAP); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion internal/interfaces/storage_volume_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ func GetStorageVolumeSnapshots(errorHandler *utils.ErrorHandler, r restclient.Re

if response == nil {
tflog.Debug(errorHandler.Ctx, fmt.Sprintf("snapshot %s not found for volume UUID %s", name, volumeUUID))
return nil, nil
return nil, errorHandler.MakeAndReportError("error reading snapshot info",
fmt.Sprintf("snapshot %s not found for volume UUID %s", name, volumeUUID))
}

var dataONTAP StorageVolumeSnapshotGetDataModelONTAP
Expand Down
6 changes: 6 additions & 0 deletions internal/interfaces/svm.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ func GetSvmByName(errorHandler *utils.ErrorHandler, r restclient.RestClient, nam
return nil, errorHandler.MakeAndReportError("error reading svm info", fmt.Sprintf("error on GET svm/svms: %s, statusCode %d", err, statusCode))
}

if response == nil {
tflog.Debug(errorHandler.Ctx, fmt.Sprintf("svm %s not found", name))
return nil, errorHandler.MakeAndReportError("error reading svm info",
fmt.Sprintf("svm %s not found", name))
}

var dataONTAP *SvmGetDataModelONTAP
if err := mapstructure.Decode(response, &dataONTAP); err != nil {
return nil, errorHandler.MakeAndReportError("failed to decode response from GET svm by name", fmt.Sprintf("error: %s, statusCode %d, response %#v", err, statusCode, response))
Expand Down
5 changes: 3 additions & 2 deletions internal/provider/protocols_nfs_service_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package provider

import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"os"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccNfsServiceResource(t *testing.T) {
Expand All @@ -16,7 +17,7 @@ func TestAccNfsServiceResource(t *testing.T) {
// Test error
{
Config: testAccNfsServiceResourceConfig("non-existant", "false"),
ExpectError: regexp.MustCompile("svm non-existant not found."),
ExpectError: regexp.MustCompile("svm non-existant not found"),
},
// Create and read
{
Expand Down
46 changes: 40 additions & 6 deletions internal/provider/storage_volume_snapshot_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provider
import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
Expand Down Expand Up @@ -201,15 +202,36 @@ func (r *StorageVolumeSnapshotResource) Read(ctx context.Context, req resource.R
if err != nil {
return
}
snapshot, err := interfaces.GetStorageVolumeSnapshot(errorHandler, *client, volume.UUID, data.ID.ValueString())
if err != nil {
return
var snapshot *interfaces.StorageVolumeSnapshotGetDataModelONTAP
if data.ID.ValueString() == "" {
snapshot, err = interfaces.GetStorageVolumeSnapshots(errorHandler, *client, data.Name.ValueString(), volume.UUID)
if err != nil {
return
}
data.ID = types.StringValue(snapshot.UUID)
} else {
snapshot, err = interfaces.GetStorageVolumeSnapshot(errorHandler, *client, volume.UUID, data.ID.ValueString())
if err != nil {
return
}
data.Name = types.StringValue(snapshot.Name)
}
data.Name = types.StringValue(snapshot.Name)

if snapshot.Comment != "" {
data.Comment = types.StringValue(snapshot.Comment)
}
if snapshot.ExpiryTime != "" {
data.ExpiryTime = types.StringValue(snapshot.ExpiryTime)
}
if snapshot.SnapmirrorLabel != "" {
data.SnapmirrorLabel = types.StringValue(snapshot.SnapmirrorLabel)
}
if snapshot.SnaplockExpiryTime != "" {
data.SnaplockExpiryTime = types.StringValue(snapshot.SnaplockExpiryTime)
}
// Write logs using the tflog package
// Documentation: https://terraform.io/plugin/log
tflog.Debug(ctx, fmt.Sprintf("read a data source: %#v", data))
tflog.Debug(ctx, fmt.Sprintf("read a snapshot data source: %#v", data))

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
Expand Down Expand Up @@ -316,5 +338,17 @@ func (r *StorageVolumeSnapshotResource) Delete(ctx context.Context, req resource

// ImportState imports a resource using ID from terraform import command by calling the Read method.
func (r *StorageVolumeSnapshotResource) 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 an volume snapshot resource: %#v", req))
idParts := strings.Split(req.ID, ",")
if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" {
resp.Diagnostics.AddError(
"Unexpected Import Identifier",
fmt.Sprintf("Expected import identifier with format: name,volume_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("volume_name"), idParts[1])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("svm_name"), idParts[2])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("cx_profile_name"), idParts[3])...)
}
11 changes: 10 additions & 1 deletion internal/provider/storage_volume_snapshot_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestAccStorageVolumeSnapshotResource(t *testing.T) {
// non-existant SVM return code 2621462. Must happen before create/read
{
Config: testAccStorageVolumeSnapshotResourceConfig("non-existant", "my comment"),
ExpectError: regexp.MustCompile("Error: No svm found"),
ExpectError: regexp.MustCompile("svm non-existant not found"),
},
// Create and read testing
{
Expand All @@ -39,6 +39,15 @@ func TestAccStorageVolumeSnapshotResource(t *testing.T) {
resource.TestCheckResourceAttr("netapp-ontap_storage_volume_snapshot_resource.example", "comment", "new comment"),
),
},
// Test importing a resource
{
ResourceName: "netapp-ontap_storage_volume_snapshot_resource.example",
ImportState: true,
ImportStateId: fmt.Sprintf("%s,%s,%s,%s", "snaptest", "carchi_test_root", "carchi-test", "cluster4"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("netapp-ontap_storage_volume_snapshot_resource.example", "name", "snaptest"),
),
},
},
})
}
Expand Down
Loading