qontract-reconcile 0.10.2.dev220__py3-none-any.whl → 0.10.2.dev222__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.dev220
3
+ Version: 0.10.2.dev222
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
@@ -131,8 +131,6 @@ OpenShift templates can be found [here](/openshift/qontract-reconcile.yaml). In
131
131
  RHIDP.
132
132
  cluster-deployment-mapper Maps ClusterDeployment resources to Cluster
133
133
  IDs.
134
- cna-resources Manage Cloud Resources using Cloud Native
135
- Assets (CNA).
136
134
  dashdotdb-cso Collects the ImageManifestVuln CRs from all
137
135
  the clusters and posts them to Dashdotdb.
138
136
  dashdotdb-dora Collects dora metrics.
@@ -9,7 +9,7 @@ reconcile/aws_iam_password_reset.py,sha256=O0JX2N5kNRKs3u2xzu4NNrI6p0ag5JWy3MTsv
9
9
  reconcile/aws_support_cases_sos.py,sha256=PDhilxQ4TBxVnxUPIUdTbKEaNUI0wzPiEsB91oHT2fY,3384
10
10
  reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
11
11
  reconcile/checkpoint.py,sha256=_JhMxrye5BgkRMxWYuf7Upli6XayPINKSsuo3ynHTRc,5010
12
- reconcile/cli.py,sha256=Pzp2XCmbkw_IH6YNemnnXEFqI-KSQNaDtg81PI-H5po,114594
12
+ reconcile/cli.py,sha256=vrUcahFtsq_yGAzaa1QDyZHbMqMsnsNHzrvW4BiV_xA,114159
13
13
  reconcile/closedbox_endpoint_monitoring_base.py,sha256=al7m8EgnnYx90rY1REryW3byN_ItfJfAzEeLtjbCfi0,4921
14
14
  reconcile/cluster_deployment_mapper.py,sha256=5gumAaRCcFXsabUJ1dnuUy9WrP_FEEM5JnOnE8ch9sE,2326
15
15
  reconcile/dashdotdb_base.py,sha256=83ZWIf5JJk3P_D69y2TmXRcQr6ELJGlv10OM0h7fJVs,4767
@@ -178,14 +178,6 @@ reconcile/change_owners/self_service_roles.py,sha256=xSe5AKZxXAIo0vWOMM5hImQ_rd-
178
178
  reconcile/change_owners/tester.py,sha256=ijDaSbFYT8fPinhjPrRlw_TCarTTJK5nUgzHSi1oVYE,8875
179
179
  reconcile/cluster_auth_rhidp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
180
180
  reconcile/cluster_auth_rhidp/integration.py,sha256=KIAiP_XFjsOA2OE8oFJa8lD0T1a7EwOmhct2xbj7tr8,9560
181
- reconcile/cna/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
182
- reconcile/cna/client.py,sha256=32-G3fDZfVvkCN1vg0EbcsMNYBdJvXoXYI2ShFg6lbc,1586
183
- reconcile/cna/integration.py,sha256=dybEWkSCl7V5OC7ZQYIN2j4QV2yWstIUEQy1GpYI2oI,5106
184
- reconcile/cna/state.py,sha256=mJghfMGZZtyh8e6GwNNajI2AxEEJQ4e51tAgQ26zEuQ,4501
185
- reconcile/cna/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
186
- reconcile/cna/assets/asset.py,sha256=KWgA4fuDAEGsJwmR52WwK_YgSJMW-1cV2la3lmNf4iE,834
187
- reconcile/cna/assets/asset_factory.py,sha256=7T7X_J6xIsoGETqBRI45_EyIKEdQcnRPt_GAuVuLQcc,785
188
- reconcile/cna/assets/null.py,sha256=85mVh97atCoC0aLuX47poTZiyOthmziJeBsUw0c924w,1658
189
181
  reconcile/dynatrace_token_provider/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
190
182
  reconcile/dynatrace_token_provider/dependencies.py,sha256=lvkdwqHMsn_2kgj-tUIJdTUnUNxVoS6z8k4nPkGglnQ,3129
191
183
  reconcile/dynatrace_token_provider/integration.py,sha256=RTGy4A6U4EgE1G4rMdS8gqgw2XIfDcdYd-eF5DL9bo0,27166
@@ -262,10 +254,6 @@ reconcile/gql_definitions/change_owners/queries/change_types.py,sha256=SjpKbLWmL
262
254
  reconcile/gql_definitions/change_owners/queries/self_service_roles.py,sha256=BcTQvnefPiShG90ajU_l2V6HUYSEXgdAzgiwY89vQew,4790
263
255
  reconcile/gql_definitions/cluster_auth_rhidp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
264
256
  reconcile/gql_definitions/cluster_auth_rhidp/clusters.py,sha256=Pp9P3Q30Be3szcVqOEOtPfYUNiGTq1xc5Juz-ApMMw0,3283
265
- reconcile/gql_definitions/cna/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
266
- reconcile/gql_definitions/cna/queries/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
267
- reconcile/gql_definitions/cna/queries/cna_provisioners.py,sha256=4k527BszdWB84Wkmd8ZE45p1Djr-fig-xZaVF5XRwPI,3009
268
- reconcile/gql_definitions/cna/queries/cna_resources.py,sha256=j9sa5iOOBsLT2qwlmEItnafSXK-vdNPXgd9Z4mg9mlc,2710
269
257
  reconcile/gql_definitions/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
270
258
  reconcile/gql_definitions/common/alerting_services_settings.py,sha256=mT7cobC9mR_bhFSYeQX1apVA5zMqSbu5fYcdd4iZ9mg,1802
271
259
  reconcile/gql_definitions/common/app_code_component_repos.py,sha256=SCpUVfnn1Vl9nN0UYs5zqJfW1-wIOE-W8_1JjhC-hK8,2034
@@ -657,7 +645,7 @@ reconcile/utils/parse_dhms_duration.py,sha256=TONpLnec5gHeF7k815YNJpQyDjXhkxZIcv
657
645
  reconcile/utils/password_validator.py,sha256=XwuWg-8CPlcuG7dl_oQ1G1h2gSVSnfMym_VkuprpWVg,2183
658
646
  reconcile/utils/prometheus.py,sha256=Ad0rwLbxRuuYjHwkwJloHEdK0bvy42h-p-HIT1DhDhs,3832
659
647
  reconcile/utils/promotion_state.py,sha256=McSgGj3oog83ThJCrMR2v8q6Xb_Pxij-HEe_RbDu8cg,3946
660
- reconcile/utils/promtool.py,sha256=xmPBWEApkk0L2qZBAvTxakNXxfTz-tVLPFxGnpsxXnM,2831
648
+ reconcile/utils/promtool.py,sha256=xPK4ejsXtK0csj7BVAs49IkilGWgWpHiC2j_oPAp4rQ,2831
661
649
  reconcile/utils/quay_api.py,sha256=uE_jxcdy3ViHtYFAfwDQuFDaO7Pr6AAPoVnmORbyHio,7822
662
650
  reconcile/utils/quay_mirror.py,sha256=dpWCNv5lITwIk6Q9RkmqaQKHNk_JPy27UQEribJ7E-U,1324
663
651
  reconcile/utils/raw_github_api.py,sha256=2WKtE8ABYYB9UGOAh9N_kLkksBWL3320Z2_scteZddI,2805
@@ -815,7 +803,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
815
803
  tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
816
804
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
817
805
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
818
- qontract_reconcile-0.10.2.dev220.dist-info/METADATA,sha256=rO1unVRKO_KPhHqQOr2hHQ0Ckya1MWmCrjTez_2dcjo,24555
819
- qontract_reconcile-0.10.2.dev220.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
820
- qontract_reconcile-0.10.2.dev220.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
821
- qontract_reconcile-0.10.2.dev220.dist-info/RECORD,,
806
+ qontract_reconcile-0.10.2.dev222.dist-info/METADATA,sha256=SFFSQXDuQJ82vGauppa3WrCsWzVdw2HsDJOCqUX14Og,24431
807
+ qontract_reconcile-0.10.2.dev222.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
808
+ qontract_reconcile-0.10.2.dev222.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
809
+ qontract_reconcile-0.10.2.dev222.dist-info/RECORD,,
reconcile/cli.py CHANGED
@@ -2414,27 +2414,6 @@ def terraform_cloudflare_users(
2414
2414
  )
