qontract-reconcile 0.10.2.dev253__py3-none-any.whl → 0.10.2.dev255__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.dev253
3
+ Version: 0.10.2.dev255
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
@@ -117,11 +117,11 @@ reconcile/vpc_peerings_validator.py,sha256=aESqrhm1tpkc2iqSL1UV5to_HjNgjRSffD0cr
117
117
  reconcile/aus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
118
  reconcile/aus/advanced_upgrade_service.py,sha256=lt684trHbKvVDLwwuNVz3Wu_MnytFSbS_7MZTIITh9k,23969
119
119
  reconcile/aus/aus_label_source.py,sha256=o0S2f0qwcII_8nzhHZhRQ83gEZ1DrSXyO4xzSwLebuU,4382
120
- reconcile/aus/base.py,sha256=Kicj39qfAlINywfk0Legu7RUcUxI4AuoBhA8vJ1gWag,51343
120
+ reconcile/aus/base.py,sha256=bMbMJ0KS5J0A9jJky3ZCeU5XHL8jT4UE4X-X_H_rMM4,51465
121
121
  reconcile/aus/cluster_version_data.py,sha256=VZWbUEIbrDKO-sroMpQtiWCTqDraTMd8tssKV0HyTQ0,7140
122
122
  reconcile/aus/healthchecks.py,sha256=jR9c-syh9impnkV0fd6XW3Bnk7iRN5zv8oCRYM-yIRY,2700
123
123
  reconcile/aus/metrics.py,sha256=qh3-oWL8-Hbj1uXgAKonw7sVXGBlPpCyHtVYJusZ9n8,4271
124
- reconcile/aus/models.py,sha256=qLjWLDJe5PGXPPtJ5PI01IVEYaSGweu9dkAgf0ZM2hk,8297
124
+ reconcile/aus/models.py,sha256=flK15hzE2wX67yUmNtQsnjOkipQazuV67emeQNyZ1Zo,8591
125
125
  reconcile/aus/node_pool_spec.py,sha256=FkMggklG-4BgQwud2Swp2m3AAAKzZmeaXgohl9uwxZ8,1138
126
126
  reconcile/aus/ocm_addons_upgrade_scheduler_org.py,sha256=PL8QdzWh8lhGneMwSbIYxOp002mJd5gHf_T0Q2cWQho,10350
127
127
  reconcile/aus/ocm_upgrade_scheduler.py,sha256=WPIUUr3n3j-ZtyE3DgsPKzBJ3Dm9i1PSHBRepAf6CF4,3783
@@ -608,7 +608,7 @@ reconcile/utils/git.py,sha256=o4p9m8jlzCJDcutl2HErvGLhL6sZ1NB4Aw3zGcQIzso,2427
608
608
  reconcile/utils/github_api.py,sha256=S1vO-hvYPzm5BIychVIHSYibMns0HBmLgS78MkPfunE,3402
609
609
  reconcile/utils/gitlab_api.py,sha256=0wJObojbXXk8Cgh8ymNWlwD1CdENmpsMo1zDSTddnoE,28335
610
610
  reconcile/utils/gpg.py,sha256=EKG7_fdMv8BMlV5yUdPiqoTx-KrzmVSEAl2sLkaKwWI,1123
611
- reconcile/utils/gql.py,sha256=C0thIm_k9MBldfqwHzyqtYZk9sIvMdm9IbbnXLGwjD8,14158
611
+ reconcile/utils/gql.py,sha256=a1SXvhqqfmFpf9dNwGxnp_6ryvhOwm_kIaFwzJmQQDQ,14683
612
612
  reconcile/utils/grouping.py,sha256=vr9SFHZ7bqmHYrvYcEZt-Er3-yQYfAAdq5sHLZVmXPY,456
613
613
  reconcile/utils/helm.py,sha256=wC1h0GylhDFeZ6hZEtYy2giAGIIQroaQhkAtURoSlI8,3893
614
614
  reconcile/utils/helpers.py,sha256=koyAtYnxsUVx-HIn6GpedcUE-ekz_VtoYDkiZ0iv8ik,1795
@@ -736,7 +736,7 @@ reconcile/utils/ocm/sre_capability_labels.py,sha256=nqh0imrYczNeeeC7ZNX3pEwuAIVk
736
736
  reconcile/utils/ocm/status_board.py,sha256=8DYeIrOsW8Bh5PCtKdvGGpaxb9Wugcc5rLxZJ8Z7b_s,4181
737
737
  reconcile/utils/ocm/subscriptions.py,sha256=hehKXsDXIhnhqvWOuiYvx6y2FGq3zt0APGYj7WiBIdI,2765
738
738
  reconcile/utils/ocm/syncsets.py,sha256=9IQm1l5BodOVZa2OFbQmow3afmh4nXe5pn-CCJ5LxTI,1169
739
- reconcile/utils/ocm/upgrades.py,sha256=Hs3R9pkl5GoFgSyF7ZYhqG1gXOBCSGPL_ymDYAT3jXA,4804
739
+ reconcile/utils/ocm/upgrades.py,sha256=UEgfSJuC8nH6jW9JjEx91_9QeeHR1UJ_9FVOX_PlvTU,4712
740
740
  reconcile/utils/rosa/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
741
741
  reconcile/utils/rosa/rosa_cli.py,sha256=bdr0fK8ARUxipLVTHehnCTxc6Kcgr8fV6k5I8FsDIhM,11335
742
742
  reconcile/utils/rosa/session.py,sha256=FkhB2vS2Ke6WhZlzm-DWXd6pqD_PgrUJujdO9Nt4vJI,6869
@@ -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=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
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.dev253.dist-info/METADATA,sha256=ghSbJj_ZdorkczmUZ05_9XdRhcny42vKQTZG9syekoM,23820
800
- qontract_reconcile-0.10.2.dev253.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
801
- qontract_reconcile-0.10.2.dev253.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
802
- qontract_reconcile-0.10.2.dev253.dist-info/RECORD,,
799
+ qontract_reconcile-0.10.2.dev255.dist-info/METADATA,sha256=o_zpsOZUysndjUn1lN3Sv7LKSNdPT0CVKbWcdLPy6gY,23820
800
+ qontract_reconcile-0.10.2.dev255.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
801
+ qontract_reconcile-0.10.2.dev255.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
802
+ qontract_reconcile-0.10.2.dev255.dist-info/RECORD,,
reconcile/aus/base.py CHANGED
@@ -606,21 +606,27 @@ def fetch_current_state(
606
606
  ocm_api, spec.cluster.id
607
607
  )
608
608
  for upgrade_policy in upgrade_policies:
609
- upgrade_policy["cluster"] = spec.cluster
610
- current_state.append(ControlPlaneUpgradePolicy(**upgrade_policy))
609
+ policy = upgrade_policy | {
610
+ "cluster": spec.cluster,
611
+ }
612
+ current_state.append(ControlPlaneUpgradePolicy(**policy))
611
613
  for node_pool in spec.node_pools:
612
614
  node_upgrade_policies = get_node_pool_upgrade_policies(
613
615
  ocm_api, spec.cluster.id, node_pool.id
614
616
  )
615
617
  for upgrade_policy in node_upgrade_policies:
616
- upgrade_policy["cluster"] = spec.cluster
617
- upgrade_policy["node_pool"] = node_pool.id
618
- current_state.append(NodePoolUpgradePolicy(**upgrade_policy))
618
+ policy = upgrade_policy | {
619
+ "cluster": spec.cluster,
620
+ "node_pool": node_pool.id,
621
+ }
622
+ current_state.append(NodePoolUpgradePolicy(**policy))
619
623
  else:
620
624
  upgrade_policies = get_upgrade_policies(ocm_api, spec.cluster.id)
621
625
  for upgrade_policy in upgrade_policies:
622
- upgrade_policy["cluster"] = spec.cluster
623
- current_state.append(ClusterUpgradePolicy(**upgrade_policy))
626
+ policy = upgrade_policy | {
627
+ "cluster": spec.cluster,
628
+ }
629
+ current_state.append(ClusterUpgradePolicy(**policy))
624
630
 
625
631
  return current_state
626
632
 
reconcile/aus/models.py CHANGED
@@ -68,7 +68,13 @@ class ClusterUpgradeSpec(BaseModel):
68
68
  return any(re.search(b, version) for b in self.blocked_versions)
69
69
 
70
70
  def get_available_upgrades(self) -> list[str]:
71
- return self.cluster.available_upgrades()
71
+ cluster_available_upgrades = self.cluster.available_upgrades()
72
+ if (
73
+ self.oldest_current_version != self.current_version
74
+ and self.current_version not in cluster_available_upgrades
75
+ ):
76
+ return [self.current_version, *cluster_available_upgrades]
77
+ return cluster_available_upgrades
72
78
 
