diff --git a/azurerm/internal/services/managedapplications/managed_application_resource.go b/azurerm/internal/services/managedapplications/managed_application_resource.go index 1789bf95e781..e8106617bfec 100644 --- a/azurerm/internal/services/managedapplications/managed_application_resource.go +++ b/azurerm/internal/services/managedapplications/managed_application_resource.go @@ -1,12 +1,15 @@ package managedapplications import ( + "bytes" + "encoding/json" "fmt" "log" "time" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-07-01/managedapplications" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" @@ -71,13 +74,24 @@ func resourceManagedApplication() *schema.Resource { }, "parameters": { - Type: schema.TypeMap, - Optional: true, + Type: schema.TypeMap, + Optional: true, + Computed: true, + ConflictsWith: []string{"parameter_values"}, Elem: &schema.Schema{ Type: schema.TypeString, }, }, + "parameter_values": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: structure.SuppressJsonDiff, + ConflictsWith: []string{"parameters"}, + }, + "plan": { Type: schema.TypeList, Optional: true, @@ -158,26 +172,20 @@ func resourceManagedApplicationCreateUpdate(d *schema.ResourceData, meta interfa ManagedResourceGroupID: utils.String(targetResourceGroupId), } } + if v, ok := d.GetOk("application_definition_id"); ok { parameters.ApplicationDefinitionID = utils.String(v.(string)) } + if v, ok := d.GetOk("plan"); ok { parameters.Plan = expandManagedApplicationPlan(v.([]interface{})) } - if v, ok := d.GetOk("parameters"); ok { - params := v.(map[string]interface{}) - newParams := make(map[string]interface{}, len(params)) - for key, val := range params { - newParams[key] = struct { - Value interface{} `json:"value"` - }{ - Value: val, - } - } - - parameters.Parameters = &newParams + params, err := expandManagedApplicationParameters(d) + if err != nil { + return fmt.Errorf("Error expanding `parameters` or `parameter_values`: %+v", err) } + parameters.Parameters = params future, err := client.CreateOrUpdate(ctx, resourceGroupName, name, parameters) if err != nil { @@ -235,6 +243,12 @@ func resourceManagedApplicationRead(d *schema.ResourceData, meta interface{}) er d.Set("managed_resource_group_name", id.ResourceGroup) d.Set("application_definition_id", props.ApplicationDefinitionID) + parameterValues, err := flattenManagedApplicationParameterValuesValueToString(props.Parameters) + if err != nil { + return fmt.Errorf("serializing JSON from `parameter_values`: %+v", err) + } + d.Set("parameter_values", parameterValues) + if err = d.Set("parameters", flattenManagedApplicationParametersOrOutputs(props.Parameters)); err != nil { return err } @@ -284,6 +298,30 @@ func expandManagedApplicationPlan(input []interface{}) *managedapplications.Plan } } +func expandManagedApplicationParameters(d *schema.ResourceData) (*map[string]interface{}, error) { + newParams := make(map[string]interface{}) + + if v, ok := d.GetOk("parameter_values"); ok { + if err := json.Unmarshal([]byte(v.(string)), &newParams); err != nil { + return nil, fmt.Errorf("unmarshalling `parameter_values`: %+v", err) + } + } + + if v, ok := d.GetOk("parameters"); ok { + params := v.(map[string]interface{}) + + for key, val := range params { + newParams[key] = struct { + Value interface{} `json:"value"` + }{ + Value: val, + } + } + } + + return &newParams, nil +} + func flattenManagedApplicationPlan(input *managedapplications.Plan) []interface{} { results := make([]interface{}, 0) if input == nil { @@ -336,3 +374,27 @@ func flattenManagedApplicationParametersOrOutputs(input interface{}) map[string] return results } + +func flattenManagedApplicationParameterValuesValueToString(input interface{}) (string, error) { + if input == nil { + return "", nil + } + + for k, v := range input.(map[string]interface{}) { + if v != nil { + delete(input.(map[string]interface{})[k].(map[string]interface{}), "type") + } + } + + result, err := json.Marshal(input) + if err != nil { + return "", err + } + + compactJson := bytes.Buffer{} + if err := json.Compact(&compactJson, result); err != nil { + return "", err + } + + return compactJson.String(), nil +} diff --git a/azurerm/internal/services/managedapplications/managed_application_resource_test.go b/azurerm/internal/services/managedapplications/managed_application_resource_test.go index 9cdaa0ffa442..f610cf4b6928 100644 --- a/azurerm/internal/services/managedapplications/managed_application_resource_test.go +++ b/azurerm/internal/services/managedapplications/managed_application_resource_test.go @@ -94,6 +94,56 @@ func TestAccManagedApplication_update(t *testing.T) { }) } +func TestAccManagedApplication_updateParameters(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_managed_application", "test") + r := ManagedApplicationResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("parameters.%").HasValue("3"), + check.That(data.ResourceName).Key("parameter_values").Exists(), + ), + }, + data.ImportStep(), + { + Config: r.parameterValues(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("parameters.%").Exists(), + check.That(data.ResourceName).Key("parameter_values").Exists(), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("parameters.%").HasValue("3"), + check.That(data.ResourceName).Key("parameter_values").Exists(), + ), + }, + data.ImportStep(), + }) +} + +func TestAccManagedApplication_parameterValues(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_managed_application", "test") + r := ManagedApplicationResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.parameterValues(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (ManagedApplicationResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { id, err := parse.ApplicationID(state.ID) if err != nil { @@ -188,6 +238,29 @@ resource "azurerm_managed_application" "test" { `, r.template(data), data.RandomInteger, data.RandomInteger) } +func (r ManagedApplicationResource) parameterValues(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_managed_application" "test" { + name = "acctestManagedApp%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + kind = "ServiceCatalog" + managed_resource_group_name = "infraGroup%d" + application_definition_id = azurerm_managed_application_definition.test.id + + parameter_values = <