2415
2415
 
2416
2416
 
2417
- @integration.command(
2418
- short_help="Manage Cloud Resources using Cloud Native Assets (CNA)."
2419
- )
2420
- @enable_deletion(default=False)
2421
- @threaded()
2422
- @click.pass_context
2423
- def cna_resources(
2424
- ctx: click.Context,
2425
- enable_deletion: bool,
2426
- thread_pool_size: int,
2427
- ) -> None:
2428
- import reconcile.cna.integration
2429
-
2430
- run_integration(
2431
- reconcile.cna.integration,
2432
- ctx,
2433
- enable_deletion,
2434
- thread_pool_size,
2435
- )
2436
-
2437
-
2438
2417
  @integration.command(short_help="Manage auto-promotions defined in SaaS files")
2439
2418
  @threaded()
2440
2419
  @click.option("--env-name", default=None, help="environment to filter saas files by")
@@ -9,7 +9,7 @@ import yaml
9
9
  from reconcile.utils.defer import defer
10
10
  from reconcile.utils.structs import CommandExecutionResult
11
11
 
12
- PROMTOOL_VERSION = ["2.54.1"]
12
+ PROMTOOL_VERSION = ["2.55.1"]
13
13
  PROMTOOL_VERSION_REGEX = r"^promtool,\sversion\s([\d]+\.[\d]+\.[\d]+).+$"
14
14
 
15
15
 
