Skip to content
Open
Show file tree
Hide file tree
Changes from 12 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
package storagecache

import (
"context"
"fmt"
"regexp"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema"
"github.com/hashicorp/go-azure-helpers/resourcemanager/location"
"github.com/hashicorp/go-azure-sdk/resource-manager/storagecache/2024-07-01/autoexportjob"
"github.com/hashicorp/go-azure-sdk/resource-manager/storagecache/2024-07-01/autoexportjobs"
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
)

type ManagedLustreFileSystemAutoExportJobModel struct {
Name string `tfschema:"name"`
ManagedLustreFileSystemId string `tfschema:"managed_lustre_file_system_id"`
Location string `tfschema:"location"`
AutoExportPrefixes []string `tfschema:"auto_export_prefixes"`
AdminStatusEnabled bool `tfschema:"admin_status_enabled"`
Tags map[string]string `tfschema:"tags"`
}

type ManagedLustreFileSystemAutoExportJobResource struct{}

var _ sdk.ResourceWithUpdate = ManagedLustreFileSystemAutoExportJobResource{}

func (r ManagedLustreFileSystemAutoExportJobResource) Attributes() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{}
}

func (r ManagedLustreFileSystemAutoExportJobResource) ModelObject() interface{} {
return &ManagedLustreFileSystemAutoExportJobModel{}
}

func (r ManagedLustreFileSystemAutoExportJobResource) ResourceType() string {
return "azurerm_managed_lustre_file_system_auto_export_job"
}

func (r ManagedLustreFileSystemAutoExportJobResource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[0-9a-zA-Z][-0-9a-zA-Z_]{0,78}[0-9a-zA-Z]$`), "name must be 3-80 characters long and can only contain alphanumeric characters, underscores, and hyphens, and must start and end with an alphanumeric character"),
},

"managed_lustre_file_system_id": commonschema.ResourceIDReferenceRequiredForceNew(&autoexportjob.AmlFilesystemId{}),

"location": commonschema.Location(),

"auto_export_prefixes": {
Type: pluginsdk.TypeList,
Required: true,
MinItems: 1,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
},
Comment on lines +60 to +70
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number of maximum allowed paths for now is 1, so we should enforce that in the schema. Since this is an array of blob paths/prefixes which defaults to / can we also add a better validation function here as well?

Suggested change
"auto_export_prefixes": {
Type: pluginsdk.TypeList,
Required: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
},
"auto_export_prefixes": {
Type: pluginsdk.TypeList,
Required: true,
MaxItems: 1,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
},

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change.


"admin_status_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: true,
},

"tags": commonschema.Tags(),
}
}

func (r ManagedLustreFileSystemAutoExportJobResource) Create() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 60 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
var model ManagedLustreFileSystemAutoExportJobModel
if err := metadata.Decode(&model); err != nil {
return fmt.Errorf("decoding model: %w", err)
}

autoExportJobsClient := metadata.Client.StorageCache.AutoExportJobs
autoExportJobClient := metadata.Client.StorageCache.AutoExportJob

amlFileSystemId, err := autoexportjob.ParseAmlFilesystemID(model.ManagedLustreFileSystemId)
if err != nil {
return err
}

id := autoexportjobs.NewAutoExportJobID(amlFileSystemId.SubscriptionId, amlFileSystemId.ResourceGroupName, amlFileSystemId.AmlFilesystemName, model.Name)

existing, err := autoExportJobsClient.Get(ctx, id)
if err != nil && !response.WasNotFound(existing.HttpResponse) {
return fmt.Errorf("checking for existing %s: %+v", id, err)
}

if !response.WasNotFound(existing.HttpResponse) {
return metadata.ResourceRequiresImport(r.ResourceType(), id)
}

props := autoexportjob.AutoExportJob{
Location: location.Normalize(model.Location),
Properties: pointer.To(autoexportjob.AutoExportJobProperties{
AutoExportPrefixes: pointer.To(model.AutoExportPrefixes),
}),
Tags: pointer.To(model.Tags),
}

if model.AdminStatusEnabled {
props.Properties.AdminStatus = pointer.To(autoexportjob.AutoExportJobAdminStatusEnable)
} else {
props.Properties.AdminStatus = pointer.To(autoexportjob.AutoExportJobAdminStatusDisable)
}

autoExportJobId := autoexportjob.NewAutoExportJobID(amlFileSystemId.SubscriptionId, amlFileSystemId.ResourceGroupName, amlFileSystemId.AmlFilesystemName, model.Name)
if err := autoExportJobClient.CreateOrUpdateThenPoll(ctx, autoExportJobId, props); err != nil {
return fmt.Errorf("creating %s: %+v", id, err)
}

metadata.SetID(autoExportJobId)
return nil
},
}
}

func (r ManagedLustreFileSystemAutoExportJobResource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.StorageCache.AutoExportJobs

id, err := autoexportjobs.ParseAutoExportJobID(metadata.ResourceData.Id())
if err != nil {
return err
}

resp, err := client.Get(ctx, *id)
if err != nil {
if response.WasNotFound(resp.HttpResponse) {
return metadata.MarkAsGone(id)
}

return fmt.Errorf("retrieving %s: %+v", id, err)
}

state := ManagedLustreFileSystemAutoExportJobModel{}
if model := resp.Model; model != nil {
state.Name = id.AutoExportJobName
state.ManagedLustreFileSystemId = autoexportjob.NewAmlFilesystemID(id.SubscriptionId, id.ResourceGroupName, id.AmlFilesystemName).ID()
state.Location = location.Normalize(model.Location)
state.Tags = pointer.From(model.Tags)

if props := model.Properties; props != nil {
state.AutoExportPrefixes = pointer.From(props.AutoExportPrefixes)
state.AdminStatusEnabled = pointer.From(props.AdminStatus) == autoexportjobs.AutoExportJobAdminStatusEnable
}
}

return metadata.Encode(&state)
},
}
}

func (r ManagedLustreFileSystemAutoExportJobResource) Delete() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 90 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.StorageCache.AutoExportJobs
id, err := autoexportjobs.ParseAutoExportJobID(metadata.ResourceData.Id())
if err != nil {
return err
}

if err := client.DeleteThenPoll(ctx, *id); err != nil {
return fmt.Errorf("deleting %s: %+v", id, err)
}

return nil
},
}
}

func (r ManagedLustreFileSystemAutoExportJobResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return autoexportjob.ValidateAutoExportJobID
}

func (r ManagedLustreFileSystemAutoExportJobResource) Update() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 60 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.StorageCache.AutoExportJob

id, err := autoexportjob.ParseAutoExportJobID(metadata.ResourceData.Id())
if err != nil {
return err
}

var model ManagedLustreFileSystemAutoExportJobModel
if err := metadata.Decode(&model); err != nil {
return fmt.Errorf("decoding: %w", err)
}

props := autoexportjob.AutoExportJob{
Properties: pointer.To(autoexportjob.AutoExportJobProperties{}),
}

if metadata.ResourceData.HasChange("auto_export_prefixes") {
props.Properties.AutoExportPrefixes = pointer.To(model.AutoExportPrefixes)
}

if metadata.ResourceData.HasChange("admin_status_enabled") {
if model.AdminStatusEnabled {
props.Properties.AdminStatus = pointer.To(autoexportjob.AutoExportJobAdminStatusEnable)
} else {
props.Properties.AdminStatus = pointer.To(autoexportjob.AutoExportJobAdminStatusDisable)
}
}

if metadata.ResourceData.HasChange("tags") {
props.Tags = pointer.To(model.Tags)
}

if err := client.CreateOrUpdateThenPoll(ctx, *id, props); err != nil {
return fmt.Errorf("updating %s: %+v", id, err)
}

return nil
},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package storagecache_test

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-sdk/resource-manager/storagecache/2024-07-01/autoexportjobs"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
)

type ManagedLustreFileSystemAutoExportJobResource struct{}

func (r ManagedLustreFileSystemAutoExportJobResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := autoexportjobs.ParseAutoExportJobID(state.ID)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add some more tests here, at least a requiresImport and an update?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

if err != nil {
return nil, err
}

client := clients.StorageCache.AutoExportJobs
resp, err := client.Get(ctx, *id)
if err != nil {
return nil, fmt.Errorf("retrieving %s: %+v", id, err)
}
return pointer.To(resp.Model != nil), nil
}

func TestAccManagedLustreFileSystemExportJob_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_managed_lustre_file_system_auto_export_job", "test")
r := ManagedLustreFileSystemAutoExportJobResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccManagedLustreFileSystemExportJob_complete(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_managed_lustre_file_system_auto_export_job", "test")
r := ManagedLustreFileSystemAutoExportJobResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.complete(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccManagedLustreFileSystemExportJob_update(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_managed_lustre_file_system_auto_export_job", "test")
r := ManagedLustreFileSystemAutoExportJobResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
{
Config: r.complete(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccManagedLustreFileSystemExportJob_requiresImport(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_managed_lustre_file_system_auto_export_job", "test")
r := ManagedLustreFileSystemAutoExportJobResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.RequiresImportErrorStep(r.requiresImport),
})
}

func (r ManagedLustreFileSystemAutoExportJobResource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%s

resource "azurerm_managed_lustre_file_system_auto_export_job" "test" {
name = "acctest-amlfsaej-%d"
managed_lustre_file_system_id = azurerm_managed_lustre_file_system.test.id
location = azurerm_resource_group.test.location

auto_export_prefixes = ["/"]
}
`, ManagedLustreFileSystemResource{}.complete(data), data.RandomInteger)
}

