-
Notifications
You must be signed in to change notification settings - Fork 3.3k
[App Service] Fix #32290: az functionapp config appsettings set --slot-settings: Fix the command failure to update existing slot settings
#32291
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
Open
jcassanji-southworks
wants to merge
27
commits into
Azure:dev
Choose a base branch
from
jcassanji-southworks:32290-function-app-slot-settings-parameter-fails-to-update-existing-function-app-slot-settings-fix
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+240
β39
Open
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
3e1176b
Improves slot setting handling in app settings update
jcassanji-southworks a5e185a
Enhances error handling in update_app_settings function and adds unitβ¦
jcassanji-southworks 40e0045
Update src/azure-cli/azure/cli/command_modules/appservice/custom.py
jcassanji-southworks f0f7e9d
Update src/azure-cli/azure/cli/command_modules/appservice/custom.py
jcassanji-southworks 7dc68fd
Adds error handling test for update_app_settings to validate invalid β¦
jcassanji-southworks ce9d520
Merge branch '32290-function-app-slot-settings-parameter-fails-to-updβ¦
jcassanji-southworks 5be2f8d
Refactor update_app_settings to improve handling of JSON objects and β¦
jcassanji-southworks 301c400
Fix update_app_settings to correctly update settings dictionary with β¦
jcassanji-southworks 261a86b
Refactor update_app_settings to simplify iteration over keys in slot β¦
jcassanji-southworks 47a6108
Update src/azure-cli/azure/cli/command_modules/appservice/custom.py
jcassanji-southworks f65e501
Update src/azure-cli/azure/cli/command_modules/appservice/custom.py
jcassanji-southworks 36ba1ca
Refactor update_app_settings and its tests to improve clarity in handβ¦
jcassanji-southworks 71ed94f
Fix update_app_settings to correctly handle setting assignment and imβ¦
jcassanji-southworks ff33936
Update src/azure-cli/azure/cli/command_modules/appservice/tests/latesβ¦
jcassanji-southworks 39f759e
Update src/azure-cli/azure/cli/command_modules/appservice/tests/latesβ¦
jcassanji-southworks 4ed5e9a
Update src/azure-cli/azure/cli/command_modules/appservice/tests/latesβ¦
jcassanji-southworks 5f445af
Update src/azure-cli/azure/cli/command_modules/appservice/tests/latesβ¦
jcassanji-southworks a916b4b
Update src/azure-cli/azure/cli/command_modules/appservice/tests/latesβ¦
jcassanji-southworks fdf6f2e
Update src/azure-cli/azure/cli/command_modules/appservice/tests/latesβ¦
jcassanji-southworks 4c27292
Refactor update_app_settings to modularize parsing logic for key=valuβ¦
jcassanji-southworks cef992e
Merge branch '32290-function-app-slot-settings-parameter-fails-to-updβ¦
jcassanji-southworks 2446b64
Update src/azure-cli/azure/cli/command_modules/appservice/custom.py
jcassanji-southworks 0ae0770
Update src/azure-cli/azure/cli/command_modules/appservice/custom.py
jcassanji-southworks 8e63318
Update src/azure-cli/azure/cli/command_modules/appservice/custom.py
jcassanji-southworks 6f88a7f
Refactor update_app_settings to remove unnecessary whitespace, improvβ¦
jcassanji-southworks b871eef
Merge branch '32290-function-app-slot-settings-parameter-fails-to-updβ¦
jcassanji-southworks 988fca4
Refactor _parse_json_setting to remove unused parameter and simplify β¦
jcassanji-southworks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -511,60 +511,112 @@ def update_app_settings_functionapp(cmd, resource_group_name, name, settings=Non | |
| return update_app_settings(cmd, resource_group_name, name, settings, slot, slot_settings) | ||
|
|
||
|
|
||
| def _parse_simple_key_value_setting(s, dest): | ||
| """ | ||
| Parse simple key=value settings format. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| s : str | ||
| The setting string to parse. | ||
| dest : dict | ||
| Dictionary to store the parsed setting. | ||
|
|
||
| Returns | ||
| ------- | ||
| bool | ||
| True if parsing succeeded, False otherwise. | ||
| """ | ||
| if ('=' in s and not s.lstrip().startswith(('{"', "[", "{")) and | ||
| not s.startswith('@')): # @ indicates file input | ||
| try: | ||
| setting_name, value = s.split('=', 1) | ||
| dest[setting_name] = value | ||
| return True | ||
| except ValueError: | ||
| pass # Fall back to JSON parsing if split fails | ||
| return False | ||
|
|
||
|
|
||
| def _parse_json_setting(s, result, slot_result, setting_type): | ||
| """ | ||
| Parse JSON format settings. | ||
|
|
||
| Parameters: | ||
| s (str): The input string containing JSON-formatted settings. | ||
| result (dict): A dictionary to store the parsed key-value pairs from the settings. | ||
| slot_result (dict): A dictionary to store slot setting flags for each key. | ||
| setting_type (str): The type of settings being parsed, either "SlotSettings" or "Settings". | ||
|
|
||
| Returns: | ||
| bool: True if parsing was successful, False otherwise. | ||
| """ | ||
| try: | ||
| temp = shell_safe_json_parse(s) | ||
| if isinstance(temp, list): # Accept the output of the "list" command | ||
| for t in temp: | ||
| if 'slotSetting' in t.keys(): | ||
| slot_result[t['name']] = t['slotSetting'] | ||
| elif setting_type == "SlotSettings": | ||
| slot_result[t['name']] = True | ||
| result[t['name']] = t['value'] | ||
| else: | ||
| # Handle JSON objects: setting_type is either "SlotSettings" or "Settings" | ||
| # Different logic needed for slot settings vs regular settings | ||
| if setting_type == "SlotSettings": | ||
| # For slot settings JSON objects, add values to result and mark as slot settings | ||
| result.update(temp) | ||
| for key in temp: | ||
| slot_result[key] = True | ||
| else: | ||
| # For regular settings JSON objects, add values to result only | ||
| result.update(temp) | ||
| return True | ||
| except InvalidArgumentValueError: | ||
| return False | ||
|
|
||
|
|
||
| def _parse_fallback_key_value_setting(s, result): | ||
| """Parse key=value as fallback when JSON parsing fails.""" | ||
| try: | ||
| setting_name, value = s.split('=', 1) | ||
| except ValueError as ex: | ||
| raise InvalidArgumentValueError( | ||
| f"Invalid setting format: '{s}'. Expected 'key=value' format or valid JSON.", | ||
| recommendation="Use 'key=value' format or provide valid JSON like '{\"key\": \"value\"}'." | ||
| ) from ex | ||
| result[setting_name] = value | ||
|
|
||
|
|
||
| def update_app_settings(cmd, resource_group_name, name, settings=None, slot=None, slot_settings=None): | ||
| if not settings and not slot_settings: | ||
| raise MutuallyExclusiveArgumentError('Usage Error: --settings |--slot-settings') | ||
| raise MutuallyExclusiveArgumentError('Please provide either --settings or --slot-settings parameter.') | ||
|
|
||
| settings = settings or [] | ||
| slot_settings = slot_settings or [] | ||
|
|
||
| app_settings = _generic_site_operation(cmd.cli_ctx, resource_group_name, name, | ||
| 'list_application_settings', slot) | ||
| result, slot_result = {}, {} | ||
| # pylint: disable=too-many-nested-blocks | ||
|
|
||
| for src, dest, setting_type in [(settings, result, "Settings"), (slot_settings, slot_result, "SlotSettings")]: | ||
| for s in src: | ||
| # Check if this looks like a simple key=value pair without JSON/dict syntax | ||
| # If so, parse it directly to avoid unnecessary warnings from ast.literal_eval | ||
| if ('=' in s and not s.lstrip().startswith(('{"', "[", "{")) and | ||
| not s.startswith('@')): # @ indicates file input | ||
| try: | ||
| setting_name, value = s.split('=', 1) | ||
| dest[setting_name] = value | ||
| continue | ||
| except ValueError: | ||
| pass # Fall back to JSON parsing if split fails | ||
| # Try simple key=value parsing first | ||
| if _parse_simple_key_value_setting(s, dest): | ||
| continue | ||
|
|
||
| try: | ||
| temp = shell_safe_json_parse(s) | ||
| if isinstance(temp, list): # a bit messy, but we'd like accept the output of the "list" command | ||
| for t in temp: | ||
| if 'slotSetting' in t.keys(): | ||
| slot_result[t['name']] = t['slotSetting'] | ||
| elif setting_type == "SlotSettings": | ||
| slot_result[t['name']] = True | ||
| result[t['name']] = t['value'] | ||
| else: | ||
| dest.update(temp) | ||
| except CLIError: | ||
| setting_name, value = s.split('=', 1) | ||
| dest[setting_name] = value | ||
| result.update(dest) | ||
| # Try JSON parsing | ||
| if _parse_json_setting(s, result, slot_result, setting_type): | ||
| continue | ||
|
|
||
| # Fallback to key=value parsing with error handling | ||
| _parse_fallback_key_value_setting(s, result) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only called if _parse_simple_key_value_setting in line 605 returns false. But then this call will also not succeed, except if there is a problem with slot_result, as this function takes result as a parameter instead of slot_result for a slot setting. |
||
|
|
||
| for setting_name, value in result.items(): | ||
| app_settings.properties[setting_name] = value | ||
| client = web_client_factory(cmd.cli_ctx) | ||
|
|
||
|
|
||
| # TODO: Centauri currently return wrong payload for update appsettings, remove this once backend has the fix. | ||
| if is_centauri_functionapp(cmd, resource_group_name, name): | ||
| update_application_settings_polling(cmd, resource_group_name, name, app_settings, slot, client) | ||
| result = _generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'list_application_settings', slot) | ||
| else: | ||
| result = _generic_settings_operation(cmd.cli_ctx, resource_group_name, name, | ||
| 'update_application_settings', | ||
| app_settings, slot, client) | ||
|
|
||
| # Process slot configurations before updating application settings to ensure proper configuration order. | ||
| app_settings_slot_cfg_names = [] | ||
| if slot_result: | ||
| slot_cfg_names = client.web_apps.list_slot_configuration_names(resource_group_name, name) | ||
|
|
@@ -578,6 +630,15 @@ def update_app_settings(cmd, resource_group_name, name, settings=None, slot=None | |
| app_settings_slot_cfg_names = slot_cfg_names.app_setting_names | ||
| client.web_apps.update_slot_configuration_names(resource_group_name, name, slot_cfg_names) | ||
|
|
||
| # TODO: Centauri currently return wrong payload for update appsettings, remove this once backend has the fix. | ||
| if is_centauri_functionapp(cmd, resource_group_name, name): | ||
| update_application_settings_polling(cmd, resource_group_name, name, app_settings, slot, client) | ||
| result = _generic_site_operation(cmd.cli_ctx, resource_group_name, name, 'list_application_settings', slot) | ||
| else: | ||
| result = _generic_settings_operation(cmd.cli_ctx, resource_group_name, name, | ||
| 'update_application_settings', | ||
| app_settings, slot, client) | ||
|
|
||
| return _build_app_settings_output(result.properties, app_settings_slot_cfg_names, redact=True) | ||
|
|
||
|
|
||
|
|
@@ -597,7 +658,7 @@ def update_application_settings_polling(cmd, resource_group_name, name, app_sett | |
| time.sleep(5) | ||
| r = send_raw_request(cmd.cli_ctx, method='get', url=poll_url) | ||
| else: | ||
| raise CLIError(ex) | ||
| raise AzureResponseError(f"Failed to update application settings: {str(ex)}") from ex | ||
|
|
||
|
|
||
| def add_azure_storage_account(cmd, resource_group_name, name, custom_id, storage_type, account_name, | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function does (almost?) the same thing as _parse_simple_key_value_setting in line 514. It would never succeed if _parse_simple_key_value_setting fails.