qontract-reconcile 0.10.1rc976__py3-none-any.whl → 0.10.1rc977__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.
- {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/RECORD +109 -109
- reconcile/aus/healthchecks.py +1 -1
- reconcile/aws_account_manager/integration.py +23 -21
- reconcile/aws_account_manager/reconciler.py +1 -1
- reconcile/aws_saml_idp/integration.py +5 -5
- reconcile/aws_saml_roles/integration.py +5 -5
- reconcile/aws_version_sync/utils.py +3 -3
- reconcile/cna/state.py +2 -2
- reconcile/database_access_manager.py +2 -5
- reconcile/external_resources/manager.py +3 -3
- reconcile/external_resources/model.py +1 -1
- reconcile/external_resources/secrets_sync.py +2 -2
- reconcile/external_resources/state.py +1 -1
- reconcile/gcr_mirror.py +2 -6
- reconcile/jira_permissions_validator.py +4 -4
- reconcile/ldap_groups/integration.py +4 -7
- reconcile/ocm_internal_notifications/integration.py +2 -2
- reconcile/openshift_base.py +14 -14
- reconcile/openshift_cluster_bots.py +1 -1
- reconcile/openshift_clusterrolebindings.py +9 -10
- reconcile/openshift_namespace_labels.py +2 -2
- reconcile/openshift_namespaces.py +1 -1
- reconcile/openshift_resources_base.py +9 -9
- reconcile/openshift_rolebindings.py +8 -11
- reconcile/openshift_saas_deploy_trigger_base.py +8 -5
- reconcile/oum/base.py +1 -1
- reconcile/quay_mirror.py +3 -10
- reconcile/queries.py +1 -1
- reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +2 -2
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
- reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +0 -1
- reconcile/skupper_network/integration.py +3 -1
- reconcile/skupper_network/site_controller.py +8 -8
- reconcile/slack_usergroups.py +10 -10
- reconcile/status_board.py +1 -1
- reconcile/statuspage/status.py +1 -3
- reconcile/terraform_cloudflare_dns.py +2 -3
- reconcile/terraform_cloudflare_users.py +2 -3
- reconcile/terraform_repo.py +5 -3
- reconcile/terraform_resources.py +16 -16
- reconcile/terraform_tgw_attachments.py +6 -6
- reconcile/terraform_vpc_peerings.py +8 -8
- reconcile/terraform_vpc_resources/integration.py +1 -1
- reconcile/test/test_aws_cloudwatch_log_retention.py +2 -5
- reconcile/test/test_github_org.py +18 -16
- reconcile/test/test_github_repo_invites.py +10 -10
- reconcile/test/test_integrations_manager.py +11 -11
- reconcile/test/test_ocm_additional_routers.py +6 -6
- reconcile/test/test_ocm_clusters.py +1 -0
- reconcile/test/test_ocm_update_recommended_version.py +2 -2
- reconcile/test/test_openshift_serviceaccount_tokens.py +5 -5
- reconcile/test/test_openshift_tekton_resources.py +3 -3
- reconcile/test/test_saasherder.py +48 -48
- reconcile/test/test_sql_query.py +1 -1
- reconcile/test/test_terraform_cloudflare_resources.py +14 -14
- reconcile/test/test_terraform_cloudflare_users.py +4 -4
- reconcile/test/test_terraform_resources.py +32 -32
- reconcile/test/test_terraform_tgw_attachments.py +5 -5
- reconcile/typed_queries/saas_files.py +1 -1
- reconcile/unleash_feature_toggles/integration.py +2 -2
- reconcile/utils/aggregated_list.py +1 -1
- reconcile/utils/aws_api.py +1 -1
- reconcile/utils/aws_api_typed/iam.py +4 -2
- reconcile/utils/aws_api_typed/service_quotas.py +2 -2
- reconcile/utils/binary.py +1 -1
- reconcile/utils/clusterhealth/telemeter.py +5 -3
- reconcile/utils/config.py +4 -2
- reconcile/utils/expiration.py +1 -1
- reconcile/utils/external_resources.py +4 -7
- reconcile/utils/git.py +1 -3
- reconcile/utils/gitlab_api.py +1 -4
- reconcile/utils/gql.py +9 -8
- reconcile/utils/helm.py +1 -1
- reconcile/utils/imap_client.py +3 -1
- reconcile/utils/internal_groups/client.py +1 -1
- reconcile/utils/jinja2/utils.py +4 -4
- reconcile/utils/jobcontroller/models.py +2 -2
- reconcile/utils/jump_host.py +1 -1
- reconcile/utils/ldap_client.py +1 -1
- reconcile/utils/merge_request_manager/merge_request_manager.py +1 -4
- reconcile/utils/models.py +2 -5
- reconcile/utils/oc.py +18 -28
- reconcile/utils/ocm/ocm.py +3 -1
- reconcile/utils/ocm/products.py +2 -2
- reconcile/utils/ocm/search_filters.py +4 -11
- reconcile/utils/ocm_base_client.py +1 -4
- reconcile/utils/openshift_resource.py +12 -19
- reconcile/utils/quay_api.py +1 -3
- reconcile/utils/repo_owners.py +2 -8
- reconcile/utils/runtime/runner.py +1 -1
- reconcile/utils/saasherder/saasherder.py +4 -4
- reconcile/utils/secret_reader.py +2 -2
- reconcile/utils/slack_api.py +1 -1
- reconcile/utils/sqs_gateway.py +1 -1
- reconcile/utils/state.py +4 -4
- reconcile/utils/terraform/config_client.py +1 -1
- reconcile/utils/terraform_client.py +2 -2
- reconcile/utils/terrascript_aws_client.py +13 -23
- reconcile/utils/three_way_diff_strategy.py +3 -9
- reconcile/utils/unleash/client.py +2 -2
- reconcile/utils/vault.py +11 -14
- reconcile/utils/vcs.py +1 -1
- reconcile/vault_replication.py +1 -1
- tools/app_interface_reporter.py +2 -3
- tools/qontract_cli.py +1 -1
- {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc977.dist-info}/top_level.txt +0 -0
@@ -252,29 +252,31 @@ class AwsAccountMgmtIntegration(
|
|
252
252
|
)
|
253
253
|
|
254
254
|
secret = self.secret_reader.read_all_secret(payer_account.automation_token)
|
255
|
-
with
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
255
|
+
with (
|
256
|
+
AWSApi(
|
257
|
+
AWSStaticCredentials(
|
258
|
+
access_key_id=secret["aws_access_key_id"],
|
259
|
+
secret_access_key=secret["aws_secret_access_key"],
|
260
|
+
region=payer_account.resources_default_region,
|
261
|
+
)
|
262
|
+
) as payer_account_aws_api,
|
263
|
+
payer_account_aws_api.assume_role(
|
263
264
|
account_id=payer_account.uid,
|
264
265
|
role=aws_account_manager_role,
|
265
|
-
) as acct_manager_role_aws_api
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
266
|
+
) as acct_manager_role_aws_api,
|
267
|
+
):
|
268
|
+
self.create_accounts(
|
269
|
+
acct_manager_role_aws_api,
|
270
|
+
reconciler,
|
271
|
+
merge_request_manager,
|
272
|
+
account_template,
|
273
|
+
payer_account.account_requests or [],
|
274
|
+
)
|
275
|
+
self.reconcile_organization_accounts(
|
276
|
+
acct_manager_role_aws_api,
|
277
|
+
reconciler,
|
278
|
+
payer_account.organization_accounts or [],
|
279
|
+
)
|
278
280
|
|
279
281
|
def reconcile_non_organization_accounts(
|
280
282
|
self,
|
@@ -204,7 +204,7 @@ class AWSReconciler:
|
|
204
204
|
except AWSResourceAlreadyExistsException:
|
205
205
|
raise AbortStateTransaction(
|
206
206
|
f"A quota increase for this {new_quota.service_code}/{new_quota.quota_code} already exists. Try it again later."
|
207
|
-
)
|
207
|
+
) from None
|
208
208
|
ids.append(req.id)
|
209
209
|
|
210
210
|
_state.value = {"last_applied_quotas": quotas_dict, "ids": ids}
|
@@ -163,11 +163,11 @@ class AwsSamlIdpIntegration(QontractReconcileIntegration[AwsSamlIdpIntegrationPa
|
|
163
163
|
if defer:
|
164
164
|
defer(tf.cleanup)
|
165
165
|
|
166
|
-
runner_params: RunnerParams =
|
167
|
-
tf
|
168
|
-
dry_run
|
169
|
-
enable_deletion
|
170
|
-
|
166
|
+
runner_params: RunnerParams = {
|
167
|
+
"tf": tf,
|
168
|
+
"dry_run": dry_run,
|
169
|
+
"enable_deletion": self.params.enable_deletion,
|
170
|
+
}
|
171
171
|
|
172
172
|
if self.params.enable_extended_early_exit and get_feature_toggle_state(
|
173
173
|
f"{QONTRACT_INTEGRATION}-extended-early-exit", default=True
|
@@ -281,11 +281,11 @@ class AwsSamlRolesIntegration(
|
|
281
281
|
if defer:
|
282
282
|
defer(tf.cleanup)
|
283
283
|
|
284
|
-
runner_params: RunnerParams =
|
285
|
-
tf
|
286
|
-
dry_run
|
287
|
-
enable_deletion
|
288
|
-
|
284
|
+
runner_params: RunnerParams = {
|
285
|
+
"tf": tf,
|
286
|
+
"dry_run": dry_run,
|
287
|
+
"enable_deletion": self.params.enable_deletion,
|
288
|
+
}
|
289
289
|
|
290
290
|
if self.params.enable_extended_early_exit and get_feature_toggle_state(
|
291
291
|
f"{QONTRACT_INTEGRATION}-extended-early-exit", default=True
|
@@ -48,13 +48,13 @@ def get_values(gql_get_resource_func: Callable, path: str) -> dict[str, Any]:
|
|
48
48
|
try:
|
49
49
|
raw_values = gql_get_resource_func(path)
|
50
50
|
except GqlGetResourceError as e:
|
51
|
-
raise FetchResourceError(str(e))
|
51
|
+
raise FetchResourceError(str(e)) from e
|
52
52
|
try:
|
53
53
|
values = anymarkup.parse(raw_values["content"], force_types=None)
|
54
54
|
values.pop("$schema", None)
|
55
|
-
except anymarkup.AnyMarkupError:
|
55
|
+
except anymarkup.AnyMarkupError as e:
|
56
56
|
e_msg = "Could not parse data. Skipping resource: {}"
|
57
|
-
raise FetchResourceError(e_msg.format(path))
|
57
|
+
raise FetchResourceError(e_msg.format(path)) from e
|
58
58
|
return values
|
59
59
|
|
60
60
|
|
reconcile/cna/state.py
CHANGED
@@ -36,10 +36,10 @@ class State:
|
|
36
36
|
def __eq__(self, other: object) -> bool:
|
37
37
|
if not isinstance(other, State):
|
38
38
|
return False
|
39
|
-
if not set(
|
39
|
+
if not set(self._assets.keys()) == set(other._assets.keys()):
|
40
40
|
return False
|
41
41
|
for kind in list(self._assets.keys()):
|
42
|
-
if not set(
|
42
|
+
if not set(self._assets[kind]) == set(other._assets[kind]):
|
43
43
|
return False
|
44
44
|
for name, asset in self._assets[kind].items():
|
45
45
|
if asset != other._assets[kind][name]:
|
@@ -406,13 +406,10 @@ class JobStatus(BaseModel):
|
|
406
406
|
conditions: list[JobStatusCondition]
|
407
407
|
|
408
408
|
def is_complete(self) -> bool:
|
409
|
-
return
|
409
|
+
return bool(self.conditions)
|
410
410
|
|
411
411
|
def has_errors(self) -> bool:
|
412
|
-
for condition in self.conditions
|
413
|
-
if condition.type == "Failed":
|
414
|
-
return True
|
415
|
-
return False
|
412
|
+
return any(condition.type == "Failed" for condition in self.conditions)
|
416
413
|
|
417
414
|
|
418
415
|
def _populate_resources(
|
@@ -210,10 +210,10 @@ class ExternalResourcesManager:
|
|
210
210
|
"""
|
211
211
|
need_secret_sync = False
|
212
212
|
|
213
|
-
if state.resource_status not in
|
213
|
+
if state.resource_status not in {
|
214
214
|
ResourceStatus.DELETE_IN_PROGRESS,
|
215
215
|
ResourceStatus.IN_PROGRESS,
|
216
|
-
|
216
|
+
}:
|
217
217
|
return False
|
218
218
|
|
219
219
|
logging.info(
|
@@ -374,5 +374,5 @@ class ExternalResourcesManager:
|
|
374
374
|
for r in triggered:
|
375
375
|
self.reconciler.get_resource_reconcile_logs(reconciliation=r)
|
376
376
|
|
377
|
-
if ReconcileStatus.ERROR in
|
377
|
+
if ReconcileStatus.ERROR in list(results.values()):
|
378
378
|
raise Exception("Some Resources have reconciliation errors.")
|
@@ -118,7 +118,7 @@ class ExternalResourcesInventory(MutableMapping):
|
|
118
118
|
return self._inventory[key]
|
119
119
|
except KeyError:
|
120
120
|
msg = f"Resource spec not found: Provider {provider}, Id: {identifier}"
|
121
|
-
raise FetchResourceError(msg)
|
121
|
+
raise FetchResourceError(msg) from None
|
122
122
|
|
123
123
|
|
124
124
|
class Action(StrEnum):
|
@@ -52,7 +52,7 @@ class VaultSecret(BaseModel):
|
|
52
52
|
class SecretHelper:
|
53
53
|
@staticmethod
|
54
54
|
def get_comparable_secret(resource: OpenshiftResource) -> OpenshiftResource:
|
55
|
-
metadata =
|
55
|
+
metadata = dict(resource.body["metadata"].items())
|
56
56
|
metadata["annotations"] = {
|
57
57
|
k: v
|
58
58
|
for k, v in metadata.get("annotations", {}).items()
|
@@ -177,7 +177,7 @@ class SecretsReconciler:
|
|
177
177
|
"""
|
178
178
|
self._populate_secret_data(specs)
|
179
179
|
|
180
|
-
to_sync_specs =
|
180
|
+
to_sync_specs = list(self._specs_with_secret(specs))
|
181
181
|
ocmap = self._init_ocmap(to_sync_specs)
|
182
182
|
|
183
183
|
for spec in to_sync_specs:
|
@@ -235,7 +235,7 @@ class ExternalResourcesStateDynamoDB:
|
|
235
235
|
return partials
|
236
236
|
|
237
237
|
def get_all_resource_keys(self) -> set[ExternalResourceKey]:
|
238
|
-
return
|
238
|
+
return set(self.partial_resources)
|
239
239
|
|
240
240
|
def get_keys_by_status(
|
241
241
|
self, resource_status: ResourceStatus
|
reconcile/gcr_mirror.py
CHANGED
@@ -124,12 +124,8 @@ class QuayMirror:
|
|
124
124
|
@staticmethod
|
125
125
|
def sync_tag(tags, tags_exclude, candidate):
|
126
126
|
if tags is not None:
|
127
|
-
|
128
|
-
|
129
|
-
return True
|
130
|
-
# When tags is defined, we don't look at
|
131
|
-
# tags_exclude
|
132
|
-
return False
|
127
|
+
# When tags is defined, we don't look at tags_exclude
|
128
|
+
return any(re.match(tag, candidate) for tag in tags)
|
133
129
|
|
134
130
|
if tags_exclude is not None:
|
135
131
|
for tag_exclude in tags_exclude:
|
@@ -277,10 +277,10 @@ def run(
|
|
277
277
|
) -> None:
|
278
278
|
gql_api = gql.get_api()
|
279
279
|
boards = get_jira_boards(query_func=gql_api.query)
|
280
|
-
runner_params: RunnerParams =
|
281
|
-
exit_on_permission_errors
|
282
|
-
boards
|
283
|
-
|
280
|
+
runner_params: RunnerParams = {
|
281
|
+
"exit_on_permission_errors": exit_on_permission_errors,
|
282
|
+
"boards": boards,
|
283
|
+
}
|
284
284
|
if enable_extended_early_exit and get_feature_toggle_state(
|
285
285
|
"jira-permissions-validator-extended-early-exit",
|
286
286
|
default=True,
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import contextlib
|
1
2
|
import logging
|
2
3
|
from collections.abc import (
|
3
4
|
Callable,
|
@@ -142,7 +143,7 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
142
143
|
def get_roles(self, query_func: Callable) -> list[RoleV1]:
|
143
144
|
"""Return the roles with ldap_group set."""
|
144
145
|
data = roles_query(query_func, variables={})
|
145
|
-
roles =
|
146
|
+
roles = list(data.roles or [])
|
146
147
|
if duplicates := find_duplicates(
|
147
148
|
role.ldap_group.name for role in roles if role.ldap_group
|
148
149
|
):
|
@@ -224,10 +225,8 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
224
225
|
"""Reach out to the internal groups API and fetch all managed groups."""
|
225
226
|
groups = []
|
226
227
|
for group_name in group_names:
|
227
|
-
|
228
|
+
with contextlib.suppress(NotFound):
|
228
229
|
groups.append(internal_groups_client.group(group_name))
|
229
|
-
except NotFound:
|
230
|
-
pass
|
231
230
|
return groups
|
232
231
|
|
233
232
|
def reconcile(
|
@@ -263,10 +262,8 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
|
|
263
262
|
for group_to_remove in diff_result.delete.values():
|
264
263
|
logging.info(["delete_ldap_group", group_to_remove.name])
|
265
264
|
if not dry_run:
|
266
|
-
|
265
|
+
with contextlib.suppress(NotFound):
|
267
266
|
internal_groups_client.delete_group(group_to_remove.name)
|
268
|
-
except NotFound:
|
269
|
-
pass
|
270
267
|
self._managed_groups.remove(group_to_remove.name)
|
271
268
|
|
272
269
|
for diff_pair in diff_result.change.values():
|
@@ -36,6 +36,7 @@ class OcmInternalNotifications(QontractReconcileIntegration[NoParams]):
|
|
36
36
|
self.slack = slackapi_from_queries(
|
37
37
|
integration_name=self.name, init_usergroups=False
|
38
38
|
)
|
39
|
+
self.slack_get_user_id_by_name = lru_cache()(self._slack_get_user_id_by_name)
|
39
40
|
|
40
41
|
@property
|
41
42
|
def name(self) -> str:
|
@@ -44,8 +45,7 @@ class OcmInternalNotifications(QontractReconcileIntegration[NoParams]):
|
|
44
45
|
def get_environments(self, query_func: Callable) -> list[OCMEnvironment]:
|
45
46
|
return ocm_environment_query(query_func).environments
|
46
47
|
|
47
|
-
|
48
|
-
def slack_get_user_id_by_name(
|
48
|
+
def _slack_get_user_id_by_name(
|
49
49
|
self, user_name: str, mail_address: str
|
50
50
|
) -> str | None:
|
51
51
|
try:
|
reconcile/openshift_base.py
CHANGED
@@ -850,7 +850,7 @@ def apply_action(
|
|
850
850
|
resource=resource,
|
851
851
|
wait_for_namespace=options.wait_for_namespace,
|
852
852
|
recycle_pods=options.recycle_pods,
|
853
|
-
privileged=
|
853
|
+
privileged=bool(options.privileged),
|
854
854
|
)
|
855
855
|
|
856
856
|
except StatusCodeError as e:
|
@@ -884,8 +884,8 @@ def delete_action(
|
|
884
884
|
namespace=namespace,
|
885
885
|
resource_type=resource_type,
|
886
886
|
name=resource_name,
|
887
|
-
enable_deletion=
|
888
|
-
privileged=
|
887
|
+
enable_deletion=bool(options.enable_deletion),
|
888
|
+
privileged=bool(options.privileged),
|
889
889
|
)
|
890
890
|
except StatusCodeError as e:
|
891
891
|
ri.register_error()
|
@@ -938,9 +938,10 @@ def _realize_resource_data_3way_diff(
|
|
938
938
|
logging.error(msg)
|
939
939
|
return actions
|
940
940
|
|
941
|
-
|
941
|
+
# don't delete resources if there are errors
|
942
|
+
options.enable_deletion = not ri.has_error_registered()
|
942
943
|
# only allow to override enable_deletion if no errors were found
|
943
|
-
if options.enable_deletion
|
944
|
+
if options.enable_deletion and options.override_enable_deletion is False:
|
944
945
|
options.enable_deletion = False
|
945
946
|
|
946
947
|
diff_result = differ.diff_mappings(
|
@@ -1359,8 +1360,9 @@ def aggregate_shared_resources_typed(
|
|
1359
1360
|
case HasOpenshiftServiceAccountTokensAndSharedResources():
|
1360
1361
|
shared_type_resources_items = []
|
1361
1362
|
for ost_shared_resources_item in namespace.shared_resources:
|
1362
|
-
if
|
1363
|
-
|
1363
|
+
if (
|
1364
|
+
shared_type_resources
|
1365
|
+
:= ost_shared_resources_item.openshift_service_account_tokens
|
1364
1366
|
):
|
1365
1367
|
shared_type_resources_items.extend(shared_type_resources)
|
1366
1368
|
if namespace.openshift_service_account_tokens:
|
@@ -1372,8 +1374,9 @@ def aggregate_shared_resources_typed(
|
|
1372
1374
|
case HasOpenShiftResourcesAndSharedResources():
|
1373
1375
|
shared_type_resources_items = []
|
1374
1376
|
for or_shared_resources_item in namespace.shared_resources:
|
1375
|
-
if
|
1376
|
-
|
1377
|
+
if (
|
1378
|
+
shared_type_resources
|
1379
|
+
:= or_shared_resources_item.openshift_resources
|
1377
1380
|
):
|
1378
1381
|
shared_type_resources_items.extend(shared_type_resources)
|
1379
1382
|
if namespace.openshift_resources:
|
@@ -1405,10 +1408,7 @@ def determine_user_keys_for_access(
|
|
1405
1408
|
return ["github_username"]
|
1406
1409
|
|
1407
1410
|
for auth in auth_list:
|
1408
|
-
if isinstance(auth, HasService)
|
1409
|
-
service = auth.service
|
1410
|
-
else:
|
1411
|
-
service = auth["service"]
|
1411
|
+
service = auth.service if isinstance(auth, HasService) else auth["service"]
|
1412
1412
|
try:
|
1413
1413
|
if AUTH_METHOD_USER_KEY[service] in user_keys:
|
1414
1414
|
continue
|
@@ -1416,7 +1416,7 @@ def determine_user_keys_for_access(
|
|
1416
1416
|
except KeyError:
|
1417
1417
|
raise NotImplementedError(
|
1418
1418
|
f"[{cluster_name}] auth service not implemented: {service}"
|
1419
|
-
)
|
1419
|
+
) from None
|
1420
1420
|
return user_keys
|
1421
1421
|
|
1422
1422
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import contextlib
|
1
2
|
import sys
|
2
3
|
|
3
4
|
import reconcile.openshift_base as ob
|
@@ -118,7 +119,9 @@ def fetch_desired_state(ri, oc_map):
|
|
118
119
|
oc_resource, resource_name = construct_user_oc_resource(
|
119
120
|
permission["cluster_role"], username
|
120
121
|
)
|
121
|
-
|
122
|
+
with contextlib.suppress(ResourceKeyExistsError):
|
123
|
+
# a user may have a Role assigned to them
|
124
|
+
# from multiple app-interface roles
|
122
125
|
ri.add_desired(
|
123
126
|
cluster,
|
124
127
|
namespace_cluster_scope,
|
@@ -126,10 +129,7 @@ def fetch_desired_state(ri, oc_map):
|
|
126
129
|
resource_name,
|
127
130
|
oc_resource,
|
128
131
|
)
|
129
|
-
|
130
|
-
# a user may have a Role assigned to them
|
131
|
-
# from multiple app-interface roles
|
132
|
-
pass
|
132
|
+
|
133
133
|
for sa in service_accounts:
|
134
134
|
if ri is None:
|
135
135
|
continue
|
@@ -137,7 +137,10 @@ def fetch_desired_state(ri, oc_map):
|
|
137
137
|
oc_resource, resource_name = construct_sa_oc_resource(
|
138
138
|
permission["cluster_role"], namespace, sa_name
|
139
139
|
)
|
140
|
-
|
140
|
+
|
141
|
+
with contextlib.suppress(ResourceKeyExistsError):
|
142
|
+
# a ServiceAccount may have a Role assigned to it
|
143
|
+
# from multiple app-interface roles
|
141
144
|
ri.add_desired(
|
142
145
|
cluster,
|
143
146
|
namespace_cluster_scope,
|
@@ -145,10 +148,6 @@ def fetch_desired_state(ri, oc_map):
|
|
145
148
|
resource_name,
|
146
149
|
oc_resource,
|
147
150
|
)
|
148
|
-
except ResourceKeyExistsError:
|
149
|
-
# a ServiceAccount may have a Role assigned to it
|
150
|
-
# from multiple app-interface roles
|
151
|
-
pass
|
152
151
|
|
153
152
|
return users_desired_state
|
154
153
|
|
@@ -164,7 +164,7 @@ class LabelInventory:
|
|
164
164
|
desired = types[DESIRED]
|
165
165
|
managed = self.get(cluster, ns, MANAGED, [])
|
166
166
|
current = self.get(cluster, ns, CURRENT, {})
|
167
|
-
changed = self.setdefault(cluster, ns, CHANGED, {})
|
167
|
+
changed = self.setdefault(cluster, ns, CHANGED, {}) # noqa: B909
|
168
168
|
|
169
169
|
# cleanup managed items
|
170
170
|
for k in managed:
|
@@ -192,7 +192,7 @@ class LabelInventory:
|
|
192
192
|
changed[k] = v
|
193
193
|
|
194
194
|
# remove old labels
|
195
|
-
for k,
|
195
|
+
for k, _ in current.items():
|
196
196
|
if k in managed and k not in desired:
|
197
197
|
changed[k] = None
|
198
198
|
|
@@ -127,7 +127,7 @@ def check_results(
|
|
127
127
|
desired_state: Iterable[Mapping[str, str]], results: Iterable[Any]
|
128
128
|
) -> bool:
|
129
129
|
err = False
|
130
|
-
for s, e in zip(desired_state, results):
|
130
|
+
for s, e in zip(desired_state, results, strict=False):
|
131
131
|
if isinstance(e, Exception):
|
132
132
|
err = True
|
133
133
|
msg = (
|
@@ -287,7 +287,7 @@ def check_alertmanager_config(
|
|
287
287
|
f"error validating alertmanager config in {path}: "
|
288
288
|
f"missing key {alertmanager_config_key}"
|
289
289
|
)
|
290
|
-
raise FetchResourceError(e_msg)
|
290
|
+
raise FetchResourceError(e_msg) from None
|
291
291
|
|
292
292
|
if decode_base64:
|
293
293
|
config = base64.b64decode(config).decode("utf-8")
|
@@ -329,10 +329,10 @@ def fetch_provider_resource(
|
|
329
329
|
except TypeError:
|
330
330
|
body_type = type(body).__name__
|
331
331
|
e_msg = f"invalid resource type {body_type} found in path: {path}"
|
332
|
-
raise FetchResourceError(e_msg)
|
332
|
+
raise FetchResourceError(e_msg) from None
|
333
333
|
except anymarkup.AnyMarkupError:
|
334
334
|
e_msg = f"Could not parse data. Skipping resource: {path}"
|
335
|
-
raise FetchResourceError(e_msg)
|
335
|
+
raise FetchResourceError(e_msg) from None
|
336
336
|
|
337
337
|
if validate_json:
|
338
338
|
files = body["data"]
|
@@ -341,7 +341,7 @@ def fetch_provider_resource(
|
|
341
341
|
json.loads(file_content)
|
342
342
|
except ValueError:
|
343
343
|
e_msg = f"invalid json in {path} under {file_name}"
|
344
|
-
raise FetchResourceError(e_msg)
|
344
|
+
raise FetchResourceError(e_msg) from None
|
345
345
|
|
346
346
|
if validate_alertmanager_config:
|
347
347
|
if body["kind"] == "Secret":
|
@@ -383,7 +383,7 @@ def fetch_provider_resource(
|
|
383
383
|
body, QONTRACT_INTEGRATION, QONTRACT_INTEGRATION_VERSION, error_details=path
|
384
384
|
)
|
385
385
|
except ConstructResourceError as e:
|
386
|
-
raise FetchResourceError(str(e))
|
386
|
+
raise FetchResourceError(str(e)) from None
|
387
387
|
|
388
388
|
|
389
389
|
def fetch_provider_vault_secret(
|
@@ -430,7 +430,7 @@ def fetch_provider_vault_secret(
|
|
430
430
|
try:
|
431
431
|
return OR(body, integration, integration_version, error_details=path)
|
432
432
|
except ConstructResourceError as e:
|
433
|
-
raise FetchResourceError(str(e))
|
433
|
+
raise FetchResourceError(str(e)) from None
|
434
434
|
|
435
435
|
|
436
436
|
# check to ensure that all of the keys are valid by looking to see if there are
|
@@ -554,7 +554,7 @@ def fetch_openshift_resource(
|
|
554
554
|
)
|
555
555
|
except Exception as e:
|
556
556
|
msg = f"could not render template at path {path}\n{e}"
|
557
|
-
raise ResourceTemplateRenderError(msg)
|
557
|
+
raise ResourceTemplateRenderError(msg) from None
|
558
558
|
elif provider == "vault-secret":
|
559
559
|
path = resource["path"]
|
560
560
|
version = resource["version"]
|
@@ -588,7 +588,7 @@ def fetch_openshift_resource(
|
|
588
588
|
settings=settings,
|
589
589
|
)
|
590
590
|
except (SecretVersionNotFound, SecretVersionIsNone) as e:
|
591
|
-
raise FetchSecretError(e)
|
591
|
+
raise FetchSecretError(e) from None
|
592
592
|
elif provider == "route":
|
593
593
|
path = resource["resource"]["path"]
|
594
594
|
_locked_debug_log(f"Processing {provider}: {path}")
|
@@ -628,7 +628,7 @@ def fetch_openshift_resource(
|
|
628
628
|
)
|
629
629
|
except Exception as e:
|
630
630
|
msg = f"could not render template at path {path}\n{e}"
|
631
|
-
raise ResourceTemplateRenderError(msg)
|
631
|
+
raise ResourceTemplateRenderError(msg) from None
|
632
632
|
|
633
633
|
else:
|
634
634
|
raise UnknownProviderError(provider)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import contextlib
|
1
2
|
import sys
|
2
3
|
|
3
4
|
import reconcile.openshift_base as ob
|
@@ -136,7 +137,9 @@ def fetch_desired_state(ri, oc_map, enforced_user_keys=None):
|
|
136
137
|
oc_resource, resource_name = construct_user_oc_resource(
|
137
138
|
permission["role"], username
|
138
139
|
)
|
139
|
-
|
140
|
+
with contextlib.suppress(ResourceKeyExistsError):
|
141
|
+
# a user may have a Role assigned to them
|
142
|
+
# from multiple app-interface roles
|
140
143
|
ri.add_desired(
|
141
144
|
cluster,
|
142
145
|
perm_namespace_name,
|
@@ -145,10 +148,7 @@ def fetch_desired_state(ri, oc_map, enforced_user_keys=None):
|
|
145
148
|
oc_resource,
|
146
149
|
privileged=privileged,
|
147
150
|
)
|
148
|
-
|
149
|
-
# a user may have a Role assigned to them
|
150
|
-
# from multiple app-interface roles
|
151
|
-
pass
|
151
|
+
|
152
152
|
for sa in service_accounts:
|
153
153
|
if ri is None:
|
154
154
|
continue
|
@@ -156,7 +156,9 @@ def fetch_desired_state(ri, oc_map, enforced_user_keys=None):
|
|
156
156
|
oc_resource, resource_name = construct_sa_oc_resource(
|
157
157
|
permission["role"], sa_namespace_name, sa_name
|
158
158
|
)
|
159
|
-
|
159
|
+
with contextlib.suppress(ResourceKeyExistsError):
|
160
|
+
# a ServiceAccount may have a Role assigned to it
|
161
|
+
# from multiple app-interface roles
|
160
162
|
ri.add_desired(
|
161
163
|
cluster,
|
162
164
|
perm_namespace_name,
|
@@ -165,11 +167,6 @@ def fetch_desired_state(ri, oc_map, enforced_user_keys=None):
|
|
165
167
|
oc_resource,
|
166
168
|
privileged=privileged,
|
167
169
|
)
|
168
|
-
except ResourceKeyExistsError:
|
169
|
-
# a ServiceAccount may have a Role assigned to it
|
170
|
-
# from multiple app-interface roles
|
171
|
-
pass
|
172
|
-
|
173
170
|
return users_desired_state
|
174
171
|
|
175
172
|
|
@@ -313,11 +313,14 @@ def _pipeline_exists(
|
|
313
313
|
if isinstance(oc, OCLogMsg):
|
314
314
|
logging.error(oc.message)
|
315
315
|
raise RuntimeError(f"No OC client for {tkn_cluster_name}: {oc.message}")
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
316
|
+
return bool(
|
317
|
+
oc.get(
|
318
|
+
namespace=tkn_namespace_name,
|
319
|
+
kind="Pipeline",
|
320
|
+
name=name,
|
321
|
+
allow_not_found=True,
|
322
|
+
)
|
323
|
+
)
|
321
324
|
|
322
325
|
|
323
326
|
def _construct_tekton_trigger_resource(
|
reconcile/oum/base.py
CHANGED
@@ -265,7 +265,7 @@ def reconcile_cluster_roles(
|
|
265
265
|
}
|
266
266
|
# only process roles present in the desired state and ignore the ones that are not
|
267
267
|
# this way a role can still be managed manually while another one is managed by this integration
|
268
|
-
for group in desired_groups
|
268
|
+
for group in desired_groups:
|
269
269
|
desired_members = desired_groups.get(group, set())
|
270
270
|
current_members = current_groups.get(group, set())
|
271
271
|
|
reconcile/quay_mirror.py
CHANGED
@@ -207,12 +207,8 @@ class QuayMirror:
|
|
207
207
|
@staticmethod
|
208
208
|
def sync_tag(tags, tags_exclude, candidate):
|
209
209
|
if tags is not None:
|
210
|
-
|
211
|
-
|
212
|
-
return True
|
213
|
-
# When tags is defined, we don't look at
|
214
|
-
# tags_exclude
|
215
|
-
return False
|
210
|
+
# When tags is defined, we don't look at tags_exclude
|
211
|
+
return any(re.match(tag, candidate) for tag in tags)
|
216
212
|
|
217
213
|
if tags_exclude is not None:
|
218
214
|
for tag_exclude in tags_exclude:
|
@@ -375,10 +371,7 @@ class QuayMirror:
|
|
375
371
|
return True
|
376
372
|
|
377
373
|
next_compare_tags = last_compare_tags + interval
|
378
|
-
|
379
|
-
return True
|
380
|
-
|
381
|
-
return False
|
374
|
+
return time.time() >= next_compare_tags
|
382
375
|
|
383
376
|
@staticmethod
|
384
377
|
def record_timestamp(path) -> None:
|
reconcile/queries.py
CHANGED
@@ -591,7 +591,7 @@ def get_state_aws_accounts(reset_passwords=False):
|
|
591
591
|
|
592
592
|
def get_queue_aws_accounts():
|
593
593
|
"""Returns AWS accounts to use for queue management"""
|
594
|
-
uid = os.environ["gitlab_pr_submitter_queue_url"].split("/")[3]
|
594
|
+
uid = os.environ["gitlab_pr_submitter_queue_url"].split("/")[3] # noqa: SIM112
|
595
595
|
return get_aws_accounts(uid=uid)
|
596
596
|
|
597
597
|
|