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

Merge App Config Provider Beta to Main #38579

Merged
merged 12 commits into from
Nov 18, 2024
Merged
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
# ServiceLabel: %App Configuration Provider

# PRLabel: %App Configuration Provider
/sdk/appconfiguration/azure-appconfiguration-provider/ @mametcal @albertofori @avanigupta @mrm9084
/sdk/appconfiguration/azure-appconfiguration-provider/ @albertofori @avanigupta @mrm9084 @rossgrambo

# ServiceLabel: %Attestation
# PRLabel: %Attestation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
# Release History

## 2.0.0b2 (2024-09-12)
## 2.0.0b4 (Unreleased)

### Features Added

### Breaking Changes

### Bugs Fixed

### Other Changes

## 2.0.0b3 (2024-11-13)

### Breaking Changes

* Allocation Id value changed so other providers can match the value.

## 2.0.0b2 (2024-10-11)

### Feature Added

* Added AllocationId to the feature flag telemetry metadata when the feature flag has telemetry enabled.

### Bugs Fixed

* Fixing ETag to be "ETag" instead of "etag" in feature flag telemetry.
* Fixed a number of cases where snake case was used instead of pascal case for feature flag telemetry.
* etag -> ETag
* feature_flag_reference -> FeatureFlagReference
* feature_flag_id -> FeatureFlagId

## 2.0.0b1 (2024-09-11)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ def load_feature_flags(
loaded_feature_flags = []
# Needs to be removed unknown keyword argument for list_configuration_settings
kwargs.pop("sentinel_keys", None)
endpoint = self._client._impl._config.endpoint # pylint: disable=protected-access
filters_used: Dict[str, bool] = {}
for select in feature_flag_selectors:
feature_flags = self._client.list_configuration_settings(
Expand All @@ -176,6 +177,7 @@ def load_feature_flags(

feature_flag_value = json.loads(feature_flag.value)

self._feature_flag_telemetry(endpoint, feature_flag, feature_flag_value)
self._feature_flag_appconfig_telemetry(feature_flag, filters_used)

loaded_feature_flags.append(feature_flag_value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import hashlib
import base64
from dataclasses import dataclass
from typing import Dict, List
from typing import Dict, List, Mapping, Any
from azure.appconfiguration import ( # type:ignore # pylint:disable=no-name-in-module
FeatureFlagConfigurationSetting,
)
Expand All @@ -20,11 +20,18 @@
PERCENTAGE_FILTER_KEY,
TIME_WINDOW_FILTER_KEY,
TARGETING_FILTER_KEY,
TELEMETRY_KEY,
METADATA_KEY,
ETAG_KEY,
FEATURE_FLAG_REFERENCE_KEY,
FEATURE_FLAG_ID_KEY,
)

FALLBACK_CLIENT_REFRESH_EXPIRED_INTERVAL = 3600 # 1 hour in seconds
MINIMAL_CLIENT_REFRESH_INTERVAL = 30 # 30 seconds

JSON = Mapping[str, Any]


@dataclass
class _ConfigurationClientWrapperBase:
Expand All @@ -36,10 +43,28 @@ def _calculate_feature_id(key, label):
if label and not label.isspace():
basic_value += f"{label}"
feature_flag_id_hash_bytes = hashlib.sha256(basic_value.encode()).digest()
encoded_flag = base64.b64encode(feature_flag_id_hash_bytes)
encoded_flag = encoded_flag.replace(b"+", b"-").replace(b"/", b"_")
encoded_flag = base64.urlsafe_b64encode(feature_flag_id_hash_bytes)
return encoded_flag[: encoded_flag.find(b"=")]

def _feature_flag_telemetry(
self, endpoint: str, feature_flag: FeatureFlagConfigurationSetting, feature_flag_value: Dict
):
if TELEMETRY_KEY in feature_flag_value:
if METADATA_KEY not in feature_flag_value[TELEMETRY_KEY]:
feature_flag_value[TELEMETRY_KEY][METADATA_KEY] = {}
feature_flag_value[TELEMETRY_KEY][METADATA_KEY][ETAG_KEY] = feature_flag.etag

if not endpoint.endswith("/"):
endpoint += "/"
feature_flag_reference = f"{endpoint}kv/{feature_flag.key}"
if feature_flag.label and not feature_flag.label.isspace():
feature_flag_reference += f"?label={feature_flag.label}"
if feature_flag_value[TELEMETRY_KEY].get("enabled"):
feature_flag_value[TELEMETRY_KEY][METADATA_KEY][FEATURE_FLAG_REFERENCE_KEY] = feature_flag_reference
feature_flag_value[TELEMETRY_KEY][METADATA_KEY][FEATURE_FLAG_ID_KEY] = self._calculate_feature_id(
feature_flag.key, feature_flag.label
)

def _feature_flag_appconfig_telemetry(
self, feature_flag: FeatureFlagConfigurationSetting, filters_used: Dict[str, bool]
):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@

TELEMETRY_KEY = "telemetry"
METADATA_KEY = "metadata"
ETAG_KEY = "ETag"

ETAG_KEY = "ETag"
FEATURE_FLAG_REFERENCE_KEY = "FeatureFlagReference"
FEATURE_FLAG_ID_KEY = "FeatureFlagId"

PERCENTAGE_FILTER_NAMES = ["Percentage", "PercentageFilter", "Microsoft.Percentage", "Microsoft.PercentageFilter"]
TIME_WINDOW_FILTER_NAMES = ["TimeWindow", "TimeWindowFilter", "Microsoft.TimeWindow", "Microsoft.TimeWindowFilter"]
TARGETING_FILTER_NAMES = ["Targeting", "TargetingFilter", "Microsoft.Targeting", "Microsoft.TargetingFilter"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
# license information.
# -------------------------------------------------------------------------

VERSION = "2.0.0b2"
VERSION = "2.0.0b4"
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ async def load_feature_flags(
loaded_feature_flags = []
# Needs to be removed unknown keyword argument for list_configuration_settings
kwargs.pop("sentinel_keys", None)
endpoint = self._client._impl._config.endpoint # pylint: disable=protected-access
filters_used: Dict[str, bool] = {}
for select in feature_flag_selectors:
feature_flags = self._client.list_configuration_settings(
Expand All @@ -178,6 +179,7 @@ async def load_feature_flags(

feature_flag_value = json.loads(feature_flag.value)

self._feature_flag_telemetry(endpoint, feature_flag, feature_flag_value)
self._feature_flag_appconfig_telemetry(feature_flag, filters_used)

loaded_feature_flags.append(feature_flag_value)
Expand Down