73
79
  @property
74
80
  def effective_mutexes(self) -> set[str]:
reconcile/utils/gql.py CHANGED
@@ -7,7 +7,7 @@ from datetime import (
7
7
  datetime,
8
8
  )
9
9
  from typing import Any
10
- from urllib.parse import urlparse
10
+ from urllib.parse import ParseResult, urlparse
11
11
 
12
12
  import requests
13
13
  from gql import (
@@ -38,7 +38,7 @@ INTEGRATIONS_QUERY = """
38
38
  requests_logger.setLevel(logging.WARNING)
39
39
 
40
40
 
41
- def capture_and_forget(error):
41
+ def capture_and_forget(error: BaseException) -> None:
42
42
  """fire-and-forget an exception to sentry
43
43
 
44
44
  :param error: exception to be captured and sent to sentry
@@ -54,7 +54,7 @@ class GqlApiError(Exception):
54
54
 
55
55
 
56
56
  class GqlApiIntegrationNotFound(Exception):
57
- def __init__(self, integration):
57
+ def __init__(self, integration: str):
58
58
  msg = f"""
59
59
  Integration not found: {integration}
60
60
 
@@ -65,7 +65,7 @@ class GqlApiIntegrationNotFound(Exception):
65
65
 
66
66
 
67
67
  class GqlApiErrorForbiddenSchema(Exception):
68
- def __init__(self, schemas):
68
+ def __init__(self, schemas: list):
69
69
  msg = f"""
70
70
  Forbidden schemas: {schemas}
71
71
 
@@ -76,7 +76,7 @@ class GqlApiErrorForbiddenSchema(Exception):
76
76
 
77
77
 
78
78
  class GqlGetResourceError(Exception):
79
- def __init__(self, path, msg):
79
+ def __init__(self, path: str, msg: str):
80
80
  super().__init__(f"Error getting resource from path {path}: {msg!s}")
81
81
 
82
82
 
@@ -88,8 +88,8 @@ class GqlApi:
88
88
  self,
89
89
  url: str,
90
90
  token: str | None = None,
91
- int_name=None,
92
- validate_schemas=False,
91
+ int_name: str | None = None,
92
+ validate_schemas: bool = False,
93
93
  commit: str | None = None,
94
94
  commit_timestamp: str | None = None,
95
95
  ) -> None:
@@ -127,14 +127,21 @@ class GqlApi:
127
127
  )
128
128
  return Client(transport=transport)
129
129
 
130
- def close(self):
130
+ def close(self) -> None:
131
131
  logging.debug("Closing GqlApi client")
132
- if self.client.transport.session:
132
+ if (
133
+ self.client.transport is not None
134
+ and hasattr(self.client.transport, "session")
135
+ and self.client.transport.session
136
+ ):
133
137
  self.client.transport.session.close()
134
138
 
135
139
  @retry(exceptions=GqlApiError, max_attempts=5, hook=capture_and_forget)
136
140
  def query(
137
- self, query: str, variables=None, skip_validation=False
141
+ self,
142
+ query: str,
143
+ variables: dict[str, Any] | None = None,
144
+ skip_validation: bool = False,
138
145
  ) -> dict[str, Any] | None:
139
146
  try:
140
147
  result = self.client.execute(
@@ -237,7 +244,7 @@ class GqlApi:
237
244
  resources = self.query(query, {"schema": schema}, skip_validation=True)
238
245
  return resources["resources"]
239
246
 
240
- def get_queried_schemas(self):
247
+ def get_queried_schemas(self) -> list:
241
248
  return list(self._queried_schemas)
242
249
 
243
250
  @property
@@ -252,7 +259,7 @@ class GqlApiSingleton:
252
259
  gqlapi_lock = threading.Lock()
253
260
 
254
261
  @classmethod
255
- def create(cls, *args, **kwargs) -> GqlApi:
262
+ def create(cls, *args: Any, **kwargs: Any) -> GqlApi:
256
263
  with cls.gqlapi_lock:
257
264
  if cls.gql_api:
258
265
  logging.debug("Resestting GqlApi instance")
@@ -261,8 +268,9 @@ class GqlApiSingleton:
261
268
  return cls.gql_api
262
269
 
263
270
  @classmethod
264
- def close_gqlapi(cls):
265
- cls.gql_api.close()
271
+ def close_gqlapi(cls) -> None:
272
+ if cls.gql_api is not None:
273
+ cls.gql_api.close()
266
274
 
267
275
  @classmethod
268
276
  def instance(cls) -> GqlApi:
@@ -281,11 +289,11 @@ class GqlApiSingleton:
281
289
  def init(
282
290
  url: str,
283
291
  token: str | None = None,
284
- integration=None,
285
- validate_schemas=False,
292
+ integration: str | None = None,
293
+ validate_schemas: bool = False,
286
294
  commit: str | None = None,
287
295
  commit_timestamp: str | None = None,
288
- ):
296
+ ) -> GqlApi:
289
297
  return GqlApiSingleton.create(
290
298
  url,
291
299
  token,
@@ -336,7 +344,7 @@ class PersistentRequestsHTTPTransport(RequestsHTTPTransport):
336
344
  # can't directly assign, due to mypy type checking
337
345
  self.session = session # type: ignore
338
346
 
339
- def connect(self):
347
+ def connect(self) -> None:
340
348
  pass
341
349
 
342
350
  def close(self) -> None:
@@ -344,7 +352,7 @@ class PersistentRequestsHTTPTransport(RequestsHTTPTransport):
344
352
 
345
353
 
346
354
  @retry(exceptions=requests.exceptions.HTTPError, max_attempts=5)
347
- def get_sha(server, token=None):
355
+ def get_sha(server: ParseResult, token: str | None = None) -> str:
348
356
  sha_endpoint = server._replace(path="/sha256")
349
357
  headers = {"Authorization": token} if token else None
350
358
  response = requests.get(sha_endpoint.geturl(), headers=headers, timeout=60)
@@ -354,7 +362,9 @@ def get_sha(server, token=None):
354
362
 
355
363
 
356
364
  @retry(exceptions=requests.exceptions.HTTPError, max_attempts=5)
357
- def get_git_commit_info(sha, server, token=None):
365
+ def get_git_commit_info(
366
+ sha: str, server: ParseResult, token: str | None = None
367
+ ) -> dict:
358
368
  git_commit_info_endpoint = server._replace(path=f"/git-commit-info/{sha}")
359
369
  headers = {"Authorization": token} if token else None
360
370
  response = requests.get(
@@ -367,12 +377,12 @@ def get_git_commit_info(sha, server, token=None):
367
377
 
368
378
  @retry(exceptions=requests.exceptions.ConnectionError, max_attempts=5)
369
379
  def init_from_config(
370
- autodetect_sha=True,
371
- sha=None,
372
- integration=None,
373
- validate_schemas=False,
374
- print_url=True,
375
- ):
380
+ autodetect_sha: bool = True,
381
+ sha: str | None = None,
382
+ integration: str | None = None,
383
+ validate_schemas: bool = False,
384
+ print_url: bool = True,
385
+ ) -> GqlApi:
376
386
  server, token, commit, timestamp = _get_gql_server_and_token(
377
387
  autodetect_sha=autodetect_sha, sha=sha
378
388
  )
@@ -1,9 +1,30 @@
1
- from typing import Any
1
+ from typing import Any, TypedDict
2
2
 
3
3
  from reconcile.utils.ocm.base import OCMVersionGate
4
4
  from reconcile.utils.ocm_base_client import OCMBaseClient
5
5
 
6
- UPGRADE_POLICY_DESIRED_KEYS = {"id", "schedule_type", "schedule", "next_run", "version"}
6
+
7
+ class UpgradePolicy(TypedDict):
8
+ id: str | None
9
+ next_run: str | None
10
+ schedule: str | None
11
+ schedule_type: str
12
+ state: str | None
13
+ version: str
14
+
15
+
16
+ def _build_upgrade_policy(
17
+ response: dict,
18
+ state: str | None,
19
+ ) -> UpgradePolicy:
20
+ return UpgradePolicy(
21
+ id=response.get("id"),
22
+ schedule_type=response["schedule_type"],
23
+ schedule=response.get("schedule"),
24
+ next_run=response.get("next_run"),
25
+ version=response["version"],
26
+ state=state,
27
+ )
7
28
 
8
29
 
9
30
  def build_cluster_url(cluster_id: str) -> str:
@@ -16,30 +37,25 @@ def build_cluster_url(cluster_id: str) -> str:
16
37
 
17
38
 
18
39
  def get_upgrade_policies(
19
- ocm_api: OCMBaseClient, cluster_id: str, schedule_type: str | None = None
20
- ) -> list[dict[str, Any]]:
40
+ ocm_api: OCMBaseClient,
41
+ cluster_id: str,
42
+ ) -> list[UpgradePolicy]:
21
43
  """Returns a list of details of Upgrade Policies
22
44
 
23
- :param cluster: cluster name
45
+ :param ocm_api: OCM API client
46
+ :param cluster_id: cluster id
24
47
 
25
- :type cluster: string
48
+ :return: list of UpgradePolicy
26
49
  """
