Skip to content

[AppService] az functionapp flex-migration: Create commands to migrate CV1 apps to Flex#31865

Merged
zhoxing-ms merged 2 commits intoAzure:devfrom
kamperiadis:cv1toflexmigration
Aug 20, 2025
Merged

[AppService] az functionapp flex-migration: Create commands to migrate CV1 apps to Flex#31865
zhoxing-ms merged 2 commits intoAzure:devfrom
kamperiadis:cv1toflexmigration

Conversation

@kamperiadis
Copy link
Copy Markdown
Contributor

Related command
az functionapp flex-migration list
az functionapp flex-migration start

Description
Linux Consumption customers have to run these steps manually in order to migrate their apps to Flex Consumption: https://learn.microsoft.com/en-us/azure/azure-functions/migration/migrate-plan-consumption-to-flex?tabs=azure-cli%2Clinux%2Csystem-assigned%2Ccontinuous%2Ctraces-table

With the az functionapp flex-migration list command, customers will get a list of the Linux Consumption apps that are eligible for the migration to Flex.
Additionally, with the az functionapp flex-migration start command, customers will be able to create a Flex Consumption app from their Linux Consumption (CV1) app`. The command will migrate the relevant CV1 configurations to the Flex app. After running this migration command, customers will just need to deploy their code content, test it and then delete the original CV1 app.

Testing Guide


This checklist is used to make sure that common guidelines for a pull request are followed.

Copilot AI review requested due to automatic review settings July 23, 2025 19:04
@azure-client-tools-bot-prd
Copy link
Copy Markdown

azure-client-tools-bot-prd bot commented Jul 23, 2025

️✔️AzureCLI-FullTest
️✔️acr
️✔️latest
️✔️3.12
️✔️3.9
️✔️acs
️✔️latest
️✔️3.12
️✔️3.9
️✔️advisor
️✔️latest
️✔️3.12
️✔️3.9
️✔️ams
️✔️latest
️✔️3.12
️✔️3.9
️✔️apim
️✔️latest
️✔️3.12
️✔️3.9
️✔️appconfig
️✔️latest
️✔️3.12
️✔️3.9
️✔️appservice
️✔️latest
️✔️3.12
️✔️3.9
️✔️aro
️✔️latest
️✔️3.12
️✔️3.9
️✔️backup
️✔️latest
️✔️3.12
️✔️3.9
️✔️batch
️✔️latest
️✔️3.12
️✔️3.9
️✔️batchai
️✔️latest
️✔️3.12
️✔️3.9
️✔️billing
️✔️latest
️✔️3.12
️✔️3.9
️✔️botservice
️✔️latest
️✔️3.12
️✔️3.9
️✔️cdn
️✔️latest
️✔️3.12
️✔️3.9
️✔️cloud
️✔️latest
️✔️3.12
️✔️3.9
️✔️cognitiveservices
️✔️latest
️✔️3.12
️✔️3.9
️✔️compute_recommender
️✔️latest
️✔️3.12
️✔️3.9
️✔️computefleet
️✔️latest
️✔️3.12
️✔️3.9
️✔️config
️✔️latest
️✔️3.12
️✔️3.9
️✔️configure
️✔️latest
️✔️3.12
️✔️3.9
️✔️consumption
️✔️latest
️✔️3.12
️✔️3.9
️✔️container
️✔️latest
️✔️3.12
️✔️3.9
️✔️containerapp
️✔️latest
️✔️3.12
️✔️3.9
️✔️core
️✔️latest
️✔️3.12
️✔️3.9
️✔️cosmosdb
️✔️latest
️✔️3.12
️✔️3.9
️✔️databoxedge
️✔️latest
️✔️3.12
️✔️3.9
️✔️dls
️✔️latest
️✔️3.12
️✔️3.9
️✔️dms
️✔️latest
️✔️3.12
️✔️3.9
️✔️eventgrid
️✔️latest
️✔️3.12
️✔️3.9
️✔️eventhubs
️✔️latest
️✔️3.12
️✔️3.9
️✔️feedback
️✔️latest
️✔️3.12
️✔️3.9
️✔️find
️✔️latest
️✔️3.12
️✔️3.9
️✔️hdinsight
️✔️latest
️✔️3.12
️✔️3.9
️✔️identity
️✔️latest
️✔️3.12
️✔️3.9
️✔️iot
️✔️latest
️✔️3.12
️✔️3.9
️✔️keyvault
️✔️latest
️✔️3.12
️✔️3.9
️✔️lab
️✔️latest
️✔️3.12
️✔️3.9
️✔️managedservices
️✔️latest
️✔️3.12
️✔️3.9
️✔️maps
️✔️latest
️✔️3.12
️✔️3.9
️✔️marketplaceordering
️✔️latest
️✔️3.12
️✔️3.9
️✔️monitor
️✔️latest
️✔️3.12
️✔️3.9
️✔️mysql
️✔️latest
️✔️3.12
️✔️3.9
️✔️netappfiles
️✔️latest
️✔️3.12
️✔️3.9
️✔️network
️✔️latest
️✔️3.12
️✔️3.9
️✔️policyinsights
️✔️latest
️✔️3.12
️✔️3.9
️✔️privatedns
️✔️latest
️✔️3.12
️✔️3.9
️✔️profile
️✔️latest
️✔️3.12
️✔️3.9
️✔️rdbms
️✔️latest
️✔️3.12
️✔️3.9
️✔️redis
️✔️latest
️✔️3.12
️✔️3.9
️✔️relay
️✔️latest
️✔️3.12
️✔️3.9
️✔️resource
️✔️latest
️✔️3.12
️✔️3.9
️✔️role
️✔️latest
️✔️3.12
️✔️3.9
️✔️search
️✔️latest
️✔️3.12
️✔️3.9
️✔️security
️✔️latest
️✔️3.12
️✔️3.9
️✔️servicebus
️✔️latest
️✔️3.12
️✔️3.9
️✔️serviceconnector
️✔️latest
️✔️3.12
️✔️3.9
️✔️servicefabric
️✔️latest
️✔️3.12
️✔️3.9
️✔️signalr
️✔️latest
️✔️3.12
️✔️3.9
️✔️sql
️✔️latest
️✔️3.12
️✔️3.9
️✔️sqlvm
️✔️latest
️✔️3.12
️✔️3.9
️✔️storage
️✔️latest
️✔️3.12
️✔️3.9
️✔️synapse
️✔️latest
️✔️3.12
️✔️3.9
️✔️telemetry
️✔️latest
️✔️3.12
️✔️3.9
️✔️util
️✔️latest
️✔️3.12
️✔️3.9
️✔️vm
️✔️latest
️✔️3.12
️✔️3.9

@azure-client-tools-bot-prd
Copy link
Copy Markdown

Hi @kamperiadis,
Since the current milestone time is less than 7 days, this pr will be reviewed in the next milestone.

@azure-client-tools-bot-prd
Copy link
Copy Markdown

azure-client-tools-bot-prd bot commented Jul 23, 2025

⚠️AzureCLI-BreakingChangeTest
⚠️appservice
rule cmd_name rule_message suggest_message
⚠️ 1011 - SubgroupAdd functionapp flex-migration sub group functionapp flex-migration added

@yonzhan
Copy link
Copy Markdown
Collaborator

yonzhan commented Jul 23, 2025

Thank you for your contribution! We will review the pull request and get back to you soon.

@github-actions
Copy link
Copy Markdown

The git hooks are available for azure-cli and azure-cli-extensions repos. They could help you run required checks before creating the PR.

Please sync the latest code with latest dev branch (for azure-cli) or main branch (for azure-cli-extensions).
After that please run the following commands to enable git hooks:

pip install azdev --upgrade
azdev setup -c <your azure-cli repo path> -r <your azure-cli-extensions repo path>

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds new CLI commands for migrating Linux Consumption function apps to the Flex Consumption plan. The feature provides automated migration capabilities to help customers transition from Linux Consumption (CV1) to Flex Consumption plans.

  • Adds az functionapp flex-migration list command to identify eligible function apps for migration
  • Adds az functionapp flex-migration start command to perform the actual migration from CV1 to Flex
  • Includes comprehensive validation, configuration migration, and error handling capabilities

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/azure-cli/azure/cli/command_modules/appservice/custom.py Core migration logic with validation, app creation, and settings migration functions
src/azure-cli/azure/cli/command_modules/appservice/commands.py Command registration for the new flex-migration command group
src/azure-cli/azure/cli/command_modules/appservice/_params.py Parameter definitions and help text for the new migration commands
src/azure-cli/azure/cli/command_modules/appservice/_help.py Documentation and examples for the migration commands
src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_functionapp_commands.py Test cases for validating migration functionality

Comment thread src/azure-cli/azure/cli/command_modules/appservice/_help.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_params.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_params.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_params.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_params.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_params.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_params.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py
@kamperiadis kamperiadis force-pushed the cv1toflexmigration branch 6 times, most recently from f1dfff0 to 8797286 Compare July 31, 2025 22:40
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_help.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_help.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_help.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/_help.py
subscription_id = get_subscription_id(cmd.cli_ctx)
web_client = get_mgmt_service_client(cmd.cli_ctx, WebSiteManagementClient)

logger.warning("Searching for function apps under the subscription '%s' that are eligible for Flex "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I know you told me that it appears ALL logs are being written using logger.warning, but that doesn't really make sense if you want to be able to have warnings stand out in output. So I guess we need general CLI guidance on why we shouldn't be using logger.info here, reserving warning/error for lines we want to stand out to the customer

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@zhoxing-ms Can you provide guidance on this?

According to the guidance document here "Log to logger.error() or logger.warning() for user messages". The next guideline is "Use the appropriate logging level for printing strings" but the example just highlights the distinction between using the logger vs returning the string as opposed to logger.info vs logger.warning.

When I switch to make these logs use logger.info instead of logger.warning, I do not see the logs unless I use the --verbose flag. It seems to be due to this dependency we use for the logging which will only show messages from warning logs and above, unless the --verbose and --debug flags are passed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If you want notification message to be displayed by default even without using parameter --verbose, you can try using print()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Isn't that against what the guidelines outlined here: https://github.com/Azure/azure-cli/blob/dev/doc/command_guidelines.md#general-patterns

Log to logger.error() or logger.warning() for user messages; do not use the print() function

Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py
_generic_site_operation(cmd.cli_ctx, resource_group, name,
'update_scm_allowed', None, csmPublishingCredentialsPoliciesEntity)

logger.warning("Successfully enabled SCM basic publishing credentials")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

you're using "enabled" rather than migrated on this and the next log, but others you're using "migrate"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I figured "enabled" would make more sense in this context since it is just a single boolean property that we are enabling as opposed to a set of properties. What do you think?

Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py
return update_configuration_polling(cmd, resource_group_name, name, slot, configs)
try:
return _generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'update_configuration', slot, configs)
except Exception as ex: # pylint: disable=broad-exception-caught
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why the removal of this exception handler block?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For context, this exception handling was added as part of this commit: ef54889

And this function is run with the az webapp config set command.

I do not think it is right that we are catching Conflict and Bad Request exceptions. I think that if either of those two exceptions are simply logged instead of thrown back to the client when run via a script in a pipeline, customers might miss that there were issues with updating the site config. Even for the purposes of this PR, the caller of this function should know via a thrown exception that something went wrong, and the caller should decide how to handle such exception.

subnet_name=subnet_info["subnet_name"],
subnet_service_delegation=FLEX_SUBNET_DELEGATION if flexconsumption_location else None)
subnet_resource_id = subnet_info["subnet_resource_id"]
vnet_route_all_enabled = True
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't have context on these changes - they don't seem related?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The reason why I made these changes is because otherwise we get the "Readonly attribute name will be ignored in class" warning since vnet_route_all_enabled is only part of the SiteConfig class (code ref) It is not part of the Site class: https://github.com/Azure/azure-sdk-for-python/blob/afce6c3a2c8c1c47688e8d0c896da9eac07477b6/sdk/appservice/azure-mgmt-web/azure/mgmt/web/v2024_11_01/models/_models_py3.py#L19638

@kamperiadis kamperiadis force-pushed the cv1toflexmigration branch 3 times, most recently from 174337f to 083c619 Compare August 5, 2025 18:30
Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py
Comment thread src/azure-cli/azure/cli/command_modules/appservice/custom.py
])


class FunctionAppFlexMigrationTest(LiveScenarioTest):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

May I ask why do you need to mark these tests as LiveScenarioTest?

Copy link
Copy Markdown
Contributor Author

@kamperiadis kamperiadis Aug 19, 2025

Choose a reason for hiding this comment

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

Much like what happened for this other PR #28001, because there are resources created on the customer's behalf (e.g. server farms, storage accounts, etc.), when I switch to using ScenarioTest, the resources that were generated in the yaml recording are different in the next run and it can't find a match. The tests run just fine when I set they run in live mode.

When using ScenarioTest, I get success the first time I run the tests. But then when I run those same tests again using the yaml recordings, I see things like this:
image

vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('q:\src\azure-cli\src\azure-cli\azure\cli\command_modules\appservice\tests\latest\recordings\test_functionapp_flex_migration_site_configuration.yaml') in your current record mode ('once').
E No match for the request (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Web/serverfarms/ASP-clitestrg000002-0c0b?api-version=2024-11-01>) was found.
E Found 8 similar requests with 1 different matcher(s) :
E
E 1 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Web/sites/srcfunc000005?api-version=2024-11-01>).
E Matchers succeeded : ['method', 'scheme', 'host', 'port', '_custom_request_query_matcher']
E Matchers failed :
E path - assertion failure :
E /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Web/serverfarms/ASP-clitestrg000002-0c0b != /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Web/sites/srcfunc000005
E
E 2 - (<Request (PUT) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Web/sites/srcfunc000005/config/appsettings?api-version=2024-11-01>).
E Matchers succeeded : ['method', 'scheme', 'host', 'port', '_custom_request_query_matcher']
E Matchers failed :
E path - assertion failure :
E /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000002/providers/Microsoft.Web/serverfarms/ASP-clitestrg000002-0c0b != /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Web/sites/srcfunc000005/config/appsettings

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Got it, thanks

@zhoxing-ms zhoxing-ms merged commit 3c8e330 into Azure:dev Aug 20, 2025
48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Auto-Assign Auto assign by bot Functions az functionapp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants