qontract-reconcile 0.10.1rc996__py3-none-any.whl → 0.10.1rc998__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.1rc996
3
+ Version: 0.10.1rc998
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
@@ -75,7 +75,7 @@ reconcile/openshift_resources.py,sha256=I2nO_C37mG3rfyGrd4cGwN3mVseVGuTAHAyhFzLy
75
75
  reconcile/openshift_resources_base.py,sha256=Seh4T8oA_JO-g0Z5TODDtL5cyRj-o7bmk6-eOmDAL4Q,40751
76
76
  reconcile/openshift_rolebindings.py,sha256=9mlJ2FjWUoH-rsjtasreA_hV-K5Z_YR00qR_RR60OZM,6555
77
77
  reconcile/openshift_routes.py,sha256=fXvuPSjcjVw1X3j2EQvUAdbOepmIFdKk-M3qP8QzPiw,1075
78
- reconcile/openshift_saas_deploy.py,sha256=b6Og_SlQ-ptYvTBNycK4Z5yP9bbvMXiY39R90TfUfZU,12728
78
+ reconcile/openshift_saas_deploy.py,sha256=UZlm29JujJVS3MzSm6uehlC3y-jZxl6WVwMeKRdN11U,12773
79
79
  reconcile/openshift_saas_deploy_change_tester.py,sha256=FfXrx_JloAlWeJVsJLIQPqFQ7OoBkaB2TgJJXlNZNCM,8796
80
80
  reconcile/openshift_saas_deploy_trigger_base.py,sha256=m7aqYEZUM-vr3EBw-hIbz1rHpXZNxs_BAJv3ndfvnAQ,14039
81
81
  reconcile/openshift_saas_deploy_trigger_cleaner.py,sha256=roLyVAVntaQptKaZbnN1LyLvCA8fyvqELfjU6M8xfeY,3511
@@ -194,7 +194,7 @@ reconcile/external_resources/meta.py,sha256=cMT9OsKcUY26qwEjlQ02EkorvOBNqWj0JVMw
194
194
  reconcile/external_resources/metrics.py,sha256=m2TIOao2N7pD6k45driFbBGVCC_N7ai44m-lLPfa5qk,454
195
195
  reconcile/external_resources/model.py,sha256=oXxJkjhV53lwwAuxUCBrjJ8aCJmQdgcKWv68ugJPK4k,7229
196
196
  reconcile/external_resources/reconciler.py,sha256=E50X_lnOD0OWYXMzyZld1P6dCFJFYjHGyICWff9bxlc,9323
197
- reconcile/external_resources/secrets_sync.py,sha256=WeoUANltYOjzr_Pn_pZ1ormGof9yRy2DiSB7LoPAQqM,15076
197
+ reconcile/external_resources/secrets_sync.py,sha256=6n0oDPLjd9Ql0lf6zsr1AZw8A6EEe3yCzl20XodtgkE,16229
198
198
  reconcile/external_resources/state.py,sha256=bWq51xPK4-BHVXWsRu6Y-vn69yg9Dse4x1RNNF7qw84,9614
199
199
  reconcile/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
200
200
  reconcile/glitchtip/integration.py,sha256=XtewM9nfTPLnPSpYebP50GrveYOnhTvKNq3seSvL6u8,8343
@@ -261,7 +261,7 @@ reconcile/gql_definitions/common/pgp_reencryption_settings.py,sha256=NPLmO6J-zSu
261
261
  reconcile/gql_definitions/common/pipeline_providers.py,sha256=JJgmmghqLIwjKOdcWYHPnf4PDgAq4GF7046i0ozrqgI,9127
262
262
  reconcile/gql_definitions/common/quay_instances.py,sha256=toBkdYYVTmEafezAHZKgaW-mQ29xEW6jeronzsAlNyI,1786
263
263
  reconcile/gql_definitions/common/reserved_networks.py,sha256=yP9qSQCaSQcva-ZgTnZp09qH27ur5_qK080ToIs04MY,2560