27
- results: list[dict[str, Any]] = []
28
-
29
- for policy in ocm_api.get_paginated(
30
- f"{build_cluster_url(cluster_id)}/upgrade_policies"
31
- ):
32
- if schedule_type and policy["schedule_type"] != schedule_type:
33
- continue
34
- policy_data = {
35
- k: v for k, v in policy.items() if k in UPGRADE_POLICY_DESIRED_KEYS
36
- }
37
- policy_data["state"] = get_upgrade_policy_state(
38
- ocm_api, cluster_id, policy["id"]
50
+ return [
51
+ _build_upgrade_policy(
52
+ policy,
53
+ state=get_upgrade_policy_state(ocm_api, cluster_id, policy["id"]),
39
54
  )
40
- results.append(policy_data)
41
-
42
- return results
55
+ for policy in ocm_api.get_paginated(
56
+ f"{build_cluster_url(cluster_id)}/upgrade_policies"
57
+ )
58
+ ]
43
59
 
44
60
 
45
61
  def get_upgrade_policy_state(
@@ -76,23 +92,21 @@ def delete_upgrade_policy(
76
92
 
77
93
 
78
94
  def get_control_plane_upgrade_policies(
79
- ocm_api: OCMBaseClient, cluster_id: str, schedule_type: str | None = None
80
- ) -> list[dict[str, Any]]:
95
+ ocm_api: OCMBaseClient,
96
+ cluster_id: str,
97
+ ) -> list[UpgradePolicy]:
81
98
  """
82
99
  Returns a list of details of Upgrade Policies
83
100
  """
84
- results: list[dict[str, Any]] = []
85
- for policy in ocm_api.get_paginated(
86
- f"{build_cluster_url(cluster_id)}/control_plane/upgrade_policies"
87
- ):
88
- if schedule_type and policy["schedule_type"] != schedule_type:
89
- continue
90
- policy_data = {
91
- k: v for k, v in policy.items() if k in UPGRADE_POLICY_DESIRED_KEYS
92
- }
93
- policy_data["state"] = policy.get("state", {}).get("value")
94
- results.append(policy_data)
95
- return results
101
+ return [
102
+ _build_upgrade_policy(
103
+ policy,
104
+ state=policy.get("state", {}).get("value"),
105
+ )
106
+ for policy in ocm_api.get_paginated(
107
+ f"{build_cluster_url(cluster_id)}/control_plane/upgrade_policies"
108
+ )
109
+ ]
96
110
 
97
111
 
98
112
  def create_control_plane_upgrade_policy(
@@ -124,18 +138,19 @@ def delete_control_plane_upgrade_policy(
124
138
 
125
139
  def get_node_pool_upgrade_policies(
126
140
  ocm_api: OCMBaseClient, cluster_id: str, node_pool: str
127
- ) -> list[dict[str, Any]]:
141
+ ) -> list[UpgradePolicy]:
128
142
  """
129
143
  Returns a list of details of Upgrade Policies
130
144
  """
131
- results: list[dict[str, Any]] = []
132
- for policy in ocm_api.get_paginated(
133
- f"{build_cluster_url(cluster_id)}/node_pools/{node_pool}/upgrade_policies"
134
- ):
135
- results.append({ # noqa: PERF401
136
- k: v for k, v in policy.items() if k in UPGRADE_POLICY_DESIRED_KEYS
137
- })
138
- return results
145
+ return [
146
+ _build_upgrade_policy(
147
+ policy,
148
+ state=policy.get("state", {}).get("value"),
149
+ )
150
+ for policy in ocm_api.get_paginated(
151
+ f"{build_cluster_url(cluster_id)}/node_pools/{node_pool}/upgrade_policies"
152
+ )
153
+ ]
139
154
 
140
155
 
141
156
  def create_node_pool_upgrade_policy(