qontract-reconcile 0.10.2.dev504__py3-none-any.whl → 0.10.2.dev505__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.
Files changed (28) hide show
  1. {qontract_reconcile-0.10.2.dev504.dist-info → qontract_reconcile-0.10.2.dev505.dist-info}/METADATA +1 -4
  2. {qontract_reconcile-0.10.2.dev504.dist-info → qontract_reconcile-0.10.2.dev505.dist-info}/RECORD +10 -28
  3. reconcile/cli.py +0 -108
  4. reconcile/gql_definitions/integrations/integrations.py +1 -31
  5. reconcile/integrations_manager.py +0 -2
  6. reconcile/utils/external_resource_spec.py +1 -2
  7. reconcile/utils/runtime/sharding.py +0 -80
  8. tools/cli_commands/systems_and_tools.py +0 -23
  9. reconcile/gql_definitions/terraform_cloudflare_dns/__init__.py +0 -0
  10. reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +0 -62
  11. reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +0 -193
  12. reconcile/gql_definitions/terraform_cloudflare_resources/__init__.py +0 -0
  13. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +0 -127
  14. reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +0 -359
  15. reconcile/gql_definitions/terraform_cloudflare_users/__init__.py +0 -0
  16. reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +0 -62
  17. reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +0 -139
  18. reconcile/terraform_cloudflare_dns.py +0 -379
  19. reconcile/terraform_cloudflare_resources.py +0 -445
  20. reconcile/terraform_cloudflare_users.py +0 -374
  21. reconcile/typed_queries/cloudflare.py +0 -10
  22. reconcile/utils/terrascript/__init__.py +0 -0
  23. reconcile/utils/terrascript/cloudflare_client.py +0 -310
  24. reconcile/utils/terrascript/cloudflare_resources.py +0 -432
  25. reconcile/utils/terrascript/models.py +0 -26
  26. reconcile/utils/terrascript/resources.py +0 -43
  27. {qontract_reconcile-0.10.2.dev504.dist-info → qontract_reconcile-0.10.2.dev505.dist-info}/WHEEL +0 -0
  28. {qontract_reconcile-0.10.2.dev504.dist-info → qontract_reconcile-0.10.2.dev505.dist-info}/entry_points.txt +0 -0
@@ -1,432 +0,0 @@
1
- # ruff: noqa: N801
2
- from collections.abc import (
3
- Iterable,
4
- MutableMapping,
5
- )
6
- from typing import Any
7
-
8
- from terrascript import (
9
- Data,
10
- Output,
11
- Resource,
12
- Variable,
13
- )
14
- from terrascript.resource import (
15
- cloudflare_account_member,
16
- cloudflare_argo,
17
- cloudflare_custom_ssl,
18
- cloudflare_logpull_retention,
19
- cloudflare_logpush_job,
20
- cloudflare_logpush_ownership_challenge,
21
- cloudflare_record,
22
- cloudflare_worker_route,
23
- cloudflare_worker_script,
24
- cloudflare_zone,
25
- cloudflare_zone_settings_override,
26
- )
27
-
28
- from reconcile import queries
29
- from reconcile.typed_queries.app_interface_vault_settings import (
30
- get_app_interface_vault_settings,
31
- )
32
- from reconcile.utils.external_resource_spec import ExternalResourceSpec
33
- from reconcile.utils.external_resources import ResourceValueResolver
34
- from reconcile.utils.github_api import GithubRepositoryApi
35
- from reconcile.utils.secret_reader import create_secret_reader
36
- from reconcile.utils.terraform import safe_resource_id
37
- from reconcile.utils.terrascript.resources import TerrascriptResource
38
-
39
-
40
- class UnsupportedCloudflareResourceError(Exception):
41
- pass
42
-
43
-
44
- class cloudflare_account(Resource):
45
- """
46
- https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/account
47
- This resource isn't supported directly by Terrascript, which is why it needs to be
48
- defined like this as a Resource.
49
- """
50
-
51
-
52
- class cloudflare_certificate_pack(Resource):
53
- """
54
- https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/certificate_pack
55
-
56
- This resource isn't supported directly by Terrascript, which is why it needs to be
57
- defined like this as a Resource.
58
- """
59
-
60
-
61
- class cloudflare_tiered_cache(Resource):
62
- """
63
- https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/tiered_cache
64
-
65
- This resource isn't supported directly by Terrascript, which is why it needs to be
66
- defined like this as a Resource.
67
- """
68
-
69
-
70
- class cloudflare_accounts(Data):
71
- """
72
- https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/data-sources/accounts
73
-
74
- This resource isn't supported directly by Terrascript, which is why it needs to be
75
- defined like this as a Resource.
76
- """
77
-
78
-
79
- class cloudflare_account_roles(Data):
80
- """
81
- https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/data-sources/account_roles
82
-
83
- This resource isn't supported directly by Terrascript, which is why it needs to be
84
- defined like this as a Resource.
85
- """
86
-
87
-
88
- # TODO: rename to include object?
89
- def create_cloudflare_terrascript_resource(
90
- spec: ExternalResourceSpec,
91
- ) -> list[Resource | Output | Data]:
92
- """
93
- Create the required Cloudflare Terrascript resources as defined by the external
94
- resources spec.
95
- """
96
- resource_type = spec.provider
97
-
98
- if resource_type == "worker_script":
99
- return CloudflareWorkerScriptTerrascriptResource(spec).populate()
100
- if resource_type == "zone":
101
- return CloudflareZoneTerrascriptResource(spec).populate()
102
- if resource_type == "account_member":
103
- return CloudflareAccountMemberTerrascriptResource(spec).populate()
104
- if resource_type == "logpush_ownership_challenge":
105
- return CloudflareLogpushOwnershipChallengeResource(spec).populate()
106
- if resource_type == "logpush_job":
107
- return CloudflareLogpushJob(spec).populate()
108
- if resource_type == "logpull_retention":
109
- return CloudflareLogpullRetention(spec).populate()
110
- raise UnsupportedCloudflareResourceError(
111
- f"The resource type {resource_type} is not supported"
112
- )
113
-
114
-
115
- class CloudflareWorkerScriptTerrascriptResource(TerrascriptResource):
116
- """Generate a cloudflare_worker_script resource"""
117
-
118
- def populate(self) -> list[Resource | Output]:
119
- values = ResourceValueResolver(self._spec).resolve()
120
-
121
- gh_repo = values["content_from_github"]["repo"]
122
- gh_path = values["content_from_github"]["path"]
123
- gh_ref = values["content_from_github"]["ref"]
124
- instance = queries.get_github_instance()
125
- vault_settings = get_app_interface_vault_settings()
126
- secret_reader = create_secret_reader(use_vault=vault_settings.vault)
127
- token = secret_reader.read(instance["token"])
128
- gh = GithubRepositoryApi(
129
- repo_url=gh_repo,
130
- token=token,
131
- )
132
- content = gh.get_file(gh_path, gh_ref)
133
- if content is None:
134
- raise ValueError(
135
- f"Could not retrieve Github file content at {gh_repo} "
136
- f"for file path {gh_path} at ref {gh_ref}"
137
- )
138
-
139
- name = values["name"]
140
- identifier = safe_resource_id(name)
141
-
142
- worker_script_content = Variable(
143
- f"{identifier}_content",
144
- type="string",
145
- default=content.decode(encoding="utf-8"),
146
- )
147
-
148
- worker_script_values = {
149
- "name": name,
150
- "content": f"${{var.{identifier}_content}}",
151
- "plain_text_binding": values.pop("vars"),
152
- "account_id": "${var.account_id}",
153
- }
154
- return [
155
- cloudflare_worker_script(identifier, **worker_script_values),
156
- worker_script_content,
157
- ]
158
-
159
-
160
- class CloudflareZoneTerrascriptResource(TerrascriptResource):
161
- """Generate a cloudflare_zone and related resources."""
162
-
163
- def _create_cloudflare_certificate_pack(
164
- self, zone: Resource, zone_certs: Iterable[MutableMapping[str, Any]]
165
- ) -> list[Resource | Output]:
166
- resources = []
167
- for cert_values in zone_certs:
168
- identifier = safe_resource_id(cert_values.pop("identifier"))
169
- zone_cert_values = {
170
- "zone_id": f"${{{zone.id}}}",
171
- "depends_on": self._get_dependencies([zone]),
172
- **cert_values,
173
- }
174
-
175
- cert_pack = cloudflare_certificate_pack(identifier, **zone_cert_values)
176
-
177
- resources.append(cert_pack)
178
-
179
- output_name = f"{self._spec.output_prefix}__validation_records"
180
- resources.append(
181
- Output(
182
- output_name,
183
- value=f"${{jsonencode({{ for value in {cert_pack.validation_records}: value.txt_name => value.txt_value }})}}",
184
- )
185
- )
186
-
187
- return resources
188
-
189
- def _create_cloudflare_custom_ssl_certificates(
190
- self,
191
- zone: Resource,
192
- zone_custom_ssl: Iterable[MutableMapping[str, Any]],
193
- ) -> list[Resource | Output]:
194
- vault_settings = get_app_interface_vault_settings()
195
- secret_reader = create_secret_reader(use_vault=vault_settings.vault)
196
-
197
- resources = []
198
- for cert_values in zone_custom_ssl:
199
- identifier = safe_resource_id(cert_values.pop("identifier"))
200
- certificate_secret = cert_values.pop("certificate_secret")
201
- certificate = secret_reader.read(certificate_secret.pop("certificate"))
202
- key = secret_reader.read(certificate_secret.pop("key"))
203
- bundle_method = cert_values.pop("bundle_method") or "ubiquitous"
204
- custom_ssl_values: dict[Any, Any] = {
205
- "zone_id": f"${{{zone.id}}}",
206
- "depends_on": self._get_dependencies([zone]),
207
- "custom_ssl_options": {
208
- "bundle_method": bundle_method,
209
- "type": cert_values.pop("type"),
210
- "certificate": certificate,
211
- "private_key": key,
212
- },
213
- }
214
- if cert_values.get("geo_restrictions", None):
215
- custom_ssl_values["custom_ssl_options"]["geo_restrictions"] = (
216
- cert_values.get("geo_resrtictions")
217
- )
218
- custom_ssl = cloudflare_custom_ssl(identifier, **custom_ssl_values)
219
- resources.append(custom_ssl)
220
- return resources
221
-
222
- def populate(self) -> list[Resource | Output]:
223
- resources = []
224
-
225
- values = ResourceValueResolver(self._spec).resolve()
226
-
227
- zone_settings = values.pop("settings", {})
228
- zone_argo = values.pop("argo", None)
229
- # TODO: Do something with this value when cache_reserve is supported in
230
- # the provider https://github.com/cloudflare/terraform-provider-cloudflare
231
- # We pop the value here because it's not supported by the provider at this
232
- # time.
233
- _ = values.pop("cache_reserve", None)
234
- zone_tiered_cache = values.pop("tiered_cache", None)
235
- zone_records = values.pop("records", [])
236
- zone_workers = values.pop("workers", [])
237
- zone_certs = values.pop("certificates", [])
238
- zone_custom_ssl = values.pop("custom_ssl_certificates", [])
239
-
240
- zone_values = {
241
- "account_id": "${var.account_id}",
242
- **values,
243
- }
244
- zone = cloudflare_zone(self._spec.identifier, **zone_values)
245
- resources.append(zone)
246
-
247
- settings_override_values = {
248
- "zone_id": f"${{{zone.id}}}",
249
- "settings": zone_settings,
250
- "depends_on": self._get_dependencies([zone]),
251
- }
252
-
253
- zone_settings_override = cloudflare_zone_settings_override(
254
- self._spec.identifier, **settings_override_values
255
- )
256
- resources.append(zone_settings_override)
257
-
258
- if zone_argo is not None:
259
- # Terraform accepts "on" and "off" as values. However our data comes from a
260
- # YAML 1.1 implementation that turns the strings "on" and "off" into True and
261
- # False booleans so we must convert them back.
262
- # See: https://stackoverflow.com/a/42284910
263
- for k in ("smart_routing", "tiered_caching"):
264
- if k in zone_argo:
265
- zone_argo[k] = "on" if zone_argo[k] is True else "off"
266
-
267
- argo_values = {
268
- "zone_id": f"${{{zone.id}}}",
269
- "depends_on": self._get_dependencies([zone]),
270
- **zone_argo,
271
- }
272
-
273
- resources.append(cloudflare_argo(self._spec.identifier, **argo_values))
274
-
275
- if zone_tiered_cache is not None:
276
- tiered_cache_values = {
277
- "zone_id": f"${{{zone.id}}}",
278
- "depends_on": self._get_dependencies([zone]),
279
- **zone_tiered_cache,
280
- }
281
-
282
- resources.append(
283
- cloudflare_tiered_cache(self._spec.identifier, **tiered_cache_values)
284
- )
285
-
286
- for record in zone_records:
287
- identifier = safe_resource_id(record.pop("identifier"))
288
- record_values = {
289
- "zone_id": f"${{{zone.id}}}",
290
- "depends_on": self._get_dependencies([zone]),
291
- **record,
292
- }
293
- resources.append(cloudflare_record(identifier, **record_values))
294
-
295
- for worker in zone_workers:
296
- identifier = safe_resource_id(worker.pop("identifier"))
297
- worker_route_values = {
298
- "zone_id": f"${{{zone.id}}}",
299
- **worker,
300
- }
301
- resources.append(cloudflare_worker_route(identifier, **worker_route_values))
302
-
303
- resources.extend(self._create_cloudflare_certificate_pack(zone, zone_certs))
304
-
305
- if zone_custom_ssl:
306
- resources.extend(
307
- self._create_cloudflare_custom_ssl_certificates(zone, zone_custom_ssl)
308
- )
309
-
310
- return resources
311
-
312
-
313
- class CloudflareAccountMemberTerrascriptResource(TerrascriptResource):
314
- def populate(self) -> list[Resource | Output]:
315
- resources = []
316
- values = ResourceValueResolver(self._spec).resolve()
317
- data_source_cloudflare_account_roles = values.pop("cloudflare_account_roles")
318
-
319
- cf_account_member = cloudflare_account_member(self._spec.identifier, **values)
320
- resources.append(cf_account_member)
321
-
322
- cf_account_roles = cloudflare_account_roles(
323
- data_source_cloudflare_account_roles.pop("identifier"),
324
- **data_source_cloudflare_account_roles,
325
- )
326
- resources.append(cf_account_roles)
327
-
328
- return resources
329
-
330
-
331
- class CloudflareLogpushJob(TerrascriptResource):
332
- class cloudflare_zone(Data):
333
- """
334
- https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/data-sources/zones
335
-
336
- This resource isn't supported directly by Terrascript, which is why it needs to be
337
- defined like this as a Resource. In addition, this data source class has name collision with resource, hence
338
- we are defining this as inner class.
339
- """
340
-
341
- def populate(self) -> list[Resource | Output | Data]:
342
- resources = []
343
- values = ResourceValueResolver(self._spec).resolve()
344
- zone = values.pop("zone_name", None)
345
- name = values.pop("job_name", None)
346
-
347
- if name:
348
- values["name"] = name
349
-
350
- if zone:
351
- resources.append(
352
- self.cloudflare_zone(
353
- safe_resource_id(zone), name=zone, account_id="${var.account_id}"
354
- )
355
- )
356
- values["zone_id"] = f"${{data.cloudflare_zone.{safe_resource_id(zone)}.id}}"
357
- else:
358
- values["account_id"] = "${var.account_id}"
359
-
360
- resources.append(cloudflare_logpush_job(self._spec.identifier, **values))
361
- return resources
362
-
363
-
364
- class CloudflareLogpushOwnershipChallengeResource(TerrascriptResource):
365
- class cloudflare_zone(Data):
366
- """
367
- https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/data-sources/zones
368
-
369
- This resource isn't supported directly by Terrascript, which is why it needs to be
370
- defined like this as a Resource. In addition, this data source class has name collision with resource, hence
371
- we are defining this as inner class.
372
- """
373
-
374
- def populate(self) -> list[Resource | Output | Data]:
375
- resources = []
376
- values = ResourceValueResolver(self._spec).resolve()
377
- destination_conf = values.get("destination_conf")
378
- zone = values.get("zone_name")
379
- if zone:
380
- resources += [
381
- self.cloudflare_zone(
382
- safe_resource_id(zone), name=zone, account_id="${var.account_id}"
383
- ),
384
- cloudflare_logpush_ownership_challenge(
385
- self._spec.identifier,
386
- zone_id=f"${{data.cloudflare_zone.{safe_resource_id(zone)}.id}}",
387
- destination_conf=destination_conf,
388
- ),
389
- ]
390
- else:
391
- resources.append(
392
- cloudflare_logpush_ownership_challenge(
393
- self._spec.identifier,
394
- account_id="${var.account_id}",
395
- destination_conf=destination_conf,
396
- )
397
- )
398
- return resources
399
-
400
-
401
- class CloudflareLogpullRetention(TerrascriptResource):
402
- class cloudflare_zone(Data):
403
- """
404
- https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/data-sources/zones
405
-
406
- This resource isn't supported directly by Terrascript, which is why it needs to be
407
- defined like this as a Resource. In addition, this data source class has name collision with resource, hence
408
- we are defining this as inner class.
409
- """
410
-
411
- def populate(self) -> list[Resource | Output | Data]:
412
- resources = []
413
- values = ResourceValueResolver(self._spec).resolve()
414
-
415
- zone = values.get("zone")
416
-
417
- # this is to appease mypy
418
- if not zone:
419
- return []
420
-
421
- resources.append(
422
- self.cloudflare_zone(
423
- safe_resource_id(zone), name=zone, account_id="${var.account_id}"
424
- )
425
- )
426
- cf_logpull_retention = cloudflare_logpull_retention(
427
- self._spec.identifier,
428
- zone_id=f"${{data.cloudflare_zone.{safe_resource_id(zone)}.id}}",
429
- enabled=values.get("enabled_flag"),
430
- )
431
- resources.append(cf_logpull_retention)
432
- return resources
@@ -1,26 +0,0 @@
1
- from dataclasses import dataclass
2
-
3
- from reconcile.utils.secret_reader import HasSecret
4
-
5
-
6
- @dataclass
7
- class Integration:
8
- name: str
9
- key: str
10
-
11
-
12
- @dataclass
13
- class TerraformStateS3:
14
- automation_token: HasSecret
15
- bucket: str
16
- region: str
17
- integration: Integration
18
-
19
-
20
- @dataclass
21
- class CloudflareAccount:
22
- name: str
23
- api_credentials: HasSecret
24
- enforce_twofactor: bool | None
25
- type: str | None
26
- provider_version: str
@@ -1,43 +0,0 @@
1
- from abc import (
2
- ABC,
3
- abstractmethod,
4
- )
5
- from collections.abc import Iterable
6
-
7
- from terrascript import (
8
- Data,
9
- Output,
10
- Resource,
11
- )
12
-
13
- from reconcile.utils.external_resource_spec import ExternalResourceSpec
14
-
15
-
16
- class TerrascriptResource(ABC):
17
- """
18
- Base class for creating Terrascript resources. New resources are added by
19
- subclassing this class and implementing the logic to return the required Terrascript
20
- resource objects.
21
-
22
- Note: each populate_tf_resource_<resource_name> methods in the TerrascriptAwsClient
23
- is a separate class using this pattern. This means that each class that implements
24
- TerrascriptResource can result in N resources being created if it makes sense to
25
- implicitly created certain resources.
26
- """
27
-
28
- def __init__(self, spec: ExternalResourceSpec) -> None:
29
- self._spec = spec
30
-
31
- @staticmethod
32
- def _get_dependencies(tf_resources: Iterable[Resource]) -> list[str]:
33
- """
34
- Formats the dependency name properly for use with depends_on configuration.
35
- """
36
- return [
37
- f"{tf_resource.__class__.__name__}.{tf_resource._name}"
38
- for tf_resource in tf_resources
39
- ]
40
-
41
- @abstractmethod
42
- def populate(self) -> list[Resource | Output | Data]:
43
- """Calling this method should return the Terrascript resources to be created."""