func (r ManagedLustreFileSystemAutoExportJobResource) complete(data acceptance.TestData) string {
return fmt.Sprintf(`
%s

resource "azurerm_managed_lustre_file_system_auto_export_job" "test" {
name = "acctest-amlfsaej-%d"
managed_lustre_file_system_id = azurerm_managed_lustre_file_system.test.id
location = azurerm_resource_group.test.location

auto_export_prefixes = ["/", "/export"]
admin_status_enabled = false
}
`, ManagedLustreFileSystemResource{}.complete(data), data.RandomInteger)
}

func (r ManagedLustreFileSystemAutoExportJobResource) requiresImport(data acceptance.TestData) string {
return fmt.Sprintf(`
%s

resource "azurerm_managed_lustre_file_system_auto_export_job" "import" {
name = azurerm_managed_lustre_file_system_auto_export_job.test.name
managed_lustre_file_system_id = azurerm_managed_lustre_file_system_auto_export_job.test.managed_lustre_file_system_id
location = azurerm_managed_lustre_file_system_auto_export_job.test.location

auto_export_prefixes = azurerm_managed_lustre_file_system_auto_export_job.test.auto_export_prefixes
}
`, r.basic(data))
}
1 change: 1 addition & 0 deletions internal/services/storagecache/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@ func (r Registration) DataSources() []sdk.DataSource {
func (r Registration) Resources() []sdk.Resource {
return []sdk.Resource{
ManagedLustreFileSystemResource{},
ManagedLustreFileSystemAutoExportJobResource{},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ This list resource supports the following attributes:

* `resource_group_name` - (Optional) The name of the resource group to query.

* `subscription_id` - (Optional) The Subscription ID to query. Defaults to the value specified in the Provider Configuration.
* `subscription_id` - (Optional) The Subscription ID to query. Defaults to the value specified in the Provider Configuration.
Loading
Loading