qontract-reconcile 0.10.2.dev414__py3-none-any.whl → 0.10.2.dev456__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.
Potentially problematic release.
This version of qontract-reconcile might be problematic. Click here for more details.
- {qontract_reconcile-0.10.2.dev414.dist-info → qontract_reconcile-0.10.2.dev456.dist-info}/METADATA +2 -2
- {qontract_reconcile-0.10.2.dev414.dist-info → qontract_reconcile-0.10.2.dev456.dist-info}/RECORD +55 -53
- {qontract_reconcile-0.10.2.dev414.dist-info → qontract_reconcile-0.10.2.dev456.dist-info}/WHEEL +1 -1
- reconcile/aus/advanced_upgrade_service.py +3 -0
- reconcile/aus/aus_sts_gate_handler.py +59 -0
- reconcile/aus/base.py +115 -8
- reconcile/aus/models.py +2 -0
- reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
- reconcile/aus/ocm_upgrade_scheduler.py +8 -1
- reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
- reconcile/aus/version_gate_approver.py +1 -16
- reconcile/aus/version_gates/sts_version_gate_handler.py +5 -72
- reconcile/automated_actions/config/integration.py +1 -1
- reconcile/aws_ecr_image_pull_secrets.py +1 -1
- reconcile/change_owners/change_owners.py +100 -34
- reconcile/cli.py +63 -5
- reconcile/external_resources/manager.py +7 -18
- reconcile/external_resources/model.py +8 -8
- reconcile/external_resources/secrets_sync.py +2 -3
- reconcile/external_resources/state.py +1 -34
- reconcile/gql_definitions/common/aws_vpc_requests.py +3 -0
- reconcile/gql_definitions/common/clusters.py +2 -0
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +3 -1
- reconcile/gql_definitions/fragments/aws_vpc_request.py +5 -0
- reconcile/gql_definitions/introspection.json +48 -0
- reconcile/gql_definitions/rhcs/certs.py +20 -74
- reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +5 -1
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +3 -0
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +1 -0
- reconcile/ocm_machine_pools.py +12 -6
- reconcile/openshift_base.py +60 -2
- reconcile/openshift_namespaces.py +3 -4
- reconcile/openshift_rhcs_certs.py +71 -34
- reconcile/rhidp/sso_client/base.py +15 -4
- reconcile/templates/rosa-classic-cluster-creation.sh.j2 +1 -1
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +1 -1
- reconcile/terraform_vpc_resources/integration.py +10 -7
- reconcile/typed_queries/saas_files.py +9 -4
- reconcile/utils/binary.py +7 -12
- reconcile/utils/environ.py +5 -0
- reconcile/utils/gitlab_api.py +12 -0
- reconcile/utils/glitchtip/client.py +2 -2
- reconcile/utils/jjb_client.py +19 -3
- reconcile/utils/jobcontroller/controller.py +1 -1
- reconcile/utils/json.py +5 -1
- reconcile/utils/oc.py +144 -113
- reconcile/utils/rhcsv2_certs.py +87 -21
- reconcile/utils/rosa/session.py +16 -0
- reconcile/utils/saasherder/saasherder.py +20 -7
- reconcile/utils/terrascript_aws_client.py +140 -50
- reconcile/utils/vault.py +1 -1
- reconcile/vpc_peerings_validator.py +13 -0
- tools/cli_commands/erv2.py +1 -3
- {qontract_reconcile-0.10.2.dev414.dist-info → qontract_reconcile-0.10.2.dev456.dist-info}/entry_points.txt +0 -0
|
@@ -272,6 +272,7 @@ VARIABLE_KEYS = [
|
|
|
272
272
|
"lifecycle",
|
|
273
273
|
"max_session_duration",
|
|
274
274
|
"secret_format",
|
|
275
|
+
"policy",
|
|
275
276
|
]
|
|
276
277
|
|
|
277
278
|
EMAIL_REGEX = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
|
|
@@ -373,6 +374,10 @@ class aws_s3_bucket_logging(Resource):
|
|
|
373
374
|
pass
|
|
374
375
|
|
|
375
376
|
|
|
377
|
+
class aws_kinesis_resource_policy(Resource):
|
|
378
|
+
pass
|
|
379
|
+
|
|
380
|
+
|
|
376
381
|
class aws_cloudfront_log_delivery_canonical_user_id(Data):
|
|
377
382
|
pass
|
|
378
383
|
|
|
@@ -2249,14 +2254,22 @@ class TerrascriptClient:
|
|
|
2249
2254
|
|
|
2250
2255
|
return lifecycle_rules
|
|
2251
2256
|
|
|
2252
|
-
def
|
|
2257
|
+
def _populate_tf_resource_s3_bucket(
|
|
2258
|
+
self,
|
|
2259
|
+
spec: ExternalResourceSpec,
|
|
2260
|
+
common_values: dict[str, Any],
|
|
2261
|
+
) -> tuple[aws_s3_bucket, list[TFResource]]:
|
|
2262
|
+
"""Create S3 bucket with configuration and notifications.
|
|
2263
|
+
|
|
2264
|
+
Creates aws_s3_bucket with versioning, encryption, lifecycle rules,
|
|
2265
|
+
CORS, logging, and replication. Also creates aws_s3_bucket_notification
|
|
2266
|
+
for SQS/SNS event notifications if configured.
|
|
2267
|
+
"""
|
|
2253
2268
|
account = spec.provisioner_name
|
|
2254
2269
|
identifier = spec.identifier
|
|
2255
|
-
common_values = self.init_values(spec)
|
|
2256
2270
|
output_prefix = spec.output_prefix
|
|
2257
2271
|
|
|
2258
2272
|
tf_resources: list[TFResource] = []
|
|
2259
|
-
self.init_common_outputs(tf_resources, spec)
|
|
2260
2273
|
|
|
2261
2274
|
# s3 bucket
|
|
2262
2275
|
# Terraform resource reference:
|
|
@@ -2433,8 +2446,7 @@ class TerrascriptClient:
|
|
|
2433
2446
|
output_name = output_prefix + "__endpoint"
|
|
2434
2447
|
tf_resources.append(Output(output_name, value=endpoint))
|
|
2435
2448
|
|
|
2436
|
-
sqs_identifier
|
|
2437
|
-
if sqs_identifier is not None:
|
|
2449
|
+
if sqs_identifier := common_values.get("sqs_identifier"):
|
|
2438
2450
|
sqs_values = {"name": sqs_identifier}
|
|
2439
2451
|
sqs_provider = values.get("provider")
|
|
2440
2452
|
if sqs_provider:
|
|
@@ -2453,11 +2465,9 @@ class TerrascriptClient:
|
|
|
2453
2465
|
}
|
|
2454
2466
|
],
|
|
2455
2467
|
}
|
|
2456
|
-
filter_prefix
|
|
2457
|
-
if filter_prefix is not None:
|
|
2468
|
+
if filter_prefix := common_values.get("filter_prefix"):
|
|
2458
2469
|
notification_values["queue"][0]["filter_prefix"] = filter_prefix
|
|
2459
|
-
filter_suffix
|
|
2460
|
-
if filter_suffix is not None:
|
|
2470
|
+
if filter_suffix := common_values.get("filter_suffix"):
|
|
2461
2471
|
notification_values["queue"][0]["filter_suffix"] = filter_suffix
|
|
2462
2472
|
|
|
2463
2473
|
notification_tf_resource = aws_s3_bucket_notification(
|
|
@@ -2537,21 +2547,48 @@ class TerrascriptClient:
|
|
|
2537
2547
|
)
|
|
2538
2548
|
tf_resources.append(notification_tf_resource)
|
|
2539
2549
|
|
|
2540
|
-
|
|
2541
|
-
if bucket_policy:
|
|
2542
|
-
values = {
|
|
2543
|
-
"bucket": identifier,
|
|
2544
|
-
"policy": bucket_policy,
|
|
2545
|
-
"depends_on": self.get_dependencies([bucket_tf_resource]),
|
|
2546
|
-
}
|
|
2547
|
-
if self._multiregion_account(account):
|
|
2548
|
-
values["provider"] = "aws." + region
|
|
2549
|
-
bucket_policy_tf_resource = aws_s3_bucket_policy(identifier, **values)
|
|
2550
|
-
tf_resources.append(bucket_policy_tf_resource)
|
|
2550
|
+
return bucket_tf_resource, tf_resources
|
|
2551
2551
|
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2552
|
+
def _populate_tf_resource_s3_bucket_policy(
|
|
2553
|
+
self,
|
|
2554
|
+
spec: ExternalResourceSpec,
|
|
2555
|
+
bucket_tf_resource: aws_s3_bucket,
|
|
2556
|
+
policy: str,
|
|
2557
|
+
common_values: dict[str, Any],
|
|
2558
|
+
) -> list[TFResource]:
|
|
2559
|
+
"""Create S3 bucket policy resource.
|
|
2560
|
+
|
|
2561
|
+
Creates aws_s3_bucket_policy with the provided policy document.
|
|
2562
|
+
"""
|
|
2563
|
+
account = spec.provisioner_name
|
|
2564
|
+
identifier = spec.identifier
|
|
2565
|
+
region = common_values.get("region") or self.default_regions.get(account)
|
|
2566
|
+
assert region # make mypy happy
|
|
2567
|
+
|
|
2568
|
+
values: dict[str, Any] = {
|
|
2569
|
+
"bucket": identifier,
|
|
2570
|
+
"policy": policy,
|
|
2571
|
+
"depends_on": self.get_dependencies([bucket_tf_resource]),
|
|
2572
|
+
}
|
|
2573
|
+
if self._multiregion_account(account):
|
|
2574
|
+
values["provider"] = "aws." + region
|
|
2575
|
+
bucket_policy_tf_resource = aws_s3_bucket_policy(identifier, **values)
|
|
2576
|
+
return [bucket_policy_tf_resource]
|
|
2577
|
+
|
|
2578
|
+
def _populate_tf_resource_s3_iam(
|
|
2579
|
+
self,
|
|
2580
|
+
spec: ExternalResourceSpec,
|
|
2581
|
+
bucket_tf_resource: aws_s3_bucket,
|
|
2582
|
+
common_values: dict[str, Any],
|
|
2583
|
+
) -> list[TFResource]:
|
|
2584
|
+
"""Create IAM resources for S3 bucket access.
|
|
2585
|
+
|
|
2586
|
+
Creates aws_iam_user, aws_iam_access_key, aws_iam_policy,
|
|
2587
|
+
and aws_iam_user_policy_attachment for bucket access.
|
|
2588
|
+
"""
|
|
2589
|
+
identifier = spec.identifier
|
|
2590
|
+
output_prefix = spec.output_prefix
|
|
2591
|
+
tf_resources: list[TFResource] = []
|
|
2555
2592
|
|
|
2556
2593
|
# iam user for bucket
|
|
2557
2594
|
values = {
|
|
@@ -2609,6 +2646,32 @@ class TerrascriptClient:
|
|
|
2609
2646
|
)
|
|
2610
2647
|
tf_resources.append(tf_user_policy_attachment)
|
|
2611
2648
|
|
|
2649
|
+
return tf_resources
|
|
2650
|
+
|
|
2651
|
+
def populate_tf_resource_s3(self, spec: ExternalResourceSpec) -> aws_s3_bucket:
|
|
2652
|
+
account = spec.provisioner_name
|
|
2653
|
+
common_values = self.init_values(spec)
|
|
2654
|
+
|
|
2655
|
+
tf_resources: list[TFResource] = []
|
|
2656
|
+
self.init_common_outputs(tf_resources, spec)
|
|
2657
|
+
|
|
2658
|
+
bucket_tf_resource, bucket_resources = self._populate_tf_resource_s3_bucket(
|
|
2659
|
+
spec, common_values
|
|
2660
|
+
)
|
|
2661
|
+
tf_resources.extend(bucket_resources)
|
|
2662
|
+
|
|
2663
|
+
bucket_policy = common_values.get("bucket_policy")
|
|
2664
|
+
if bucket_policy:
|
|
2665
|
+
tf_resources.extend(
|
|
2666
|
+
self._populate_tf_resource_s3_bucket_policy(
|
|
2667
|
+
spec, bucket_tf_resource, bucket_policy, common_values
|
|
2668
|
+
)
|
|
2669
|
+
)
|
|
2670
|
+
|
|
2671
|
+
tf_resources.extend(
|
|
2672
|
+
self._populate_tf_resource_s3_iam(spec, bucket_tf_resource, common_values)
|
|
2673
|
+
)
|
|
2674
|
+
|
|
2612
2675
|
self.add_resources(account, tf_resources)
|
|
2613
2676
|
|
|
2614
2677
|
return bucket_tf_resource
|
|
@@ -3383,42 +3446,53 @@ class TerrascriptClient:
|
|
|
3383
3446
|
common_values = self.init_values(spec)
|
|
3384
3447
|
output_prefix = spec.output_prefix
|
|
3385
3448
|
|
|
3386
|
-
bucket_tf_resource = self.populate_tf_resource_s3(spec)
|
|
3387
|
-
|
|
3388
3449
|
tf_resources: list[TFResource] = []
|
|
3450
|
+
self.init_common_outputs(tf_resources, spec)
|
|
3451
|
+
|
|
3452
|
+
bucket_tf_resource, bucket_resources = self._populate_tf_resource_s3_bucket(
|
|
3453
|
+
spec, common_values
|
|
3454
|
+
)
|
|
3455
|
+
tf_resources.extend(bucket_resources)
|
|
3456
|
+
|
|
3457
|
+
tf_resources.extend(
|
|
3458
|
+
self._populate_tf_resource_s3_iam(spec, bucket_tf_resource, common_values)
|
|
3459
|
+
)
|
|
3389
3460
|
|
|
3390
3461
|
# cloudfront origin access identity
|
|
3391
3462
|
values = {"comment": f"{identifier}-cf-identity"}
|
|
3392
3463
|
cf_oai_tf_resource = aws_cloudfront_origin_access_identity(identifier, **values)
|
|
3393
3464
|
tf_resources.append(cf_oai_tf_resource)
|
|
3394
3465
|
|
|
3395
|
-
# bucket policy for cloudfront
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
"
|
|
3399
|
-
"
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
"Action": "s3:GetObject",
|
|
3405
|
-
"Resource": [
|
|
3406
|
-
f"arn:aws:s3:::{identifier}/{enable_dir}/*"
|
|
3407
|
-
for enable_dir in common_values.get(
|
|
3408
|
-
"get_object_enable_dirs", []
|
|
3409
|
-
)
|
|
3410
|
-
],
|
|
3411
|
-
}
|
|
3466
|
+
# bucket policy for cloudfront - merge custom policy with CloudFront access statement
|
|
3467
|
+
cf_statement = {
|
|
3468
|
+
"Sid": "Grant access to CloudFront Origin Identity",
|
|
3469
|
+
"Effect": "Allow",
|
|
3470
|
+
"Principal": {"AWS": "${" + cf_oai_tf_resource.iam_arn + "}"},
|
|
3471
|
+
"Action": "s3:GetObject",
|
|
3472
|
+
"Resource": [
|
|
3473
|
+
f"arn:aws:s3:::{identifier}/{enable_dir}/*"
|
|
3474
|
+
for enable_dir in common_values.get("get_object_enable_dirs", [])
|
|
3412
3475
|
],
|
|
3413
3476
|
}
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3477
|
+
|
|
3478
|
+
custom_bucket_policy = common_values.get("bucket_policy")
|
|
3479
|
+
if custom_bucket_policy:
|
|
3480
|
+
# if the user specifies a custom bucket policy then we merge their statements with the cloudfront origin identity policy
|
|
3481
|
+
if isinstance(custom_bucket_policy, str):
|
|
3482
|
+
custom_bucket_policy = json.loads(custom_bucket_policy)
|
|
3483
|
+
custom_bucket_policy.setdefault("Statement", []).append(cf_statement)
|
|
3484
|
+
policy = custom_bucket_policy
|
|
3485
|
+
else:
|
|
3486
|
+
policy = {
|
|
3487
|
+
"Version": "2012-10-17",
|
|
3488
|
+
"Statement": [cf_statement],
|
|
3489
|
+
}
|
|
3490
|
+
|
|
3491
|
+
tf_resources.extend(
|
|
3492
|
+
self._populate_tf_resource_s3_bucket_policy(
|
|
3493
|
+
spec, bucket_tf_resource, json_dumps(policy), common_values
|
|
3494
|
+
)
|
|
3495
|
+
)
|
|
3422
3496
|
|
|
3423
3497
|
distribution_config = common_values.get("distribution_config", {})
|
|
3424
3498
|
# aws_s3_bucket_acl
|
|
@@ -4019,6 +4093,22 @@ class TerrascriptClient:
|
|
|
4019
4093
|
kinesis_tf_resource = aws_kinesis_stream(identifier, **kinesis_values)
|
|
4020
4094
|
tf_resources.append(kinesis_tf_resource)
|
|
4021
4095
|
|
|
4096
|
+
# kinesis resource policy (optional)
|
|
4097
|
+
# Terraform resource reference:
|
|
4098
|
+
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kinesis_resource_policy
|
|
4099
|
+
if policy := common_values.get("policy"):
|
|
4100
|
+
policy_identifier = f"{identifier}-policy"
|
|
4101
|
+
policy_values: dict[str, Any] = {
|
|
4102
|
+
"resource_arn": "${" + kinesis_tf_resource.arn + "}",
|
|
4103
|
+
"policy": policy,
|
|
4104
|
+
}
|
|
4105
|
+
if provider:
|
|
4106
|
+
policy_values["provider"] = provider
|
|
4107
|
+
kinesis_policy_tf_resource = aws_kinesis_resource_policy(
|
|
4108
|
+
policy_identifier, **policy_values
|
|
4109
|
+
)
|
|
4110
|
+
tf_resources.append(kinesis_policy_tf_resource)
|
|
4111
|
+
|
|
4022
4112
|
es_identifier = common_values.get("es_identifier", None)
|
|
4023
4113
|
if es_identifier:
|
|
4024
4114
|
es_resource = self._find_resource_spec(
|
reconcile/utils/vault.py
CHANGED
|
@@ -200,7 +200,7 @@ class VaultClient:
|
|
|
200
200
|
a v2 KV engine)
|
|
201
201
|
"""
|
|
202
202
|
secret_path = secret["path"]
|
|
203
|
-
secret_version = secret.get("version"
|
|
203
|
+
secret_version = secret.get("version") or SECRET_VERSION_LATEST
|
|
204
204
|
|
|
205
205
|
kv_version = self._get_mount_version_by_secret_path(secret_path)
|
|
206
206
|
|
|
@@ -159,6 +159,19 @@ def validate_no_public_to_public_peerings(
|
|
|
159
159
|
if peer.internal or (peer.spec and peer.spec.private):
|
|
160
160
|
continue
|
|
161
161
|
|
|
162
|
+
# If both sides are allowed to override this check, then we can
|
|
163
|
+
# allow the peering.
|
|
164
|
+
if (
|
|
165
|
+
cluster.allowed_to_bypass_public_peering_restriction
|
|
166
|
+
and peer.allowed_to_bypass_public_peering_restriction
|
|
167
|
+
):
|
|
168
|
+
logging.debug(
|
|
169
|
+
f"{cluster.name} and {peer.name} are both allowed to skip \
|
|
170
|
+
the check 'no peering with public clusters' check, so their \
|
|
171
|
+
peering is allowed"
|
|
172
|
+
)
|
|
173
|
+
continue
|
|
174
|
+
|
|
162
175
|
valid = False
|
|
163
176
|
pair = {cluster.name, peer.name}
|
|
164
177
|
if pair in found_pairs:
|
tools/cli_commands/erv2.py
CHANGED
|
@@ -133,9 +133,7 @@ class Erv2Cli:
|
|
|
133
133
|
|
|
134
134
|
@property
|
|
135
135
|
def input_data(self) -> str:
|
|
136
|
-
return self._resource.
|
|
137
|
-
exclude={"data": {FLAG_RESOURCE_MANAGED_BY_ERV2}}
|
|
138
|
-
)
|
|
136
|
+
return self._resource.export(exclude={"data": {FLAG_RESOURCE_MANAGED_BY_ERV2}})
|
|
139
137
|
|
|
140
138
|
@property
|
|
141
139
|
def image(self) -> str:
|
|
File without changes
|