qontract-reconcile 0.10.2.dev168__py3-none-any.whl → 0.10.2.dev170__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.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev168
3
+ Version: 0.10.2.dev170
4
4
  Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
5
5
  Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
6
6
  Project-URL: repository, https://github.com/app-sre/qontract-reconcile
@@ -22,7 +22,7 @@ reconcile/database_access_manager.py,sha256=Z3aAmw2LsmMIIor-bOGzziVZdVNC82Gmw8oH
22
22
  reconcile/deadmanssnitch.py,sha256=n-5W-djUgwzpmdDM4eQIZpkkDmHY0vndt-42LJXI4Y8,7491
23
23
  reconcile/email_sender.py,sha256=38Wvl6WHqCwlqLx4oxVJOIeDmoJsyitD3g1F4jTkAj8,4246
24
24
  reconcile/gabi_authorized_users.py,sha256=Jwvo97nzUX3NIl2VHKuZlT0-I40qk2VnACbafe91T2o,4854
25
- reconcile/gcp_image_mirror.py,sha256=M5pimd0j13BBWCa8vX0fftWO0pHBfQCATIIpOGggDSA,10332
25
+ reconcile/gcp_image_mirror.py,sha256=1ThuUff_04ZdF6uxcLoDuHhoNA3OIw0V-z0-CwdPE2w,9538
26
26
  reconcile/github_org.py,sha256=Wc5cZamatuWsW2ZJT2ib5ps8l3iY3RXHwNUxVJerqz0,14173
27
27
  reconcile/github_owners.py,sha256=viE1KJ-zaTxuZ5yItg2C263J0brn-Q-3hR_DkYDMbhY,3122
28
28
  reconcile/github_repo_invites.py,sha256=U9UCzNVwrZ7MqODtFah8ogH0NNY-XjBin7G9gqHtCUY,2690
@@ -90,7 +90,7 @@ reconcile/openshift_users.py,sha256=JUWLb13USlQ4KvXZVsi3JES4csZnXlH0plhxskg_p6A,
90
90
  reconcile/openshift_vault_secrets.py,sha256=9rTqV6wzCQx2Oh712E_Xj8wMG7u8Oh-pY8DWjlv4mZw,1660
91
91
  reconcile/quay_base.py,sha256=h5xNjb7EZm8L2JgpO42r6w0UA4im5dabZXJSIW69zKU,1987
92
92
  reconcile/quay_membership.py,sha256=cmeoRdr3-wVlymNHVhzhW0W-Tq6qt1hd2OOIhGXsmrY,6398
93
- reconcile/quay_mirror.py,sha256=0KtQFwrvMNtlsPJ9F_-ICaVIjgIUjFxqipvAPcvyg3Q,15338
93
+ reconcile/quay_mirror.py,sha256=PBooiA0ShZpWYfO6oeKFqYYT6Syi7Q8JJD9kj0wRRLg,14030
94
94
  reconcile/quay_mirror_org.py,sha256=tXKuF6JtmaNRwu8_g_65U_Vpd6sFBYeXmJA-flVhylE,10764
95
95
  reconcile/quay_permissions.py,sha256=9KOutS1w4RFQqkvMSy54VtsKNx56-phzP6yI_rEW-B8,4244
96
96
  reconcile/quay_repos.py,sha256=cuEYG0HUe0ut5yvLdEwOF5-CmccpXQHRb_wDazvDrvQ,6895
@@ -651,6 +651,7 @@ reconcile/utils/prometheus.py,sha256=Ad0rwLbxRuuYjHwkwJloHEdK0bvy42h-p-HIT1DhDhs
651
651
  reconcile/utils/promotion_state.py,sha256=McSgGj3oog83ThJCrMR2v8q6Xb_Pxij-HEe_RbDu8cg,3946
652
652
  reconcile/utils/promtool.py,sha256=xmPBWEApkk0L2qZBAvTxakNXxfTz-tVLPFxGnpsxXnM,2831
653
653
  reconcile/utils/quay_api.py,sha256=uE_jxcdy3ViHtYFAfwDQuFDaO7Pr6AAPoVnmORbyHio,7822
