diff --git a/internal/services/resource/client/client.go b/internal/services/resource/client/client.go index 029cb5a48a13..73e0742446a2 100644 --- a/internal/services/resource/client/client.go +++ b/internal/services/resource/client/client.go @@ -6,11 +6,13 @@ import ( "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2015-12-01/features" // nolint: staticcheck "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-09-01/locks" // nolint: staticcheck "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2020-06-01/resources" // nolint: staticcheck + "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-10-01/deploymentscripts" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) type Client struct { DeploymentsClient *resources.DeploymentsClient + DeploymentScriptsClient *deploymentscripts.DeploymentScriptsClient FeaturesClient *features.Client GroupsClient *resources.GroupsClient LocksClient *locks.ManagementLocksClient @@ -27,6 +29,9 @@ func NewClient(o *common.ClientOptions) *Client { deploymentsClient := resources.NewDeploymentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&deploymentsClient.Client, o.ResourceManagerAuthorizer) + deploymentScriptsClient := deploymentscripts.NewDeploymentScriptsClientWithBaseURI(o.ResourceManagerEndpoint) + o.ConfigureClient(&deploymentScriptsClient.Client, o.ResourceManagerAuthorizer) + featuresClient := features.NewClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&featuresClient.Client, o.ResourceManagerAuthorizer) @@ -56,6 +61,7 @@ func NewClient(o *common.ClientOptions) *Client { return &Client{ GroupsClient: &groupsClient, DeploymentsClient: &deploymentsClient, + DeploymentScriptsClient: &deploymentScriptsClient, FeaturesClient: &featuresClient, LocksClient: &locksClient, ProvidersClient: &providersClient, diff --git a/internal/services/resource/registration.go b/internal/services/resource/registration.go index bb187c38f04a..df581a429361 100644 --- a/internal/services/resource/registration.go +++ b/internal/services/resource/registration.go @@ -61,5 +61,7 @@ func (r Registration) DataSources() []sdk.DataSource { func (r Registration) Resources() []sdk.Resource { return []sdk.Resource{ ResourceProviderRegistrationResource{}, + ResourceDeploymentScriptAzurePowerShellResource{}, + ResourceDeploymentScriptAzureCliResource{}, } } diff --git a/internal/services/resource/resource_deployment_script_azure_cli_resource.go b/internal/services/resource/resource_deployment_script_azure_cli_resource.go new file mode 100644 index 000000000000..d11b235decc8 --- /dev/null +++ b/internal/services/resource/resource_deployment_script_azure_cli_resource.go @@ -0,0 +1,224 @@ +package resource + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-10-01/deploymentscripts" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type ResourceDeploymentScriptAzureCliModel ResourceDeploymentScriptModel + +type ResourceDeploymentScriptAzureCliResource struct{} + +var _ sdk.ResourceWithUpdate = ResourceDeploymentScriptAzureCliResource{} + +func (r ResourceDeploymentScriptAzureCliResource) ResourceType() string { + return "azurerm_resource_deployment_script_azure_cli" +} + +func (r ResourceDeploymentScriptAzureCliResource) ModelObject() interface{} { + return &ResourceDeploymentScriptAzureCliModel{} +} + +func (r ResourceDeploymentScriptAzureCliResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return deploymentscripts.ValidateDeploymentScriptID +} + +func (r ResourceDeploymentScriptAzureCliResource) Arguments() map[string]*pluginsdk.Schema { + return getDeploymentScriptArguments(AzureCliKind) +} + +func (r ResourceDeploymentScriptAzureCliResource) Attributes() map[string]*pluginsdk.Schema { + return getDeploymentScriptAttributes() +} + +func (r ResourceDeploymentScriptAzureCliResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model ResourceDeploymentScriptAzureCliModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.Resource.DeploymentScriptsClient + subscriptionId := metadata.Client.Account.SubscriptionId + id := deploymentscripts.NewDeploymentScriptID(subscriptionId, model.ResourceGroupName, model.Name) + existing, err := client.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) + } + + properties := &deploymentscripts.AzureCliScript{ + Location: location.Normalize(model.Location), + Properties: deploymentscripts.AzureCliScriptProperties{ + AzCliVersion: model.Version, + CleanupPreference: &model.CleanupPreference, + RetentionInterval: model.RetentionInterval, + SupportingScriptUris: &model.SupportingScriptUris, + ContainerSettings: expandContainerConfigurationModel(model.ContainerSettings), + EnvironmentVariables: expandEnvironmentVariableModelArray(model.EnvironmentVariables), + StorageAccountSettings: expandStorageAccountConfigurationModel(model.StorageAccountSettings), + }, + } + + identityValue, err := expandManagedServiceIdentityModel(metadata.ResourceData.Get("identity").([]interface{})) + if err != nil { + return err + } + + properties.Identity = identityValue + + if model.Arguments != "" { + properties.Properties.Arguments = &model.Arguments + } + + if model.ForceUpdateTag != "" { + properties.Properties.ForceUpdateTag = &model.ForceUpdateTag + } + + if model.PrimaryScriptUri != "" { + properties.Properties.PrimaryScriptUri = &model.PrimaryScriptUri + } + + if model.ScriptContent != "" { + properties.Properties.ScriptContent = &model.ScriptContent + } + + if model.Timeout != "" { + properties.Properties.Timeout = &model.Timeout + } + + if model.Tags != nil { + properties.Tags = &model.Tags + } + + if err := client.CreateThenPoll(ctx, id, *properties); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r ResourceDeploymentScriptAzureCliResource) Update() sdk.ResourceFunc { + return updateDeploymentScript() +} + +func (r ResourceDeploymentScriptAzureCliResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Resource.DeploymentScriptsClient + + id, err := deploymentscripts.ParseDeploymentScriptID(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) + } + + model, ok := (*resp.Model).(deploymentscripts.AzureCliScript) + if !ok { + return fmt.Errorf("retrieving %s: model was nil", id) + } + + state := ResourceDeploymentScriptAzureCliModel{ + Name: id.ScriptName, + ResourceGroupName: id.ResourceGroupName, + Location: location.Normalize(model.Location), + } + + identityValue, err := flattenManagedServiceIdentityModel(model.Identity) + if err != nil { + return err + } + + if err := metadata.ResourceData.Set("identity", identityValue); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + + properties := &model.Properties + if properties.Arguments != nil { + state.Arguments = *properties.Arguments + } + + state.Version = properties.AzCliVersion + + if properties.CleanupPreference != nil { + state.CleanupPreference = *properties.CleanupPreference + } + + state.ContainerSettings = flattenContainerConfigurationModel(properties.ContainerSettings) + + var originalModel ResourceDeploymentScriptAzureCliModel + if err := metadata.Decode(&originalModel); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + state.EnvironmentVariables = flattenEnvironmentVariableModelArray(properties.EnvironmentVariables, originalModel.EnvironmentVariables) + + if properties.ForceUpdateTag != nil { + state.ForceUpdateTag = *properties.ForceUpdateTag + } + + if properties.Outputs != nil && *properties.Outputs != nil { + outputsValue, err := json.Marshal(*properties.Outputs) + if err != nil { + return err + } + + state.Outputs = string(outputsValue) + } + + if properties.PrimaryScriptUri != nil { + state.PrimaryScriptUri = *properties.PrimaryScriptUri + } + + state.RetentionInterval = properties.RetentionInterval + + if properties.ScriptContent != nil { + state.ScriptContent = *properties.ScriptContent + } + + state.StorageAccountSettings = flattenStorageAccountConfigurationModel(properties.StorageAccountSettings, originalModel.StorageAccountSettings) + + if properties.SupportingScriptUris != nil { + state.SupportingScriptUris = *properties.SupportingScriptUris + } + + if properties.Timeout != nil { + state.Timeout = *properties.Timeout + } + if model.Tags != nil { + state.Tags = *model.Tags + } + + return metadata.Encode(&state) + }, + } +} + +func (r ResourceDeploymentScriptAzureCliResource) Delete() sdk.ResourceFunc { + return deleteDeploymentScript() +} diff --git a/internal/services/resource/resource_deployment_script_azure_cli_resource_test.go b/internal/services/resource/resource_deployment_script_azure_cli_resource_test.go new file mode 100644 index 000000000000..8c471c66b290 --- /dev/null +++ b/internal/services/resource/resource_deployment_script_azure_cli_resource_test.go @@ -0,0 +1,289 @@ +package resource_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-10-01/deploymentscripts" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "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" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ResourceDeploymentScriptAzureCLIResource struct{} + +func TestAccResourceDeploymentScriptAzureCLI_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_cli", "test") + r := ResourceDeploymentScriptAzureCLIResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccResourceDeploymentScriptAzureCLI_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_cli", "test") + r := ResourceDeploymentScriptAzureCLIResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccResourceDeploymentScriptAzureCLI_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_cli", "test") + r := ResourceDeploymentScriptAzureCLIResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("environment_variable.0.secure_value", "storage_account.0.key"), + }) +} + +func TestAccResourceDeploymentScriptAzureCLI_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_cli", "test") + r := ResourceDeploymentScriptAzureCLIResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("environment_variable.0.secure_value", "storage_account.0.key"), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("environment_variable.0.secure_value", "storage_account.0.key"), + }) +} + +func (r ResourceDeploymentScriptAzureCLIResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := deploymentscripts.ParseDeploymentScriptID(state.ID) + if err != nil { + return nil, err + } + + client := clients.Resource.DeploymentScriptsClient + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return utils.Bool(resp.Model != nil && *resp.Model != nil), nil +} + +func (r ResourceDeploymentScriptAzureCLIResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-rg-%d" + location = "%s" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r ResourceDeploymentScriptAzureCLIResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_resource_deployment_script_azure_cli" "test" { + name = "acctest-rdsac-%d" + resource_group_name = azurerm_resource_group.test.name + location = "%s" + version = "2.40.0" + retention_interval = "P1D" + script_content = < $AZ_SCRIPTS_OUTPUT_PATH + EOF +} +`, template, data.RandomInteger, data.Locations.Primary) +} + +func (r ResourceDeploymentScriptAzureCLIResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` + %s + +resource "azurerm_resource_deployment_script_azure_cli" "import" { + name = azurerm_resource_deployment_script_azure_cli.test.name + resource_group_name = azurerm_resource_deployment_script_azure_cli.test.resource_group_name + location = azurerm_resource_deployment_script_azure_cli.test.location + version = azurerm_resource_deployment_script_azure_cli.test.version + retention_interval = azurerm_resource_deployment_script_azure_cli.test.retention_interval + script_content = azurerm_resource_deployment_script_azure_cli.test.script_content +} +`, config) +} + +func (r ResourceDeploymentScriptAzureCLIResource) complete(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %[1]s + +resource "azurerm_user_assigned_identity" "test" { + name = "acctestUAI-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%[4]s" + resource_group_name = azurerm_resource_group.test.name + + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + + +resource "azurerm_resource_deployment_script_azure_cli" "test" { + name = "acctest-rdsac-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = "%[3]s" + version = "2.40.0" + retention_interval = "P1D" + command_line = "'foo' 'bar'" + cleanup_preference = "OnSuccess" + force_update_tag = "1" + timeout = "PT30M" + + script_content = < $AZ_SCRIPTS_OUTPUT_PATH + EOF + + supporting_script_uris = ["https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/deployment-script/create-cert.ps1"] + + container { + container_group_name = "cgn-%[2]d" + } + + environment_variable { + name = "UserName" + value = "jdole" + } + + environment_variable { + name = "Password" + secure_value = "jDolePassword" + } + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.test.id + ] + } + + storage_account { + name = azurerm_storage_account.test.name + key = azurerm_storage_account.test.primary_access_key + } + + tags = { + key = "value" + } + +} +`, template, data.RandomInteger, data.Locations.Primary, data.RandomString) +} + +func (r ResourceDeploymentScriptAzureCLIResource) update(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %[1]s + +resource "azurerm_user_assigned_identity" "test" { + name = "acctestUAI-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%[4]s" + resource_group_name = azurerm_resource_group.test.name + + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + + +resource "azurerm_resource_deployment_script_azure_cli" "test" { + name = "acctest-rdsac-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = "%[3]s" + version = "2.40.0" + retention_interval = "P1D" + command_line = "'foo' 'bar'" + cleanup_preference = "OnSuccess" + force_update_tag = "1" + timeout = "PT30M" + + script_content = < $AZ_SCRIPTS_OUTPUT_PATH + EOF + + supporting_script_uris = ["https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/deployment-script/create-cert.ps1"] + + container { + container_group_name = "cgn-%[2]d" + } + + environment_variable { + name = "UserName" + value = "jdole" + } + + environment_variable { + name = "Password" + secure_value = "jDolePassword" + } + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.test.id + ] + } + + storage_account { + name = azurerm_storage_account.test.name + key = azurerm_storage_account.test.primary_access_key + } + + tags = { + key = "value2" + } + +} +`, template, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/internal/services/resource/resource_deployment_script_azure_power_shell_resource.go b/internal/services/resource/resource_deployment_script_azure_power_shell_resource.go new file mode 100644 index 000000000000..522c02c33f7e --- /dev/null +++ b/internal/services/resource/resource_deployment_script_azure_power_shell_resource.go @@ -0,0 +1,224 @@ +package resource + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-10-01/deploymentscripts" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type ResourceDeploymentScriptAzurePowerShellModel ResourceDeploymentScriptModel + +type ResourceDeploymentScriptAzurePowerShellResource struct{} + +var _ sdk.ResourceWithUpdate = ResourceDeploymentScriptAzurePowerShellResource{} + +func (r ResourceDeploymentScriptAzurePowerShellResource) ResourceType() string { + return "azurerm_resource_deployment_script_azure_power_shell" +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) ModelObject() interface{} { + return &ResourceDeploymentScriptAzurePowerShellModel{} +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return deploymentscripts.ValidateDeploymentScriptID +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) Arguments() map[string]*pluginsdk.Schema { + return getDeploymentScriptArguments(AzurePowerShellKind) +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) Attributes() map[string]*pluginsdk.Schema { + return getDeploymentScriptAttributes() +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model ResourceDeploymentScriptAzurePowerShellModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.Resource.DeploymentScriptsClient + subscriptionId := metadata.Client.Account.SubscriptionId + id := deploymentscripts.NewDeploymentScriptID(subscriptionId, model.ResourceGroupName, model.Name) + existing, err := client.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) + } + + properties := &deploymentscripts.AzurePowerShellScript{ + Location: location.Normalize(model.Location), + Properties: deploymentscripts.AzurePowerShellScriptProperties{ + AzPowerShellVersion: model.Version, + CleanupPreference: &model.CleanupPreference, + RetentionInterval: model.RetentionInterval, + SupportingScriptUris: &model.SupportingScriptUris, + ContainerSettings: expandContainerConfigurationModel(model.ContainerSettings), + EnvironmentVariables: expandEnvironmentVariableModelArray(model.EnvironmentVariables), + StorageAccountSettings: expandStorageAccountConfigurationModel(model.StorageAccountSettings), + }, + } + + identityValue, err := expandManagedServiceIdentityModel(metadata.ResourceData.Get("identity").([]interface{})) + if err != nil { + return err + } + + properties.Identity = identityValue + + if model.Arguments != "" { + properties.Properties.Arguments = &model.Arguments + } + + if model.ForceUpdateTag != "" { + properties.Properties.ForceUpdateTag = &model.ForceUpdateTag + } + + if model.PrimaryScriptUri != "" { + properties.Properties.PrimaryScriptUri = &model.PrimaryScriptUri + } + + if model.ScriptContent != "" { + properties.Properties.ScriptContent = &model.ScriptContent + } + + if model.Timeout != "" { + properties.Properties.Timeout = &model.Timeout + } + + if model.Tags != nil { + properties.Tags = &model.Tags + } + + if err := client.CreateThenPoll(ctx, id, *properties); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) Update() sdk.ResourceFunc { + return updateDeploymentScript() +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Resource.DeploymentScriptsClient + + id, err := deploymentscripts.ParseDeploymentScriptID(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) + } + + model, ok := (*resp.Model).(deploymentscripts.AzurePowerShellScript) + if !ok { + return fmt.Errorf("retrieving %s: model was nil", id) + } + + state := ResourceDeploymentScriptAzurePowerShellModel{ + Name: id.ScriptName, + ResourceGroupName: id.ResourceGroupName, + Location: location.Normalize(model.Location), + } + + identityValue, err := flattenManagedServiceIdentityModel(model.Identity) + if err != nil { + return err + } + + if err := metadata.ResourceData.Set("identity", identityValue); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + + properties := &model.Properties + if properties.Arguments != nil { + state.Arguments = *properties.Arguments + } + + state.Version = properties.AzPowerShellVersion + + if properties.CleanupPreference != nil { + state.CleanupPreference = *properties.CleanupPreference + } + + state.ContainerSettings = flattenContainerConfigurationModel(properties.ContainerSettings) + + var originalModel ResourceDeploymentScriptAzurePowerShellModel + if err := metadata.Decode(&originalModel); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + state.EnvironmentVariables = flattenEnvironmentVariableModelArray(properties.EnvironmentVariables, originalModel.EnvironmentVariables) + + if properties.ForceUpdateTag != nil { + state.ForceUpdateTag = *properties.ForceUpdateTag + } + + if properties.Outputs != nil && *properties.Outputs != nil { + outputsValue, err := json.Marshal(*properties.Outputs) + if err != nil { + return err + } + + state.Outputs = string(outputsValue) + } + + if properties.PrimaryScriptUri != nil { + state.PrimaryScriptUri = *properties.PrimaryScriptUri + } + + state.RetentionInterval = properties.RetentionInterval + + if properties.ScriptContent != nil { + state.ScriptContent = *properties.ScriptContent + } + + state.StorageAccountSettings = flattenStorageAccountConfigurationModel(properties.StorageAccountSettings, originalModel.StorageAccountSettings) + + if properties.SupportingScriptUris != nil { + state.SupportingScriptUris = *properties.SupportingScriptUris + } + + if properties.Timeout != nil { + state.Timeout = *properties.Timeout + } + if model.Tags != nil { + state.Tags = *model.Tags + } + + return metadata.Encode(&state) + }, + } +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) Delete() sdk.ResourceFunc { + return deleteDeploymentScript() +} diff --git a/internal/services/resource/resource_deployment_script_azure_power_shell_resource_test.go b/internal/services/resource/resource_deployment_script_azure_power_shell_resource_test.go new file mode 100644 index 000000000000..74db46efa949 --- /dev/null +++ b/internal/services/resource/resource_deployment_script_azure_power_shell_resource_test.go @@ -0,0 +1,331 @@ +package resource_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-sdk/resource-manager/resources/2020-10-01/deploymentscripts" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "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" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type ResourceDeploymentScriptAzurePowerShellResource struct{} + +func TestAccResourceDeploymentScriptAzurePowerShell_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_power_shell", "test") + r := ResourceDeploymentScriptAzurePowerShellResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccResourceDeploymentScriptAzurePowerShell_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_power_shell", "test") + r := ResourceDeploymentScriptAzurePowerShellResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccResourceDeploymentScriptAzurePowerShell_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_power_shell", "test") + r := ResourceDeploymentScriptAzurePowerShellResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("environment_variable.0.secure_value", "storage_account.0.key"), + }) +} + +func TestAccResourceDeploymentScriptAzurePowerShell_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_power_shell", "test") + r := ResourceDeploymentScriptAzurePowerShellResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("environment_variable.0.secure_value", "storage_account.0.key"), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("environment_variable.0.secure_value", "storage_account.0.key"), + }) +} + +func TestAccResourceDeploymentScriptAzurePowerShell_scriptUri(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_resource_deployment_script_azure_power_shell", "test") + r := ResourceDeploymentScriptAzurePowerShellResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.scriptUri(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("environment_variable.0.secure_value", "storage_account.0.key"), + }) +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := deploymentscripts.ParseDeploymentScriptID(state.ID) + if err != nil { + return nil, err + } + + client := clients.Resource.DeploymentScriptsClient + resp, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return utils.Bool(resp.Model != nil && *resp.Model != nil), nil +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctest-rg-%d" + location = "%s" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (r ResourceDeploymentScriptAzurePowerShellResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` + %s + +resource "azurerm_resource_deployment_script_azure_power_shell" "test" { + name = "acctest-rdsaps-%d" + resource_group_name = azurerm_resource_group.test.name + location = "%s" + version = "8.3" + retention_interval = "P1D" + script_content = < $AZ_SCRIPTS_OUTPUT_PATH + EOF + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.example.id + ] + } + + tags = { + key = "value" + } +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name which should be used for this Resource Deployment Script. The name length must be from 1 to 260 characters. The name can only contain alphanumeric, underscore, parentheses, hyphen and period, and it cannot end with a period. Changing this forces a new Resource Deployment Script to be created. + +* `resource_group_name` - (Required) Specifies the name of the Resource Group where the Resource Deployment Script should exist. Changing this forces a new Resource Deployment Script to be created. + +* `location` - (Required) Specifies the Azure Region where the Resource Deployment Script should exist. Changing this forces a new Resource Deployment Script to be created. + +* `version` - (Required) Azure CLI module version to be used. The supported versions are `2.0.77`, `2.0.78`, `2.0.79`, `2.0.80`, `2.0.81`, `2.1.0`, `2.10.0`, `2.10.1`, `2.11.0`, `2.11.1`, `2.12.0`, `2.12.1`, `2.13.0`, `2.14.0`, `2.14.1`, `2.14.2`, `2.15.0`, `2.15.1`, `2.16.0`, `2.17.0`, `2.17.1`, `2.18.0`, `2.19.0`, `2.19.1`, `2.2.0`, `2.20.0`, `2.21.0`, `2.22.0`, `2.22.1`, `2.23.0`, `2.24.0`, `2.24.1`, `2.24.2`, `2.25.0`, `2.26.0`, `2.26.1`, `2.27.0`, `2.27.1`, `2.27.2`, `2.28.0`, `2.29.0`, `2.29.1`, `2.29.2`, `2.3.0`, `2.3.1`, `2.30.0`, `2.31.0`, `2.32.0`, `2.33.0`, `2.33.1`, `2.34.0`, `2.34.1`, `2.35.0`, `2.36.0`, `2.37.0`, `2.38.0`, `2.39.0`, `2.4.0`, `2.40.0`, `2.41.0`, `2.5.0`, `2.5.1`, `2.6.0`, `2.7.0`, `2.8.0`, `2.9.0`, `2.9.1`. Changing this forces a new Resource Deployment Script to be created. + +* `retention_interval` - (Required) Interval for which the service retains the script resource after it reaches a terminal state. Resource will be deleted when this duration expires. The time duration should be between `1` hour and `26` hours (inclusive) and should be specified in ISO 8601 format. Changing this forces a new Resource Deployment Script to be created. + +* `command_line` - (Optional) Command line arguments to pass to the script. Changing this forces a new Resource Deployment Script to be created. + +* `cleanup_preference` - (Optional) Specifies the cleanup preference when the script execution gets in a terminal state. Possible values are `Always`, `OnExpiration`, `OnSuccess`. Defaults to `Always`. Changing this forces a new Resource Deployment Script to be created. + +* `container` - (Optional) A `container` block as defined below. Changing this forces a new Resource Deployment Script to be created. + +* `environment_variable` - (Optional) An `environment_variable` block as defined below. Changing this forces a new Resource Deployment Script to be created. + +* `force_update_tag` - (Optional) Gets or sets how the deployment script should be forced to execute even if the script resource has not changed. Can be current time stamp or a GUID. Changing this forces a new Resource Deployment Script to be created. + +* `identity` - (Optional) An `identity` block as defined below. Changing this forces a new Resource Deployment Script to be created. + +* `primary_script_uri` - (Optional) Uri for the script. This is the entry point for the external script. Changing this forces a new Resource Deployment Script to be created. + +* `script_content` - (Optional) Script body. Changing this forces a new Resource Deployment Script to be created. + +* `storage_account` - (Optional) A `storage_account` block as defined below. Changing this forces a new Resource Deployment Script to be created. + +* `supporting_script_uris` - (Optional) Supporting files for the external script. Changing this forces a new Resource Deployment Script to be created. + +* `timeout` - (Optional) Maximum allowed script execution time specified in ISO 8601 format. Needs to be greater than 0 and smaller than 1 day. Defaults to `P1D`. Changing this forces a new Resource Deployment Script to be created. + +* `tags` - (Optional) A mapping of tags which should be assigned to the Resource Deployment Script. + +--- + +A `container` block supports the following: + +* `container_group_name` - (Optional) Container group name, if not specified then the name will get auto-generated. For more information, please refer to the [Container Configuration](https://learn.microsoft.com/en-us/rest/api/resources/deployment-scripts/create?tabs=HTTP#containerconfiguration) documentation. + +--- + +An `environment_variable` block supports the following: + +* `name` - (Required) Specifies the name of the environment variable. + +* `secure_value` - (Optional) Specifies the value of the secure environment variable. + +* `value` - (Optional) Specifies the value of the environment variable. + +--- + +An `identity` block supports the following: + +* `type` - (Optional) Type of the managed identity. + +* `user_assigned_identities` - (Optional) Specifies the list of user-assigned managed identities associated with the resource. Key is the Azure resource Id of the managed identity. + +--- + +A `storage_account` block supports the following: + +* `key` - (Required) Specifies the storage account access key. + +* `name` - (Required) Specifies the storage account name. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Resource Deployment Script. + +* `outputs` - List of script outputs. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Resource Deployment Script. +* `read` - (Defaults to 5 minutes) Used when retrieving the Resource Deployment Script. +* `update` - (Defaults to 30 minutes) Used when updating the Resource Deployment Script. +* `delete` - (Defaults to 30 minutes) Used when deleting the Resource Deployment Script. + +## Import + +Resource Deployment Script can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_resource_deployment_script_azure_cli.example /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/resourceGroup1/providers/Microsoft.Resources/deploymentScripts/script1 +``` diff --git a/website/docs/r/resource_deployment_script_azure_power_shell.html.markdown b/website/docs/r/resource_deployment_script_azure_power_shell.html.markdown new file mode 100644 index 000000000000..bf1b7580c7bd --- /dev/null +++ b/website/docs/r/resource_deployment_script_azure_power_shell.html.markdown @@ -0,0 +1,152 @@ +--- +subcategory: "Template" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_resource_deployment_script_azure_power_shell" +description: |- + Manages a Resource Deployment Script of Azure PowerShell. +--- + +# azurerm_resource_deployment_script_azure_power_shell + +Manages a Resource Deployment Script of Azure PowerShell. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_user_assigned_identity" "example" { + name = "example-uai" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_resource_deployment_script_azure_power_shell" "example" { + name = "example-rdsaps" + resource_group_name = azurerm_resource_group.example.name + location = "West Europe" + version = "8.3" + retention_interval = "P1D" + command_line = "-name \"John Dole\"" + cleanup_preference = "OnSuccess" + force_update_tag = "1" + timeout = "PT30M" + + script_content = <