Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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,244 @@
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/services/storagecache/validate"
"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"`
ResourceGroupName string `tfschema:"resource_group_name"`
AmlFileSystemName string `tfschema:"aml_file_system_name"`
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"),
},

"location": commonschema.Location(),

"resource_group_name": commonschema.ResourceGroupName(),

"aml_file_system_name": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.ManagedLustreFileSystemName,
},
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.

When there are multiple properties required to create the parent resource's ID, we generally expose it as a single resource ID property, e.g.

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

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.

Sure. Will address this.


"auto_export_prefixes": {
Type: pluginsdk.TypeList,
Required: true,
MaxItems: 1,
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.

Is MaxItems: 1 correct here? If users can only specify one prefix this should probably be auto_export_prefix and TypeString.

Unless this is meant to be MinItems: 1?

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.

Right, this should be MinItems. Will fix.

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
subscriptionId := metadata.Client.Account.SubscriptionId
id := autoexportjobs.NewAutoExportJobID(subscriptionId, model.ResourceGroupName, model.AmlFileSystemName, model.Name)

existing, err := autoExportJobsClient.Get(ctx, id)
if err != nil && !response.WasNotFound(existing.HttpResponse) {
return fmt.Errorf("checking for existing Auto Export Job %s: %+v", id, err)
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.

Suggested change
return fmt.Errorf("checking for existing Auto Export Job %s: %+v", id, err)
return fmt.Errorf("checking for existing %s: %+v", id, err)

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 fix.

}

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(subscriptionId, model.ResourceGroupName, model.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.ResourceGroupName = id.ResourceGroupName
state.Location = location.Normalize(model.Location)
state.Tags = pointer.From(model.Tags)
state.AmlFileSystemName = id.AmlFilesystemName

if props := model.Properties; props != nil {
state.AutoExportPrefixes = pointer.From(props.AutoExportPrefixes)
if props.AdminStatus != nil && string(pointer.From(props.AdminStatus)) == string(autoexportjob.AutoExportJobAdminStatusEnable) {
state.AdminStatusEnabled = true
} else {
state.AdminStatusEnabled = false
}
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.

We could simplify this to:

Suggested change
if props.AdminStatus != nil && string(pointer.From(props.AdminStatus)) == string(autoexportjob.AutoExportJobAdminStatusEnable) {
state.AdminStatusEnabled = true
} else {
state.AdminStatusEnabled = false
}
state.AdminStatusEnabled = pointer.From(props.AdminStatus) == autoexportjobs.AutoExportJobAdminStatusEnable

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 fix.

}
}

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

func (r ManagedLustreFileSystemAutoExportJobResource) Delete() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 60 * 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,148 @@
package storagecache_test

import (
"context"
"fmt"
"testing"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-helpers/lang/response"
"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 {
if response.WasNotFound(resp.HttpResponse) {
return pointer.To(false), nil
}
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.

we generally just return any error encounter in the Exists func

Suggested change
if response.WasNotFound(resp.HttpResponse) {
return pointer.To(false), nil
}

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 remove.

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"
resource_group_name = azurerm_resource_group.test.name
aml_file_system_name = azurerm_managed_lustre_file_system.test.name
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"
resource_group_name = azurerm_resource_group.test.name
aml_file_system_name = azurerm_managed_lustre_file_system.test.name
location = azurerm_resource_group.test.location

auto_export_prefixes = ["/"]
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.

Could you update this value so it's different from the value specified in the basic test?

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.

Sure.

admin_status_enabled = true
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.

Since this defaults to true, could you change it to false for the complete test to ensure we can update this property?

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.

}
`, 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
resource_group_name = azurerm_managed_lustre_file_system_auto_export_job.test.resource_group_name
aml_file_system_name = azurerm_managed_lustre_file_system_auto_export_job.test.aml_file_system_name
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
admin_status_enabled = azurerm_managed_lustre_file_system_auto_export_job.test.admin_status_enabled
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.

import config should match referenced config (r.basic)

Suggested change
admin_status_enabled = azurerm_managed_lustre_file_system_auto_export_job.test.admin_status_enabled

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 fix.

}
`, r.basic(data))
}
Loading
Loading