|
3 | 3 | # Licensed under the MIT License. See License.txt in the project root for
|
4 | 4 | # license information.
|
5 | 5 | # -------------------------------------------------------------------------
|
6 |
| -import json |
7 | 6 | import time
|
8 | 7 | import random
|
9 | 8 | import hashlib
|
10 | 9 | import base64
|
11 | 10 | from dataclasses import dataclass
|
12 |
| -from typing import Dict, List, Optional, Mapping, Any |
| 11 | +from typing import Dict, List, Mapping, Any |
13 | 12 | from azure.appconfiguration import ( # type:ignore # pylint:disable=no-name-in-module
|
14 | 13 | FeatureFlagConfigurationSetting,
|
15 | 14 | )
|
|
26 | 25 | ETAG_KEY,
|
27 | 26 | FEATURE_FLAG_REFERENCE_KEY,
|
28 | 27 | FEATURE_FLAG_ID_KEY,
|
29 |
| - ALLOCATION_ID_KEY, |
30 | 28 | )
|
31 | 29 |
|
32 | 30 | FALLBACK_CLIENT_REFRESH_EXPIRED_INTERVAL = 3600 # 1 hour in seconds
|
|
39 | 37 | class _ConfigurationClientWrapperBase:
|
40 | 38 | endpoint: str
|
41 | 39 |
|
42 |
| - @staticmethod |
43 |
| - def _generate_allocation_id(feature_flag_value: Dict[str, JSON]) -> Optional[str]: |
44 |
| - """ |
45 |
| - Generates an allocation ID for the specified feature. |
46 |
| - seed=123abc\ndefault_when_enabled=Control\npercentiles=0,Control,20;20,Test,100\nvariants=Control,standard;Test,special # pylint:disable=line-too-long |
47 |
| -
|
48 |
| - :param Dict[str, JSON] feature_flag_value: The feature to generate an allocation ID for. |
49 |
| - :rtype: str |
50 |
| - :return: The allocation ID. |
51 |
| - """ |
52 |
| - |
53 |
| - allocation_id = "" |
54 |
| - allocated_variants = [] |
55 |
| - |
56 |
| - allocation: Optional[JSON] = feature_flag_value.get("allocation") |
57 |
| - |
58 |
| - if not allocation: |
59 |
| - return None |
60 |
| - |
61 |
| - # Seed |
62 |
| - allocation_id = f"seed={allocation.get('seed', '')}" |
63 |
| - |
64 |
| - # DefaultWhenEnabled |
65 |
| - if "default_when_enabled" in allocation: |
66 |
| - allocated_variants.append(allocation.get("default_when_enabled")) |
67 |
| - |
68 |
| - allocation_id += f"\ndefault_when_enabled={allocation.get('default_when_enabled', '')}" |
69 |
| - |
70 |
| - # Percentile |
71 |
| - allocation_id += "\npercentiles=" |
72 |
| - |
73 |
| - percentile = allocation.get("percentile") |
74 |
| - |
75 |
| - if percentile: |
76 |
| - percentile_allocations = sorted( |
77 |
| - (x for x in percentile if x.get("from") != x.get("to")), |
78 |
| - key=lambda x: x.get("from"), |
79 |
| - ) |
80 |
| - |
81 |
| - for percentile_allocation in percentile_allocations: |
82 |
| - if "variant" in percentile_allocation: |
83 |
| - allocated_variants.append(percentile_allocation.get("variant")) |
84 |
| - |
85 |
| - allocation_id += ";".join( |
86 |
| - f"{pa.get('from')}," f"{base64.b64encode(pa.get('variant').encode()).decode()}," f"{pa.get('to')}" |
87 |
| - for pa in percentile_allocations |
88 |
| - ) |
89 |
| - |
90 |
| - if not allocated_variants and (not allocation or not allocation.get("seed")): |
91 |
| - return None |
92 |
| - |
93 |
| - # Variants |
94 |
| - allocation_id += "\nvariants=" |
95 |
| - |
96 |
| - variants_value = feature_flag_value.get("variants") |
97 |
| - if variants_value and (isinstance(variants_value, list) or all(isinstance(v, dict) for v in variants_value)): |
98 |
| - if ( |
99 |
| - allocated_variants |
100 |
| - and isinstance(variants_value, list) |
101 |
| - and all(isinstance(v, dict) for v in variants_value) |
102 |
| - ): |
103 |
| - sorted_variants: List[Dict[str, Any]] = sorted( |
104 |
| - (v for v in variants_value if v.get("name") in allocated_variants), |
105 |
| - key=lambda v: v.get("name"), |
106 |
| - ) |
107 |
| - |
108 |
| - for v in sorted_variants: |
109 |
| - allocation_id += f"{base64.b64encode(v.get('name', '').encode()).decode()}," |
110 |
| - if "configuration_value" in v: |
111 |
| - allocation_id += ( |
112 |
| - f"{json.dumps(v.get('configuration_value', ''), separators=(',', ':'), sort_keys=True)}" |
113 |
| - ) |
114 |
| - allocation_id += ";" |
115 |
| - if sorted_variants: |
116 |
| - allocation_id = allocation_id[:-1] |
117 |
| - |
118 |
| - # Create a sha256 hash of the allocation_id |
119 |
| - hash_object = hashlib.sha256(allocation_id.encode()) |
120 |
| - hash_digest = hash_object.digest() |
121 |
| - |
122 |
| - # Encode the first 15 bytes in base64 url |
123 |
| - allocation_id_hash = base64.urlsafe_b64encode(hash_digest[:15]).decode() |
124 |
| - return allocation_id_hash |
125 |
| - |
126 | 40 | @staticmethod
|
127 | 41 | def _calculate_feature_id(key, label):
|
128 | 42 | basic_value = f"{key}\n"
|
@@ -150,9 +64,6 @@ def _feature_flag_telemetry(
|
150 | 64 | feature_flag_value[TELEMETRY_KEY][METADATA_KEY][FEATURE_FLAG_ID_KEY] = self._calculate_feature_id(
|
151 | 65 | feature_flag.key, feature_flag.label
|
152 | 66 | )
|
153 |
| - allocation_id = self._generate_allocation_id(feature_flag_value) |
154 |
| - if allocation_id: |
155 |
| - feature_flag_value[TELEMETRY_KEY][METADATA_KEY][ALLOCATION_ID_KEY] = allocation_id |
156 | 67 |
|
157 | 68 | def _feature_flag_appconfig_telemetry(
|
158 | 69 | self, feature_flag: FeatureFlagConfigurationSetting, filters_used: Dict[str, bool]
|
|
0 commit comments