264
- reconcile/gql_definitions/common/saas_files.py,sha256=O57zDNuEfW3MKWdqEjhHNIsvHmZdrQ9fn1TAeAcLivk,16594
264
+ reconcile/gql_definitions/common/saas_files.py,sha256=JZdFKBygaZVxGwBUYMki9EbnsGdmfmxuAreMZ3dchwo,16702
265
265
  reconcile/gql_definitions/common/saas_target_namespaces.py,sha256=4VYP2VbwY8WVwtSFk2-jsUNhSmRD3X4FWKxetOKvmd0,2835
266
266
  reconcile/gql_definitions/common/saasherder_settings.py,sha256=nqQLcMwYxLseqq0BEcVvmrpIj2eQq0h8XDSpLN6GGCw,1793
267
267
  reconcile/gql_definitions/common/slack_workspaces.py,sha256=2o0kgi4QiaRuNmZJnc_By4F6NsKIdRaXkrufRQw7Nok,1753
@@ -618,7 +618,7 @@ reconcile/typed_queries/pagerduty_instances.py,sha256=zxCNxMak4iikryePaRi71lTADV
618
618
  reconcile/typed_queries/quay.py,sha256=OvkSDDbS3o4a4W5MqVxTAVmo47p5XegeoEVNiuqsevg,242
619
619
  reconcile/typed_queries/repos.py,sha256=8A93dKDt6igT4ClqMjt7YUTsoP4qh1Wnm0W3xsMgj48,824
620
620
  reconcile/typed_queries/reserved_networks.py,sha256=-f_CIrTn8u-dotj5VKFlAcD7TX1CSSuR7Ko2zC8OKEM,358
621
- reconcile/typed_queries/saas_files.py,sha256=IgXwDR3gfArCdmpPEEBXYDO7x-M_pwcEuKK-VbL2BEM,13931
621
+ reconcile/typed_queries/saas_files.py,sha256=lPJNh5F2ThJUjW2zvsCKPLm2DVNBnbHFbzWByqTg2uM,14012
622
622
  reconcile/typed_queries/slack.py,sha256=r30lspctHloyygPn8_DVybxPwUWwiBpvBRRXiTVcQYk,251
623
623
  reconcile/typed_queries/slo_documents.py,sha256=l7H6Uq85EcvvWUgmi5c1YHeJGk60KN-TBmi8d0w-XyU,375
624
624
  reconcile/typed_queries/smtp.py,sha256=aSLglYa5bHKmlGwKkxq2RZqyMWuAf0a4S_mOuhDa084,542
@@ -803,7 +803,7 @@ reconcile/utils/runtime/sharding.py,sha256=r0ieUtNed7NvknSw6qQrCkKpVXE1shuHGnfFc
803
803
  reconcile/utils/saasherder/__init__.py,sha256=J3MBZBFa5YmhqYm08QsjBXz8mFcVOCiOCkyIcw41t7E,343
804
804
  reconcile/utils/saasherder/interfaces.py,sha256=C2wrw34OXypshVocAsPrVZsSHptgw4g9u7Haa2wulZQ,9087
805
805
  reconcile/utils/saasherder/models.py,sha256=z8ln03zi2a8cu716NcNUDHp8Dv1VcVbhqdWVxCl7x9A,10148
806
- reconcile/utils/saasherder/saasherder.py,sha256=sC48LMtbKW2Mhyql2VwTMEYHugCXI9imdz8yeYlq0dk,84729
806
+ reconcile/utils/saasherder/saasherder.py,sha256=8yKSNuwLVJaJnOxGOHjhFaRqEmEbJxKqBj1-phI618o,84863
807
807
  reconcile/utils/terraform/__init__.py,sha256=zNbiyTWo35AT1sFTElL2j_AA0jJ_yWE_bfFn-nD2xik,250
808
808
  reconcile/utils/terraform/config.py,sha256=5UVrd563TMcvi4ooa5JvWVDW1I3bIWg484u79evfV_8,164
