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

Adds support to specify linux_fx_version for Function Apps #2767

Merged
20 changes: 20 additions & 0 deletions azurerm/resource_arm_function_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ func resourceArmFunctionApp() *schema.Resource {

"location": locationSchema(),

"kind": {
Type: schema.TypeString,
Computed: true,
},

"app_service_plan_id": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -183,6 +188,11 @@ func resourceArmFunctionApp() *schema.Resource {
Optional: true,
Default: false,
},
"linux_fx_version": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
},
},
},
Expand Down Expand Up @@ -447,6 +457,8 @@ func resourceArmFunctionAppRead(d *schema.ResourceData, meta interface{}) error

d.Set("name", name)
d.Set("resource_group_name", resGroup)
d.Set("kind", resp.Kind)

if location := resp.Location; location != nil {
d.Set("location", azureRMNormalizeLocation(*location))
}
Expand Down Expand Up @@ -622,6 +634,10 @@ func expandFunctionAppSiteConfig(d *schema.ResourceData) web.SiteConfig {
siteConfig.WebSocketsEnabled = utils.Bool(v.(bool))
}

if v, ok := config["linux_fx_version"]; ok {
siteConfig.LinuxFxVersion = utils.String(v.(string))
}

return siteConfig
}

Expand All @@ -646,6 +662,10 @@ func flattenFunctionAppSiteConfig(input *web.SiteConfig) []interface{} {
result["websockets_enabled"] = *input.WebSocketsEnabled
}

if input.LinuxFxVersion != nil {
result["linux_fx_version"] = *input.LinuxFxVersion
}

results = append(results, result)
return results
}
Expand Down
152 changes: 149 additions & 3 deletions azurerm/resource_arm_function_app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,34 @@ func TestAccAzureRMFunctionApp_siteConfig(t *testing.T) {
})
}

