qontract-reconcile 0.10.2.dev294__py3-none-any.whl → 0.10.2.dev295__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.dev294
3
+ Version: 0.10.2.dev295
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
@@ -4,7 +4,7 @@ reconcile/acs_rbac.py,sha256=15vNfNzdG_DeXaJ-f5m8DSaJh__LUK766_xAECqyTsg,22657
4
4
  reconcile/aws_ami_share.py,sha256=M_gT7y3cSAyT_Pm90PBCNDSmbZtqREqe2jNETh0i9Qs,3808
5
5
  reconcile/aws_ecr_image_pull_secrets.py,sha256=F58PtX1GlB9XHqj8hGy9ItiTznXLAAKTNlWD9iT2MWI,2593
6
6
  reconcile/aws_iam_keys.py,sha256=pVqaXus2pH1LcRlog0C9UsWFttW420tuf7n_Ox-OJs4,4091
7
- reconcile/aws_iam_password_reset.py,sha256=FpAqAXngmLFqkOtOjrz_i90qteUyLHJL0GMjotc2tJE,3178
7
+ reconcile/aws_iam_password_reset.py,sha256=5oajSspJVAvpGd445hKsxtEGYb75dM4l1_PJTzrfHk0,3253
8
8
  reconcile/aws_support_cases_sos.py,sha256=G9g0oM6ohvuJ5N592ePjiPeaDug4_vapAy58RyG-S3Y,3478
9
9
  reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
10
10
  reconcile/checkpoint.py,sha256=gjtS8g6KIyKFYlHMSZjAqDUOlVh83nh4go-9yNrhWZU,5016
@@ -44,7 +44,7 @@ reconcile/jenkins_worker_fleets.py,sha256=tLFEF3ijnqF0jA7hgmFOOrshmfjGYXHFlQcvMZ
44
44
  reconcile/jira_permissions_validator.py,sha256=nVHZg7kNn04Q-ryNM20wthMrhXos28g3O9b0ahzxAKc,14690
45
45
  reconcile/ldap_users.py,sha256=oP1CAxmgSi3zDJ3vKTPySjap6WmEX1U469FmFrov5l4,4599
46
46
  reconcile/mr_client_gateway.py,sha256=3L21YncbetuUI3HYvDAEb5JX5HO5KG2CfUyjapX3w8E,2063
47
- reconcile/ocm_additional_routers.py,sha256=e5P_OJAaV0jp0626dJ0Hp1-xUsEKXRCnrJzFTIQBdJg,3854
47
+ reconcile/ocm_additional_routers.py,sha256=FUtMeh14i1u2TJ5LSL0pAVjkdBRB7_FietObWO0s_UU,3942
48
48
  reconcile/ocm_addons.py,sha256=b59NWAMmd_zW4pxAH7hm8jzAkis0VZrUBmPYgduVlJc,3684
49
49
  reconcile/ocm_addons_upgrade_tests_trigger.py,sha256=A9zXeYG-_52DsS1dz47yDSnHz62du5XpPBlaeRa6zxY,3975
50
50
  reconcile/ocm_aws_infrastructure_access.py,sha256=f-zVCEf0ucdslhWvfeLcXxQ6Y4xtfCXUG6pxswGgWnU,7251
@@ -88,7 +88,7 @@ reconcile/quay_mirror.py,sha256=pA1_OujRduwQ6dYljoWXU_VJgAwlv7DzThk26ymKmGs,1432
88
88
  reconcile/quay_mirror_org.py,sha256=2xLD-PZggP33LhZYxun5I3deF8hwGH9zueMtAByphzE,10842
89
89
  reconcile/quay_permissions.py,sha256=BF539lRxjpgwm88WzazklzgaCF_ipRALwbO2AdpqUqE,4388
90
90
  reconcile/quay_repos.py,sha256=woB2afCBgz0UPekHcYtV8zwQCZHZZBL8VDf82ATWZxE,7524
91
- reconcile/queries.py,sha256=aaffpfMIlmHy73CUxos--NnUsTR5ms3VPeaUY3dnvIs,49879
91
+ reconcile/queries.py,sha256=FLUZBtFC2S-e6yjtC1Oq968CJP6t3nc36NPj0wYa0bE,53472
92
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
@@ -728,7 +728,7 @@ reconcile/utils/ocm/identity_providers.py,sha256=dKed09N8iWmn39tI_MpwgVe47x23eLs
728
728
  reconcile/utils/ocm/label_sources.py,sha256=ES_5VP4X6gsRxMFZ95WgbwE_HqqIUo_JRjHjdGYw6Ss,1846
729
729
  reconcile/utils/ocm/labels.py,sha256=CmAgaOEPiaUb4gLtKab9vNkSDJceuREPd4ApgGcIA1U,6240
730
730
  reconcile/utils/ocm/manifests.py,sha256=Q6kgOeiAwLbJY_vO_BEW2oePvbLDZcMZk20YpJJGpOA,1195
731
- reconcile/utils/ocm/ocm.py,sha256=iCAOxRYaQcJchKLrkwfeDbibZfieQYI8k3uelP0w_Y0,31366
731
+ reconcile/utils/ocm/ocm.py,sha256=tHRGWdpHkvrq6XakDjE1KrXNijdh-ubxKgK183fdhyQ,31378
732
732
  reconcile/utils/ocm/products.py,sha256=UtWpkAvSMCxPOulEB7aV5ZY8ej_rmErlE_HVdm9Gnjk,26021
733
733
  reconcile/utils/ocm/search_filters.py,sha256=09p4Wq1d1HGrDiinf1dmLJ46VtFhkkRCOL4V-N-zwjY,14808
734
734
  reconcile/utils/ocm/service_log.py,sha256=RG1f0MMn6joKaRCAm2xveSJCavdOPP1BVo9FXecDxaI,2018
@@ -765,12 +765,12 @@ reconcile/utils/unleash/server.py,sha256=907gDh9Ee8UxLqusnfpzE-7LUnttB38D4xhVJ0v
765
765
  tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
766
766
  tools/alert_report.py,sha256=cyQTei8_SYOggW_6uYvzhrF7Nae-9xOz-jmh9O9V8R8,5589
767
767
  tools/app_interface_metrics_exporter.py,sha256=mCi6SZf20mo5yvRI2VoqmrCdz46Ph3JhpEJPvryXncY,2261
768
- tools/app_interface_reporter.py,sha256=8pxjJTPOcMKlUVUqpafpDmvUEpeqMiKik7Eopoe-qtU,17204
768
+ tools/app_interface_reporter.py,sha256=m6zAtwIR0l388khSFyoytDSjyEoSg5fjXMAMA9KhCIU,17602
769
769
  tools/app_sre_tekton_access_reporter.py,sha256=5qmkevJdlb2j_lpGC5Pu1Pmo0eomX5ZxzS_GNkqHAEE,3104
770
770
  tools/app_sre_tekton_access_revalidation.py,sha256=vwL1o_j7oSTOhrHNH1znpgjA2LHGzb8yc5iG3aaY4m0,2684
771
771
  tools/glitchtip_access_reporter.py,sha256=wnaiDGW4MkYONV_erltnJ6nGkEj0kQrAiv04NNnOS0k,2859
772
772
  tools/glitchtip_access_revalidation.py,sha256=jjeLO53LTbz_LfQw3G2Cs8lVLO_6xqU39BYyTH3cEPE,2764
773
- tools/qontract_cli.py,sha256=S6TorZiixrXe1nd9m9QhP-uUS3_gOy45_y6wP7X0z80,159520
773
+ tools/qontract_cli.py,sha256=KyK2iCSh68cPolZygQtYb18ZtjIUlFw4aZT9D5p91kw,159892
774
774
  tools/template_validation.py,sha256=Xn9X4sGFznx-rvBDnq9Kq16rfET8V3bqH1EwavsGBac,3335
775
775
  tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
776
776
  tools/cli_commands/container_images_report.py,sha256=8mAjCS6XR0yD7k0mfiVBlt6xbYU47q_ftdYNi5o5VKE,5566
@@ -796,7 +796,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
796
796
  tools/saas_promotion_state/saas_promotion_state.py,sha256=uQv2QJAmUXP1g2GPIH30WTlvL9soY6m9lefpZEVDM5w,3965
797
797
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
798
798
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
799
- qontract_reconcile-0.10.2.dev294.dist-info/METADATA,sha256=5ZB0vx3CC7pReUDOAiLvr3MqYohLV2skk6DSZ6XQ_wE,24916
800
- qontract_reconcile-0.10.2.dev294.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
801
- qontract_reconcile-0.10.2.dev294.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
802
- qontract_reconcile-0.10.2.dev294.dist-info/RECORD,,
799
+ qontract_reconcile-0.10.2.dev295.dist-info/METADATA,sha256=b48r1FF0GwIfFEiB6y-etqnHajQ5GHIn079H9KABEys,24916
800
+ qontract_reconcile-0.10.2.dev295.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
801
+ qontract_reconcile-0.10.2.dev295.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
802
+ qontract_reconcile-0.10.2.dev295.dist-info/RECORD,,
@@ -90,16 +90,16 @@ def run(dry_run: bool, defer: Callable | None = None) -> None:
90
90
  )
91
91
  )
92
92
 
93
- for a in accounts_to_reset:
94
- if not a.reset_passwords:
93
+ for account_to_reset in accounts_to_reset:
94
+ if not account_to_reset.reset_passwords:
95
95
  continue
96
96
 
97
- with AWSApi(1, [a.account], settings=settings) as aws_api:
98
- for r in a.reset_passwords:
97
+ with AWSApi(1, [account_to_reset.account], settings=settings) as aws_api:
98
+ for r in account_to_reset.reset_passwords:
99
99
  user_name = r.user_name
100
100
  state_key = r.state_key
101
101
 
102
- account_name = a.account["name"]
102
+ account_name = account_to_reset.account["name"]
103
103
 
104
104
  logging.info(["reset_password", account_name, user_name])
105
105
 
@@ -1,8 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
  import logging
3
5
  import sys
4
- from collections.abc import Iterable, Mapping, MutableMapping
5
- from typing import Any
6
+ from typing import TYPE_CHECKING, Any
6
7
 
7
8
  from reconcile import queries
8
9
  from reconcile.status import ExitCodes
@@ -12,13 +13,16 @@ from reconcile.utils.ocm import (
12
13
  OCMMap,
13
14
  )
14
15
 
16
+ if TYPE_CHECKING:
17
+ from collections.abc import Iterable, Mapping, MutableMapping, Sequence
18
+
15
19
  QONTRACT_INTEGRATION = "ocm-additional-routers"
16
20
 
17
21
  SUPPORTED_OCM_PRODUCTS = [OCM_PRODUCT_OSD]
18
22
 
19
23
 
20
24
  def fetch_current_state(
21
- clusters: list[Mapping[str, Any]],
25
+ clusters: Sequence[Mapping[str, Any]],
22
26
  ) -> tuple[OCMMap, list[dict[str, Any]]]:
23
27
  settings = queries.get_app_interface_settings()
24
28
  ocm_map = OCMMap(
reconcile/queries.py CHANGED
@@ -25,7 +25,10 @@ SECRET_READER_SETTINGS = """
25
25
  def get_secret_reader_settings() -> Mapping[str, Any] | None:
26
26
  """Returns SecretReader settings"""
27
27
  gqlapi = gql.get_api()
28
- settings = gqlapi.query(SECRET_READER_SETTINGS)["settings"]
28
+ data = gqlapi.query(SECRET_READER_SETTINGS)
29
+ if not data:
30
+ return None
31
+ settings = data.get("settings")
29
32
  if settings:
30
33
  # assuming a single settings file for now
31
34
  return settings[0]
@@ -114,14 +117,13 @@ APP_INTERFACE_SETTINGS_QUERY = """
114
117
  """
115
118
 
116
119
 
117
- def get_app_interface_settings():
120
+ def get_app_interface_settings() -> dict[str, Any]:
118
121
  """Returns App Interface settings"""
119
122
  gqlapi = gql.get_api()
120
- settings = gqlapi.query(APP_INTERFACE_SETTINGS_QUERY)["settings"]
121
- if settings:
122
- # assuming a single settings file for now
123
- return settings[0]
124
- return None
123
+ data = gqlapi.query(APP_INTERFACE_SETTINGS_QUERY)
124
+ if not data or not (settings := data.get("settings")):
125
+ raise ValueError("no App Interface settings found")
126
+ return settings[0]
125
127
 
126
128
 
127
129
  CREDENTIALS_REQUESTS_QUERY = """
@@ -139,10 +141,13 @@ CREDENTIALS_REQUESTS_QUERY = """
139
141
  """
140
142
 
141
143
 
142
- def get_credentials_requests():
144
+ def get_credentials_requests() -> list[dict[str, Any]]:
143
145
  """Returns Credentials Requests resources defined in app-interface"""
144
146
  gqlapi = gql.get_api()
145
- return gqlapi.query(CREDENTIALS_REQUESTS_QUERY)["credentials_requests"]
147
+ data = gqlapi.query(CREDENTIALS_REQUESTS_QUERY)
148
+ if not data:
149
+ return []
150
+ return data.get("credentials_requests") or []
146
151
 
147
152
 
148
153
  JUMPHOST_FIELDS = """
@@ -252,11 +257,13 @@ INTEGRATIONS_QUERY = """
252
257
  """ % (indent(JUMPHOST_FIELDS, 12 * " "),)
253
258
 
254
259
 
255
- def get_integrations(managed=False):
260
+ def get_integrations(managed: bool = False) -> list[dict[str, Any]]:
256
261
  gqlapi = gql.get_api()
257
- if managed:
258
- return gqlapi.query(INTEGRATIONS_QUERY)["integrations"]
259
- return gqlapi.query(gql.INTEGRATIONS_QUERY)["integrations"]
262
+ query = INTEGRATIONS_QUERY if managed else gql.INTEGRATIONS_QUERY
263
+ data = gqlapi.query(query)
264
+ if not data:
265
+ return []
266
+ return data.get("integrations") or []
260
267
 
261
268
 
262
269
  JENKINS_INSTANCES_QUERY = """
@@ -326,16 +333,19 @@ JENKINS_INSTANCES_QUERY = """
326
333
  """
327
334
 
328
335
 
329
- def get_jenkins_instances(worker_fleets=False):
336
+ def get_jenkins_instances(worker_fleets: bool = False) -> list[dict[str, Any]]:
330
337
  """Returns a list of Jenkins instances"""
331
338
  gqlapi = gql.get_api()
332
339
  query = Template(JENKINS_INSTANCES_QUERY).render(worker_fleets=worker_fleets)
333
- return gqlapi.query(query)["instances"]
340
+ data = gqlapi.query(query)
341
+ if not data:
342
+ return []
343
+ return data.get("instances") or []
334
344
 
335
345
 
336
- def get_jenkins_instances_previous_urls():
346
+ def get_jenkins_instances_previous_urls() -> list[str]:
337
347
  instances = get_jenkins_instances()
338
- all_previous_urls = []
348
+ all_previous_urls: list[str] = []
339
349
  for instance in instances:
340
350
  previous_urls = instance.get("previousUrls")
341
351
  if previous_urls:
@@ -364,11 +374,13 @@ GITLAB_INSTANCES_QUERY = """
364
374
  """
365
375
 
366
376
 
367
- def get_gitlab_instance():
377
+ def get_gitlab_instance() -> dict[str, Any]:
368
378
  """Returns a single GitLab instance"""
369
379
  gqlapi = gql.get_api()
370
- # assuming a single GitLab instance for now
371
- return gqlapi.query(GITLAB_INSTANCES_QUERY)["instances"][0]
380
+ data = gqlapi.query(GITLAB_INSTANCES_QUERY)
381
+ if not data or not (instances := data.get("instances")):
382
+ raise ValueError("no GitLab instance found")
383
+ return instances[0]
372
384
 
373
385
 
374
386
  GITHUB_INSTANCE_QUERY = """
@@ -386,13 +398,16 @@ GITHUB_INSTANCE_QUERY = """
386
398
  """
387
399
 
388
400
 
389
- def get_github_instance():
401
+ def get_github_instance() -> dict[str, Any]:
390
402
  """Returns a single Github instance"""
391
403
  gqlapi = gql.get_api()
392
- instances = gqlapi.query(GITHUB_INSTANCE_QUERY)["instances"]
404
+ data = gqlapi.query(GITHUB_INSTANCE_QUERY)
405
+ if not data or not (instances := data.get("instances")):
406
+ raise ValueError("no Github instance found")
393
407
  for instance in instances:
394
408
  if instance["url"] == "https://github.com/app-sre":
395
409
  return instance
410
+ raise ValueError("no Github instance found")
396
411
 
397
412
 
398
413
  GITHUB_ORGS_QUERY = """
@@ -411,10 +426,13 @@ GITHUB_ORGS_QUERY = """
411
426
  """
412
427
 
413
428
 
414
- def get_github_orgs():
429
+ def get_github_orgs() -> list[dict[str, Any]]:
415
430
  """Returns all GitHub orgs"""
416
431
  gqlapi = gql.get_api()
417
- return gqlapi.query(GITHUB_ORGS_QUERY)["orgs"]
432
+ data = gqlapi.query(GITHUB_ORGS_QUERY)
433
+ if not data:
434
+ return []
435
+ return data.get("orgs") or []
418
436
 
419
437
 
420
438
  AWS_ACCOUNTS_QUERY = """
@@ -521,14 +539,14 @@ AWS_ACCOUNTS_QUERY = """
521
539
 
522
540
 
523
541
  def get_aws_accounts(
524
- reset_passwords=False,
525
- name=None,
526
- uid=None,
527
- sharing=False,
528
- terraform_state=False,
529
- ecrs=True,
530
- cleanup=False,
531
- ):
542
+ reset_passwords: bool = False,
543
+ name: str | None = None,
544
+ uid: str | None = None,
545
+ sharing: bool = False,
546
+ terraform_state: bool = False,
547
+ ecrs: bool = True,
548
+ cleanup: bool = False,
549
+ ) -> list[dict[str, Any]]:
532
550
  """Returns all AWS accounts"""
533
551
  gqlapi = gql.get_api()
534
552
  search = name or uid
@@ -542,16 +560,19 @@ def get_aws_accounts(
542
560
  ecrs=ecrs,
543
561
  cleanup=cleanup,
544
562
  )
545
- return gqlapi.query(query)["accounts"]
563
+ data = gqlapi.query(query)
564
+ if not data:
565
+ return []
566
+ return data.get("accounts") or []
546
567
 
547
568
 
548
- def get_state_aws_accounts(reset_passwords=False):
569
+ def get_state_aws_accounts(reset_passwords: bool = False) -> list[dict[str, Any]]:
549
570
  """Returns AWS accounts to use for state management"""
550
571
  name = os.environ["APP_INTERFACE_STATE_BUCKET_ACCOUNT"]
551
572
  return get_aws_accounts(reset_passwords=reset_passwords, name=name)
552
573
 
553
574
 
554
- def get_queue_aws_accounts():
575
+ def get_queue_aws_accounts() -> list[dict[str, Any]]:
555
576
  """Returns AWS accounts to use for queue management"""
556
577
  uid = os.environ["gitlab_pr_submitter_queue_url"].split("/")[3] # noqa: SIM112
557
578
  return get_aws_accounts(uid=uid)
@@ -987,7 +1008,9 @@ CLUSTERS_MINIMAL_QUERY = """
987
1008
  )
988
1009
 
989
1010
 
990
- def get_clusters(minimal: bool = False, aws_infrastructure_access: bool = False):
1011
+ def get_clusters(
1012
+ minimal: bool = False, aws_infrastructure_access: bool = False
1013
+ ) -> list[dict[str, Any]]:
991
1014
  """Returns all Clusters"""
992
1015
  gqlapi = gql.get_api()
993
1016
  tmpl = CLUSTERS_MINIMAL_QUERY if minimal else CLUSTERS_QUERY
@@ -995,7 +1018,10 @@ def get_clusters(minimal: bool = False, aws_infrastructure_access: bool = False)
995
1018
  filter=None,
996
1019
  aws_infrastructure_access=aws_infrastructure_access,
997
1020
  )
998
- return gqlapi.query(query)["clusters"]
1021
+ data = gqlapi.query(query)
1022
+ if not data:
1023
+ return []
1024
+ return data.get("clusters") or []
999
1025
 
1000
1026
 
1001
1027
  CLUSTER_PEERING_QUERY = """
@@ -1223,7 +1249,10 @@ CLUSTER_PEERING_QUERY = """
1223
1249
 
1224
1250
 
1225
1251
  def get_clusters_with_peering_settings() -> list[dict[str, Any]]:
1226
- clusters = gql.get_api().query(CLUSTER_PEERING_QUERY)["clusters"]
1252
+ data = gql.get_api().query(CLUSTER_PEERING_QUERY)
1253
+ if not data:
1254
+ return []
1255
+ clusters = data.get("clusters") or []
1227
1256
  return [c for c in clusters if c.get("peering") is not None]
1228
1257
 
1229
1258
 
@@ -1232,14 +1261,19 @@ class ClusterFilter:
1232
1261
  name: str = ""
1233
1262
 
1234
1263
 
1235
- def get_clusters_by(filter: ClusterFilter, minimal: bool = False) -> list[dict]:
1264
+ def get_clusters_by(
1265
+ filter: ClusterFilter, minimal: bool = False
1266
+ ) -> list[dict[str, Any]]:
1236
1267
  """Returns all Clusters fitting given filter"""
1237
1268
  gqlapi = gql.get_api()
1238
1269
  tmpl = CLUSTERS_MINIMAL_QUERY if minimal else CLUSTERS_QUERY
1239
1270
  query = Template(tmpl).render(
1240
1271
  filter=filter,
1241
1272
  )
1242
- return gqlapi.query(query)["clusters"]
1273
+ data = gqlapi.query(query)
1274
+ if not data:
1275
+ return []
1276
+ return data.get("clusters") or []
1243
1277
 
1244
1278
 
1245
1279
  OCM_QUERY = """