reconcile/cna/__init__.py DELETED
File without changes
File without changes
@@ -1,43 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from abc import (
4
- ABC,
5
- abstractmethod,
6
- )
7
- from dataclasses import (
8
- dataclass,
9
- field,
10
- )
11
- from enum import Enum
12
- from typing import Any
13
-
14
-
15
- class AssetError(Exception):
16
- pass
17
-
18
-
19
- class AssetType(Enum):
20
- NULL = "null"
21
-
22
-
23
- class AssetStatus(Enum):
24
- TERMINATED = "Terminated"
25
- PENDING = "Pending"
26
- RUNNING = "Running"
27
-
28
-
29
- @dataclass(frozen=True)
30
- class Asset(ABC):
31
- uuid: str | None = field(compare=False, hash=True)
32
- href: str | None = field(compare=False, hash=True)
33
- status: AssetStatus | None = field(compare=False, hash=True)
34
- name: str
35
- kind: AssetType
36
-
37
- @abstractmethod
38
- def api_payload(self) -> dict[str, Any]:
39
- raise NotImplementedError()
40
-
41
- @abstractmethod
42
- def update_from(self, asset: Asset) -> Asset:
43
- raise NotImplementedError()
@@ -1,25 +0,0 @@
1
- from collections.abc import Mapping
2
- from typing import Any
3
-
4
- from reconcile.cna.assets.asset import (
5
- Asset,
6
- AssetError,
7
- )
8
- from reconcile.cna.assets.null import NullAsset
9
- from reconcile.gql_definitions.cna.queries.cna_resources import (
10
- CNANullAssetV1,
11
- CNAssetV1,
12
- )
13
-
14
-
15
- def asset_factory_from_schema(schema_asset: CNAssetV1) -> Asset:
16
- if isinstance(schema_asset, CNANullAssetV1):
17
- return NullAsset.from_query_class(schema_asset)
18
- raise AssetError(f"Unknown schema asset type {schema_asset}")
19
-
20
-
21
- def asset_factory_from_raw_data(data_asset: Mapping[str, Any]) -> Asset:
22
- asset_type = data_asset.get("asset_type")
23
- if asset_type == "null":
24
- return NullAsset.from_api_mapping(data_asset)
25
- raise AssetError(f"Unknown data asset type {data_asset}")
@@ -1,61 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import Mapping
4
- from dataclasses import dataclass
5
- from typing import Any
6
-
7
- from reconcile.cna.assets.asset import (
8
- Asset,
9
- AssetError,
10
- AssetStatus,
11
- AssetType,
12
- )
13
- from reconcile.gql_definitions.cna.queries.cna_resources import CNANullAssetV1
14
-
15
-
16
- @dataclass(frozen=True)
17
- class NullAsset(Asset):
18
- addr_block: str | None
19
-
20
- def api_payload(self) -> dict[str, Any]:
21
- return {
22
- "asset_type": "null",
23
- "name": self.name,
24
- "parameters": {
25
- "addr_block": self.addr_block,
26
- },
27
- }
28
-
29
- def update_from(self, asset: Asset) -> Asset:
30
- if not isinstance(asset, NullAsset):
31
- raise AssetError(f"Cannot create NullAsset from {asset}")
32
- return NullAsset(
33
- uuid=self.uuid,
34
- href=self.href,
35
- status=self.status,
36
- name=self.name,
37
- kind=self.kind,
38
- addr_block=asset.addr_block,
39
- )
40
-
41
- @staticmethod
42
- def from_query_class(asset: CNANullAssetV1) -> NullAsset:
43
- return NullAsset(
44
- uuid=None,
45
- href=None,
46
- status=None,
47
- kind=AssetType.NULL,
48
- name=asset.name,
49
- addr_block=asset.addr_block,
50
- )
51
-
52
- @staticmethod
53
- def from_api_mapping(asset: Mapping[str, Any]) -> NullAsset:
54
- return NullAsset(
55
- uuid=asset.get("id"),
56
- href=asset.get("href"),
57
- status=AssetStatus(asset.get("status")),
58
- kind=AssetType.NULL,
59
- name=asset.get("name", ""),
60
- addr_block=asset.get("addr_block"),
61
- )
reconcile/cna/client.py DELETED
@@ -1,52 +0,0 @@
1
- import logging
2
- from typing import Any
3
-
4
- from reconcile.cna.assets.asset import Asset
5
- from reconcile.utils.ocm_base_client import OCMBaseClient
6
-
7
-
8
- class CNAClient:
9
- """
10
- Client used to interact with CNA. CNA API doc can be found here:
11
- https://gitlab.cee.redhat.com/service/cna-management/-/blob/main/openapi/openapi.yaml#/
12
- """
13
-
14
- def __init__(self, ocm_client: OCMBaseClient):
15
- self._ocm_client = ocm_client
16
-
17
- def list_assets(self) -> list[dict[str, Any]]:
18
- """
19
- We use this to fetch the current real-world state
20
- of our assets
21
- """
22
- # TODO: properly handle paging
23
- cnas = self._ocm_client.get(api_path="/api/cna-management/v1/cnas")
24
- return cnas.get("items", [])
25
-
26
- def create(self, asset: Asset, dry_run: bool = False) -> None:
27
- if dry_run:
28
- logging.info("CREATE %s", asset)
29
- return
30
- self._ocm_client.post(
31
- api_path="/api/cna-management/v1/cnas",
32
- data=asset.api_payload(),
33
- )
34
-
35
- def delete(self, asset: Asset, dry_run: bool = False) -> None:
36
- if dry_run:
37
- logging.info("DELETE %s", asset)
38
- return
39
- if asset.href:
40
- self._ocm_client.delete(
41
- api_path=asset.href,
42
- )
43
-
44
- def update(self, asset: Asset, dry_run: bool = False) -> None:
45
- if dry_run:
46
- logging.info("UPDATE %s", asset)
47
- return
48
- if asset.href:
49
- self._ocm_client.patch(
50
- api_path=asset.href,
51
- data=asset.api_payload(),
52
- )
@@ -1,137 +0,0 @@
1
- from collections import defaultdict
2
- from collections.abc import (
3
- Iterable,
4
- Mapping,
5
- )
6
-
7
- from reconcile.cna.assets.asset_factory import asset_factory_from_schema
8
- from reconcile.cna.client import CNAClient
9
- from reconcile.cna.state import State
10
- from reconcile.gql_definitions.cna.queries.cna_provisioners import (
11
- CNAExperimentalProvisionerV1,
12
- )
13
- from reconcile.gql_definitions.cna.queries.cna_provisioners import (
14
- query as cna_provisioners_query,
15
- )
16
- from reconcile.gql_definitions.cna.queries.cna_resources import (
17
- NamespaceCNAssetV1,
18
- NamespaceV1,
19
- )
20
- from reconcile.gql_definitions.cna.queries.cna_resources import (
21
- query as namespaces_query,
22
- )
23
- from reconcile.typed_queries.app_interface_vault_settings import (
24
- get_app_interface_vault_settings,
25
- )
26
- from reconcile.utils import gql
27
- from reconcile.utils.ocm_base_client import OCMBaseClient
28
- from reconcile.utils.secret_reader import (
29
- SecretReaderBase,
30
- create_secret_reader,
31
- )
32
- from reconcile.utils.semver_helper import make_semver
33
-
34
- QONTRACT_INTEGRATION = "cna_resources"
35
- QONTRACT_INTEGRATION_VERSION = make_semver(0, 1, 0)
36
-
37
-
38
- class CNAConfigException(Exception):
39
- pass
40
-
41
-
42
- class CNAIntegration:
43
- def __init__(
44
- self,
45
- cna_clients: Mapping[str, CNAClient],
46
- namespaces: Iterable[NamespaceV1],
47
- desired_states: Mapping[str, State] | None = None,
48
- current_states: Mapping[str, State] | None = None,
49
- ) -> None:
50
- self._cna_clients = cna_clients
51
- self._namespaces = namespaces
52
- self._desired_states = desired_states or defaultdict(State)
53
- self._current_states = current_states or defaultdict(State)
54
-
55
- def assemble_desired_states(self) -> None:
56
- self._desired_states = defaultdict(State)
57
- for namespace in self._namespaces:
58
- for provider in namespace.external_resources or []:
59
- # TODO: this should probably be filtered within the query already
60
- if not isinstance(provider, NamespaceCNAssetV1):
61
- continue
62
- for resource in provider.resources or []:
63
- self._desired_states[provider.provisioner.name].add_asset(
64
- asset_factory_from_schema(resource)
65
- )
66
-
67
- def assemble_current_states(self) -> None:
68
- self._current_states = defaultdict(State)
69
- for name, client in self._cna_clients.items():
70
- cnas = client.list_assets()
71
- state = State()
72
- state.add_raw_data(cnas)
73
- self._current_states[name] = state
74
-
75
- def provision(self, dry_run: bool = False) -> None:
76
- for provisioner_name, cna_client in self._cna_clients.items():
77
- desired_state = self._desired_states[provisioner_name]
78
- current_state = self._current_states[provisioner_name]
79
-
80
- additions = desired_state - current_state
81
- for asset in additions:
82
- cna_client.create(asset=asset, dry_run=dry_run)
83
-
84
- deletions = current_state - desired_state
85
- for asset in deletions:
86
- cna_client.delete(asset=asset, dry_run=dry_run)
87
-
88
- updates = current_state.required_updates_to_reach(desired_state)
89
- for assets in updates:
90
- cna_client.update(asset=assets, dry_run=dry_run)
91
-
92
-
93
- def build_cna_clients(
94
- secret_reader: SecretReaderBase,
95
- cna_provisioners: list[CNAExperimentalProvisionerV1],
96
- ) -> dict[str, CNAClient]:
97
- clients: dict[str, CNAClient] = {}
98
- for provisioner in cna_provisioners:
99
- access_token_client_secret = (
100
- provisioner.ocm.access_token_client_secret
101
- or provisioner.ocm.environment.access_token_client_secret
102
- )
103
- secret_data = secret_reader.read_all_secret(access_token_client_secret)
104
- ocm_client = OCMBaseClient(
105
- url=provisioner.ocm.environment.url,
106
- access_token_client_secret=secret_data["client_secret"],
107
- access_token_url=provisioner.ocm.access_token_url
108
- or provisioner.ocm.environment.access_token_url,
109
- access_token_client_id=provisioner.ocm.access_token_client_id
110
- or provisioner.ocm.environment.access_token_client_id,
111
- )
112
- clients[provisioner.name] = CNAClient(
113
- ocm_client=ocm_client,
114
- )
115
- return clients
116
-
117
-
118
- def run(
119
- dry_run: bool,
120
- # TODO: Threadpool not used yet - will be used once we understand scopes in more detail
121
- thread_pool_size: int,
122
- ) -> None:
123
- settings = get_app_interface_vault_settings()
124
- secret_reader = create_secret_reader(use_vault=settings.vault)
125
-
126
- query_func = gql.get_api().query
127
- cna_provisioners = cna_provisioners_query(query_func).cna_provisioners or []
128
- namespaces = namespaces_query(query_func).namespaces or []
129
-
130
- cna_clients = build_cna_clients(
131
- secret_reader=secret_reader, cna_provisioners=cna_provisioners
132
- )
133
-
134
- integration = CNAIntegration(cna_clients=cna_clients, namespaces=namespaces)
135
- integration.assemble_current_states()
136
- integration.assemble_desired_states()
137
- integration.provision(dry_run=dry_run)
reconcile/cna/state.py DELETED
@@ -1,128 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import (
4
- Iterable,
5
- Mapping,
6
- )
7
- from typing import Any
8
-
9
- from reconcile.cna.assets.asset import (
10
- Asset,
11
- AssetStatus,
12
- AssetType,
13
- )
14
- from reconcile.cna.assets.asset_factory import asset_factory_from_raw_data
15
-
16
-
17
- class CNAStateError(Exception):
18
- pass
19
-
20
-
21
- class State:
22
- """
23
- State object is a collection of assets.
24
- It can be used to describe actual or desired state.
25
- Main objective is to calculate required additions,
26
- deletions and updates to reach another state.
27
- """
28
-
29
- def __init__(self, assets: dict[AssetType, dict[str, Asset]] | None = None):
30
- self._assets: dict[AssetType, dict[str, Asset]] = {}
31
- for kind in AssetType:
32
- self._assets[kind] = {}
33
- if assets:
34
- self._assets = assets
35
-
36
- def __eq__(self, other: object) -> bool:
37
- if not isinstance(other, State):
38
- return False
39
- if not set(self._assets.keys()) == set(other._assets.keys()):
40
- return False
41
- for kind in list(self._assets.keys()):
42
- if not set(self._assets[kind]) == set(other._assets[kind]):
43
- return False
44
- for name, asset in self._assets[kind].items():
45
- if asset != other._assets[kind][name]:
46
- return False
47
- return True
48
-
49
- def __repr__(self) -> str:
50
- # pytest should show nice diff
51
- return str(self._assets)
52
-
53
- def _validate_addition(self, asset: Asset) -> None:
54
- if asset.kind not in self._assets:
55
- raise CNAStateError(f"State doesn't know asset_kind {asset.kind}")
56
- if asset.name in self._assets[asset.kind]:
57
- raise CNAStateError(
58
- f"Duplicate asset name found in state: kind={asset.kind}, name={asset.name}"
59
- )
60
-
61
- def add_asset(self, asset: Asset) -> None:
62
- self._validate_addition(asset=asset)
63
- self._assets[asset.kind][asset.name] = asset
64
-
65
- def add_raw_data(self, data: Iterable[Mapping[str, Any]]) -> None:
66
- for cna in data:
67
- asset = asset_factory_from_raw_data(cna)
68
- self._validate_addition(asset=asset)
69
- self._assets[asset.kind][asset.name] = asset
70
-
71
- def required_updates_to_reach(self, other: State) -> State:
72
- """
73
- This operation is NOT commutative, i.e.,:
74
- a.required_updates_to_reach(b) != b.required_updates_to_reach(a)
75
-
76
- This is supposed to be called on actual state (self).
77
- I.e., actual.required_updates_to_reach(desired)
78
- """
79
- ans = State()
80
- for kind in AssetType:
81
- for asset_name, other_asset in other._assets[kind].items():
82
- if asset_name not in self._assets[kind]:
83
- continue
84
- asset = self._assets[kind][asset_name]
85
- if asset.status in {AssetStatus.TERMINATED, AssetStatus.PENDING}:
86
- continue
87
- if asset == other_asset:
88
- # There is no diff - no need to update
89
- continue
90
- ans.add_asset(asset=asset.update_from(other_asset))
91
- return ans
92
-
93
- def __sub__(self, other: State) -> State:
94
- """
95
- This is used to determine creations and deletions
96
- of assets. We only check the existance of the name
97
- in each state. TERMINATED and PENDING assets are
98
- omitted.
99
-
100
- additions = self - other
101
- deletions = other - self
102
- """
103
- ans = State()
104
- for kind in AssetType:
105
- for asset_name, asset in self._assets[kind].items():
106
- if asset.status in {AssetStatus.TERMINATED, AssetStatus.PENDING}:
107
- continue
108
- if other_asset := other._assets[kind].get(asset_name):
109
- if other_asset.status == AssetStatus.TERMINATED:
110
- raise CNAStateError(
111
- f"Trying to create/update terminated asset {asset}. Currently not possible."
112
- )
113
- continue
114
- ans.add_asset(asset)
115
- return ans
116
-
117
- def __iter__(self) -> State:
118
- self._i = 0
119
- self._assets_list: list[Asset] = []
120
- for kind in AssetType:
121
- self._assets_list += list(self._assets[kind].values())
122
- return self
123
-
124
- def __next__(self) -> Asset:
125
- if self._i < len(self._assets_list):
126
- self._i += 1
127
- return self._assets_list[self._i - 1]
128
- raise StopIteration
File without changes
File without changes
@@ -1,106 +0,0 @@
1
- """
2
- Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY!
3
- """
4
- from collections.abc import Callable # noqa: F401 # pylint: disable=W0611
5
- from datetime import datetime # noqa: F401 # pylint: disable=W0611
6
- from enum import Enum # noqa: F401 # pylint: disable=W0611
7
- from typing import ( # noqa: F401 # pylint: disable=W0611
8
- Any,
9
- Optional,
10
- Union,
11
- )
12
-
13
- from pydantic import ( # noqa: F401 # pylint: disable=W0611
14
- BaseModel,
15
- Extra,
16
- Field,
17
- Json,
18
- )
19
-
20
- from reconcile.gql_definitions.fragments.ocm_environment import OCMEnvironment
21
- from reconcile.gql_definitions.fragments.vault_secret import VaultSecret
22
-
23
-
24
- DEFINITION = """
25
- fragment OCMEnvironment on OpenShiftClusterManagerEnvironment_v1 {
26
- name
27
- description
28
- labels
29
- url
30
- accessTokenClientId
31
- accessTokenUrl
32
- accessTokenClientSecret {
33
- ... VaultSecret
34
- }
35
- }
36
-
37
- fragment VaultSecret on VaultSecret_v1 {
38
- path
39
- field
40
- version
41
- format
42
- }
43
-
44
- query CNAProvisioners {
45
- cna_provisioners: cna_experimental_provisioners_v1 {
46
- name
47
- description
48
- ocm {
49
- name
50
- orgId
51
- accessTokenUrl
52
- accessTokenClientId
53
- accessTokenClientSecret {
54
- ... VaultSecret
55
- }
56
- environment {
57
- ... OCMEnvironment
58
- }
59
- }
60
- }
61
- }
62
- """
63
-
64
-
65
- class ConfiguredBaseModel(BaseModel):
66
- class Config:
67
- smart_union=True
68
- extra=Extra.forbid
69
-
70
-
71
- class OpenShiftClusterManagerV1(ConfiguredBaseModel):
72
- name: str = Field(..., alias="name")
73
- org_id: str = Field(..., alias="orgId")
74
- access_token_url: Optional[str] = Field(..., alias="accessTokenUrl")
75
- access_token_client_id: Optional[str] = Field(..., alias="accessTokenClientId")
76
- access_token_client_secret: Optional[VaultSecret] = Field(..., alias="accessTokenClientSecret")
77
- environment: OCMEnvironment = Field(..., alias="environment")
78
-
79
-
80
- class CNAExperimentalProvisionerV1(ConfiguredBaseModel):
81
- name: str = Field(..., alias="name")
82
- description: Optional[str] = Field(..., alias="description")
83
- ocm: OpenShiftClusterManagerV1 = Field(..., alias="ocm")
84
-
85
-
86
- class CNAProvisionersQueryData(ConfiguredBaseModel):
87
- cna_provisioners: Optional[list[CNAExperimentalProvisionerV1]] = Field(..., alias="cna_provisioners")
88
-
89
-
90
- def query(query_func: Callable, **kwargs: Any) -> CNAProvisionersQueryData:
91
- """
92
- This is a convenience function which queries and parses the data into
93
- concrete types. It should be compatible with most GQL clients.
94
- You do not have to use it to consume the generated data classes.
95
- Alternatively, you can also mime and alternate the behavior
96
- of this function in the caller.
97
-
98
- Parameters:
99
- query_func (Callable): Function which queries your GQL Server
100
- kwargs: optional arguments that will be passed to the query function
101
-
102
- Returns:
103
- CNAProvisionersQueryData: queried data parsed into generated classes
104
- """
105
- raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs)
106
- return CNAProvisionersQueryData(**raw_data)
@@ -1,98 +0,0 @@
1
- """
2
- Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY!
3
- """
4
- from collections.abc import Callable # noqa: F401 # pylint: disable=W0611
5
- from datetime import datetime # noqa: F401 # pylint: disable=W0611
6
- from enum import Enum # noqa: F401 # pylint: disable=W0611
7
- from typing import ( # noqa: F401 # pylint: disable=W0611
8
- Any,
9
- Optional,
10
- Union,
11
- )
12
-
13
- from pydantic import ( # noqa: F401 # pylint: disable=W0611
14
- BaseModel,
15
- Extra,
16
- Field,
17
- Json,
18
- )
19
-
20
-
21
- DEFINITION = """
22
- query CNAssets {
23
- namespaces: namespaces_v1 {
24
- name
25
- externalResources {
26
- provider
27
- provisioner {
28
- name
29
- }
30
- ... on NamespaceCNAsset_v1 {
31
- resources {
32
- provider
33
- ... on CNANullAsset_v1 {
34
- name: identifier
35
- addr_block
36
- }
37
- }
38
- }
39
- }
40
- }
41
- }
42
- """
43
-
44
-
45
- class ConfiguredBaseModel(BaseModel):
46
- class Config:
47
- smart_union=True
48
- extra=Extra.forbid
49
-
50
-
51
- class ExternalResourcesProvisionerV1(ConfiguredBaseModel):
52
- name: str = Field(..., alias="name")
53
-
54
-
55
- class NamespaceExternalResourceV1(ConfiguredBaseModel):
56
- provider: str = Field(..., alias="provider")
57
- provisioner: ExternalResourcesProvisionerV1 = Field(..., alias="provisioner")
58
-
59
-
60
- class CNAssetV1(ConfiguredBaseModel):
61
- provider: str = Field(..., alias="provider")
62
-
63
-
64
- class CNANullAssetV1(CNAssetV1):
65
- name: str = Field(..., alias="name")
66
- addr_block: Optional[str] = Field(..., alias="addr_block")
67
-
68
-
69
- class NamespaceCNAssetV1(NamespaceExternalResourceV1):
70
- resources: list[Union[CNANullAssetV1, CNAssetV1]] = Field(..., alias="resources")
71
-
72
-
73
- class NamespaceV1(ConfiguredBaseModel):
74
- name: str = Field(..., alias="name")
75
- external_resources: Optional[list[Union[NamespaceCNAssetV1, NamespaceExternalResourceV1]]] = Field(..., alias="externalResources")
76
-
77
-
78
- class CNAssetsQueryData(ConfiguredBaseModel):
79
- namespaces: Optional[list[NamespaceV1]] = Field(..., alias="namespaces")
80
-
81
-
82
- def query(query_func: Callable, **kwargs: Any) -> CNAssetsQueryData:
83
- """
84
- This is a convenience function which queries and parses the data into
85
- concrete types. It should be compatible with most GQL clients.
86
- You do not have to use it to consume the generated data classes.
87
- Alternatively, you can also mime and alternate the behavior
88
- of this function in the caller.
89
-
90
- Parameters:
91
- query_func (Callable): Function which queries your GQL Server
92
- kwargs: optional arguments that will be passed to the query function
93
-
94
- Returns:
95
- CNAssetsQueryData: queried data parsed into generated classes
96
- """
97
- raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs)
98
- return CNAssetsQueryData(**raw_data)