Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function app consumption plan bug #1515

Merged
merged 6 commits into from
Jul 16, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
59 changes: 52 additions & 7 deletions azurerm/resource_arm_function_app.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package azurerm

import (
"context"
"fmt"
"log"
"strings"

"github.com/Azure/azure-sdk-for-go/services/web/mgmt/2016-09-01/web"
"github.com/hashicorp/terraform/helper/schema"
Expand Down Expand Up @@ -214,7 +216,13 @@ func resourceArmFunctionAppCreate(d *schema.ResourceData, meta interface{}) erro
clientAffinityEnabled := d.Get("client_affinity_enabled").(bool)
httpsOnly := d.Get("https_only").(bool)
tags := d.Get("tags").(map[string]interface{})
basicAppSettings := getBasicFunctionAppAppSettings(d)
appServiceTier, err := getFunctionAppServiceTier(ctx, appServicePlanID, meta)
if err != nil {
return err
}

basicAppSettings := getBasicFunctionAppAppSettings(d, appServiceTier)

siteConfig := expandFunctionAppSiteConfig(d)
siteConfig.AppSettings = &basicAppSettings

Expand Down Expand Up @@ -279,7 +287,13 @@ func resourceArmFunctionAppUpdate(d *schema.ResourceData, meta interface{}) erro
clientAffinityEnabled := d.Get("client_affinity_enabled").(bool)
httpsOnly := d.Get("https_only").(bool)
tags := d.Get("tags").(map[string]interface{})
basicAppSettings := getBasicFunctionAppAppSettings(d)

appServiceTier, err := getFunctionAppServiceTier(ctx, appServicePlanID, meta)

if err != nil {
return err
}
basicAppSettings := getBasicFunctionAppAppSettings(d, appServiceTier)
siteConfig := expandFunctionAppSiteConfig(d)
siteConfig.AppSettings = &basicAppSettings

Expand Down Expand Up @@ -312,7 +326,7 @@ func resourceArmFunctionAppUpdate(d *schema.ResourceData, meta interface{}) erro
return err
}

appSettings := expandFunctionAppAppSettings(d)
appSettings := expandFunctionAppAppSettings(d, appServiceTier)
settings := web.StringDictionary{
Properties: appSettings,
}
Expand Down Expand Up @@ -458,7 +472,7 @@ func resourceArmFunctionAppDelete(d *schema.ResourceData, meta interface{}) erro
return nil
}

