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

[AppConfig] appconfig feature list/show and appconfig kv import/export: Support microsoft feature management schema #30376

Merged
merged 49 commits into from
Jan 22, 2025

Conversation

ChristineWanjau
Copy link
Contributor

@ChristineWanjau ChristineWanjau commented Nov 18, 2024

Related command

  • appconfig kv import
  • appconfig kv export
  • appconfig feature show
  • appconfig feature list

Description
This PR updates the import and export of features to support new feature management schema.
The currently supported schema is the Feature Managment Dotnet Schema.

This PR also adds the use of a new environment variable called [AZURE_APPCONFIG_FM_COMPATIBILE] when exporting to a file for backward compatibility for users. This ensures our systems can process data in both old and new formats, avoiding disruptions for users of the previous version and maintaining functionality during the transition.

Default compatibility mode to true.
If compatibility mode true:

  1. Export classic feature flags using the legacy schema (Dotnet schema currently being used)
  2. Export variants feature flags using the new feature management schema
  3. If both variants and classic feature flags exist in the export, have both schemas exist in the file:
    Example,
    {
    "FeatureManagement":{
    // old schema
    }
    "feature_management":{
    "feature_flags": [
    // new schema
    ]
    }
    }
    If compatibility mode is false:
  4. All feature flags will be exported using the new feature management schema
    "feature_management":{
    "feature_flags": [
    // new schema
    ]
    }

Link to design doc

Testing Guide

History Notes

[App Config] az appconfig kv import: Support microsoft feature management schema
[App Config] az appconfig kv export: Support microsoft feature management schema
[App Config] az appconfig kv export: Introduce a new environment variable called AZURE_APPCONFIG_FM_COMPATIBILE when exporting to a file for backward compatibility for users
[App Config] az appconfig feature show: Support microsoft feature management schema
[App Config] az appconfig feature list: Support microsoft feature management schema


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

Copy link

azure-client-tools-bot-prd bot commented Nov 18, 2024

️✔️AzureCLI-FullTest
️✔️acr
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️acs
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️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
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️cosmosdb
️✔️latest
️✔️3.12
️✔️3.9
️✔️databoxedge
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️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
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️keyvault
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️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
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️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
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️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
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️synapse
️✔️latest
️✔️3.12
️✔️3.9
️✔️telemetry
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9
️✔️util
️✔️latest
️✔️3.12
️✔️3.9
️✔️vm
️✔️2018-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2019-03-01-hybrid
️✔️3.12
️✔️3.9
️✔️2020-09-01-hybrid
️✔️3.12
️✔️3.9
️✔️latest
️✔️3.12
️✔️3.9

Copy link

azure-client-tools-bot-prd bot commented Nov 18, 2024

️✔️AzureCLI-BreakingChangeTest
️✔️Non Breaking Changes

@yonzhan
Copy link
Collaborator

yonzhan commented Nov 18, 2024

AppConfig

Comment on lines +926 to +927
elif feature_flag_version == FeatureFlagVersion.V1:
feature_flag_dict[FeatureFlagConstants.CONDITIONS] = default_conditions
Copy link
Member

Choose a reason for hiding this comment

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

this looks odd. which if statement is this elif corresponding to?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It corresponds to the first if checking if conditions are None. If None and Feature Flag is version 1, we set the conditions to the default conditions.


# Backend returns conditions: {client_filters: None} for flags with no conditions.
# No need to write empty conditions to key-values.
if conditions.get(FeatureFlagConstants.CLIENT_FILTERS, None) is None and conditions.get(FeatureFlagConstants.REQUIREMENT_TYPE, None) is None:
Copy link
Member

Choose a reason for hiding this comment

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

you could simplify this:

if client_filters or requirement_type:
    feature_flag_dict[FeatureFlagConstants.CONDITIONS] = conditions
elif feature_flag_version == FeatureFlagVersion.V1:
     feature_flag_dict[FeatureFlagConstants.CONDITIONS] = default_conditions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. Updated

@@ -939,6 +989,25 @@ def is_feature_flag(kv):
return False


def convert_boolean_value(enabled, feature_name):
Copy link
Member

Choose a reason for hiding this comment

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

We can make this method generic for converting any boolean to string.
def convert_string_to_bool(value, feature_name)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, this has been updated

"""
enabled = None
telemetry_enabled = feature_telemetry_dict.get(FeatureFlagConstants.ENABLED, None)
if telemetry_enabled is not None:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if telemetry_enabled is not None:
if telemetry_enabled:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

telemetry_enabled could be false and we don't want to remove it if its explictly defined as False

FeatureFlagConstants.TELEMETRY,
FeatureFlagConstants.DISPLAY_NAME
}
if valid_fields.union(feature_flag_dict.keys()) == valid_fields:
Copy link
Member

Choose a reason for hiding this comment

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

Should this be !=?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, nice catch! Updated

featurefilterdict = {}

for key, value in conditions_dict.items():
if key == FeatureFlagConstants.CLIENT_FILTERS:
featurefilterdict[key] = [feature_filter.__dict__ for feature_filter in value]
if value is not None:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if value is not None:
if value:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was wondering a case where we have conditions: {client_filters: [] } I was thinking we would want to retain this, if we just check it as suggested it might be removed.

Comment on lines 873 to 874
description = feature_flag_dict.get(FeatureFlagConstants.DESCRIPTION, "") # assign empty string as default
feature_flag_dict[FeatureFlagConstants.DESCRIPTION] = description
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
description = feature_flag_dict.get(FeatureFlagConstants.DESCRIPTION, "") # assign empty string as default
feature_flag_dict[FeatureFlagConstants.DESCRIPTION] = description
feature_flag_dict[FeatureFlagConstants.DESCRIPTION] = feature_flag_dict.get(FeatureFlagConstants.DESCRIPTION, "") # assign empty string as default

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated

Comment on lines 936 to 937
variant_list = []
if variants:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
variant_list = []
if variants:
if variants:
variant_list = []

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated

if variants:
for variant in variants:
feature_variant = FeatureVariant.convert_from_dict(variant)
if feature_variant:
Copy link
Member

Choose a reason for hiding this comment

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

Is there a condition under which convert_from_dict can retun None?
Should we rather check if variant is not None first before trying to convert?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, we should. This has been updated

Comment on lines +215 to +218
for keywordset in FeatureManagementReservedKeywords.ALL:
if keywordset.feature_management == dotnet_schema_keyword:
feature_management_keywords = keywordset
break
Copy link
Member

@albertofori albertofori Jan 9, 2025

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think there is a need to do that since the keywords are already defined in the keywordset.

@ChristineWanjau
Copy link
Contributor Author

Hello @zhoxing-ms this PR is ready to be merged.

@ChristineWanjau ChristineWanjau changed the title [AppConfig] appconfig feature list/show and appconfig kv import/export: Support new microsoft feature management schema [AppConfig] appconfig feature list/show and appconfig kv import/export: Support microsoft feature management schema Jan 17, 2025
@yanzhudd
Copy link
Contributor

Since there are multiple changes in this PR, it is better to seperate the changelog into small ones and list in the History Notes section, e.g.,
[App Config] az appconfig kv import: Support microsoft feature management schema
...

@yanzhudd
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

yanzhudd
yanzhudd previously approved these changes Jan 22, 2025
@yanzhudd
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@yanzhudd yanzhudd merged commit ceeff1e into Azure:dev Jan 22, 2025
53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants