qontract-reconcile 0.10.1rc1025__py3-none-any.whl → 0.10.1rc1027__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc1025
3
+ Version: 0.10.1rc1027
4
4
  Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
5
5
  Home-page: https://github.com/app-sre/qontract-reconcile
6
6
  Author: Red Hat App-SRE Team
@@ -181,7 +181,7 @@ reconcile/cna/assets/asset_factory.py,sha256=7T7X_J6xIsoGETqBRI45_EyIKEdQcnRPt_G
181
181
  reconcile/cna/assets/null.py,sha256=85mVh97atCoC0aLuX47poTZiyOthmziJeBsUw0c924w,1658
182
182
  reconcile/dynatrace_token_provider/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
183
183
  reconcile/dynatrace_token_provider/dependencies.py,sha256=41q05A4C_eS3E8-MR4veeMxtQNsPoGdxmEa3d-OKxq4,2814
184
- reconcile/dynatrace_token_provider/integration.py,sha256=QY-k5vsbBOm80yW_RB6G2JZD5NY21zCyqHigos7GjRM,20876
184
+ reconcile/dynatrace_token_provider/integration.py,sha256=jOpj2qtkI95b_Ih0IH3cYV5G63RBuxhG6kX4RADBWeg,23003
185
185
  reconcile/dynatrace_token_provider/metrics.py,sha256=xiKkl8fTEBQaXJelGCPNTZhHAWdO1M3pCXNr_Tei63c,1285
186
186
  reconcile/dynatrace_token_provider/model.py,sha256=gkpqo5rRRueBXnIMjp4EEHqBUBuU65TRI8zpdb8GJ0A,241
187
187
  reconcile/dynatrace_token_provider/ocm.py,sha256=iHMsgbsLs-dlrB9UXmWNDF7E4UDe49JOsLa9rnowKfo,4282
@@ -781,7 +781,7 @@ reconcile/utils/mr/labels.py,sha256=9QRTRjZAtq45zELd9SwavaraczMjwjn5no3RK1YxFTg,
781
781
  reconcile/utils/mr/notificator.py,sha256=cp80wFzu_ZzrJPye7L1pI0H6JRGb7hOGuNxJYUq4Yr8,2967
782
782
  reconcile/utils/mr/ocm_update_recommended_version.py,sha256=p_aVP0TGrlKk9WBwgQnYWqUDsED_Hg6G5Bqj0UvtRwA,1536
783
783
  reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py,sha256=ojnIjw-8vRnmCCxOGBOEgPZLH4nC1hcuef74LWw2Rpk,3004
784
- reconcile/utils/mr/promote_qontract.py,sha256=4rUMZJGor2AE84BMqnekSbmFyu3ZOUfkxwel8Hnc3-M,5948
784
+ reconcile/utils/mr/promote_qontract.py,sha256=3o_Lpn3gQc8HP3kSJRB1d7TvaDoIAKWLap5bhagQRaM,5945
785
785
  reconcile/utils/mr/user_maintenance.py,sha256=cHPBn8zrReWLHalyk-EFdkFJe9zjVjRoZhT4t2zZfGE,3956
786
786
  reconcile/utils/ocm/__init__.py,sha256=xv7CJp7K9LCQfa4gL_W0MMCOD1P4qOy8t5aZj1xXNUE,808
787
787
  reconcile/utils/ocm/addons.py,sha256=_LDdJ-gapM3s5exKlIUt-MlXZTAUoHezbYBU0QmvfWQ,7335
@@ -865,8 +865,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
865
865
  tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
866
866
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
867
867
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
868
- qontract_reconcile-0.10.1rc1025.dist-info/METADATA,sha256=dUsRqkEgrR_aSPJqnY-4retmHRgWmF0hqlNW9n8MXQA,2213
869
- qontract_reconcile-0.10.1rc1025.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
870
- qontract_reconcile-0.10.1rc1025.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
871
- qontract_reconcile-0.10.1rc1025.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
872
- qontract_reconcile-0.10.1rc1025.dist-info/RECORD,,
868
+ qontract_reconcile-0.10.1rc1027.dist-info/METADATA,sha256=NZ2RmjjS7vqLah46hp_j6Gny8RHEeRBbHu9EMHd49dc,2213
869
+ qontract_reconcile-0.10.1rc1027.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
870
+ qontract_reconcile-0.10.1rc1027.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
871
+ qontract_reconcile-0.10.1rc1027.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
872
+ qontract_reconcile-0.10.1rc1027.dist-info/RECORD,,
@@ -1,6 +1,7 @@
1
1
  import base64
2
+ import hashlib
2
3
  import logging
3
- from collections.abc import Iterable, Mapping
4
+ from collections.abc import Iterable, Mapping, MutableMapping
4
5
  from datetime import timedelta
5
6
  from typing import Any
6
7
 
@@ -140,7 +141,7 @@ class DynatraceTokenProviderIntegration(
140
141
  if tenant_id not in existing_dtp_tokens:
141
142
  existing_dtp_tokens[tenant_id] = (
142
143
  dt_client.get_token_ids_map_for_name_prefix(
143
- prefix="dtp-"
144
+ prefix="dtp"
144
145
  )
145
146
  )
146
147
 
@@ -172,7 +173,7 @@ class DynatraceTokenProviderIntegration(
172
173
  cluster: Cluster,
173
174
  dt_client: DynatraceClient,
174
175
  ocm_client: OCMClient,
175
- existing_dtp_tokens: Mapping[str, str],
176
+ existing_dtp_tokens: MutableMapping[str, str],
176
177
  tenant_id: str,
177
178
  token_spec: DynatraceTokenProviderTokenSpecV1,
178
179
  ) -> None:
@@ -276,12 +277,52 @@ class DynatraceTokenProviderIntegration(
276
277
  f"Patched {token_spec.name=} for {SYNCSET_AND_MANIFEST_ID} in {cluster.external_id=}."
277
278
  )
278
279
 
280
+ def scopes_hash(self, scopes: Iterable[str], length: int) -> str:
281
+ m = hashlib.sha256()
282
+ msg = ",".join(sorted(scopes))
283
+ m.update(msg.encode("utf-8"))
284
+ return m.hexdigest()[:length]
285
+
286
+ def dynatrace_token_name(self, spec: DynatraceAPITokenV1, cluster_uuid: str) -> str:
287
+ scopes_hash = self.scopes_hash(scopes=spec.scopes, length=12)
288
+ # We have a limit of 100 chars
289
+ # cluster_uuid = 36 chars
290
+ # scopes_hash = 12 chars
291
+ # prefix + separators = 6 chars
292
+ return f"dtp_{spec.name[:46]}_{cluster_uuid}_{scopes_hash}"
293
+
294
+ def sync_token_in_dynatrace(
295
+ self,
296
+ token_id: str,
297
+ spec: DynatraceAPITokenV1,
298
+ cluster_uuid: str,
299
+ dt_client: DynatraceClient,
300
+ token_name_in_dt_api: str,
301
+ dry_run: bool,
302
+ ) -> None:
303
+ """
304
+ We ensure that the given token is properly configured in Dynatrace
305
+ according to the given spec.
306
+
307
+ A list query on the tokens does not return each tokens configuration.
308
+ We encode the token configuration in the token name to save API calls.
309
+ """
310
+ expected_name = self.dynatrace_token_name(spec=spec, cluster_uuid=cluster_uuid)
311
+ if token_name_in_dt_api != expected_name:
312
+ logging.info(
313
+ f"{token_name_in_dt_api=} != {expected_name=}. Sync dynatrace token {token_id=} with {spec=} for {cluster_uuid=}."
314
+ )
315
+ if not dry_run:
316
+ dt_client.update_token(
317
+ token_id=token_id, name=expected_name, scopes=spec.scopes
318
+ )
319
+
279
320
  def generate_desired(
280
321
  self,
281
322
  dry_run: bool,
282
323
  current_k8s_secrets: Iterable[K8sSecret],
283
324
  desired_spec: DynatraceTokenProviderTokenSpecV1,
284
- existing_dtp_tokens: Mapping[str, str],
325
+ existing_dtp_tokens: MutableMapping[str, str],
285
326
  dt_client: DynatraceClient,
286
327
  cluster_uuid: str,
287
328
  ) -> tuple[bool, Iterable[K8sSecret]]:
@@ -301,15 +342,24 @@ class DynatraceTokenProviderIntegration(
301
342
  else {}
302
343
  )
303
344
  for desired_token in secret.tokens:
304
- new_token = current_tokens_by_name.get(desired_token.name)
305
- if not new_token or new_token.id not in existing_dtp_tokens:
345
+ cur_token = current_tokens_by_name.get(desired_token.name)
346
+ if not cur_token or cur_token.id not in existing_dtp_tokens:
306
347
  has_diff = True
307
348
  if not dry_run:
308
- new_token = self.create_dynatrace_token(
349
+ cur_token = self.create_dynatrace_token(
309
350
  dt_client, cluster_uuid, desired_token
310
351
  )
311
- if new_token:
312
- desired_tokens.append(new_token)
352
+ existing_dtp_tokens[cur_token.id] = cur_token.name
353
+ if cur_token:
354
+ self.sync_token_in_dynatrace(
355
+ token_id=cur_token.id,
356
+ spec=desired_token,
357
+ cluster_uuid=cluster_uuid,
358
+ dt_client=dt_client,
359
+ dry_run=dry_run,
360
+ token_name_in_dt_api=existing_dtp_tokens[cur_token.id],
361
+ )
362
+ desired_tokens.append(cur_token)
313
363
  desired.append(
314
364
  K8sSecret(
315
365
  secret_name=secret.name,
@@ -323,7 +373,7 @@ class DynatraceTokenProviderIntegration(
323
373
  def create_dynatrace_token(
324
374
  self, dt_client: DynatraceClient, cluster_uuid: str, token: DynatraceAPITokenV1
325
375
  ) -> DynatraceAPIToken:
326
- token_name = f"dtp-{token.name}-{cluster_uuid}"
376
+ token_name = self.dynatrace_token_name(spec=token, cluster_uuid=cluster_uuid)
327
377
  new_token = dt_client.create_api_token(
328
378
  name=token_name,
329
379
  scopes=token.scopes,
@@ -169,5 +169,5 @@ class PromoteQontractReconcileCommercial(MergeRequestBase):
169
169
  gitlab_cli=gitlab_cli,
170
170
  path="data/pipelines/tekton-provider-global-defaults.yaml",
171
171
  search_text="$.taskTemplates[?(@.name == 'openshift-saas-deploy')].variables.qontract_reconcile_image_tag",
172
- replace_text=self.commit_sha,
172
+ replace_text=self.version,
173
173
  )