From bffb3b3da5dff6d9f5ccb041c5c47badefad8fd7 Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Mon, 12 Aug 2019 22:04:04 +0100 Subject: [PATCH 1/9] WIP Adding function keys to output --- azurerm/resource_arm_function_app.go | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/azurerm/resource_arm_function_app.go b/azurerm/resource_arm_function_app.go index a459bb72435f..310d1e25d848 100644 --- a/azurerm/resource_arm_function_app.go +++ b/azurerm/resource_arm_function_app.go @@ -224,6 +224,27 @@ func resourceArmFunctionApp() *schema.Resource { }, }, }, + + "functions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "key": { + Type: schema.TypeString, + Computed: true, + }, + "trigger_url": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, }, } } @@ -556,6 +577,21 @@ func resourceArmFunctionAppRead(d *schema.ResourceData, meta interface{}) error return err } + functions, err := client.ListFunctionsComplete(ctx, resGroup, name) + if err != nil { + return err + } + getSecretsFunc := func(functionName string) (web.FunctionSecrets, error) { + return client.ListFunctionSecrets(ctx, resGroup, name, functionName) + } + functionsFlattened, err := flattenFunctions(getSecretsFunc, functions.Response()) + if err != nil { + return err + } + if err = d.Set("functions", functionsFlattened); err != nil { + return err + } + flattenAndSetTags(d, resp.Tags) return nil @@ -793,3 +829,34 @@ func flattenFunctionAppSiteCredential(input *web.UserProperties) []interface{} { return append(results, result) } + +func flattenFunctions(getSecrets func(name string) (web.FunctionSecrets, error), functions web.FunctionEnvelopeCollection) ([]interface{}, error) { + results := make([]interface{}, 0) + + funcs := *functions.Value + if len(funcs) < 1 { + log.Printf("[DEBUG] Functions collection is empty") + return results, nil + } + + for _, function := range funcs { + if function.Name == nil { + log.Printf("[DEBUG] Function name is nil") + continue + } + + functionName := *function.Name + result := make(map[string]interface{}) + result["name"] = functionName + secret, err := getSecrets(functionName) + if err != nil { + log.Printf("[DEBUG] Failed to get secrets for function %v", functionName) + return results, err + } + result["key"] = secret.Key + result["trigger_url"] = secret.TriggerURL + results = append(results, result) + } + + return results, nil +} From c906f7d8b54becf47598dd5c705ae58fd32f0e07 Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Fri, 6 Sep 2019 13:50:40 +0100 Subject: [PATCH 2/9] Create data source for function --- azurerm/data_source_function.go | 103 ++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 azurerm/data_source_function.go diff --git a/azurerm/data_source_function.go b/azurerm/data_source_function.go new file mode 100644 index 000000000000..42db6ed8b36c --- /dev/null +++ b/azurerm/data_source_function.go @@ -0,0 +1,103 @@ +package azurerm + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmFunction() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmServiceBusNamespaceRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "function_name": { + Type: schema.TypeString, + Computed: true, + }, + + "key": { + Type: schema.TypeString, + Computed: true, + }, + "trigger_url": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceArmFunctionRead(d *schema.ResourceData, meta interface{}) error { + webClient := meta.(*ArmClient).web + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + functionName := d.Get("function_name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + log.Printf("[DEBUG] Waiting for Function %q in Function app %q (Resource Group %q) to become available", functionName, name, resourceGroup) + stateConf := &resource.StateChangeConf{ + Pending: []string{"pending"}, + Target: []string{"available"}, + Refresh: functionAvailabilityChecker(ctx, name, functionName, resourceGroup, webClient), + Timeout: 10 * time.Minute, + Delay: 30 * time.Second, + PollInterval: 10 * time.Second, + ContinuousTargetOccurence: 3, + } + + if _, err := stateConf.WaitForState(); err != nil { + return fmt.Errorf("Error waiting for Function %q in Function app %q (Resource Group %q) to become available", functionName, name, resourceGroup) + } + + resp, err := webClient.AppServicesClient.ListFunctionSecrets(ctx, resourceGroup, name, functionName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Function %q was not found in Function App %q in Resource Group %q", functionName, name, resourceGroup) + } + + return fmt.Errorf("Error retrieving Function %q (Resource Group %q): %s", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + if triggerUrl := resp.TriggerURL; triggerUrl != nil { + d.Set("trigger_url", triggerUrl) + } + + if key := resp.Key; key != nil { + d.Set("key", key) + } + + return nil +} + +func functionAvailabilityChecker(ctx context.Context, name, functionName, resourceGroup string, client *web.Client) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + log.Printf("[DEBUG] Checking to see if Function %q is available..", functionName) + + _, err := client.AppServicesClient.GetFunction(ctx, name, functionName, resourceGroup) + if err != nil { + log.Printf("[DEBUG] Didn't find Function at %q", name) + return nil, "pending", err + } + + log.Printf("[DEBUG] Found function at %q", functionName) + return "available", "available", nil + } +} From a418ffc9f347febb4b9438cb5fb963b003e0d430 Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Fri, 6 Sep 2019 20:21:53 +0100 Subject: [PATCH 3/9] Continue work on data_source version --- .gitignore | 1 + azurerm/data_source_function.go | 52 ++++++++------- azurerm/data_source_function_test.go | 99 ++++++++++++++++++++++++++++ azurerm/provider.go | 1 + azurerm/resource_arm_function_app.go | 28 ++++---- 5 files changed, 142 insertions(+), 39 deletions(-) create mode 100644 azurerm/data_source_function_test.go diff --git a/.gitignore b/.gitignore index 247ea4cb6fdc..3ac5b74e8491 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ examples/**/terraform.zip #never upload the build to git terraform-provider-azurerm +azurerm/testdata/testfunc.zip diff --git a/azurerm/data_source_function.go b/azurerm/data_source_function.go index 42db6ed8b36c..7fff3484341a 100644 --- a/azurerm/data_source_function.go +++ b/azurerm/data_source_function.go @@ -1,7 +1,9 @@ package azurerm import ( + "bytes" "context" + "encoding/json" "fmt" "log" "time" @@ -10,12 +12,13 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + + webmgmt "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2018-02-01/web" ) func dataSourceArmFunction() *schema.Resource { return &schema.Resource{ - Read: dataSourceArmServiceBusNamespaceRead, + Read: dataSourceArmFunctionRead, Schema: map[string]*schema.Schema{ "name": { @@ -27,7 +30,7 @@ func dataSourceArmFunction() *schema.Resource { "function_name": { Type: schema.TypeString, - Computed: true, + Required: true, }, "key": { @@ -58,31 +61,19 @@ func dataSourceArmFunctionRead(d *schema.ResourceData, meta interface{}) error { Timeout: 10 * time.Minute, Delay: 30 * time.Second, PollInterval: 10 * time.Second, - ContinuousTargetOccurence: 3, - } - - if _, err := stateConf.WaitForState(); err != nil { - return fmt.Errorf("Error waiting for Function %q in Function app %q (Resource Group %q) to become available", functionName, name, resourceGroup) + ContinuousTargetOccurence: 2, } - resp, err := webClient.AppServicesClient.ListFunctionSecrets(ctx, resourceGroup, name, functionName) + resp, err := stateConf.WaitForState() if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Function %q was not found in Function App %q in Resource Group %q", functionName, name, resourceGroup) - } - - return fmt.Errorf("Error retrieving Function %q (Resource Group %q): %s", name, resourceGroup, err) + return fmt.Errorf("Error waiting for Function %q in Function app %q (Resource Group %q) to become available", functionName, name, resourceGroup) } - d.SetId(*resp.ID) - - if triggerUrl := resp.TriggerURL; triggerUrl != nil { - d.Set("trigger_url", triggerUrl) - } + functionSecret := resp.(webmgmt.FunctionSecretsProperties) + d.SetId(*functionSecret.TriggerURL) - if key := resp.Key; key != nil { - d.Set("key", key) - } + d.Set("trigger_url", functionSecret.TriggerURL) + d.Set("key", functionSecret.Key) return nil } @@ -91,13 +82,24 @@ func functionAvailabilityChecker(ctx context.Context, name, functionName, resour return func() (interface{}, string, error) { log.Printf("[DEBUG] Checking to see if Function %q is available..", functionName) - _, err := client.AppServicesClient.GetFunction(ctx, name, functionName, resourceGroup) - if err != nil { + function, err := client.AppServicesClient.ListFunctionSecrets(ctx, resourceGroup, name, functionName) + + // Workaround for https://github.com/Azure/azure-rest-api-specs/issues/7143 + // Can be removed once definition is fixed. + buf := new(bytes.Buffer) + buf.ReadFrom(function.Body) + jsonBody := buf.String() + // Doesn't work because the buffer has already be read. + + var response webmgmt.FunctionSecretsProperties + json.Unmarshal([]byte(jsonBody), &response) + + if err != nil || function.StatusCode != 200 || response.Key == nil { log.Printf("[DEBUG] Didn't find Function at %q", name) return nil, "pending", err } log.Printf("[DEBUG] Found function at %q", functionName) - return "available", "available", nil + return response, "available", nil } } diff --git a/azurerm/data_source_function_test.go b/azurerm/data_source_function_test.go new file mode 100644 index 000000000000..acc2f4e652d3 --- /dev/null +++ b/azurerm/data_source_function_test.go @@ -0,0 +1,99 @@ +package azurerm + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" +) + +func TestAccDataSourceAzureRMFunction_basic(t *testing.T) { + dataSourceName := "data.azurerm_function.test" + rInt := tf.AccRandTimeInt() + location := testLocation() + rs := strings.ToLower(acctest.RandString(11)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMFirewallDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFunction_basic(rInt, location, rs), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "trigger_url", "configuration"), + resource.TestCheckResourceAttr(dataSourceName, "key", "stuff"), + ), + }, + }, + }) +} + +func testAccDataSourceFunction_basic(rInt int, location, storage string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_storage_account" "test" { + name = "acctestsa%[3]s" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_storage_container" "test" { + name = "function-releases" + + storage_account_name = "${azurerm_storage_account.test.name}" + container_access_type = "container" +} + +resource "azurerm_storage_blob" "javazip" { + name = "testfunc.zip" + + resource_group_name = "${azurerm_resource_group.test.name}" + + storage_account_name = "${azurerm_storage_account.test.name}" + storage_container_name = "${azurerm_storage_container.test.name}" + + type = "block" + source = "testdata/testfunc.zip" +} + +resource "azurerm_function_app" "test" { + name = "acctest-%[1]d-func" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + storage_connection_string = "${azurerm_storage_account.test.primary_connection_string}" + + app_settings = { + WEBSITE_RUN_FROM_PACKAGE = "https://${azurerm_storage_account.test.name}.blob.core.windows.net/${azurerm_storage_container.test.name}/testfunc.zip" + FUNCTIONS_WORKER_RUNTIME = "node" + } +} + +data "azurerm_function" "test" { + name = "${azurerm_function_app.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" + function_name = "testfunc" +} +`, rInt, location, storage) +} diff --git a/azurerm/provider.go b/azurerm/provider.go index 3a9ccc2d2281..8d17b098ccd9 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -66,6 +66,7 @@ func Provider() terraform.ResourceProvider { "azurerm_eventhub_namespace": dataSourceEventHubNamespace(), "azurerm_express_route_circuit": dataSourceArmExpressRouteCircuit(), "azurerm_firewall": dataSourceArmFirewall(), + "azurerm_function": dataSourceArmFunction(), "azurerm_image": dataSourceArmImage(), "azurerm_hdinsight_cluster": dataSourceArmHDInsightSparkCluster(), "azurerm_maps_account": dataSourceArmMapsAccount(), diff --git a/azurerm/resource_arm_function_app.go b/azurerm/resource_arm_function_app.go index 310d1e25d848..0e8590ea07db 100644 --- a/azurerm/resource_arm_function_app.go +++ b/azurerm/resource_arm_function_app.go @@ -577,20 +577,20 @@ func resourceArmFunctionAppRead(d *schema.ResourceData, meta interface{}) error return err } - functions, err := client.ListFunctionsComplete(ctx, resGroup, name) - if err != nil { - return err - } - getSecretsFunc := func(functionName string) (web.FunctionSecrets, error) { - return client.ListFunctionSecrets(ctx, resGroup, name, functionName) - } - functionsFlattened, err := flattenFunctions(getSecretsFunc, functions.Response()) - if err != nil { - return err - } - if err = d.Set("functions", functionsFlattened); err != nil { - return err - } + // functions, err := client.ListFunctionsComplete(ctx, resGroup, name) + // if err != nil { + // return err + // } + // getSecretsFunc := func(functionName string) (web.FunctionSecrets, error) { + // return client.ListFunctionSecrets(ctx, resGroup, name, functionName) + // } + // functionsFlattened, err := flattenFunctions(getSecretsFunc, functions.Response()) + // if err != nil { + // return err + // } + // if err = d.Set("functions", functionsFlattened); err != nil { + // return err + // } flattenAndSetTags(d, resp.Tags) From 05b2b5e93ec7ef7ef85578adcf81c3a2f9ed2c37 Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Thu, 12 Sep 2019 14:11:00 +0100 Subject: [PATCH 4/9] Tweaks for testing --- azurerm/data_source_function.go | 16 ++-------------- azurerm/data_source_function_test.go | 2 +- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/azurerm/data_source_function.go b/azurerm/data_source_function.go index 7fff3484341a..2529e2370e4f 100644 --- a/azurerm/data_source_function.go +++ b/azurerm/data_source_function.go @@ -1,9 +1,7 @@ package azurerm import ( - "bytes" "context" - "encoding/json" "fmt" "log" "time" @@ -84,22 +82,12 @@ func functionAvailabilityChecker(ctx context.Context, name, functionName, resour function, err := client.AppServicesClient.ListFunctionSecrets(ctx, resourceGroup, name, functionName) - // Workaround for https://github.com/Azure/azure-rest-api-specs/issues/7143 - // Can be removed once definition is fixed. - buf := new(bytes.Buffer) - buf.ReadFrom(function.Body) - jsonBody := buf.String() - // Doesn't work because the buffer has already be read. - - var response webmgmt.FunctionSecretsProperties - json.Unmarshal([]byte(jsonBody), &response) - - if err != nil || function.StatusCode != 200 || response.Key == nil { + if err != nil || function.StatusCode != 200 { log.Printf("[DEBUG] Didn't find Function at %q", name) return nil, "pending", err } log.Printf("[DEBUG] Found function at %q", functionName) - return response, "available", nil + return function, "available", nil } } diff --git a/azurerm/data_source_function_test.go b/azurerm/data_source_function_test.go index acc2f4e652d3..e7efff5dff56 100644 --- a/azurerm/data_source_function_test.go +++ b/azurerm/data_source_function_test.go @@ -38,7 +38,7 @@ resource "azurerm_resource_group" "test" { name = "acctestRG-%[1]d" location = "%[2]s" } - + resource "azurerm_storage_account" "test" { name = "acctestsa%[3]s" resource_group_name = "${azurerm_resource_group.test.name}" From 2e80beb2ca638b4aff72bcdf1e6b62e52c21b442 Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Thu, 12 Sep 2019 15:24:03 +0100 Subject: [PATCH 5/9] Revert changes to resource in favour of datasource --- azurerm/data_source_function.go | 23 ++++++---- azurerm/data_source_function_test.go | 26 ++++++++++- azurerm/resource_arm_function_app.go | 67 ---------------------------- 3 files changed, 39 insertions(+), 77 deletions(-) diff --git a/azurerm/data_source_function.go b/azurerm/data_source_function.go index 2529e2370e4f..6f624f55e1ad 100644 --- a/azurerm/data_source_function.go +++ b/azurerm/data_source_function.go @@ -53,13 +53,12 @@ func dataSourceArmFunctionRead(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Waiting for Function %q in Function app %q (Resource Group %q) to become available", functionName, name, resourceGroup) stateConf := &resource.StateChangeConf{ - Pending: []string{"pending"}, - Target: []string{"available"}, - Refresh: functionAvailabilityChecker(ctx, name, functionName, resourceGroup, webClient), - Timeout: 10 * time.Minute, - Delay: 30 * time.Second, - PollInterval: 10 * time.Second, - ContinuousTargetOccurence: 2, + Pending: []string{"pending"}, + Target: []string{"available"}, + Refresh: functionAvailabilityChecker(ctx, name, functionName, resourceGroup, webClient), + Timeout: 10 * time.Minute, + Delay: 30 * time.Second, + PollInterval: 10 * time.Second, } resp, err := stateConf.WaitForState() @@ -67,7 +66,15 @@ func dataSourceArmFunctionRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error waiting for Function %q in Function app %q (Resource Group %q) to become available", functionName, name, resourceGroup) } - functionSecret := resp.(webmgmt.FunctionSecretsProperties) + functionSecret := resp.(webmgmt.FunctionSecrets) + + if functionSecret.TriggerURL == nil { + return fmt.Errorf("Error retrieving key for Function %q in Function app %q (Resource Group %q). TriggerURL returned nil from API", functionName, name, resourceGroup) + } + if functionSecret.Key == nil { + return fmt.Errorf("Error retrieving key for Function %q in Function app %q (Resource Group %q). Key returned nil from API", functionName, name, resourceGroup) + } + d.SetId(*functionSecret.TriggerURL) d.Set("trigger_url", functionSecret.TriggerURL) diff --git a/azurerm/data_source_function_test.go b/azurerm/data_source_function_test.go index e7efff5dff56..386c7710f3d8 100644 --- a/azurerm/data_source_function_test.go +++ b/azurerm/data_source_function_test.go @@ -24,8 +24,30 @@ func TestAccDataSourceAzureRMFunction_basic(t *testing.T) { { Config: testAccDataSourceFunction_basic(rInt, location, rs), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(dataSourceName, "trigger_url", "configuration"), - resource.TestCheckResourceAttr(dataSourceName, "key", "stuff"), + resource.TestCheckResourceAttrSet(dataSourceName, "trigger_url"), + resource.TestCheckResourceAttrSet(dataSourceName, "key"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMFunction_wait(t *testing.T) { + dataSourceName := "data.azurerm_function.test" + rInt := tf.AccRandTimeInt() + location := testLocation() + rs := strings.ToLower(acctest.RandString(11)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMFirewallDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceFunction_basic(rInt, location, rs), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "trigger_url"), + resource.TestCheckResourceAttrSet(dataSourceName, "key"), ), }, }, diff --git a/azurerm/resource_arm_function_app.go b/azurerm/resource_arm_function_app.go index 0e8590ea07db..a459bb72435f 100644 --- a/azurerm/resource_arm_function_app.go +++ b/azurerm/resource_arm_function_app.go @@ -224,27 +224,6 @@ func resourceArmFunctionApp() *schema.Resource { }, }, }, - - "functions": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Computed: true, - }, - "key": { - Type: schema.TypeString, - Computed: true, - }, - "trigger_url": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, }, } } @@ -577,21 +556,6 @@ func resourceArmFunctionAppRead(d *schema.ResourceData, meta interface{}) error return err } - // functions, err := client.ListFunctionsComplete(ctx, resGroup, name) - // if err != nil { - // return err - // } - // getSecretsFunc := func(functionName string) (web.FunctionSecrets, error) { - // return client.ListFunctionSecrets(ctx, resGroup, name, functionName) - // } - // functionsFlattened, err := flattenFunctions(getSecretsFunc, functions.Response()) - // if err != nil { - // return err - // } - // if err = d.Set("functions", functionsFlattened); err != nil { - // return err - // } - flattenAndSetTags(d, resp.Tags) return nil @@ -829,34 +793,3 @@ func flattenFunctionAppSiteCredential(input *web.UserProperties) []interface{} { return append(results, result) } - -func flattenFunctions(getSecrets func(name string) (web.FunctionSecrets, error), functions web.FunctionEnvelopeCollection) ([]interface{}, error) { - results := make([]interface{}, 0) - - funcs := *functions.Value - if len(funcs) < 1 { - log.Printf("[DEBUG] Functions collection is empty") - return results, nil - } - - for _, function := range funcs { - if function.Name == nil { - log.Printf("[DEBUG] Function name is nil") - continue - } - - functionName := *function.Name - result := make(map[string]interface{}) - result["name"] = functionName - secret, err := getSecrets(functionName) - if err != nil { - log.Printf("[DEBUG] Failed to get secrets for function %v", functionName) - return results, err - } - result["key"] = secret.Key - result["trigger_url"] = secret.TriggerURL - results = append(results, result) - } - - return results, nil -} From 9ea25d4d22af243dfb3453db46f445297e590b35 Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Mon, 16 Sep 2019 17:46:07 +0100 Subject: [PATCH 6/9] Add docs. Set sensitive output. Tweak naming of fields --- azurerm/data_source_function.go | 19 ++++++++------ website/docs/d/function.html.markdown | 36 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 website/docs/d/function.html.markdown diff --git a/azurerm/data_source_function.go b/azurerm/data_source_function.go index 6f624f55e1ad..d6c05311a0e7 100644 --- a/azurerm/data_source_function.go +++ b/azurerm/data_source_function.go @@ -2,6 +2,8 @@ package azurerm import ( "context" + "crypto/sha256" + "encoding/hex" "fmt" "log" "time" @@ -19,7 +21,7 @@ func dataSourceArmFunction() *schema.Resource { Read: dataSourceArmFunctionRead, Schema: map[string]*schema.Schema{ - "name": { + "function_app_name": { Type: schema.TypeString, Required: true, }, @@ -32,12 +34,14 @@ func dataSourceArmFunction() *schema.Resource { }, "key": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Computed: true, + Sensitive: true, }, "trigger_url": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Computed: true, + Sensitive: true, // Note the trigger url contains the key }, }, } @@ -47,7 +51,7 @@ func dataSourceArmFunctionRead(d *schema.ResourceData, meta interface{}) error { webClient := meta.(*ArmClient).web ctx := meta.(*ArmClient).StopContext - name := d.Get("name").(string) + name := d.Get("function_app_name").(string) functionName := d.Get("function_name").(string) resourceGroup := d.Get("resource_group_name").(string) @@ -75,7 +79,8 @@ func dataSourceArmFunctionRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error retrieving key for Function %q in Function app %q (Resource Group %q). Key returned nil from API", functionName, name, resourceGroup) } - d.SetId(*functionSecret.TriggerURL) + triggerUrlHash := sha256.Sum256([]byte(*functionSecret.TriggerURL)) + d.SetId(hex.EncodeToString(triggerUrlHash[:])) d.Set("trigger_url", functionSecret.TriggerURL) d.Set("key", functionSecret.Key) diff --git a/website/docs/d/function.html.markdown b/website/docs/d/function.html.markdown new file mode 100644 index 000000000000..5eb870003543 --- /dev/null +++ b/website/docs/d/function.html.markdown @@ -0,0 +1,36 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_function" +sidebar_current: "docs-azurerm-datasource-function" +description: |- + Gets information about an Azure Function hosted in an FunctionApp. +--- + +# Data Source: azurerm_function + +Use this data source to access information about an Azure Function hosted in a Function App. + +## Example Usage + +```hcl +data "azurerm_functions_key" "test" { + function_app_name = "function_app_name_here" + resource_group_name = "resource_group_here" + function_name = "name_of_function_you_want_key_for_here" +} + +output "key" { + value = "${data.azurerm_function.test.key}" +} +``` + +## Argument Reference + +* `function_app_name` - (Required) Specifies the name of the Function App in which the Function is hosted. +* `function_name` - (Required) Specifies the name of the Function. +* `resource_group_name` - (Required) Specifies the name of the resource group the Function App is located. + +## Attributes Reference + +* `key` - The Function Key +* `trigger_url` - The full URL with Function Key used to trigger the function From 5025ccf0eece0ae3cf05a680d3177f7d4a37a2d4 Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Wed, 18 Sep 2019 10:45:52 +0100 Subject: [PATCH 7/9] Add missing test data zip --- .gitignore | 1 - azurerm/testdata/testfunc.zip | Bin 0 -> 2692 bytes 2 files changed, 1 deletion(-) create mode 100644 azurerm/testdata/testfunc.zip diff --git a/.gitignore b/.gitignore index 3ac5b74e8491..247ea4cb6fdc 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,3 @@ examples/**/terraform.zip #never upload the build to git terraform-provider-azurerm -azurerm/testdata/testfunc.zip diff --git a/azurerm/testdata/testfunc.zip b/azurerm/testdata/testfunc.zip new file mode 100644 index 0000000000000000000000000000000000000000..61a29006da18e7120ae3c25a875d9e5827647a9b GIT binary patch literal 2692 zcmWIWW@Zs#0D&K&M*d(1l;B}dVDKm@DF`XbOixcO(hm*cWng#x+ZYSOr4`%^j4Ush z85qDs0N5lB1`ZUH{xdQ#h@hF2nU|7Up_f%m$i&_W2lEaY2)MlW_;Xl;-9y7G;Hq$7 zzD$6>$5Zw@DZ)CE);DH%t$1?(wMu})sfE=av%;)@+qh4@-j!q(er(fW>z3@2wnf(@ zy%!6nxf#!`9g%RKaIad?woYQN^c2n%M;gE{QjFDvdOoeF~FOh!|d+ei~oTU0t!a# z0W1!bkwgpNw9>rflFa-(U>N7;5entfK1aSo3IeX*ZI8B;`ah72*=4M^s>h&HR)9_T za>4hYRYAgc9scdHpKM;r@XBXRr*DY0#WWs+tJ^0icHVu=oX@&4`%(9VH6WUkZfSGLi52becoF+9}TXpZTM~`6S(HG??OJ_Q_BMvl?PtYp7(10@BI5~FUSi| ze=^-GhW~k<<=k|Tf735*U)BlqFUVIA|AJB@a~NvULaUzzF)%INbY;<_Gk>M7G zZ%mQ^8VE8Jk>Qc8>j26K1Fg%+PfpCyD^4vb$;?YHMzvTCr^NvQpLEL3dh4yy(eU&Q z+!W;DeMZyoDr0B6>a!`!#F$%GHQFfL*S&Jy^2p`;`WAL~>`&Y_)v(jJqJQM_b#tp`PrE&TU+^MZ?s_^rW`^N{byT`!x)0MVBm*>aJKT6yU8Jt_$|d`O~&-*+AEV zT#Vf>O+Xn?JyVdFoSm4Sis}ha$YBq?fPhopXM9691qB3MV*Ge2sJqMf^Jf7j&6P(_ zy3S-()o2n}n54?8-I}E!uMspUDu!v2zwfyd;T?gWPKPseifD%{oA%=6%cB~aj8m^R zeN~$_E#--LGFuvTSs92gK9HRbG8Q?TfeHo~*wQ!$Xe=4U1iA&t83L4BVPH#R1{(uO Xc{jkD6{rK0E;t$dfelA_b`TE$o4#s? literal 0 HcmV?d00001 From 30407ac3b4c79c806b7b565187d3c84ffc249500 Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Fri, 18 Oct 2019 16:39:05 +0100 Subject: [PATCH 8/9] dependencies: update to v34.2 of github.com/Azure/azure-sdk-for-go --- go.mod | 3 ++- go.sum | 4 ++++ vendor/github.com/Azure/azure-sdk-for-go/version/version.go | 2 +- vendor/modules.txt | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 05c0f84a5eb6..bd6d7bc5b94f 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,8 @@ module github.com/terraform-providers/terraform-provider-azurerm require ( - github.com/Azure/azure-sdk-for-go v34.1.0+incompatible + github.com/Azure/azure-sdk-for-go v34.2.0+incompatible + github.com/Azure/go-autorest v13.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.9.0 github.com/Azure/go-autorest/autorest/date v0.2.0 github.com/btubbs/datetime v0.1.0 diff --git a/go.sum b/go.sum index 5a9de3c28e6b..91bb1c0c7a43 100644 --- a/go.sum +++ b/go.sum @@ -15,9 +15,13 @@ github.com/Azure/azure-sdk-for-go v32.5.0+incompatible h1:Hn/DsObfmw0M7dMGS/c0Ml github.com/Azure/azure-sdk-for-go v32.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v34.1.0+incompatible h1:uW/dgSzmRQEPXwaRUN8WzBHJy5J2cp8cw1ea908uFj0= github.com/Azure/azure-sdk-for-go v34.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v34.2.0+incompatible h1:nOMcbdfRmT5VX7Az7AJ4LRi5cpBOOfr+mF7QpoetwyI= +github.com/Azure/azure-sdk-for-go v34.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-autorest v10.15.4+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v13.0.0+incompatible h1:56c11ykhsFSPNNQuS73Ri8h/ezqVhr2h6t9LJIEKVO0= github.com/Azure/go-autorest v13.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v13.2.0+incompatible h1:jK9tnWNPzdvf5gTuueYWLCfIvAhg15iZ2f6+qkD43s8= +github.com/Azure/go-autorest v13.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU= diff --git a/vendor/github.com/Azure/azure-sdk-for-go/version/version.go b/vendor/github.com/Azure/azure-sdk-for-go/version/version.go index 8947c1ffc9c0..0951e96d1253 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/version/version.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/version/version.go @@ -18,4 +18,4 @@ package version // Changes may cause incorrect behavior and will be lost if the code is regenerated. // Number contains the semantic version of this SDK. -const Number = "v34.1.0" +const Number = "v34.2.0" diff --git a/vendor/modules.txt b/vendor/modules.txt index be3a6d571659..721e5c3e322d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -6,7 +6,7 @@ cloud.google.com/go/internal/optional cloud.google.com/go/internal/trace cloud.google.com/go/internal/version cloud.google.com/go/storage -# github.com/Azure/azure-sdk-for-go v34.1.0+incompatible +# github.com/Azure/azure-sdk-for-go v34.2.0+incompatible github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources github.com/Azure/azure-sdk-for-go/services/analysisservices/mgmt/2017-08-01/analysisservices github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2018-01-01/apimanagement From 345b9327c08bfeba6bf64b483d2e70c6cc0a163b Mon Sep 17 00:00:00 2001 From: Lawrence Gripper Date: Fri, 18 Oct 2019 17:17:24 +0100 Subject: [PATCH 9/9] Fix merge issues --- azurerm/data_source_function.go | 11 +++++++---- azurerm/data_source_function_test.go | 8 +++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/azurerm/data_source_function.go b/azurerm/data_source_function.go index d6c05311a0e7..e693d963bef7 100644 --- a/azurerm/data_source_function.go +++ b/azurerm/data_source_function.go @@ -8,8 +8,8 @@ import ( "log" "time" - "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web" @@ -48,7 +48,7 @@ func dataSourceArmFunction() *schema.Resource { } func dataSourceArmFunctionRead(d *schema.ResourceData, meta interface{}) error { - webClient := meta.(*ArmClient).web + webClient := meta.(*ArmClient).Web ctx := meta.(*ArmClient).StopContext name := d.Get("function_app_name").(string) @@ -70,7 +70,10 @@ func dataSourceArmFunctionRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error waiting for Function %q in Function app %q (Resource Group %q) to become available", functionName, name, resourceGroup) } - functionSecret := resp.(webmgmt.FunctionSecrets) + functionSecret, cast := resp.(webmgmt.FunctionSecrets) + if !cast { + return fmt.Errorf("Error retrieving key for Function %q in Function app %q (Resource Group %q). functionSecret returned nil from API", functionName, name, resourceGroup) + } if functionSecret.TriggerURL == nil { return fmt.Errorf("Error retrieving key for Function %q in Function app %q (Resource Group %q). TriggerURL returned nil from API", functionName, name, resourceGroup) diff --git a/azurerm/data_source_function_test.go b/azurerm/data_source_function_test.go index 386c7710f3d8..72b1d726036b 100644 --- a/azurerm/data_source_function_test.go +++ b/azurerm/data_source_function_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform/helper/acctest" - "github.com/hashicorp/terraform/helper/resource" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" ) @@ -90,8 +90,6 @@ resource "azurerm_storage_container" "test" { resource "azurerm_storage_blob" "javazip" { name = "testfunc.zip" - resource_group_name = "${azurerm_resource_group.test.name}" - storage_account_name = "${azurerm_storage_account.test.name}" storage_container_name = "${azurerm_storage_container.test.name}" @@ -113,8 +111,8 @@ resource "azurerm_function_app" "test" { } data "azurerm_function" "test" { - name = "${azurerm_function_app.test.name}" - resource_group_name = "${azurerm_resource_group.test.name}" + function_app_name = "${azurerm_function_app.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" function_name = "testfunc" } `, rInt, location, storage)