@@ -1352,7 +1386,10 @@ OCM_QUERY = """
1352
1386
 
1353
1387
 
1354
1388
  def get_openshift_cluster_managers() -> list[dict[str, Any]]:
1355
- return gql.get_api().query(OCM_QUERY)["instances"]
1389
+ data = gql.get_api().query(OCM_QUERY)
1390
+ if not data:
1391
+ return []
1392
+ return data.get("instances") or []
1356
1393
 
1357
1394
 
1358
1395
  NAMESPACES_QUERY = """
@@ -1510,12 +1547,14 @@ NAMESPACES_MINIMAL_QUERY = """
1510
1547
  """ % (indent(JUMPHOST_FIELDS, 8 * " "),)
1511
1548
 
1512
1549
 
1513
- def get_namespaces(minimal=False):
1550
+ def get_namespaces(minimal: bool = False) -> list[dict[str, Any]]:
1514
1551
  """Returns all Namespaces"""
1515
1552
  gqlapi = gql.get_api()
1516
- if minimal:
1517
- return gqlapi.query(NAMESPACES_MINIMAL_QUERY)["namespaces"]
1518
- return gqlapi.query(NAMESPACES_QUERY)["namespaces"]
1553
+ query = NAMESPACES_MINIMAL_QUERY if minimal else NAMESPACES_QUERY
1554
+ data = gqlapi.query(query)
1555
+ if not data:
1556
+ return []
1557
+ return data.get("namespaces") or []
1519
1558
 
1520
1559
 
1521
1560
  PRODUCTS_QUERY = """
@@ -1533,10 +1572,13 @@ PRODUCTS_QUERY = """
1533
1572
  """
1534
1573
 
1535
1574
 
1536
- def get_products():
1575
+ def get_products() -> list[dict[str, Any]]:
1537
1576
  """Returns all Products"""
1538
1577
  gqlapi = gql.get_api()
1539
- return gqlapi.query(PRODUCTS_QUERY)["products"]
1578
+ data = gqlapi.query(PRODUCTS_QUERY)
1579
+ if not data:
1580
+ return []
1581
+ return data.get("products") or []
1540
1582
 
1541
1583
 
1542
1584
  ENVIRONMENTS_QUERY = """
@@ -1562,10 +1604,13 @@ ENVIRONMENTS_QUERY = """
1562
1604
  """
1563
1605
 
1564
1606
 
1565
- def get_environments():
1607
+ def get_environments() -> list[dict[str, Any]]:
1566
1608
  """Returns all Products"""
1567
1609
  gqlapi = gql.get_api()
1568
- return gqlapi.query(ENVIRONMENTS_QUERY)["environments"]
1610
+ data = gqlapi.query(ENVIRONMENTS_QUERY)
1611
+ if not data:
1612
+ return []
1613
+ return data.get("environments") or []
1569
1614
 
1570
1615
 
1571
1616
  APPS_QUERY = """
@@ -1630,13 +1675,16 @@ CODE_COMPONENT_REPO_QUERY = """
1630
1675
  """
1631
1676
 
1632
1677
 
1633
- def get_apps():
1678
+ def get_apps() -> list[dict[str, Any]]:
1634
1679
  """Returns all Apps."""
1635
1680
  gqlapi = gql.get_api()
1636
- return gqlapi.query(APPS_QUERY)["apps"]
1681
+ data = gqlapi.query(APPS_QUERY)
1682
+ if not data:
1683
+ return []
1684
+ return data.get("apps") or []
1637
1685
 
1638
1686
 
1639
- def get_code_components():
1687
+ def get_code_components() -> list[dict[str, Any]]:
1640
1688
  """Returns code components from all apps."""
1641
1689
  apps = get_apps()
1642
1690
  code_components_lists = [
@@ -1646,13 +1694,13 @@ def get_code_components():
1646
1694
  return code_components
1647
1695
 
1648
1696
 
1649
- def get_review_repos():
1697
+ def get_review_repos() -> list[dict[str, str]]:
1650
1698
  """Returns name and url of code components marked for review"""
1651
1699
  code_components = get_code_components()
1652
1700
  return [
1653
1701
  {"url": c["url"], "name": c["name"]}
1654
1702
  for c in code_components
1655
- if c is not None and c["showInReviewQueue"] is not None
1703
+ if c["showInReviewQueue"] is not None
1656
1704
  ]
1657
1705
 
1658
1706
 
@@ -1661,7 +1709,10 @@ def get_repos(server: str = "", exclude_manage_permissions: bool = False) -> lis
1661
1709
  Optional arguments:
1662
1710
  server: url of the server to return. for example: https://github.com
1663
1711
  """
1664
- apps = gql.get_api().query(CODE_COMPONENT_REPO_QUERY)["apps"]
1712
+ data = gql.get_api().query(CODE_COMPONENT_REPO_QUERY)
1713
+ if not data:
1714
+ return []
1715
+ apps = data.get("apps") or []
1665
1716
  repos: list[str] = []
1666
1717
  for a in apps:
1667
1718
  if a["codeComponents"] is not None:
@@ -1673,7 +1724,7 @@ def get_repos(server: str = "", exclude_manage_permissions: bool = False) -> lis
1673
1724
  return repos
1674
1725
 
1675
1726
 
1676
- def get_repos_gitlab_owner(server=""):
1727
+ def get_repos_gitlab_owner(server: str = "") -> list[dict[str, Any]]:
1677
1728
  """Returns all repos defined under codeComponents that have gitlabOwner
1678
1729
  enabled.
1679
1730
  Optional arguments:
@@ -1689,7 +1740,7 @@ def get_repos_gitlab_owner(server=""):
1689
1740
  ]
1690
1741
 
1691
1742
 
1692
- def get_repos_gitlab_housekeeping(server=""):
1743
+ def get_repos_gitlab_housekeeping(server: str = "") -> list[dict[str, Any]]:
1693
1744
  """Returns all repos defined under codeComponents that have
1694
1745
  gitlabHousekeeping enabled.
1695
1746
  Optional arguments:
@@ -1705,7 +1756,7 @@ def get_repos_gitlab_housekeeping(server=""):
1705
1756
  ]
1706
1757
 
1707
1758
 
1708
- def get_repos_gitlab_jira(server=""):
1759
+ def get_repos_gitlab_jira(server: str = "") -> list[dict[str, Any]]:
1709
1760
  code_components = get_code_components()