func getBasicFunctionAppAppSettings(d *schema.ResourceData) []web.NameValuePair {
func getBasicFunctionAppAppSettings(d *schema.ResourceData, appServiceTier string) []web.NameValuePair {
dashboardPropName := "AzureWebJobsDashboard"
storagePropName := "AzureWebJobsStorage"
functionVersionPropName := "FUNCTIONS_EXTENSION_VERSION"
Expand All @@ -469,19 +483,50 @@ func getBasicFunctionAppAppSettings(d *schema.ResourceData) []web.NameValuePair
functionVersion := d.Get("version").(string)
contentShare := d.Get("name").(string) + "-content"

return []web.NameValuePair{
basicSettings := []web.NameValuePair{
{Name: &dashboardPropName, Value: &storageConnection},
{Name: &storagePropName, Value: &storageConnection},
{Name: &functionVersionPropName, Value: &functionVersion},
}

consumptionSettings := []web.NameValuePair{
{Name: &contentSharePropName, Value: &contentShare},
{Name: &contentFileConnStringPropName, Value: &storageConnection},
}

// If the application plan is NOT dynamic (consumption plan), we do NOT want to include WEBSITE_CONTENT components
if !strings.EqualFold(appServiceTier, "dynamic") {
return basicSettings
}
return append(basicSettings, consumptionSettings...)
}

func getFunctionAppServiceTier(ctx context.Context, appServicePlanId string, meta interface{}) (string, error) {
id, err := parseAzureResourceID(appServicePlanId)
if err != nil {
return "", fmt.Errorf("[ERROR] Unable to parse App Service Plan ID %q: %+v", appServicePlanId, err)
}

log.Printf("[DEBUG] Retrieving App Server Plan %s", id.Path["serverfarms"])

appServicePlansClient := meta.(*ArmClient).appServicePlansClient
appServicePlan, err := appServicePlansClient.Get(ctx, id.ResourceGroup, id.Path["serverfarms"])
if err != nil {
return "", fmt.Errorf("[ERROR] Could not retrieve App Service Plan ID %q: %+v", appServicePlanId, err)
}

if sku := appServicePlan.Sku; sku != nil {
if tier := sku.Tier; tier != nil {
return *tier, nil
}
}
return "", fmt.Errorf("No `sku` block was returned for App Service Plan ID %q", appServicePlanId)
}

func expandFunctionAppAppSettings(d *schema.ResourceData) map[string]*string {
func expandFunctionAppAppSettings(d *schema.ResourceData, appServiceTier string) map[string]*string {
output := expandAppServiceAppSettings(d)

basicAppSettings := getBasicFunctionAppAppSettings(d)
basicAppSettings := getBasicFunctionAppAppSettings(d, appServiceTier)
for _, p := range basicAppSettings {
output[*p.Name] = p.Value
}
Expand Down
66 changes: 66 additions & 0 deletions azurerm/resource_arm_function_app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func TestAccAzureRMFunctionApp_basic(t *testing.T) {
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMFunctionAppExists(resourceName),
testCheckAzureRMFunctionAppHasNoContentShare(resourceName),
resource.TestCheckResourceAttr(resourceName, "version", "~1"),
),
},
Expand Down Expand Up @@ -328,6 +329,7 @@ func TestAccAzureRMFunctionApp_consumptionPlan(t *testing.T) {
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMFunctionAppExists(resourceName),
testCheckAzureRMFunctionAppHasContentShare(resourceName),
resource.TestCheckResourceAttr(resourceName, "site_config.0.use_32_bit_worker_process", "true"),
),
},
Expand Down Expand Up @@ -453,6 +455,70 @@ func testCheckAzureRMFunctionAppExists(name string) resource.TestCheckFunc {
}
}

func testCheckAzureRMFunctionAppHasContentShare(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
// Ensure we have enough information in state to look up in API
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s", name)
}

functionAppName := rs.Primary.Attributes["name"]
resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"]
if !hasResourceGroup {
return fmt.Errorf("Bad: no resource group found in state for Function App: %s", functionAppName)
}

client := testAccProvider.Meta().(*ArmClient).appServicesClient
ctx := testAccProvider.Meta().(*ArmClient).StopContext

appSettingsResp, err := client.ListApplicationSettings(ctx, resourceGroup, functionAppName)
if err != nil {
return fmt.Errorf("Error making Read request on AzureRM Function App AppSettings %q: %+v", functionAppName, err)
}

for k, _ := range appSettingsResp.Properties {
if strings.EqualFold("WEBSITE_CONTENTSHARE", k) {
return nil
}
}

return fmt.Errorf("Function App %q does not contain the Website Content Share!", functionAppName)
}
}

func testCheckAzureRMFunctionAppHasNoContentShare(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
// Ensure we have enough information in state to look up in API
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s", name)
}

functionAppName := rs.Primary.Attributes["name"]
resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"]
if !hasResourceGroup {
return fmt.Errorf("Bad: no resource group found in state for Function App: %s", functionAppName)
}

client := testAccProvider.Meta().(*ArmClient).appServicesClient
ctx := testAccProvider.Meta().(*ArmClient).StopContext

appSettingsResp, err := client.ListApplicationSettings(ctx, resourceGroup, functionAppName)
if err != nil {
return fmt.Errorf("Error making Read request on AzureRM Function App AppSettings %q: %+v", functionAppName, err)
}

for k, v := range appSettingsResp.Properties {
if strings.EqualFold("WEBSITE_CONTENTSHARE", k) && v != nil && *v != "" {
return fmt.Errorf("Function App %q contains the Website Content Share!", functionAppName)
}
}

return nil
}
}

func testAccAzureRMFunctionApp_basic(rInt int, storage string, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
Expand Down