qontract-reconcile 0.10.2.dev285__py3-none-any.whl → 0.10.2.dev287__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.dev285
3
+ Version: 0.10.2.dev287
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
@@ -84,12 +84,12 @@ reconcile/openshift_users.py,sha256=h4dH3gTCFFQID76PFuYeMWNzFQ9DgTUtsOcvxfj-3cs,
84
84
  reconcile/openshift_vault_secrets.py,sha256=Ax-_EBWWU1VRHYyKaUkGJkIjHGwWM3bZgjXL5CkPW8k,1883
85
85
  reconcile/quay_base.py,sha256=GQkUpuEzC1V_QrHEu_PoELVGnlNRvgFnTqVKp-xkgC4,2070
86
86
  reconcile/quay_membership.py,sha256=No2sgEyTVj-hr5VPLy_xdrYAPvt-xo-CPpOt0X3x_6o,6623
87
- reconcile/quay_mirror.py,sha256=PBooiA0ShZpWYfO6oeKFqYYT6Syi7Q8JJD9kj0wRRLg,14030
88
- reconcile/quay_mirror_org.py,sha256=PG_WpzE4TymICs74mFt3lh7XA4Rg91y4EVREMEd8PFk,10815
89
- reconcile/quay_permissions.py,sha256=9KOutS1w4RFQqkvMSy54VtsKNx56-phzP6yI_rEW-B8,4244
90
- reconcile/quay_repos.py,sha256=cuEYG0HUe0ut5yvLdEwOF5-CmccpXQHRb_wDazvDrvQ,6895
87
+ reconcile/quay_mirror.py,sha256=pA1_OujRduwQ6dYljoWXU_VJgAwlv7DzThk26ymKmGs,14327
88
+ reconcile/quay_mirror_org.py,sha256=2xLD-PZggP33LhZYxun5I3deF8hwGH9zueMtAByphzE,10842
89
+ reconcile/quay_permissions.py,sha256=BF539lRxjpgwm88WzazklzgaCF_ipRALwbO2AdpqUqE,4388
90
+ reconcile/quay_repos.py,sha256=woB2afCBgz0UPekHcYtV8zwQCZHZZBL8VDf82ATWZxE,7524
91
91
  reconcile/queries.py,sha256=aaffpfMIlmHy73CUxos--NnUsTR5ms3VPeaUY3dnvIs,49879
92
- reconcile/query_validator.py,sha256=MSh5pKLBksws4AqfuvT8nrIGucIbqX-IOzYyPYTLO7k,1491
92
+ reconcile/query_validator.py,sha256=csOSkKxcf6ZlpchJu4ck2jLYKUN6y1l-UmSQUFHgssY,1618
93
93
  reconcile/requests_sender.py,sha256=914iluuF4UVgG3VyxxtnHOu4yf6YKS2fIy6PViSsFTQ,3875
94
94
  reconcile/resource_scraper.py,sha256=sg10j7lwAE8JxsyBTaxixOR3QYnePctsNuwOLiz4QVg,2309
95
95
  reconcile/resource_template_tester.py,sha256=DsKvBuNLPxm4Fa-e1YHHySnhThm5i_j-nF3G4b02Mz0,2416
@@ -152,7 +152,7 @@ reconcile/aws_saml_idp/integration.py,sha256=rop8ahl7v0WUheSgVLb-4MU3Ldy6Eb3LknF
152
152
  reconcile/aws_saml_roles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
153
153
  reconcile/aws_saml_roles/integration.py,sha256=mLRCnSfClp2ia8UynSmY5HZe5YmrJTc1RwxyMeU2yBw,11319
154
154
  reconcile/aws_version_sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
155
- reconcile/aws_version_sync/integration.py,sha256=7D76Zy5TLndLgLdKJEnDl1OWex148dMEvtNkSDjnijo,19461
155
+ reconcile/aws_version_sync/integration.py,sha256=hB97__QCJXAd1pRGs7h1-T5SWVYqZBb2eigXYW7YO7g,20011
156
156
  reconcile/aws_version_sync/utils.py,sha256=x-45QT7zAwdNvCg7w_qJNwLaksFcfz1_6KQoD_0IVuA,1727
157
157
  reconcile/aws_version_sync/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
158
158
  reconcile/aws_version_sync/merge_request_manager/merge_request.py,sha256=2FbqLLdqxycWNvX1eNbwMjWSVBb7q0p-8t5Db0m7b4Q,4842
@@ -797,7 +797,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
797
797
  tools/saas_promotion_state/saas_promotion_state.py,sha256=uQv2QJAmUXP1g2GPIH30WTlvL9soY6m9lefpZEVDM5w,3965
798
798
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
799
799
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
800
- qontract_reconcile-0.10.2.dev285.dist-info/METADATA,sha256=PjjUS6ZZbXTIIPtcrF-Tzub9hRWdkUrTlyEJaFPtV68,24916
801
- qontract_reconcile-0.10.2.dev285.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
802
- qontract_reconcile-0.10.2.dev285.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
803
- qontract_reconcile-0.10.2.dev285.dist-info/RECORD,,
800
+ qontract_reconcile-0.10.2.dev287.dist-info/METADATA,sha256=bNiscvOvdISiKXDWToNXZt4kG5-3tiNNIocP9BOBpQ4,24916
801
+ qontract_reconcile-0.10.2.dev287.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
802
+ qontract_reconcile-0.10.2.dev287.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
803
+ qontract_reconcile-0.10.2.dev287.dist-info/RECORD,,
@@ -356,6 +356,15 @@ class AVSIntegration(QontractReconcileIntegration[AVSIntegrationParams]):
356
356
  # AWS ElastiCache Redis 6 could use a version like 6.x. Then, we don't need to manage it
357
357
  continue
358
358
 
359
+ if (
360
+ resource.provider == SupportedResourceProvider.RDS
361
+ and EXTENDED_SUPPORT_VERSION_INDICATOR
362
+ in values["engine_version"]
363
+ ):
364
+ # AWS RDS PostgreSQL 11 and 12 extended support versions are not supported by this integration
365
+ # See https://aws.amazon.com/about-aws/whats-new/2025/04/amazon-rds-postgresql-extended-support-11-22-rds-20250220-12-22-rds-20250220/
366
+ continue
367
+
359
368
  external_resources.append(
360
369
  ExternalResource(
361
370
  namespace_file=ns.path,
reconcile/quay_mirror.py CHANGED
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  import os
3
5
  import sys
@@ -7,8 +9,8 @@ from collections import (
7
9
  defaultdict,
8
10
  namedtuple,
9
11
  )
10
- from collections.abc import Iterable
11
12
  from typing import (
13
+ TYPE_CHECKING,
12
14
  Any,
13
15
  Self,
14
16
  )
@@ -33,6 +35,9 @@ from reconcile.utils.instrumented_wrappers import InstrumentedSkopeo as Skopeo
33
35
  from reconcile.utils.quay_mirror import record_timestamp, sync_tag
34
36
  from reconcile.utils.secret_reader import SecretReader
35
37
 
38
+ if TYPE_CHECKING:
39
+ from collections.abc import Iterable
40
+
36
41
  _LOG = logging.getLogger(__name__)
37
42
 
38
43
  QONTRACT_INTEGRATION = "quay-mirror"
@@ -203,7 +208,7 @@ class QuayMirror:
203
208
  })
204
209
  return summary
205
210
 
206
- def process_sync_tasks(self):
211
+ def process_sync_tasks(self) -> defaultdict[OrgKey, list[dict[str, str | None]]]:
207
212
  if self.is_compare_tags:
208
213
  _LOG.warning("Making a compare-tags run. This is a slow operation.")
209
214
  summary = self.process_repos_query(
@@ -308,12 +313,12 @@ class QuayMirror:
308
313
  pass
309
314
  finally:
310
315
  self.response_cache_hits.inc(
311
- upstream.response_cache_hits
312
- + downstream.response_cache_hits
316
+ (upstream.response_cache_hits or 0)
317
+ + (downstream.response_cache_hits or 0)
313
318
  )
314
319
  self.response_cache_misses.inc(
315
- upstream.response_cache_misses
316
- + downstream.response_cache_misses
320
+ (upstream.response_cache_misses or 0)
321
+ + (downstream.response_cache_misses or 0)
317
322
  )
318
323
 
319
324
  _LOG.debug(
@@ -346,7 +351,7 @@ class QuayMirror:
346
351
  return self._has_enough_time_passed_since_last_compare_tags
347
352
 
348
353
  @staticmethod
349
- def check_compare_tags_elapsed_time(path, interval) -> bool:
354
+ def check_compare_tags_elapsed_time(path: str, interval: float) -> bool:
350
355
  try:
351
356
  with open(path, encoding="locale") as file_obj:
352
357
  last_compare_tags = float(file_obj.read())
@@ -356,12 +361,15 @@ class QuayMirror:
356
361
  next_compare_tags = last_compare_tags + interval
357
362
  return time.time() >= next_compare_tags
358
363
 
359
- def _get_push_creds(self):
364
+ def _get_push_creds(self) -> dict[OrgKey, str]:
360
365
  result = self.gqlapi.query(self.QUAY_ORG_CATALOG_QUERY)
361
366
 
362
- creds = {}
363
- for org_data in result["quay_orgs"]:
364
- push_secret = org_data["pushCredentials"]
367
+ creds: dict[OrgKey, str] = {}
368
+ if not result:
369
+ return creds
370
+
371
+ for org_data in result.get("quay_orgs") or []:
372
+ push_secret = org_data.get("pushCredentials")
365
373
  if push_secret is None:
366
374
  continue
367
375
 
@@ -375,13 +383,13 @@ class QuayMirror:
375
383
 
376
384
 
377
385
  def run(
378
- dry_run,
386
+ dry_run: bool,
379
387
  control_file_dir: str | None,
380
388
  compare_tags: bool | None,
381
389
  compare_tags_interval: int,
382
390
  repository_urls: Iterable[str] | None,
383
391
  exclude_repository_urls: Iterable[str] | None,
384
- ):
392
+ ) -> None:
385
393
  with QuayMirror(
386
394
  dry_run,
387
395
  control_file_dir,
@@ -393,7 +401,7 @@ def run(
393
401
  quay_mirror.run()
394
402
 
395
403
 
396
- def early_exit_desired_state(*args, **kwargs) -> dict[str, Any]:
404
+ def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
397
405
  with QuayMirror(dry_run=True) as quay_mirror:
398
406
  return {
399
407
  "repos": quay_mirror.process_repos_query(session=quay_mirror.session),
@@ -1,9 +1,10 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  import os
3
5
  import tempfile
4
6
  from collections import defaultdict
5
- from collections.abc import Iterable
6
- from typing import Any, Self
7
+ from typing import TYPE_CHECKING, Any, Self
7
8
 
8
9
  import requests
9
10
  from sretoolbox.container import (
@@ -20,6 +21,11 @@ from reconcile.quay_base import get_quay_api_store
20
21
  from reconcile.quay_mirror import QuayMirror
21
22
  from reconcile.utils.quay_mirror import record_timestamp, sync_tag
22
23
 
24
+ if TYPE_CHECKING:
25
+ from collections.abc import Iterable
26
+
27
+ from reconcile.quay_base import OrgKey
28
+
23
29
  _LOG = logging.getLogger(__name__)
24
30
 
25
31
  QONTRACT_INTEGRATION = "quay-mirror-org"
@@ -66,7 +72,7 @@ class QuayMirrorOrg:
66
72
  def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
67
73
  self.session.close()
68
74
 
69
- def run(self):
75
+ def run(self) -> None:
70
76
  sync_tasks = self.process_sync_tasks()
71
77
  for org, data in sync_tasks.items():
72
78
  for item in data:
@@ -83,19 +89,11 @@ class QuayMirrorOrg:
83
89
  if self.is_compare_tags and not self.dry_run:
84
90
  record_timestamp(self.control_file_path)
85
91
 
86
- def process_org_mirrors(self, summary):
87
- """adds new keys to the summary dict with information about mirrored
88
- orgs
89
-
90
- It collects the list of repositories in the upstream org from an API
92
+ def process_org_mirrors(self) -> dict[OrgKey, list[dict[str, Any]]]:
93
+ """It collects the list of repositories in the upstream org from an API
91
94
  call and not from App-Interface.
92
-
93
- :param summary: summary
94
- :type summary: dict
95
- :return: summary
96
- :rtype: dict
97
95
  """
98
-
96
+ summary = defaultdict(list)
99
97
  for org_key, org_info in self.quay_api_store.items():
100
98
  if not org_info.get("mirror"):
101
99
  continue
@@ -128,7 +126,7 @@ class QuayMirrorOrg:
128
126
  "username": username,
129
127
  "token": token,
130
128
  },
131
- "mirror_filters": org_info.get("mirror_filters").get(
129
+ "mirror_filters": org_info.get("mirror_filters", {}).get(
132
130
  repo["name"], {}
133
131
  ),
134
132
  }
@@ -136,9 +134,8 @@ class QuayMirrorOrg:
136
134
 
137
135
  return summary
138
136
 
139
- def process_sync_tasks(self):
140
- summary = defaultdict(list)
141
- self.process_org_mirrors(summary)
137
+ def process_sync_tasks(self) -> dict[OrgKey, list[dict[str, Any]]]:
138
+ summary = self.process_org_mirrors()
142
139
 
143
140
  sync_tasks = defaultdict(list)
144
141
  for org_key, data in summary.items():
@@ -274,7 +271,7 @@ class QuayMirrorOrg:
274
271
 
275
272
  return self._has_enough_time_passed_since_last_compare_tags
276
273
 
277
- def get_push_creds(self, org_key):
274
+ def get_push_creds(self, org_key: OrgKey) -> str:
278
275
  """returns username and password for the given org
279
276
 
280
277
  :param org_key: org_key
@@ -296,7 +293,7 @@ def run(
296
293
  compare_tags_interval: int,
297
294
  orgs: Iterable[str] | None,
298
295
  repositories: Iterable[str] | None,
299
- ):
296
+ ) -> None:
300
297
  with QuayMirrorOrg(
301
298
  dry_run,
302
299
  control_file_dir,
@@ -1,7 +1,8 @@
1
1
  import logging
2
2
  import sys
3
+ from typing import Any
3
4
 
4
- from reconcile.quay_base import get_quay_api_store
5
+ from reconcile.quay_base import OrgKey, get_quay_api_store
5
6
  from reconcile.status import ExitCodes
6
7
  from reconcile.utils import gql
7
8
 
@@ -49,9 +50,13 @@ QUAY_REPOS_QUERY = """
49
50
  QONTRACT_INTEGRATION = "quay-permissions"
50
51
 
51
52
 
52
- def run(dry_run):
53
+ def run(dry_run: bool) -> None:
53
54
  gqlapi = gql.get_api()
54
- apps = gqlapi.query(QUAY_REPOS_QUERY)["apps"]
55
+ result = gqlapi.query(QUAY_REPOS_QUERY)
56
+ if not result:
57
+ return
58
+
59
+ apps: list[dict[str, Any]] = result.get("apps") or []
55
60
  quay_api_store = get_quay_api_store()
56
61
  error = False
57
62
  for app in apps:
@@ -61,7 +66,7 @@ def run(dry_run):
61
66
  for quay_repo_config in quay_repo_configs:
62
67
  instance_name = quay_repo_config["org"]["instance"]["name"]
63
68
  org_name = quay_repo_config["org"]["name"]
64
- org_key = (instance_name, org_name)
69
+ org_key = OrgKey(instance_name, org_name)
65
70
 
66
71
  if not quay_repo_config["org"]["managedRepos"]:
67
72
  logging.error(
@@ -95,7 +100,7 @@ def run(dry_run):
95
100
  )
96
101
  continue
97
102
 
98
- perm_org_key = (
103
+ perm_org_key = OrgKey(
99
104
  permission["quayOrg"]["instance"]["name"],
100
105
  permission["quayOrg"]["name"],
101
106
  )
reconcile/quay_repos.py CHANGED
@@ -1,6 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import logging
2
4
  import sys
3
5
  from collections import namedtuple
6
+ from typing import TYPE_CHECKING
4
7
 
5
8
  from reconcile.quay_base import (
6
9
  OrgKey,
@@ -9,6 +12,9 @@ from reconcile.quay_base import (
9
12
  from reconcile.status import ExitCodes
10
13
  from reconcile.utils import gql
11
14
 
15
+ if TYPE_CHECKING:
16
+ from reconcile.quay_base import QuayApiStore
17
+
12
18
  QUAY_REPOS_QUERY = """
13
19
  {
14
20
  apps: apps_v1 {
@@ -37,7 +43,7 @@ QONTRACT_INTEGRATION = "quay-repos"
37
43
  RepoInfo = namedtuple("RepoInfo", ["org_key", "name", "public", "description"])
38
44
 
39
45
 
40
- def fetch_current_state(quay_api_store):
46
+ def fetch_current_state(quay_api_store: QuayApiStore) -> list[RepoInfo]:
41
47
  state = []
42
48
 
43
49
  for org_key, org_info in quay_api_store.items():
@@ -60,16 +66,17 @@ def fetch_current_state(quay_api_store):
60
66
  return state
61
67
 
62
68
 
63
- def fetch_desired_state(quay_api_store):
69
+ def fetch_desired_state(quay_api_store: QuayApiStore) -> list[RepoInfo]:
64
70
  gqlapi = gql.get_api()
65
71
  result = gqlapi.query(QUAY_REPOS_QUERY)
72
+ # fetch from quayRepos
73
+ if not result:
74
+ return []
66
75
 
67
76
  state = []
68
-
69
77
  seen_repos = set()
70
78
 
71
- # fetch from quayRepos
72
- for app in result["apps"]:
79
+ for app in result.get("apps") or []:
73
80
  quay_repos = app.get("quayRepos")
74
81
 
75
82
  if quay_repos is None:
@@ -115,7 +122,9 @@ def fetch_desired_state(quay_api_store):
115
122
  return state
116
123
 
117
124
 
118
- def get_downstream_orgs(quay_api_store, upstream_org_key):
125
+ def get_downstream_orgs(
126
+ quay_api_store: QuayApiStore, upstream_org_key: OrgKey
127
+ ) -> list[OrgKey]:
119
128
  downstream_orgs = []
120
129
  for org_key, org_info in quay_api_store.items():
121
130
  if org_info.get("mirror") == upstream_org_key:
@@ -124,14 +133,16 @@ def get_downstream_orgs(quay_api_store, upstream_org_key):
124
133
  return downstream_orgs
125
134
 
126
135
 
127
- def get_repo_from_state(state, repo_info):
136
+ def get_repo_from_state(state: list[RepoInfo], repo_info: RepoInfo) -> RepoInfo | None:
128
137
  for item in state:
129
138
  if item.org_key == repo_info.org_key and item.name == repo_info.name:
130
139
  return item
131
140
  return None
132
141
 
133
142
 
134
- def act_delete(dry_run, quay_api_store, current_repo):
143
+ def act_delete(
144
+ dry_run: bool, quay_api_store: QuayApiStore, current_repo: RepoInfo
145
+ ) -> None:
135
146
  logging.info([
136
147
  "delete_repo",
137
148
  current_repo.org_key.instance,
@@ -143,7 +154,9 @@ def act_delete(dry_run, quay_api_store, current_repo):
143
154
  api.repo_delete(current_repo.name)
144
155
 
145
156
 
146
- def act_create(dry_run, quay_api_store, desired_repo):
157
+ def act_create(
158
+ dry_run: bool, quay_api_store: QuayApiStore, desired_repo: RepoInfo
159
+ ) -> None:
147
160
  logging.info([
148
161
  "create_repo",
149
162
  desired_repo.org_key.instance,
@@ -157,7 +170,9 @@ def act_create(dry_run, quay_api_store, desired_repo):
157
170
  )
158
171
 
159
172
 
160
- def act_description(dry_run, quay_api_store, desired_repo):
173
+ def act_description(
174
+ dry_run: bool, quay_api_store: QuayApiStore, desired_repo: RepoInfo
175
+ ) -> None:
161
176
  logging.info([
162
177
  "update_desc",
163
178
  desired_repo.org_key.instance,
@@ -169,7 +184,9 @@ def act_description(dry_run, quay_api_store, desired_repo):
169
184
  api.repo_update_description(desired_repo.name, desired_repo.description)
170
185
 
171
186
 
172
- def act_public(dry_run, quay_api_store, desired_repo):
187
+ def act_public(
188
+ dry_run: bool, quay_api_store: QuayApiStore, desired_repo: RepoInfo
189
+ ) -> None:
173
190
  logging.info([
174
191
  "update_public",
175
192
  desired_repo.org_key.instance,
@@ -184,24 +201,28 @@ def act_public(dry_run, quay_api_store, desired_repo):
184
201
  api.repo_make_private(desired_repo.name)
185
202
 
186
203
 
187
- def act(dry_run, quay_api_store, current_state, desired_state):
188
- for current_repo in current_state:
189
- desired_repo = get_repo_from_state(desired_state, current_repo)
190
- if not desired_repo:
191
- act_delete(dry_run, quay_api_store, current_repo)
204
+ def act(
205
+ dry_run: bool,
206
+ quay_api_store: QuayApiStore,
207
+ current_state: list[RepoInfo],
208
+ desired_state: list[RepoInfo],
209
+ ) -> None:
210
+ for current_state_repo in current_state:
211
+ if not get_repo_from_state(desired_state, current_state_repo):
212
+ act_delete(dry_run, quay_api_store, current_state_repo)
192
213
 
193
- for desired_repo in desired_state:
194
- current_repo = get_repo_from_state(current_state, desired_repo)
214
+ for desired_state_repo in desired_state:
215
+ current_repo = get_repo_from_state(current_state, desired_state_repo)
195
216
  if not current_repo:
196
- act_create(dry_run, quay_api_store, desired_repo)
217
+ act_create(dry_run, quay_api_store, desired_state_repo)
197
218
  else:
198
- if current_repo.public != desired_repo.public:
199
- act_public(dry_run, quay_api_store, desired_repo)
200
- if current_repo.description != desired_repo.description:
201
- act_description(dry_run, quay_api_store, desired_repo)
219
+ if current_repo.public != desired_state_repo.public:
220
+ act_public(dry_run, quay_api_store, desired_state_repo)
221
+ if current_repo.description != desired_state_repo.description:
222
+ act_description(dry_run, quay_api_store, desired_state_repo)
202
223
 
203
224
 
204
- def run(dry_run):
225
+ def run(dry_run: bool) -> None:
205
226
  quay_api_store = get_quay_api_store()
206
227
 
207
228
  # consistency checks
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import sys
3
3
  from textwrap import indent
4
+ from typing import Any
4
5
 
5
6
  from reconcile import queries
6
7
  from reconcile.openshift_resources_base import (
@@ -30,14 +31,17 @@ QUERY_VALIDATIONS_QUERY = """
30
31
  """ % (indent(OPENSHIFT_RESOURCE, 6 * " "),)
31
32
 
32
33
 
33
- def run(dry_run):
34
+ def run(dry_run: bool) -> None:
34
35
  gqlapi = gql.get_api()
35
- query_validations = gqlapi.query(QUERY_VALIDATIONS_QUERY)["validations"]
36
+ data = gqlapi.query(QUERY_VALIDATIONS_QUERY)
37
+ if not data:
38
+ return
39
+ query_validations: list[dict[str, Any]] = data.get("validations") or []
36
40
  settings = queries.get_secret_reader_settings()
37
41
  error = False
38
42
  for qv in query_validations:
39
43
  qv_name = qv["name"]
40
- for q in qv["queries"]:
44
+ for q in qv.get("queries") or []:
41
45
  try:
42
46
  gqlapi.query(gql.get_resource(q["path"])["content"])
43
47
  except (gql.GqlGetResourceError, gql.GqlApiError) as e: