Skip to content

Commit

Permalink
azurerm_logic_app_workflow - add supports for workflow_parameters (
Browse files Browse the repository at this point in the history
…#12314)

Add supports for the workflow_parameters (the paramter definition),
and also make the parameters (the paramter value) to support different
kinds of types (previously it only supports String).

Fixes: #7241, #11505
  • Loading branch information
magodo authored Jul 30, 2021
1 parent 1be96d0 commit f9687a6
Show file tree
Hide file tree
Showing 3 changed files with 302 additions and 20 deletions.
237 changes: 218 additions & 19 deletions azurerm/internal/services/logic/logic_app_workflow_resource.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package logic

import (
"encoding/json"
"fmt"
"log"
"regexp"
"strconv"
"time"

"github.com/Azure/azure-sdk-for-go/services/logic/mgmt/2019-05-01/logic"
Expand Down Expand Up @@ -91,6 +93,14 @@ func resourceLogicAppWorkflow() *pluginsdk.Resource {
Default: "1.0.0.0",
},

"workflow_parameters": {
Type: pluginsdk.TypeMap,
Optional: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
},
},

"access_endpoint": {
Type: pluginsdk.TypeString,
Computed: true,
Expand Down Expand Up @@ -146,10 +156,18 @@ func resourceLogicAppWorkflowCreate(d *pluginsdk.ResourceData, meta interface{})
}

location := azure.NormalizeLocation(d.Get("location").(string))
parameters := expandLogicAppWorkflowParameters(d.Get("parameters").(map[string]interface{}))

workflowSchema := d.Get("workflow_schema").(string)
workflowVersion := d.Get("workflow_version").(string)
workflowParameters, err := expandLogicAppWorkflowWorkflowParameters(d.Get("workflow_parameters").(map[string]interface{}))
if err != nil {
return fmt.Errorf("expanding `workflow_parameters`: %+v", err)
}

parameters, err := expandLogicAppWorkflowParameters(d.Get("parameters").(map[string]interface{}), workflowParameters)
if err != nil {
return err
}
t := d.Get("tags").(map[string]interface{})

properties := logic.Workflow{
Expand All @@ -160,6 +178,7 @@ func resourceLogicAppWorkflowCreate(d *pluginsdk.ResourceData, meta interface{})
"contentVersion": workflowVersion,
"actions": make(map[string]interface{}),
"triggers": make(map[string]interface{}),
"parameters": workflowParameters,
},
Parameters: parameters,
},
Expand Down Expand Up @@ -227,13 +246,24 @@ func resourceLogicAppWorkflowUpdate(d *pluginsdk.ResourceData, meta interface{})
}

location := azure.NormalizeLocation(d.Get("location").(string))
parameters := expandLogicAppWorkflowParameters(d.Get("parameters").(map[string]interface{}))
workflowParameters, err := expandLogicAppWorkflowWorkflowParameters(d.Get("workflow_parameters").(map[string]interface{}))
if err != nil {
return fmt.Errorf("expanding `workflow_parameters`: %+v", err)
}
parameters, err := expandLogicAppWorkflowParameters(d.Get("parameters").(map[string]interface{}), workflowParameters)
if err != nil {
return err
}

t := d.Get("tags").(map[string]interface{})

definition := read.WorkflowProperties.Definition.(map[string]interface{})
definition["parameters"] = workflowParameters

properties := logic.Workflow{
Location: utils.String(location),
WorkflowProperties: &logic.WorkflowProperties{
Definition: read.WorkflowProperties.Definition,
Definition: definition,
Parameters: parameters,
},
Tags: tags.Expand(t),
Expand Down Expand Up @@ -282,11 +312,6 @@ func resourceLogicAppWorkflowRead(d *pluginsdk.ResourceData, meta interface{}) e
}

if props := resp.WorkflowProperties; props != nil {
parameters := flattenLogicAppWorkflowParameters(props.Parameters)
if err := d.Set("parameters", parameters); err != nil {
return fmt.Errorf("Error setting `parameters`: %+v", err)
}

d.Set("access_endpoint", props.AccessEndpoint)

if props.EndpointsConfiguration == nil || props.EndpointsConfiguration.Connector == nil {
Expand All @@ -312,6 +337,25 @@ func resourceLogicAppWorkflowRead(d *pluginsdk.ResourceData, meta interface{}) e
if v["contentVersion"] != nil {
d.Set("workflow_version", v["contentVersion"].(string))
}
if p, ok := v["parameters"]; ok {
workflowParameters, err := flattenLogicAppWorkflowWorkflowParameters(p.(map[string]interface{}))
if err != nil {
return fmt.Errorf("flattening `workflow_parameters`: %+v", err)
}
if err := d.Set("workflow_parameters", workflowParameters); err != nil {
return fmt.Errorf("setting `workflow_parameters`: %+v", err)
}

// The props.Parameters (the value of the param) is accompany with the "parameters" (the definition of the param) inside the props.Definition.
// We will need to make use of the definition of the parameters in order to properly flatten the value of the parameters being set (for kinds of types).
parameters, err := flattenLogicAppWorkflowParameters(d, props.Parameters, p.(map[string]interface{}))
if err != nil {
return fmt.Errorf("flattening `parameters`: %v", err)
}
if err := d.Set("parameters", parameters); err != nil {
return fmt.Errorf("Error setting `parameters`: %+v", err)
}
}
}
}

Expand Down Expand Up @@ -363,35 +407,190 @@ func resourceLogicAppWorkflowDelete(d *pluginsdk.ResourceData, meta interface{})
return nil
}

func expandLogicAppWorkflowParameters(input map[string]interface{}) map[string]*logic.WorkflowParameter {
func expandLogicAppWorkflowParameters(input map[string]interface{}, paramDefs map[string]interface{}) (map[string]*logic.WorkflowParameter, error) {
output := make(map[string]*logic.WorkflowParameter)

for k, v := range input {
defRaw, ok := paramDefs[k]
if !ok {
return nil, fmt.Errorf("no parameter definition for %s", k)
}
def := defRaw.(map[string]interface{})
t := logic.ParameterType(def["type"].(string))

v := v.(string)

var value interface{}
switch t {
case logic.ParameterTypeBool:
var uv bool
if err := json.Unmarshal([]byte(v), &uv); err != nil {
return nil, fmt.Errorf("unmarshalling %s to bool: %v", k, err)
}
value = uv
case logic.ParameterTypeFloat:
var uv float64
if err := json.Unmarshal([]byte(v), &uv); err != nil {
return nil, fmt.Errorf("unmarshalling %s to float64: %v", k, err)
}
value = uv
case logic.ParameterTypeInt:
var uv int
if err := json.Unmarshal([]byte(v), &uv); err != nil {
return nil, fmt.Errorf("unmarshalling %s to int: %v", k, err)
}
value = uv
case logic.ParameterTypeArray:
var uv []interface{}
if err := json.Unmarshal([]byte(v), &uv); err != nil {
return nil, fmt.Errorf("unmarshalling %s to []interface{}: %v", k, err)
}
value = uv
case logic.ParameterTypeObject,
logic.ParameterTypeSecureObject:
var uv map[string]interface{}
if err := json.Unmarshal([]byte(v), &uv); err != nil {
return nil, fmt.Errorf("unmarshalling %s to map[string]interface{}: %v", k, err)
}
value = uv
case logic.ParameterTypeString,
logic.ParameterTypeSecureString:
value = v
}

output[k] = &logic.WorkflowParameter{
Type: logic.ParameterTypeString,
Value: v.(string),
Type: t,
Value: value,
}
}

return output
return output, nil
}

func flattenLogicAppWorkflowParameters(input map[string]*logic.WorkflowParameter) map[string]interface{} {
func flattenLogicAppWorkflowParameters(d *pluginsdk.ResourceData, input map[string]*logic.WorkflowParameter, paramDefs map[string]interface{}) (map[string]interface{}, error) {
output := make(map[string]interface{})

// Read the "parameters" from state, which is used to fill in the "sensitive" properties.
paramInState := make(map[string]interface{})
paramsRaw := d.Get("parameters")
if params, ok := paramsRaw.(map[string]interface{}); ok {
paramInState = params
}

for k, v := range input {
if v != nil {
// we only support string parameters at this time
val, ok := v.Value.(string)
defRaw, ok := paramDefs[k]
if !ok {
// This should never happen.
log.Printf("[WARN] The parameter %s is not defined in the Logic App Workflow", k)
continue
}

if v == nil {
log.Printf("[WARN] The value of parameter %s is nil", k)
continue
}

def := defRaw.(map[string]interface{})
t := logic.ParameterType(def["type"].(string))

var value string
switch t {
case logic.ParameterTypeBool:
tv, ok := v.Value.(bool)
if !ok {
return nil, fmt.Errorf("the value of parameter %s is expected to be bool, but got %T", k, v.Value)
}
value = "true"
if !tv {
value = "false"
}
case logic.ParameterTypeFloat:
// Note that the json unmarshalled response doesn't differ between float and int, as json has only type number.
tv, ok := v.Value.(float64)
if !ok {
return nil, fmt.Errorf("the value of parameter %s is expected to be float64, but got %T", k, v.Value)
}
value = strconv.FormatFloat(tv, 'f', -1, 64)
case logic.ParameterTypeInt:
// Note that the json unmarshalled response doesn't differ between float and int, as json has only type number.
tv, ok := v.Value.(float64)
if !ok {
return nil, fmt.Errorf("the value of parameter %s is expected to be float64, but got %T", k, v.Value)
}
value = strconv.Itoa(int(tv))

case logic.ParameterTypeArray:
tv, ok := v.Value.([]interface{})
if !ok {
log.Printf("[DEBUG] Skipping parameter %q since it's not a string", k)
return nil, fmt.Errorf("the value of parameter %s is expected to be []interface{}, but got %T", k, v.Value)
}
obj, err := json.Marshal(tv)
if err != nil {
return nil, fmt.Errorf("converting %+v from json: %v", tv, err)
}
value = string(obj)

case logic.ParameterTypeObject:
tv, ok := v.Value.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("the value of parameter %s is expected to be map[string]interface{}, but got %T", k, v.Value)
}
obj, err := json.Marshal(tv)
if err != nil {
return nil, fmt.Errorf("converting %+v from json: %v", tv, err)
}
value = string(obj)

case logic.ParameterTypeString:
tv, ok := v.Value.(string)
if !ok {
return nil, fmt.Errorf("the value of parameter %s is expected to be string, but got %T", k, v.Value)
}
value = tv

case logic.ParameterTypeSecureString,
logic.ParameterTypeSecureObject:
// This is not returned from API, we will try to read them from the state instead.
if v, ok := paramInState[k]; ok {
value = v.(string) // The value in state here is guaranteed to be a string, so directly cast the type.
}
}

output[k] = value
}

return output, nil
}

func expandLogicAppWorkflowWorkflowParameters(input map[string]interface{}) (map[string]interface{}, error) {
if len(input) == 0 {
return nil, nil
}

output[k] = val
output := make(map[string]interface{})
for k, v := range input {
obj, err := pluginsdk.ExpandJsonFromString(v.(string))
if err != nil {
return nil, err
}
output[k] = obj
}
return output, nil
}

return output
func flattenLogicAppWorkflowWorkflowParameters(input map[string]interface{}) (map[string]interface{}, error) {
if input == nil {
return nil, nil
}
output := make(map[string]interface{})
for k, v := range input {
objstr, err := pluginsdk.FlattenJsonToString(v.(map[string]interface{}))
if err != nil {
return nil, err
}
output[k] = objstr
}
return output, nil
}

func flattenIPAddresses(input *[]logic.IPAddress) []interface{} {
Expand Down
Loading

0 comments on commit f9687a6

Please sign in to comment.