1710
1761
  return [
1711
1762
  {"url": c["url"], "jira": c["jira"]}
@@ -1754,10 +1805,13 @@ QUAY_ORGS_QUERY = """
1754
1805
  """
1755
1806
 
1756
1807
 
1757
- def get_quay_orgs():
1808
+ def get_quay_orgs() -> list[dict[str, Any]]:
1758
1809
  """Returns all Quay orgs."""
1759
1810
  gqlapi = gql.get_api()
1760
- return gqlapi.query(QUAY_ORGS_QUERY)["quay_orgs"]
1811
+ data = gqlapi.query(QUAY_ORGS_QUERY)
1812
+ if not data:
1813
+ return []
1814
+ return data.get("quay_orgs") or []
1761
1815
 
1762
1816
 
1763
1817
  USERS_QUERY = """
@@ -1880,22 +1934,33 @@ ROLES_QUERY = """
1880
1934
  """
1881
1935
 
1882
1936
 
1883
- def get_roles(aws=True, saas_files=True, sendgrid=False, permissions=True):
1937
+ def get_roles(
1938
+ aws: bool = True,
1939
+ saas_files: bool = True,
1940
+ sendgrid: bool = False,
1941
+ permissions: bool = True,
1942
+ ) -> list[dict[str, Any]]:
1884
1943
  gqlapi = gql.get_api()
1885
1944
  query = Template(ROLES_QUERY).render(
1886
1945
  aws=aws, saas_files=saas_files, sendgrid=sendgrid, permissions=permissions
1887
1946
  )
1888
- return gqlapi.query(query)["users"]
1947
+ data = gqlapi.query(query)
1948
+ if not data:
1949
+ return []
1950
+ return data.get("users") or []
1889
1951
 
1890
1952
 
1891
- def get_users(refs=False):
1953
+ def get_users(refs: bool = False) -> list[dict[str, Any]]:
1892
1954
  """Returnes all Users."""
1893
1955
  gqlapi = gql.get_api()
1894
1956
  query = Template(USERS_QUERY).render(
1895
1957
  filter=None,
1896
1958
  refs=refs,
1897
1959
  )
1898
- return gqlapi.query(query)["users"]
1960
+ data = gqlapi.query(query)
1961
+ if not data:
1962
+ return []
1963
+ return data.get("users") or []
1899
1964
 
1900
1965
 
1901
1966
  @dataclass
@@ -1910,7 +1975,10 @@ def get_users_by(filter: UserFilter, refs: bool = False) -> list[dict[str, str]]
1910
1975
  filter=filter,
1911
1976
  refs=refs,
1912
1977
  )
1913
- return gqlapi.query(query)["users"]
1978
+ data = gqlapi.query(query)
1979
+ if not data:
1980
+ return []
1981
+ return data.get("users") or []
1914
1982
 
1915
1983
 
1916
1984
  BOTS_QUERY = """
@@ -1926,10 +1994,13 @@ BOTS_QUERY = """
1926
1994
  """
1927
1995
 
1928
1996
 
1929
- def get_bots():
1997
+ def get_bots() -> list[dict[str, Any]]:
1930
1998
  """Returnes all Bots."""
1931
1999
  gqlapi = gql.get_api()
1932
- return gqlapi.query(BOTS_QUERY)["bots"]
2000
+ data = gqlapi.query(BOTS_QUERY)
2001
+ if not data:
2002
+ return []
2003
+ return data.get("bots") or []
1933
2004
 
1934
2005
 
1935
2006
  EXTERNAL_USERS_QUERY = """
@@ -1943,10 +2014,13 @@ EXTERNAL_USERS_QUERY = """
1943
2014
  """
1944
2015
 
1945
2016
 
1946
- def get_external_users():
2017
+ def get_external_users() -> list[dict[str, Any]]:
1947
2018
  """Returnes all Users."""
1948
2019
  gqlapi = gql.get_api()
1949
- return gqlapi.query(EXTERNAL_USERS_QUERY)["external_users"]
2020
+ data = gqlapi.query(EXTERNAL_USERS_QUERY)
2021
+ if not data:
2022
+ return []
2023
+ return data.get("external_users") or []
1950
2024
 
1951
2025
 
1952
2026
  APP_INTERFACE_SQL_QUERIES_QUERY = """
@@ -2019,10 +2093,13 @@ APP_INTERFACE_SQL_QUERIES_QUERY = """
2019
2093
  """
2020
2094
 
2021
2095
 
2022
- def get_app_interface_sql_queries():
2096
+ def get_app_interface_sql_queries() -> list[dict[str, Any]]:
2023
2097
  """Returns SqlQuery resources defined in app-interface"""
2024
2098
  gqlapi = gql.get_api()
2025
- return gqlapi.query(APP_INTERFACE_SQL_QUERIES_QUERY)["sql_queries"]
2099
+ data = gqlapi.query(APP_INTERFACE_SQL_QUERIES_QUERY)
2100
+ if not data:
2101
+ return []
2102
+ return data.get("sql_queries") or []
2026
2103
 
2027
2104
 
2028
2105
  PIPELINES_PROVIDERS_QUERY = """
@@ -2121,10 +2198,13 @@ PIPELINES_PROVIDERS_QUERY = """
2121
2198
  """ % (indent(JUMPHOST_FIELDS, 12 * " "),)
2122
2199
 
2123
2200
 
2124
- def get_pipelines_providers():
2201
+ def get_pipelines_providers() -> list[dict[str, Any]]:
2125
2202
  """Returns PipelinesProvider resources defined in app-interface."""
2126
2203
  gqlapi = gql.get_api()
2127
- pipelines_providers = gqlapi.query(PIPELINES_PROVIDERS_QUERY)["pipelines_providers"]
2204
+ data = gqlapi.query(PIPELINES_PROVIDERS_QUERY)
2205
+ if not data:
2206
+ return []
2207
+ pipelines_providers = data.get("pipelines_providers") or []
2128
2208
 
2129
2209
  for pp in pipelines_providers:
2130
2210
  defaults = pp.pop("defaults")
@@ -2156,10 +2236,13 @@ JIRA_BOARDS_QUICK_QUERY = """
2156
2236
  """
2157
2237
 
2158
2238
 
2159
- def get_simple_jira_boards(app_path: str):
2239
+ def get_simple_jira_boards(app_path: str) -> list[dict[str, Any]]:
2160
2240
  gqlapi = gql.get_api()
2161
2241
  query = JIRA_BOARDS_QUICK_QUERY.replace("APATH", shlex.quote(app_path))
2162
- return gqlapi.query(query)["jira_boards"]
2242
+ data = gqlapi.query(query)
2243
+ if not data:
2244
+ return []
2245
+ return data.get("jira_boards") or []
2163
2246
 
2164
2247
 
2165
2248
  UNLEASH_INSTANCES_QUERY = """
@@ -2207,10 +2290,13 @@ UNLEASH_INSTANCES_QUERY = """
2207
2290
  """
2208
2291
 
2209
2292
 
2210
- def get_unleash_instances():
2293
+ def get_unleash_instances() -> list[dict[str, Any]]:
2211
2294
  """Returns Unleash instances defined in app-interface"""
2212
2295
  gqlapi = gql.get_api()
2213
- return gqlapi.query(UNLEASH_INSTANCES_QUERY)["unleash_instances"]
2296
+ data = gqlapi.query(UNLEASH_INSTANCES_QUERY)
2297
+ if not data:
2298
+ return []
2299
+ return data.get("unleash_instances") or []
2214
2300
 
2215
2301
 
2216
2302
  DNS_RECORD = """
@@ -2304,12 +2390,15 @@ DNS_ZONES_QUERY = """
2304
2390
  """ % (indent(DNS_RECORD, 6 * " "),)
2305
2391
 
2306
2392
 
2307
- def get_dns_zones(account_name=None):
2393
+ def get_dns_zones(account_name: str | None = None) -> list[dict[str, Any]]:
2308
2394
  """Returnes all AWS Route53 DNS Zones."""
2309
2395
  gqlapi = gql.get_api()
2310
- zones = gqlapi.query(DNS_ZONES_QUERY)["zones"]
2396
+ data = gqlapi.query(DNS_ZONES_QUERY)
2397
+ if not data:
2398
+ return []
2399
+ zones = data.get("zones") or []
2311
2400
  if account_name:
2312
- zones = [z for z in zones if z["account"]["name"] == account_name]
2401
+ zones = [z for z in zones if z.get("account", {}).get("name") == account_name]
2313
2402
 
2314
2403
  return zones
2315
2404
 
@@ -2345,13 +2434,16 @@ SLACK_WORKSPACES_QUERY = """
2345
2434
  """
2346
2435
 
2347
2436
 
2348
- def get_slack_workspace():
2437
+ def get_slack_workspace() -> dict[str, Any] | None:
2349
2438
  """Returns a single Slack workspace"""
2350
2439
  gqlapi = gql.get_api()
2351
- slack_workspaces = gqlapi.query(SLACK_WORKSPACES_QUERY)["slack_workspaces"]
2352
- if len(slack_workspaces) != 1:
2440
+ data = gqlapi.query(SLACK_WORKSPACES_QUERY)
2441
+ if not data:
2442
+ return None
2443
+ slack_workspaces = data.get("slack_workspaces") or []
2444
+ if len(slack_workspaces) > 1:
2353
2445
  logging.warning("multiple Slack workspaces found.")
2354
- return slack_workspaces[0]
2446
+ return slack_workspaces[0] if slack_workspaces else None
2355
2447
 
2356
2448
 
2357
2449
  SENDGRID_ACCOUNTS_QUERY = """
@@ -2370,10 +2462,13 @@ SENDGRID_ACCOUNTS_QUERY = """
2370
2462
  """
2371
2463
 
2372
2464
 
2373
- def get_sendgrid_accounts():
2465
+ def get_sendgrid_accounts() -> list[dict[str, Any]]:
2374
2466
  """Returns SendGrid accounts"""
2375
2467
  gqlapi = gql.get_api()
2376
- return gqlapi.query(SENDGRID_ACCOUNTS_QUERY)["sendgrid_accounts"]
2468
+ data = gqlapi.query(SENDGRID_ACCOUNTS_QUERY)
2469
+ if not data:
2470
+ return []
2471
+ return data.get("sendgrid_accounts") or []
2377
2472
 
2378
2473
 
2379
2474
  QUAY_REPOS_QUERY = """
@@ -2408,9 +2503,12 @@ QUAY_REPOS_QUERY = """
2408
2503
  """
2409
2504
 
2410
2505
 
2411
- def get_quay_repos():
2506
+ def get_quay_repos() -> list[dict[str, Any]]:
2412
2507
  gqlapi = gql.get_api()
2413
- return gqlapi.query(QUAY_REPOS_QUERY)["apps"]
2508
+ data = gqlapi.query(QUAY_REPOS_QUERY)
2509
+ if not data:
2510
+ return []
2511
+ return data.get("apps") or []
2414
2512
 
2415
2513
 
2416
2514
  SRE_CHECKPOINTS_QUERY = """
@@ -2426,9 +2524,12 @@ SRE_CHECKPOINTS_QUERY = """
2426
2524
  """
2427
2525
 
2428
2526
 
2429
- def get_sre_checkpoints():
2527
+ def get_sre_checkpoints() -> list[dict[str, Any]]:
2430
2528
  gqlapi = gql.get_api()
2431
- return gqlapi.query(SRE_CHECKPOINTS_QUERY)["sre_checkpoints"]
2529
+ data = gqlapi.query(SRE_CHECKPOINTS_QUERY)
2530
+ if not data:
2531
+ return []
2532
+ return data.get("sre_checkpoints") or []
2432
2533
 
2433
2534
 
2434
2535
  GABI_INSTANCES_QUERY = """
@@ -2490,9 +2591,12 @@ GABI_INSTANCES_QUERY = """
2490
2591
  """ % (indent(JUMPHOST_FIELDS, 12 * " "),)
2491
2592
 
2492
2593
 
2493
- def get_gabi_instances():
2594
+ def get_gabi_instances() -> list[dict[str, Any]]:
2494
2595
  gqlapi = gql.get_api()
2495
- return gqlapi.query(GABI_INSTANCES_QUERY)["gabi_instances"]
2596
+ data = gqlapi.query(GABI_INSTANCES_QUERY)
2597
+ if not data:
2598
+ return []
2599
+ return data.get("gabi_instances") or []
2496
2600
 
2497
2601
 
2498
2602
  CLOSED_BOX_MONITORING_PROBES_QUERY = """
@@ -2556,9 +2660,12 @@ CLOSED_BOX_MONITORING_PROBES_QUERY = """
2556
2660
  """
2557
2661
 
2558
2662
 
2559
- def get_service_monitoring_endpoints():
2663
+ def get_service_monitoring_endpoints() -> list[dict[str, Any]]:
2560
2664
  gqlapi = gql.get_api()
2561
- return gqlapi.query(CLOSED_BOX_MONITORING_PROBES_QUERY)["apps"]
2665
+ data = gqlapi.query(CLOSED_BOX_MONITORING_PROBES_QUERY)
2666
+ if not data:
2667
+ return []
2668
+ return data.get("apps") or []
2562
2669
 
2563
2670
 
2564
2671
  # Use APATH as place holder because query strings have a lot of curly
@@ -2606,7 +2713,10 @@ def get_app_metadata(app_path: str) -> dict:
2606
2713
  """Fetch the metadata for the path stored in app_path."""
2607
2714
  app_query = APP_METADATA.replace("APATH", shlex.quote(app_path))
2608
2715
  gqlapi = gql.get_api()
2609
- return gqlapi.query(app_query)["apps"]
2716
+ data = gqlapi.query(app_query)
2717
+ if not data:
2718
+ return {}
2719
+ return data.get("apps", {})
2610
2720
 
2611
2721
 
2612
2722
  BLACKBOX_EXPORTER_MONITORING_PROVIDER = """
@@ -2631,7 +2741,10 @@ BLACKBOX_EXPORTER_MONITORING_PROVIDER = """
2631
2741
 
2632
2742
  def get_blackbox_exporter_monitoring_provider() -> dict:
2633
2743
  gqlapi = gql.get_api()
2634
- return gqlapi.query(BLACKBOX_EXPORTER_MONITORING_PROVIDER)["providers"]
2744
+ data = gqlapi.query(BLACKBOX_EXPORTER_MONITORING_PROVIDER)
2745
+ if not data:
2746
+ return {}
2747
+ return data.get("providers", {})
2635
2748
 
2636
2749
 
2637
2750
  JENKINS_CONFIGS = """
@@ -2662,9 +2775,12 @@ JENKINS_CONFIGS = """
2662
2775
  """
2663
2776
 
2664
2777
 
2665
- def get_jenkins_configs():
2778
+ def get_jenkins_configs() -> list[dict[str, Any]]:
2666
2779
  gqlapi = gql.get_api()
2667
- return gqlapi.query(JENKINS_CONFIGS)["jenkins_configs"]
2780
+ data = gqlapi.query(JENKINS_CONFIGS)
2781
+ if not data:
2782
+ return []
2783
+ return data.get("jenkins_configs") or []
2668
2784
 
2669
2785
 
2670
2786
  TF_RESOURCES_PROVIDER_EXCLUSIONS_BY_PROVISIONER = """
@@ -2686,10 +2802,15 @@ def get_tf_resources_provider_exclusions_by_provisioner() -> (
2686
2802
  list[dict[str, Any]] | None
2687
2803
  ):
2688
2804
  gqlapi = gql.get_api()
2689
- settings = gqlapi.query(TF_RESOURCES_PROVIDER_EXCLUSIONS_BY_PROVISIONER)[
2690
- "tf_provider_exclusions"
2691
- ]
2692
- if len(settings) == 1 and "terraformResourcesProviderExclusions" in settings[0]:
2805
+ data = gqlapi.query(TF_RESOURCES_PROVIDER_EXCLUSIONS_BY_PROVISIONER)
2806
+ if not data:
2807
+ return None
2808
+ settings = data.get("tf_provider_exclusions")
2809
+ if (
2810
+ settings
2811
+ and len(settings) == 1
2812
+ and "terraformResourcesProviderExclusions" in settings[0]
2813
+ ):
2693
2814
  return settings[0]["terraformResourcesProviderExclusions"]
2694
2815
  return None
2695
2816
 
@@ -2719,4 +2840,7 @@ SCHEMAS_QUERY = """
2719
2840
  # TODO: replace with typed query following https://issues.redhat.com/browse/APPSRE-10983
2720
2841
  def get_schemas() -> dict:
2721
2842
  gqlapi = gql.get_api()
2722
- return gqlapi.query(SCHEMAS_QUERY)["schemas"]
2843
+ data = gqlapi.query(SCHEMAS_QUERY)
2844
+ if not data:
2845
+ return {}
2846
+ return data.get("schemas", {})
@@ -403,7 +403,7 @@ class OCM:
403
403
  api = (
404
404
  f"{CS_API_BASE}/v1/clusters/{cluster_id}" + "/external_configuration/labels"
405
405
  )
406
- items = self._get_json(api).get("items")
406
+ items = self._get_json(api).get("items", [])
407
407
  item = [item for item in items if label.items() <= item.items()]
408
408
  if not item:
409
409
  return
@@ -597,14 +597,14 @@ class OCM:
597
597
  def _init_addons(self):
598
598
  """Returns a list of Addons"""
599
599
  api = f"{CS_API_BASE}/v1/addons"
600
- self.addons = self._get_json(api).get("items")
600
+ self.addons = self._get_json(api).get("items", [])
601
601
 
602
602
  def _init_version_gates(self):
603
603
  """Returns a list of version gates"""
604
604
  if self.version_gates:
605
605
  return
606
606
  api = f"{CS_API_BASE}/v1/version_gates"
607
- self.version_gates = self._get_json(api).get("items")
607
+ self.version_gates = self._get_json(api).get("items", [])
608
608
 
609
609
  def get_addon(self, id):
610
610
  for addon in self.addons:
@@ -275,17 +275,17 @@ def get_apps_data(
275
275
  cluster = sample.labels["cluster"]
276
276
  if app_namespace["cluster"]["name"] != cluster:
277
277
  continue
278
- namespace = sample.labels["namespace"]
279
- if app_namespace["name"] != namespace:
278
+ sample_namespace = sample.labels["namespace"]
279
+ if app_namespace["name"] != sample_namespace:
280
280
  continue
281
281
  severity = sample.labels["severity"]
282
282
  if cluster not in vuln_mx:
283
283
  vuln_mx[cluster] = {}
284
- if namespace not in vuln_mx[cluster]:
285
- vuln_mx[cluster][namespace] = {}
286
- if severity not in vuln_mx[cluster][namespace]:
284
+ if sample_namespace not in vuln_mx[cluster]:
285
+ vuln_mx[cluster][sample_namespace] = {}
286
+ if severity not in vuln_mx[cluster][sample_namespace]:
287
287
  value = int(sample.value)
288
- vuln_mx[cluster][namespace][severity] = value
288
+ vuln_mx[cluster][sample_namespace][severity] = value
289
289
  for family in text_string_to_metric_families(validt_metrics):
290
290
  for sample in family.samples:
291
291
  if sample.name == "deploymentvalidation_total":
@@ -293,8 +293,8 @@ def get_apps_data(
293
293
  cluster = sample.labels["cluster"]
294
294
  if app_namespace["cluster"]["name"] != cluster:
295
295
  continue
296
- namespace = sample.labels["namespace"]
297
- if app_namespace["name"] != namespace:
296
+ sample_namespace = sample.labels["namespace"]
297
+ if app_namespace["name"] != sample_namespace:
298
298
  continue
299
299
  validation = sample.labels["validation"]
300
300
  # dvo: fail == 1, pass == 0, py: true == 1, false == 0
@@ -302,14 +302,19 @@ def get_apps_data(
302
302
  status = ("Passed", "Failed")[int(sample.labels["status"])]
303
303
  if cluster not in validt_mx:
304
304
  validt_mx[cluster] = {}
305
- if namespace not in validt_mx[cluster]:
306
- validt_mx[cluster][namespace] = {}
307
- if validation not in validt_mx[cluster][namespace]:
308
- validt_mx[cluster][namespace][validation] = {}
309
- if status not in validt_mx[cluster][namespace][validation]:
310
- validt_mx[cluster][namespace][validation][status] = {}
305
+ if sample_namespace not in validt_mx[cluster]:
306
+ validt_mx[cluster][sample_namespace] = {}
307
+ if validation not in validt_mx[cluster][sample_namespace]:
308
+ validt_mx[cluster][sample_namespace][validation] = {}
309
+ if (
310
+ status
311
+ not in validt_mx[cluster][sample_namespace][validation]
312
+ ):
313
+ validt_mx[cluster][sample_namespace][validation][
314
+ status
315
+ ] = {}
311
316
  value = int(sample.value)
312
- validt_mx[cluster][namespace][validation][status] = value
317
+ validt_mx[cluster][sample_namespace][validation][status] = value
313
318
  for family in text_string_to_metric_families(slo_metrics):
314
319
  for sample in family.samples:
315
320
  if sample.name == "serviceslometrics":
@@ -317,25 +322,28 @@ def get_apps_data(
317
322
  cluster = sample.labels["cluster"]
318
323
  if app_namespace["cluster"]["name"] != cluster:
319
324
  continue
320
- namespace = sample.labels["namespace"]
321
- if app_namespace["name"] != namespace:
325
+ sample_namespace = sample.labels["namespace"]
326
+ if app_namespace["name"] != sample_namespace:
322
327
  continue
323
328
  slo_doc_name = sample.labels["slodoc"]
324
329
  slo_name = sample.labels["name"]
325
330
  if cluster not in slo_mx:
326
331
  slo_mx[cluster] = {}
327
- if namespace not in slo_mx[cluster]:
328
- slo_mx[cluster][namespace] = {}
329
- if slo_doc_name not in slo_mx[cluster][namespace]:
330
- slo_mx[cluster][namespace][slo_doc_name] = {}
331
- if slo_name not in slo_mx[cluster][namespace][slo_doc_name]:
332
- slo_mx[cluster][namespace][slo_doc_name][slo_name] = {
333
- sample.labels["type"]: sample.value
334
- }
332
+ if sample_namespace not in slo_mx[cluster]:
333
+ slo_mx[cluster][sample_namespace] = {}
334
+ if slo_doc_name not in slo_mx[cluster][sample_namespace]:
335
+ slo_mx[cluster][sample_namespace][slo_doc_name] = {}
336
+ if (
337
+ slo_name
338
+ not in slo_mx[cluster][sample_namespace][slo_doc_name]
339
+ ):
340
+ slo_mx[cluster][sample_namespace][slo_doc_name][
341
+ slo_name
342
+ ] = {sample.labels["type"]: sample.value}
335
343
  else:
336
- slo_mx[cluster][namespace][slo_doc_name][slo_name].update({
337
- sample.labels["type"]: sample.value
338
- })
344
+ slo_mx[cluster][sample_namespace][slo_doc_name][
345
+ slo_name
346
+ ].update({sample.labels["type"]: sample.value})
339
347
  app["container_vulnerabilities"] = vuln_mx
340
348
  app["deployment_validations"] = validt_mx
341
349
  app["service_slo"] = slo_mx
tools/qontract_cli.py CHANGED
@@ -1715,7 +1715,10 @@ def add_resource(item: dict, resource: Mapping, columns: list[str]) -> None:
1715
1715
  @click.pass_context
1716
1716
  def cluster_openshift_resources(ctx: click.Context) -> None:
1717
1717
  gqlapi = gql.get_api()
1718
- namespaces = gqlapi.query(orb.NAMESPACES_QUERY)["namespaces"]
1718
+ data = gqlapi.query(orb.NAMESPACES_QUERY)
1719
+ if not data:
1720
+ raise ValueError("no namespaces found")
1721
+ namespaces = data.get("namespaces", [])
1719
1722
  columns = ["name", "total"]
1720
1723
  results: dict = {}
1721
1724
  for ns_info in namespaces:
@@ -1912,6 +1915,7 @@ def rds_recommendations(ctx: click.Context) -> None:
1912
1915
  print("[TOC]")
1913
1916
  for account in accounts:
1914
1917
  account_name = account.get("name")
1918
+ assert account_name is not None # make mypy happy
1915
1919
  account_deployment_regions = account.get("supportedDeploymentRegions")
1916
1920
  for region in account_deployment_regions or []:
1917
1921
  with AWSApi(1, [account], settings=settings, init_users=False) as aws:
@@ -1926,9 +1930,9 @@ def rds_recommendations(ctx: click.Context) -> None:
1926
1930
  recommendations = [
1927
1931
  {
1928
1932
  **rec,
1929
- "ResourceName": rec["ResourceArn"].split(":")[-1],
1933
+ "ResourceName": rec.get("ResourceArn", "").split(":")[-1],
1930
1934
  # The Description field has \n that are causing issues with the markdown table
1931
- "Description": rec["Description"].replace("\n", " "),
1935
+ "Description": rec.get("Description", "").replace("\n", " "),
1932
1936
  }
1933
1937
  for rec in db_recommendations
1934
1938
  if rec.get("Status") not in ignored_statuses
@@ -2710,16 +2714,16 @@ def ec2_jenkins_workers(
2710
2714
  )
2711
2715
  continue
2712
2716
  instance = ec2.Instance(i["InstanceId"])
2713
- state = instance.state["Name"]
2717
+ state = instance.state.get("Name")
2714
2718
  if state != "running":
2715
2719
  continue
2716
2720
  os = ""
2717
2721
  url = ""
2718
2722
  for t in instance.tags:
2719
2723
  if t.get("Key") == "os":
2720
- os = t["Value"]
2724
+ os = t.get("Value", "")
2721
2725
  if t.get("Key") == "jenkins_controller":
2722
- url = f"https://{t['Value'].replace('-', '.')}.devshift.net/computer/{instance.id}"
2726
+ url = f"https://{t.get('Value', '').replace('-', '.')}.devshift.net/computer/{instance.id}"
2723
2727
  image = ec2.Image(instance.image_id)
2724
2728
  commit_url = ""
2725
2729
  for t in image.tags:
@@ -3633,7 +3637,10 @@ def template(
3633
3637
  secret_reader: str,
3634
3638
  ) -> None:
3635
3639
  gqlapi = gql.get_api()
3636
- namespaces = gqlapi.query(orb.NAMESPACES_QUERY)["namespaces"]
3640
+ data = gqlapi.query(orb.NAMESPACES_QUERY)
3641
+ if not data:
3642
+ raise ValueError("no namespaces found")
3643
+ namespaces = data.get("namespaces", [])
3637
3644
  namespaces_info = [
3638
3645
  n
3639
3646
  for n in namespaces
@@ -3725,7 +3732,7 @@ def run_prometheus_test(
3725
3732
  ptr.run_test(test=test, alerting_services=get_alerting_services())
3726
3733
 
3727
3734
  print(test.result)
3728
- if not test.result:
3735
+ if test.result is None:
3729
3736
  sys.exit(1)
3730
3737
 
3731
3738
 
@@ -3804,7 +3811,10 @@ def alert_to_receiver(
3804
3811
  additional_labels[key] = value
3805
3812
 
3806
3813
  gqlapi = gql.get_api()
3807
- namespaces = gqlapi.query(orb.NAMESPACES_QUERY)["namespaces"]
3814
+ data = gqlapi.query(orb.NAMESPACES_QUERY)
3815
+ if not data:
3816
+ raise ValueError("no namespaces found")
3817
+ namespaces = data.get("namespaces", [])
3808
3818
  cluster_namespaces = [n for n in namespaces if n["cluster"]["name"] == cluster]
3809
3819
 
3810
3820
  if len(cluster_namespaces) == 0:
@@ -4027,15 +4037,16 @@ def query(output: str, query: str) -> None:
4027
4037
  def promquery(cluster: str, query: str) -> None:
4028
4038
  """Run a PromQL query"""
4029
4039
  config_data = config.get_config()
4030
- auth = {"path": config_data["promql-auth"]["secret_path"], "field": "token"}
4040
+ prom_auth = {"path": config_data["promql-auth"]["secret_path"], "field": "token"}
4031
4041
  settings = queries.get_app_interface_settings()
4032
4042
  secret_reader = SecretReader(settings=settings)
4033
- prom_auth_creds = secret_reader.read(auth)
4034
- prom_auth = requests.auth.HTTPBasicAuth(*prom_auth_creds.split(":"))
4043
+ prom_user, prom_pass = secret_reader.read(prom_auth).split(":")
4035
4044
 
4036
4045
  url = f"https://prometheus.{cluster}.devshift.net/api/v1/query"
4037
4046
 
4038
- response = requests.get(url, params={"query": query}, auth=prom_auth, timeout=60)
4047
+ response = requests.get(
4048
+ url, params={"query": query}, auth=(prom_user, prom_pass), timeout=60
4049
+ )
4039
4050
  response.raise_for_status()
4040
4051
 
4041
4052
  print(json.dumps(response.json(), indent=4))
@@ -4092,11 +4103,12 @@ def sre_checkpoint_metadata(
4092
4103
  board_info = queries.get_simple_jira_boards(jiradef)
4093
4104
  else:
4094
4105
  board_info = app["escalationPolicy"]["channels"]["jiraBoard"]
4095
- board_info = board_info[0]
4106
+ assert board_info # make mypy happy
4107
+ board = board_info[0]
4096
4108
  # Overrides for easier testing
4097
4109
  if jiraboard:
4098
- board_info["name"] = jiraboard
4099
- report_invalid_metadata(app, app_path, board_info, settings, parent_ticket, dry_run)
4110
+ board["name"] = jiraboard
4111
+ report_invalid_metadata(app, app_path, board, settings, parent_ticket, dry_run)
4100
4112
 
4101
4113
 
4102
4114
  @root.command()