pulumi / pulumi-azure-native

Azure Native Provider
Apache License 2.0
128 stars 34 forks source link

Changing Azure web app "kind" from "app" to "functionapp" acts like it works but no change occurs #2394

Closed donniehale-awh closed 5 months ago

donniehale-awh commented 1 year ago

What happened?

This is mostly my fault, but based on a brief conversation in Slack, a Pulumi individual said it seems like a bug.

I created an Azure WebApp that was intended to be an Azure Function. I did the pulumi up, and from pulumi's POV, everything looked right. However, in the Azure portal, it just showed as a regular "app service". Checking my code, I see that I forgot to set the Kind property to FunctionApp (sort of a big deal - I know).

So I added the property, and pulumi preview said it would update based on that property change. However, when I ran pulumi up, though it thinks it succeeded, the portal still shows it as an "app service." And the ARM template within the Azure portal shows that the value of "kind" for the resource is still "app."

Expected Behavior

After changing the Kind property on the WebApp from (not set) to FunctionApp, and based on pulumi seeing the change and calling for an "update," I expected the Azure resource to change from a regular app service to an Azure Function.

Steps to reproduce

Here's the code which creates the Azure Function and required / related resources. (I don't have time to create a stand-alone repro.)

Use the code by creating an instance of the class from a normal C# "main" Stack.cs file:

// These required parameters will need to be accounted for
new SampleAzureNotificationsFunctionResources(
    rgName, "dev", storageResources, appConnString, notificationsConnString);

If you run it as-is, you'll get a standard Azure app service. Then uncomment out this line:

// Kind = "FunctionApp", // *** UNCOMMENT THIS PROPERTY TO CAUSE PULUMI TO SEE THE "UPDATE"

and re-run pulumi preview. Both it and pulumi up will say that an "update" should happen based on the kind property. But after re-running pulumi up, the resource in Azure is still a standard app service.

using Pulumi;
using Pulumi.AzureNative.Authorization;
using Pulumi.AzureNative.Insights;
using Pulumi.AzureNative.Web;
using Pulumi.AzureNative.Web.Inputs;

public class SampleAzureNotificationsFunctionResources
{
    public Output<string> NotificationsFunctionName { get; }

    public SampleAzureNotificationsFunctionResources(
        Output<string> rgName, 
        string envTagName,
        SampleAzureStorageResources storageResources,
        Output<string> appDbConnectionString,
        Output<string> notificationsDbConnectionString)
    {
        var aspId = DefineAppServicePlan(rgName, envTagName);

        var appInsights = DefineApplicationInsights(rgName, envTagName);

        NotificationsFunctionName = DefineNotificationsAzureFunction(
            rgName,
            aspId,
            appInsights,
            appDbConnectionString,
            notificationsDbConnectionString,
            storageResources,
            envTagName);
    }

    private static Output<string> DefineAppServicePlan(Output<string> rgName, string envTagName)
    {
        var apiAppServicePlan = new AppServicePlan("Sample-notifications-asp", new AppServicePlanArgs
        {
            ResourceGroupName = rgName,
            Kind = "app",
            Location = ApiResourcesStack.ApiLocation,
            Sku = new SkuDescriptionArgs
            {
                Capacity = 1,
                Family = "B",
                Name = "B1",
                Size = "B1",
                Tier = "Basic",
            },
            Tags =
            {
                { ApiResourcesStack.TagEnvironment, envTagName },
            },
        });

        return apiAppServicePlan.Id;
    }

    private static Component DefineApplicationInsights(Output<string> rgName, string envTagName)
    {
        var appInsights = new Component("Sample-notifications-azfunc", new ComponentArgs
        {
            ApplicationType = "web",
            FlowType = "Bluefield",
            IngestionMode = "ApplicationInsights",
            Kind = "web",
            Location = ApiResourcesStack.ApiLocation,
            RequestSource = "rest",
            ResourceGroupName = rgName,
            RetentionInDays = 90,
            Tags =
            {
                { ApiResourcesStack.TagEnvironment, envTagName },
            },
        });

        return appInsights;
    }

    private static Output<string> DefineNotificationsAzureFunction(
        Output<string> rgName,
        Output<string> aspId,
        Component appInsights,
        Output<string> appDbConnectionString,
        Output<string> notificationsDbConnectionString,
        SampleAzureStorageResources storageResources,
        string envTagName)
    {
        var notificationsFunction = new WebApp("Sample-notifications-azfunc", new WebAppArgs
        {
            ResourceGroupName = rgName,
            // Kind = "FunctionApp", // *** UNCOMMENT THIS PROPERTY TO CAUSE PULUMI TO SEE THE "UPDATE"
            ServerFarmId = aspId,
            Identity = new ManagedServiceIdentityArgs
            {
                Type = ManagedServiceIdentityType.SystemAssigned
            },
            HttpsOnly = true,
            Location = ApiResourcesStack.ApiLocation,
            SiteConfig = new SiteConfigArgs
            {
                AlwaysOn = true,
                FtpsState = FtpsState.FtpsOnly,
                Http20Enabled = true,
                MinTlsVersion = "1.2",
                NetFrameworkVersion = "v6.0",
                NumberOfWorkers = 1,
                Use32BitWorkerProcess = false,
                AppSettings =
                {
                    new NameValuePairArgs { Name = "APPINSIGHTS_INSTRUMENTATIONKEY", Value = appInsights.InstrumentationKey },
                    new NameValuePairArgs { Name = "APPLICATIONINSIGHTS_CONNECTION_STRING", Value = appInsights.InstrumentationKey.Apply(key => $"InstrumentationKey={key}") },
                    new NameValuePairArgs { Name = "APPINSIGHTS_PROFILERFEATURE_VERSION", Value = "1.0.0" },
                    new NameValuePairArgs { Name = "APPINSIGHTS_SNAPSHOTFEATURE_VERSION", Value = "1.0.0" },
                    new NameValuePairArgs { Name = "runtime", Value = "dotnet" },
                    new NameValuePairArgs { Name = "FUNCTIONS_WORKER_RUNTIME", Value = "dotnet-isolated" },
                    new NameValuePairArgs { Name = "FUNCTIONS_EXTENSION_VERSION", Value = "~4" },
                    new NameValuePairArgs { Name = "AzureWebJobsStorage__accountName", Value = storageResources.StorageAccountName },
                    new NameValuePairArgs { Name = "WEBSITE_RUN_FROM_PACKAGE", Value = "1" },
                },
                ConnectionStrings =
                {
                    new ConnStringInfoArgs
                    {
                        Name = "AppDb",
                        Type = ConnectionStringType.SQLAzure,
                        ConnectionString = appDbConnectionString,
                    },
                    new ConnStringInfoArgs
                    {
                        Name = "NotificationsDb",
                        Type = ConnectionStringType.SQLAzure,
                        ConnectionString = notificationsDbConnectionString,
                    },
                }
            },
            Tags =
            {
                { ApiResourcesStack.TagEnvironment, envTagName },
            },
        });

        var _ = new RoleAssignment("Sample-StorageBlobDataOwner", new RoleAssignmentArgs
        {
            PrincipalId = notificationsFunction.Identity.Apply(i => i!.PrincipalId),
            PrincipalType = PrincipalType.ServicePrincipal,
            RoleDefinitionId = SampleAzureStorageResources.StorageBlobDataOwner,
            Scope = storageResources.StorageAccountId
        });

        return notificationsFunction.Name;
    }
}

Output of pulumi about

running 'dotnet build -nologo .'
  Determining projects to restore...

  All projects are up-to-date for restore.

  grv-api-resources -> D:\Src\GeneralRV\dev\sprint24\api\Devops\azure-environment\pulumi\grv-api-resources\bin\Debug\netcoreapp3.1\grv-api-resources.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.72

'dotnet build -nologo .' completed successfully
CLI
Version      3.64.0
Go Version   go1.20.3
Go Compiler  gc

Plugins
NAME          VERSION
azure-native  1.99.2
dotnet        unknown

Host
OS       Microsoft Windows 11 Pro
Version  10.0.22621 Build 22621
Arch     x86_64

This project is written in dotnet: executable='C:\Program Files\dotnet\dotnet.exe' version='7.0.202'

Current Stack: grv-api-dev

TYPE                                        URN
pulumi:pulumi:Stack                         urn:pulumi:grv-api-dev::grv-api-resources::pulumi:pulumi:Stack::grv-api-resources-grv-api-dev
pulumi:providers:azure-native               urn:pulumi:grv-api-dev::grv-api-resources::pulumi:providers:azure-native::default_1_100_1
azure-native:resources:ResourceGroup        urn:pulumi:grv-api-dev::grv-api-resources::azure-native:resources:ResourceGroup::grv-api-dev-rg
azure-native:sql:Server                     urn:pulumi:grv-api-dev::grv-api-resources::azure-native:sql:Server::grv-dev
azure-native:insights:Component             urn:pulumi:grv-api-dev::grv-api-resources::azure-native:insights:Component::grv-api-app
azure-native:web:AppServicePlan             urn:pulumi:grv-api-dev::grv-api-resources::azure-native:web:AppServicePlan::grv-api-asp
azure-native:storage:StorageAccount         urn:pulumi:grv-api-dev::grv-api-resources::azure-native:storage:StorageAccount::appstoragedev
azure-native:sql:FirewallRule               urn:pulumi:grv-api-dev::grv-api-resources::azure-native:sql:FirewallRule::AllowAllWindowsAzureIps
azure-native:sql:FirewallRule               urn:pulumi:grv-api-dev::grv-api-resources::azure-native:sql:FirewallRule::AWH_VPN_2.0
azure-native:sql:Database                   urn:pulumi:grv-api-dev::grv-api-resources::azure-native:sql:Database::grv-dev
azure-native:storage:BlobContainer          urn:pulumi:grv-api-dev::grv-api-resources::azure-native:storage:BlobContainer::rv-photos
azure-native:storage:BlobServiceProperties  urn:pulumi:grv-api-dev::grv-api-resources::azure-native:storage:BlobServiceProperties::GrvAppBlobServicesProperties
azure-native:web:WebApp                     urn:pulumi:grv-api-dev::grv-api-resources::azure-native:web:WebApp::grv-api-app
pulumi:providers:azure-native               urn:pulumi:grv-api-dev::grv-api-resources::pulumi:providers:azure-native::default_1_99_2
azure-native:sql:Database                   urn:pulumi:grv-api-dev::grv-api-resources::azure-native:sql:Database::grv-notifications-dev
azure-native:web:AppServicePlan             urn:pulumi:grv-api-dev::grv-api-resources::azure-native:web:AppServicePlan::grv-notifications-asp
azure-native:insights:Component             urn:pulumi:grv-api-dev::grv-api-resources::azure-native:insights:Component::grv-notifications-azfunc
azure-native:web:WebApp                     urn:pulumi:grv-api-dev::grv-api-resources::azure-native:web:WebApp::grv-notifications-azfunc
azure-native:authorization:RoleAssignment   urn:pulumi:grv-api-dev::grv-api-resources::azure-native:authorization:RoleAssignment::grv-StorageBlobDataOwner

Found no pending operations associated with grv-api-dev

Backend
Name           SIMPLICITY
URL            azblob://api-pulumi-state
User           SIMPLICITY\dhale
Organizations

Dependencies:
NAME                VERSION
Pulumi              3.54.1
Pulumi.AzureNative  1.99.2

Additional context

Not sure how long this Slack thread will be around, but the discussion began here:

https://pulumi-community.slack.com/archives/CRVK66N5U/p1682024152418909

Contributing

Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

mikhailshilkov commented 1 year ago

The kind property should be marked as causing replacement in the Rest API specs, but it's not.