809
809
  reconcile/utils/terraform/config_client.py,sha256=gRL1rQ0AqvShei_rcGqC3HDYGskOFKE1nPrJyJE9yno,4676
@@ -854,8 +854,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
854
854
  tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
855
855
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
856
856
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
857
- qontract_reconcile-0.10.1rc996.dist-info/METADATA,sha256=1yk8ORxJ5XgceH637jz-GGaURn1NIRcEEF228Yd0_UM,2262
858
- qontract_reconcile-0.10.1rc996.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
859
- qontract_reconcile-0.10.1rc996.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
860
- qontract_reconcile-0.10.1rc996.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
861
- qontract_reconcile-0.10.1rc996.dist-info/RECORD,,
857
+ qontract_reconcile-0.10.1rc998.dist-info/METADATA,sha256=C-FKJi66DUTRsEPvxIam7tbqEn2MiaX4Of5mxG-eYhA,2262
858
+ qontract_reconcile-0.10.1rc998.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
859
+ qontract_reconcile-0.10.1rc998.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
860
+ qontract_reconcile-0.10.1rc998.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
861
+ qontract_reconcile-0.10.1rc998.dist-info/RECORD,,
@@ -95,6 +95,43 @@ class SecretHelper:
95
95
  return three_way_diff_using_hash(cmp_current, cmp_desired)
96
96
 
97
97
 
98
+ class OutputSecretsFormatter:
99
+ """Class to format Module output keys/values into suitable values for K8s Secrets. It currently implements the same
100
+ behavior as Terraform-Resources."""
101
+
102
+ def __init__(self, secret_reader: SecretReaderBase) -> None:
103
+ self.secret_reader = secret_reader
104
+
105
+ def _key_must_be_populated(self, key: str) -> bool:
106
+ "Only keys containing '__' must be populated to Secrets"
107
+ return "__" in key
108
+
109
+ def _format_key(self, key: str) -> str:
110
+ if "__" not in key:
111
+ return key
112
+ k_split = key.split("__")
113
+ output_key = k_split[1]
114
+ if output_key.startswith("db"):
115
+ output_key = output_key.replace("db_", "db.")
116
+ return output_key
117
+
118
+ def _format_value(self, value: str) -> str:
119
+ decoded_value = base64.b64decode(value).decode("utf-8")
120
+ if decoded_value.startswith("__vault__:"):
121
+ _secret_ref = json.loads(decoded_value.replace("__vault__:", ""))
122
+ secret_ref = VaultSecret(**_secret_ref)
123
+ return self.secret_reader.read_secret(secret_ref)
124
+ else:
125
+ return decoded_value
126
+
127
+ def format(self, data: Mapping[str, str]) -> dict[str, str]:
128
+ return {
129
+ self._format_key(key): self._format_value(value)
130
+ for key, value in data.items()
131
+ if self._key_must_be_populated(key)
132
+ }
133
+
134
+
98
135
  class SecretsReconciler:
99
136
  def __init__(
100
137
  self,
@@ -281,6 +318,7 @@ class InClusterSecretsReconciler(SecretsReconciler):
281
318
  cluster: str,
282
319
  namespace: str,
283
320
  oc: OCCli,
321
+ output_secrets_formatter: OutputSecretsFormatter,
284
322
  thread_pool_size: int,
285
323
  dry_run: bool,
286
324
  ):
@@ -292,6 +330,7 @@ class InClusterSecretsReconciler(SecretsReconciler):
292
330
  self.source_secrets: list[str] = []
293
331
  self.vault_client = vault_client
294
332
  self.vault_path = vault_path
333
+ self.output_secrets_formatter = output_secrets_formatter
295
334
 
296
335
  def _get_spec_hash(self, spec: ExternalResourceSpec) -> str:
297
336
  secret_key = f"{spec.provision_provider}-{spec.provisioner_name}-{spec.provider}-{spec.identifier}"
@@ -313,21 +352,10 @@ class InClusterSecretsReconciler(SecretsReconciler):
313
352
  for secret in secrets:
314
353
  secret_name = secret["metadata"]["name"]
315
354
  spec = secrets_map[secret_name]
316
- data = dict[str, str]()
317
- for k, v in secret["data"].items():
318
- decoded = base64.b64decode(v).decode("utf-8")
319
-
320
- if decoded.startswith("__vault__:"):
321
- _secret_ref = json.loads(decoded.replace("__vault__:", ""))
322
- secret_ref = VaultSecret(**_secret_ref)
323
- data[k] = self.secrets_reader.read_secret(secret_ref)
324
- else:
325
- data[k] = decoded
326
-
355
+ spec.secret = self.output_secrets_formatter.format(secret["data"])
327
356
  spec.metadata[SECRET_UPDATED_AT] = datetime.now(UTC).strftime(
328
357
  SECRET_UPDATED_AT_TIMEFORMAT
329
358
  )
330
- spec.secret = data
331
359
 
332
360
  def _delete_source_secret(self, spec: ExternalResourceSpec) -> None:
333
361
  secret_name = self._get_spec_outputs_secret_name(spec)
@@ -396,6 +424,7 @@ def build_incluster_secrets_reconciler(
396
424
  vault_path=vault_path,
397
425
  vault_client=VaultClient(),
398
426
  secrets_reader=secrets_reader,
427
+ output_secrets_formatter=OutputSecretsFormatter(secrets_reader),
399
428
  thread_pool_size=thread_pool_size,
400
429
  dry_run=dry_run,
401
430
  )
@@ -233,6 +233,7 @@ query SaasFiles {
233
233
  }
234
234
  }
235
235
  validateTargetsInApp
236
+ validatePlannedData
236
237
  resourceTemplates {
237
238
  name
238
239
  url
@@ -560,6 +561,7 @@ class SaasFileV2(ConfiguredBaseModel):
560
561
  parameters: Optional[Json] = Field(..., alias="parameters")
561
562
  secret_parameters: Optional[list[SaasSecretParametersV1]] = Field(..., alias="secretParameters")
562
563
  validate_targets_in_app: Optional[bool] = Field(..., alias="validateTargetsInApp")
564
+ validate_planned_data: Optional[bool] = Field(..., alias="validatePlannedData")
563
565
  resource_templates: list[SaasResourceTemplateV2] = Field(..., alias="resourceTemplates")
564
566
  self_service_roles: Optional[list[SaasFileV2_RoleV1]] = Field(..., alias="selfServiceRoles")
565
567
 
@@ -238,7 +238,8 @@ def run(
238
238
 
239
239
  # validate that the deployment will succeed
240
240
  # to the best of our ability to predict
241
- ob.validate_planned_data(ri, oc_map)
241
+ if saasherder.validate_planned_data:
242
+ ob.validate_planned_data(ri, oc_map)
242
243
 
243
244
  # if saas_file_name is defined, the integration
244
245
  # is being called from multiple running instances
@@ -126,6 +126,7 @@ class SaasFile(ConfiguredBaseModel):
126
126
  ..., alias="secretParameters"
127
127
  )
128
128
  validate_targets_in_app: bool | None = Field(..., alias="validateTargetsInApp")
129
+ validate_planned_data: bool | None = Field(..., alias="validatePlannedData")
129
130
  managed_resource_names: list[ManagedResourceNamesV1] | None = Field(
130
131
  ..., alias="managedResourceNames"
131
132
  )
@@ -158,6 +158,9 @@ class SaasHerder: # pylint: disable=too-many-public-methods
158
158
  self.compare = self._get_saas_file_feature_enabled("compare", default=True)
159
159
  self.publish_job_logs = self._get_saas_file_feature_enabled("publish_job_logs")
160
160
  self.cluster_admin = self._get_saas_file_feature_enabled("cluster_admin")
161
+ self.validate_planned_data = self._get_saas_file_feature_enabled(
162
+ "validate_planned_data", default=True
163
+ )
161
164
 
162
165
  def __enter__(self) -> "SaasHerder":
163
166
  return self