func TestAccAzureRMFunctionApp_linuxFxVersion(t *testing.T) {
resourceName := "azurerm_function_app.test"
ri := tf.AccRandTimeInt()
rs := strings.ToLower(acctest.RandString(11))
config := testAccAzureRMFunctionApp_linuxFxVersion(ri, rs, testLocation())

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMFunctionAppDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMFunctionAppExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "kind", "functionapp,linux,container"),
resource.TestCheckResourceAttr(resourceName, "site_config.0.linux_fx_version", "DOCKER|(golang:latest)"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAzureRMFunctionApp_connectionStrings(t *testing.T) {
resourceName := "azurerm_function_app.test"
ri := tf.AccRandTimeInt()
Expand Down Expand Up @@ -242,7 +270,8 @@ func TestAccAzureRMFunctionApp_siteConfigMulti(t *testing.T) {
configBase := testAccAzureRMFunctionApp_basic(ri, rs, testLocation())
configUpdate1 := testAccAzureRMFunctionApp_appSettings(ri, rs, testLocation())
configUpdate2 := testAccAzureRMFunctionApp_appSettingsAlwaysOn(ri, rs, testLocation())
configUpdate3 := testAccAzureRMFunctionApp_appSettingsAlwaysOnConnectionStrings(ri, rs, testLocation())
configUpdate3 := testAccAzureRMFunctionApp_appSettingsAlwaysOnLinuxFxVersion(ri, rs, testLocation())
configUpdate4 := testAccAzureRMFunctionApp_appSettingsAlwaysOnLinuxFxVersionConnectionStrings(ri, rs, testLocation())

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand Down Expand Up @@ -277,9 +306,22 @@ func TestAccAzureRMFunctionApp_siteConfigMulti(t *testing.T) {
Config: configUpdate3,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMFunctionAppExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "kind", "functionapp,linux,container"),
resource.TestCheckResourceAttr(resourceName, "app_settings.%", "1"),
resource.TestCheckResourceAttr(resourceName, "app_settings.hello", "world"),
resource.TestCheckResourceAttr(resourceName, "site_config.0.always_on", "true"),
resource.TestCheckResourceAttr(resourceName, "site_config.0.linux_fx_version", "DOCKER|(golang:latest)"),
),
},
{
Config: configUpdate4,
Check: resource.ComposeTestCheckFunc(
testCheckAzureRMFunctionAppExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "kind", "functionapp,linux,container"),
resource.TestCheckResourceAttr(resourceName, "app_settings.%", "1"),
resource.TestCheckResourceAttr(resourceName, "app_settings.hello", "world"),
resource.TestCheckResourceAttr(resourceName, "site_config.0.always_on", "true"),
resource.TestCheckResourceAttr(resourceName, "site_config.0.linux_fx_version", "DOCKER|(golang:latest)"),
resource.TestCheckResourceAttr(resourceName, "connection_string.0.name", "Example"),
resource.TestCheckResourceAttr(resourceName, "connection_string.0.value", "some-postgresql-connection-string"),
resource.TestCheckResourceAttr(resourceName, "connection_string.0.type", "PostgreSQL"),
Expand Down Expand Up @@ -920,6 +962,52 @@ resource "azurerm_function_app" "test" {
`, rInt, location, rString)
}

func testAccAzureRMFunctionApp_linuxFxVersion(rInt int, rString, location 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}"
kind = "Linux"
resource_group_name = "${azurerm_resource_group.test.name}"

sku {
tier = "Standard"
size = "S1"
}

properties {
reserved = true
}
}

resource "azurerm_function_app" "test" {
name = "acctest-%[1]d-func"
location = "${azurerm_resource_group.test.location}"
version = "~2"
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}"

site_config {
linux_fx_version = "DOCKER|(golang:latest)"
}
}
`, rInt, location, rString)
}

func testAccAzureRMFunctionApp_connectionStrings(rInt int, rString, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
Expand Down Expand Up @@ -1006,7 +1094,7 @@ resource "azurerm_function_app" "test" {
`, rInt, location, rString)
}

func testAccAzureRMFunctionApp_appSettingsAlwaysOnConnectionStrings(rInt int, rString, location string) string {
func testAccAzureRMFunctionApp_appSettingsAlwaysOnLinuxFxVersion(rInt int, rString, location string) string {
return fmt.Sprintf(`
resource "azurerm_resource_group" "test" {
name = "acctestRG-%[1]d"
Expand All @@ -1024,27 +1112,85 @@ resource "azurerm_storage_account" "test" {
resource "azurerm_app_service_plan" "test" {
name = "acctestASP-%[1]d"
location = "${azurerm_resource_group.test.location}"
kind = "Linux"
resource_group_name = "${azurerm_resource_group.test.name}"

sku {
tier = "Standard"
size = "S1"
}

properties {
reserved = true
}
}

resource "azurerm_function_app" "test" {
name = "acctest-%[1]d-func"
location = "${azurerm_resource_group.test.location}"
version = "~2"
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 {
"hello" = "world"
}

site_config {
always_on = true
linux_fx_version = "DOCKER|(golang:latest)"
}
}
`, rInt, location, rString)
}

func testAccAzureRMFunctionApp_appSettingsAlwaysOnLinuxFxVersionConnectionStrings(rInt int, rString, location 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}"
kind = "Linux"
resource_group_name = "${azurerm_resource_group.test.name}"

sku {
tier = "Standard"
size = "S1"
}

properties {
reserved = true
}
}

resource "azurerm_function_app" "test" {
name = "acctest-%[1]d-func"
location = "${azurerm_resource_group.test.location}"
version = "~2"
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 {
"hello" = "world"
}

site_config {
always_on = true
always_on = true
linux_fx_version = "DOCKER|(golang:latest)"
}

connection_string {
Expand Down
4 changes: 3 additions & 1 deletion website/docs/r/function_app.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ The following arguments are supported:
~> **Note:** when using an App Service Plan in the `Free` or `Shared` Tiers `use_32_bit_worker_process` must be set to `true`.

* `websockets_enabled` - (Optional) Should WebSockets be enabled?

* `linux_fx_version` - (Optional) Linux App Framework and version for the AppService, e.g. `DOCKER|(golang:latest)`.
---

`identity` supports the following:
Expand All @@ -157,6 +157,8 @@ The following attributes are exported:

* `site_credential` - A `site_credential` block as defined below, which contains the site-level credentials used to publish to this App Service.

* `kind` - The Function App kind - such as `functionapp,linux,container`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we separate these values:

Suggested change
* `kind` - The Function App kind - such as `functionapp,linux,container`
* `kind` - The Function App kind - such as `functionapp`, `linux`, `container`

Copy link
Contributor Author

@joakimhew joakimhew Feb 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I could do that, this is how Azure will write it back to the user though. Should I still separate it? (This is an example of an function app with multiple kinds so its actually a valid kind 😀)

Edit:

I think the possible computed kinds for a Function App right now is;
functionapp
functionapp,linux,container

There might be more combinations but I’m not entirely sure. Microsoft’s documentation on this is very lacking unfortunately


---

`identity` exports the following:
Expand Down