654
+ reconcile/utils/quay_mirror.py,sha256=dpWCNv5lITwIk6Q9RkmqaQKHNk_JPy27UQEribJ7E-U,1324
654
655
  reconcile/utils/raw_github_api.py,sha256=2WKtE8ABYYB9UGOAh9N_kLkksBWL3320Z2_scteZddI,2805
655
656
  reconcile/utils/repo_owners.py,sha256=BHrAXxKyvn4qWJwFPWYGTtfgnLmYnWtYFEJGFeD__FE,6573
656
657
  reconcile/utils/rest_api_base.py,sha256=MT7tp6CQO2S5aKfVOzw_hipWg7wAGoOqkm4qurI1hEU,4342
@@ -758,9 +759,9 @@ reconcile/utils/runtime/meta.py,sha256=dWdKS9eHVuowFkTK4lgXJ723vS1y9giOMzePUKnHn
758
759
  reconcile/utils/runtime/runner.py,sha256=I30KRrX1UQbHc_Ir1cIZX3OfNSdoHKdnDSPAEB69Ilk,7944
759
760
  reconcile/utils/runtime/sharding.py,sha256=r0ieUtNed7NvknSw6qQrCkKpVXE1shuHGnfFcnpA_k4,16142
760
761
  reconcile/utils/saasherder/__init__.py,sha256=3U8plqMAPRE1kjwZ5YnIsYsggTf4_gS7flRUEuXVBAs,343
761
- reconcile/utils/saasherder/interfaces.py,sha256=2Fjc34Us5q166P6bWVmSEBeYNTnWAPrI9EHwYUnEeuw,9098
762
+ reconcile/utils/saasherder/interfaces.py,sha256=NEYQspYfyWQhBeJyNCqSFbixi1A4wRVGB7FeNM5BDCk,9141
762
763
  reconcile/utils/saasherder/models.py,sha256=JaOz_DEtudJZhiDe90kaBlJkppFufn81V92oK9PHYx0,10208
763
- reconcile/utils/saasherder/saasherder.py,sha256=13LeAw12QR7wg4eU92iDsNXTCSCBrBp6LKvACn8ndp0,86834
764
+ reconcile/utils/saasherder/saasherder.py,sha256=ZeYwUSrWbJ0XkmQv92dUGPrhxd5zBKnDEM7_uzRroFE,87067
764
765
  reconcile/utils/terraform/__init__.py,sha256=zNbiyTWo35AT1sFTElL2j_AA0jJ_yWE_bfFn-nD2xik,250
765
766
  reconcile/utils/terraform/config.py,sha256=5UVrd563TMcvi4ooa5JvWVDW1I3bIWg484u79evfV_8,164
766
767
  reconcile/utils/terraform/config_client.py,sha256=gRL1rQ0AqvShei_rcGqC3HDYGskOFKE1nPrJyJE9yno,4676
@@ -806,7 +807,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
806
807
  tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
807
808
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
808
809
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
809
- qontract_reconcile-0.10.2.dev168.dist-info/METADATA,sha256=wzA6vkcwYuN-6Jx92482hVcUXLcXr8p0BqSuz1gW-34,24627
810
- qontract_reconcile-0.10.2.dev168.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
811
- qontract_reconcile-0.10.2.dev168.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
812
- qontract_reconcile-0.10.2.dev168.dist-info/RECORD,,
810
+ qontract_reconcile-0.10.2.dev170.dist-info/METADATA,sha256=IxuslsyvfmcIfSm5c8XRE2Y_QlEVTeZN4Pv1DiT1g0A,24627
811
+ qontract_reconcile-0.10.2.dev170.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
812
+ qontract_reconcile-0.10.2.dev170.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
813
+ qontract_reconcile-0.10.2.dev170.dist-info/RECORD,,
@@ -1,7 +1,6 @@
1
1
  import base64
2
2
  import logging
3
3
  import os
4
- import re
5
4
  import tempfile
6
5
  import time
7
6
  from typing import Any, Self
@@ -23,6 +22,7 @@ from reconcile.gql_definitions.fragments.container_image_mirror import (
23
22
  )
24
23
  from reconcile.gql_definitions.fragments.vault_secret import VaultSecret
25
24
  from reconcile.utils import gql
25
+ from reconcile.utils.quay_mirror import record_timestamp, sync_tag
26
26
  from reconcile.utils.secret_reader import SecretReader
27
27
 
28
28
  QONTRACT_INTEGRATION = "gcp-image-mirror"
@@ -112,25 +112,6 @@ class QuayMirror:
112
112
 
113
113
  return summary
114
114
 
115
- @staticmethod
116
- def sync_tag(
117
- tags: list[str] | None, tags_exclude: list[str] | None, candidate: str
118
- ) -> bool:
119
- if tags is not None:
120
- # When tags is defined, we don't look at tags_exclude
121
- return any(re.match(tag, candidate) for tag in tags)
122
-
123
- if tags_exclude is not None:
124
- return any(re.match(tag, candidate) for tag in tags_exclude)
125
- for tag_exclude in tags_exclude:
126
- if re.match(tag_exclude, candidate):
127
- return False
128
- return True
129
-
130
- # Both tags and tags_exclude are None, so
131
- # tag must be synced
132
- return True
133
-
134
115
  # second layer of processing that matches up pull/push creds with each repo and determines what tags need to be synced
135
116
  def process_sync_tasks(self, repos_to_sync: list[ImageSyncItem]) -> list[SyncTask]:
136
117
  eight_hours = 28800 # 60 * 60 * 8
@@ -165,7 +146,7 @@ class QuayMirror:
165
146
  )
166
147
 
167
148
  for tag in image_mirror:
168
- if not self.sync_tag(
149
+ if not sync_tag(
169
150
  tags=item.mirror.tags,
170
151
  tags_exclude=item.mirror.tags_exclude,
171
152
  candidate=tag,
@@ -234,12 +215,12 @@ class QuayMirror:
234
215
  with open(control_file_path, encoding="locale") as file_obj:
235
216
  last_deep_sync = float(file_obj.read())
236
217
  except FileNotFoundError:
237
- self._record_timestamp(control_file_path)
218
+ record_timestamp(control_file_path)
238
219
  return True
239
220
 
240
221
  next_deep_sync = last_deep_sync + interval
241
222
  if time.time() >= next_deep_sync:
242
- self._record_timestamp(control_file_path)
223
+ record_timestamp(control_file_path)
243
224
  return True
244
225
 
245
226
  return False
@@ -249,11 +230,6 @@ class QuayMirror:
249
230
  token = base64.b64decode(raw_data["token"]).decode()
250
231
  return f"{raw_data['user']}:{token}"
251
232
 
252
- @staticmethod
253
- def _record_timestamp(path: str) -> None:
254
- with open(path, "w", encoding="locale") as file_object:
255
- file_object.write(str(time.time()))
256
-
257
233
  def _get_push_creds(self) -> dict[str, str]:
258
234
  result = gql_gcp_projects.query(query_func=self.gqlapi.query)
259
235
 
reconcile/quay_mirror.py CHANGED
@@ -28,9 +28,9 @@ from reconcile.utils import (
28
28
  metrics,
29
29
  sharding,
30
30
  )
31
- from reconcile.utils.helpers import match_patterns
32
31
  from reconcile.utils.instrumented_wrappers import InstrumentedImage as Image
33
32
  from reconcile.utils.instrumented_wrappers import InstrumentedSkopeo as Skopeo
33
+ from reconcile.utils.quay_mirror import record_timestamp, sync_tag
34
34
  from reconcile.utils.secret_reader import SecretReader
35
35
 
36
36
  _LOG = logging.getLogger(__name__)
@@ -136,7 +136,7 @@ class QuayMirror:
136
136
  _LOG.error("skopeo command error message: '%s'", details)
137
137
 
138
138
  if self.is_compare_tags and not self.dry_run:
139
- self.record_timestamp(self.control_file_path)
139
+ record_timestamp(self.control_file_path)
140
140
 
141
141
  @classmethod
142
142
  def process_repos_query(
@@ -203,40 +203,6 @@ class QuayMirror:
203
203
  })
204
204
  return summary
205
205
 
206
- @staticmethod
207
- def sync_tag(
208
- tags: Iterable[str] | None,
209
- tags_exclude: Iterable[str] | None,
210
- candidate: str,
211
- ) -> bool:
212
- """
213
- Determine if the candidate tag should sync, tags_exclude check take precedence.
214
- :param tags: regex patterns to filter, match means to sync, None means no filter
215
- :param tags_exclude: regex patterns to filter, match means not to sync, None means no filter
216
- :param candidate: tag to check
217
- :return: bool, True means to sync, False means not to sync
218
- """
219
- if not tags and not tags_exclude:
220
- return True
221
-
222
- if not tags:
223
- # only tags_exclude provided
224
- assert tags_exclude # mypy can't infer not None
225
- return not match_patterns(tags_exclude, candidate)
226
-
227
- if not tags_exclude:
228
- # only tags provided
229
- return match_patterns(tags, candidate)
230
-
231
- # both tags and tags_exclude provided
232
- return not match_patterns(
233
- tags_exclude,
234
- candidate,
235
- ) and match_patterns(
236
- tags,
237
- candidate,
238
- )
239
-
240
206
  def process_sync_tasks(self):
241
207
  if self.is_compare_tags:
242
208
  _LOG.warning("Making a compare-tags run. This is a slow operation.")
@@ -282,7 +248,7 @@ class QuayMirror:
282
248
  tags_exclude = item["mirror"].get("tagsExclude")
283
249
 
284
250
  for tag in image_mirror:
285
- if not self.sync_tag(
251
+ if not sync_tag(
286
252
  tags=tags, tags_exclude=tags_exclude, candidate=tag
287
253
  ):
288
254
  continue
@@ -390,11 +356,6 @@ class QuayMirror:
390
356
  next_compare_tags = last_compare_tags + interval
391
357
  return time.time() >= next_compare_tags
392
358
 
393
- @staticmethod
394
- def record_timestamp(path) -> None:
395
- with open(path, "w", encoding="locale") as file_object:
396
- file_object.write(str(time.time()))
397
-
398
359
  def _get_push_creds(self):
399
360
  result = self.gqlapi.query(self.QUAY_ORG_CATALOG_QUERY)
400
361
 
@@ -0,0 +1,42 @@
1
+ import time
2
+ from collections.abc import Iterable
3
+
4
+ from reconcile.utils.helpers import match_patterns
5
+
6
+
7
+ def record_timestamp(path: str) -> None:
8
+ with open(path, "w", encoding="locale") as file_object:
9
+ file_object.write(str(time.time()))
10
+
11
+
12
+ def sync_tag(
13
+ tags: Iterable[str] | None,
14
+ tags_exclude: Iterable[str] | None,
15
+ candidate: str,
16
+ ) -> bool:
17
+ """
18
+ Determine if the candidate tag should sync, tags_exclude check take precedence.
19
+ :param tags: regex patterns to filter, match means to sync, None means no filter
20
+ :param tags_exclude: regex patterns to filter, match means not to sync, None means no filter
21
+ :param candidate: tag to check
22
+ :return: bool, True means to sync, False means not to sync
23
+ """
24
+ if tags:
25
+ if tags_exclude:
26
+ # both tags and tags_exclude provided
27
+ return not match_patterns(
28
+ tags_exclude,
29
+ candidate,
30
+ ) and match_patterns(
31
+ tags,
32
+ candidate,
33
+ )
34
+ else:
35
+ # only tags provided
36
+ return match_patterns(tags, candidate)
37
+ elif tags_exclude:
38
+ # only tags_exclude provided
39
+ return not match_patterns(tags_exclude, candidate)
40
+ else:
41
+ # neither tags nor tags_exclude provided
42
+ return True
@@ -367,6 +367,8 @@ class ManagedResourceName(Protocol):
367
367
  resource: str
368
368
  resource_names: list[str]
369
369
 
370
+ def dict(self) -> dict[str, str]: ...
371
+
370
372
 
371
373
  class SaasFile(HasParameters, HasSecretParameters, Protocol):
372
374
  path: str
@@ -1784,6 +1784,11 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1784
1784
  desired_target_config["saas_file_managed_resource_types"] = (
1785
1785
  saas_file.managed_resource_types
1786
1786
  )
1787
+ if saas_file.managed_resource_names:
1788
+ desired_target_config["saas_file_managed_resource_names"] = [
1789
+ m.dict() for m in saas_file.managed_resource_names
1790
+ ]
1791
+
1787
1792
  desired_target_config["url"] = rt.url
1788
1793
  desired_target_config["path"] = rt.path
1789
1794
  # before the GQL classes are introduced, the parameters attribute