qontract-reconcile 0.10.1rc879__py3-none-any.whl → 0.10.1rc894__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.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/RECORD +291 -284
- reconcile/acs_rbac.py +1 -2
- reconcile/aus/advanced_upgrade_service.py +14 -14
- reconcile/aus/aus_label_source.py +1 -2
- reconcile/aus/base.py +23 -26
- reconcile/aus/cluster_version_data.py +4 -4
- reconcile/aus/models.py +2 -3
- reconcile/aus/version_gate_approver.py +2 -6
- reconcile/aus/version_gates/__init__.py +1 -3
- reconcile/aus/version_gates/sts_version_gate_handler.py +2 -3
- reconcile/aws_account_manager/integration.py +9 -14
- reconcile/aws_account_manager/reconciler.py +51 -1
- reconcile/aws_account_manager/utils.py +3 -0
- reconcile/aws_ami_cleanup/integration.py +3 -4
- reconcile/aws_iam_password_reset.py +2 -5
- reconcile/aws_version_sync/integration.py +2 -2
- reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
- reconcile/change_owners/approver.py +4 -5
- reconcile/change_owners/bundle.py +20 -22
- reconcile/change_owners/change_types.py +23 -24
- reconcile/change_owners/changes.py +13 -16
- reconcile/change_owners/decision.py +2 -5
- reconcile/change_owners/diff.py +11 -15
- reconcile/change_owners/self_service_roles.py +1 -2
- reconcile/change_owners/tester.py +7 -10
- reconcile/checkpoint.py +2 -5
- reconcile/cli.py +26 -12
- reconcile/closedbox_endpoint_monitoring_base.py +8 -11
- reconcile/cluster_deployment_mapper.py +2 -5
- reconcile/cna/assets/asset.py +4 -7
- reconcile/cna/assets/null.py +2 -5
- reconcile/cna/integration.py +2 -3
- reconcile/cna/state.py +2 -5
- reconcile/dashdotdb_base.py +8 -11
- reconcile/dashdotdb_cso.py +3 -6
- reconcile/dashdotdb_dora.py +10 -14
- reconcile/dashdotdb_dvo.py +10 -13
- reconcile/dashdotdb_slo.py +5 -8
- reconcile/database_access_manager.py +5 -6
- reconcile/dynatrace_token_provider/integration.py +3 -6
- reconcile/dynatrace_token_provider/integration_v2.py +20 -0
- reconcile/dynatrace_token_provider/meta.py +1 -0
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +4 -4
- reconcile/external_resources/model.py +3 -3
- reconcile/external_resources/secrets_sync.py +5 -5
- reconcile/external_resources/state.py +5 -5
- reconcile/gabi_authorized_users.py +3 -6
- reconcile/gcr_mirror.py +1 -1
- reconcile/github_org.py +1 -3
- reconcile/github_repo_invites.py +2 -5
- reconcile/gitlab_housekeeping.py +7 -11
- reconcile/gitlab_labeler.py +1 -2
- reconcile/gitlab_members.py +2 -5
- reconcile/gitlab_permissions.py +1 -3
- reconcile/glitchtip/integration.py +5 -8
- reconcile/glitchtip_project_alerts/integration.py +57 -33
- reconcile/glitchtip_project_dsn/integration.py +8 -11
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +6 -0
- reconcile/gql_definitions/fragments/aws_account_managed.py +8 -0
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +4 -4
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +27 -7
- reconcile/integrations_manager.py +5 -8
- reconcile/jenkins/types.py +5 -6
- reconcile/jenkins_job_builder.py +9 -12
- reconcile/jenkins_roles.py +1 -1
- reconcile/jira_watcher.py +2 -2
- reconcile/ldap_groups/integration.py +2 -5
- reconcile/ocm/types.py +21 -26
- reconcile/ocm_addons_upgrade_tests_trigger.py +3 -6
- reconcile/ocm_clusters.py +8 -8
- reconcile/ocm_internal_notifications/integration.py +1 -2
- reconcile/ocm_labels/integration.py +2 -5
- reconcile/ocm_machine_pools.py +11 -15
- reconcile/ocm_upgrade_scheduler_org_updater.py +2 -5
- reconcile/openshift_base.py +29 -30
- reconcile/openshift_groups.py +15 -20
- reconcile/openshift_namespace_labels.py +8 -14
- reconcile/openshift_namespaces.py +5 -8
- reconcile/openshift_network_policies.py +2 -4
- reconcile/openshift_resources_base.py +19 -29
- reconcile/openshift_saas_deploy.py +9 -10
- reconcile/openshift_saas_deploy_change_tester.py +7 -10
- reconcile/openshift_saas_deploy_trigger_base.py +4 -7
- reconcile/openshift_saas_deploy_trigger_cleaner.py +5 -8
- reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
- reconcile/openshift_saas_deploy_trigger_images.py +1 -2
- reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
- reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
- reconcile/openshift_tekton_resources.py +7 -11
- reconcile/openshift_upgrade_watcher.py +10 -13
- reconcile/openshift_users.py +8 -11
- reconcile/oum/base.py +3 -4
- reconcile/oum/labelset.py +1 -2
- reconcile/oum/metrics.py +2 -2
- reconcile/oum/models.py +1 -2
- reconcile/oum/standalone.py +2 -3
- reconcile/prometheus_rules_tester/integration.py +6 -9
- reconcile/quay_membership.py +1 -2
- reconcile/quay_mirror.py +12 -13
- reconcile/quay_mirror_org.py +10 -10
- reconcile/queries.py +4 -7
- reconcile/resource_scraper.py +3 -4
- reconcile/rhidp/common.py +2 -2
- reconcile/saas_auto_promotions_manager/integration.py +5 -6
- reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +1 -2
- reconcile/saas_auto_promotions_manager/publisher.py +5 -6
- reconcile/saas_auto_promotions_manager/subscriber.py +36 -15
- reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +8 -0
- reconcile/saas_file_validator.py +2 -5
- reconcile/signalfx_endpoint_monitoring.py +2 -5
- reconcile/skupper_network/integration.py +3 -6
- reconcile/skupper_network/models.py +3 -5
- reconcile/slack_base.py +4 -7
- reconcile/slack_usergroups.py +15 -17
- reconcile/sql_query.py +5 -9
- reconcile/status_board.py +4 -5
- reconcile/statuspage/atlassian.py +14 -15
- reconcile/statuspage/integrations/maintenances.py +3 -3
- reconcile/statuspage/page.py +8 -8
- reconcile/statuspage/state.py +4 -5
- reconcile/statuspage/status.py +7 -8
- reconcile/templating/lib/rendering.py +8 -8
- reconcile/templating/renderer.py +10 -11
- reconcile/templating/validator.py +4 -4
- reconcile/terraform_aws_route53.py +3 -6
- reconcile/terraform_cloudflare_dns.py +9 -12
- reconcile/terraform_cloudflare_resources.py +9 -11
- reconcile/terraform_cloudflare_users.py +8 -11
- reconcile/terraform_init/integration.py +2 -2
- reconcile/terraform_repo.py +11 -14
- reconcile/terraform_resources.py +20 -21
- reconcile/terraform_tgw_attachments.py +32 -36
- reconcile/terraform_users.py +6 -7
- reconcile/terraform_vpc_resources/integration.py +6 -6
- reconcile/test/conftest.py +7 -10
- reconcile/test/fixtures.py +1 -1
- reconcile/test/saas_auto_promotions_manager/conftest.py +3 -2
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +2 -2
- reconcile/test/test_database_access_manager.py +3 -6
- reconcile/test/test_gitlab_labeler.py +2 -5
- reconcile/test/test_jump_host.py +5 -8
- reconcile/test/test_ocm_machine_pools.py +1 -4
- reconcile/test/test_openshift_base.py +3 -6
- reconcile/test/test_openshift_cluster_bots.py +5 -5
- reconcile/test/test_openshift_namespace_labels.py +2 -3
- reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +2 -2
- reconcile/test/test_saasherder.py +9 -12
- reconcile/test/test_slack_base.py +4 -6
- reconcile/test/test_status_board.py +4 -7
- reconcile/test/test_terraform_tgw_attachments.py +14 -20
- reconcile/typed_queries/alerting_services_settings.py +1 -2
- reconcile/typed_queries/app_interface_custom_messages.py +2 -3
- reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +1 -3
- reconcile/typed_queries/app_interface_repo_url.py +1 -2
- reconcile/typed_queries/app_interface_state_settings.py +1 -3
- reconcile/typed_queries/app_interface_vault_settings.py +1 -2
- reconcile/typed_queries/aws_vpc_requests.py +1 -3
- reconcile/typed_queries/aws_vpcs.py +1 -3
- reconcile/typed_queries/clusters.py +2 -4
- reconcile/typed_queries/clusters_minimal.py +1 -3
- reconcile/typed_queries/clusters_with_dms.py +1 -3
- reconcile/typed_queries/dynatrace_environments.py +14 -0
- reconcile/typed_queries/external_resources.py +3 -4
- reconcile/typed_queries/pagerduty_instances.py +1 -2
- reconcile/typed_queries/repos.py +2 -3
- reconcile/typed_queries/reserved_networks.py +1 -3
- reconcile/typed_queries/saas_files.py +49 -59
- reconcile/typed_queries/slo_documents.py +1 -3
- reconcile/typed_queries/status_board.py +3 -7
- reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
- reconcile/typed_queries/terraform_namespaces.py +1 -2
- reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +1 -3
- reconcile/utils/acs/base.py +2 -3
- reconcile/utils/acs/notifiers.py +3 -3
- reconcile/utils/acs/policies.py +3 -3
- reconcile/utils/aggregated_list.py +1 -1
- reconcile/utils/amtool.py +1 -2
- reconcile/utils/aws_api.py +28 -31
- reconcile/utils/aws_api_typed/account.py +23 -0
- reconcile/utils/aws_api_typed/api.py +20 -9
- reconcile/utils/binary.py +1 -3
- reconcile/utils/clusterhealth/providerbase.py +1 -2
- reconcile/utils/clusterhealth/telemeter.py +2 -2
- reconcile/utils/deadmanssnitch_api.py +1 -2
- reconcile/utils/disabled_integrations.py +4 -6
- reconcile/utils/environ.py +1 -1
- reconcile/utils/expiration.py +3 -7
- reconcile/utils/external_resource_spec.py +3 -4
- reconcile/utils/external_resources.py +4 -7
- reconcile/utils/filtering.py +1 -2
- reconcile/utils/git.py +3 -9
- reconcile/utils/git_secrets.py +5 -5
- reconcile/utils/github_api.py +5 -9
- reconcile/utils/gitlab_api.py +2 -3
- reconcile/utils/glitchtip/client.py +2 -4
- reconcile/utils/glitchtip/models.py +8 -11
- reconcile/utils/gql.py +26 -35
- reconcile/utils/grouping.py +1 -3
- reconcile/utils/imap_client.py +2 -5
- reconcile/utils/internal_groups/client.py +1 -2
- reconcile/utils/internal_groups/models.py +8 -9
- reconcile/utils/jenkins_api.py +4 -4
- reconcile/utils/jinja2/extensions.py +1 -1
- reconcile/utils/jinja2/filters.py +4 -4
- reconcile/utils/jinja2/utils.py +16 -16
- reconcile/utils/jira_client.py +10 -11
- reconcile/utils/jjb_client.py +14 -17
- reconcile/utils/jobcontroller/controller.py +5 -5
- reconcile/utils/jobcontroller/models.py +2 -2
- reconcile/utils/jsonpath.py +4 -5
- reconcile/utils/jump_host.py +7 -8
- reconcile/utils/keycloak.py +3 -7
- reconcile/utils/ldap_client.py +2 -3
- reconcile/utils/lean_terraform_client.py +13 -17
- reconcile/utils/membershipsources/app_interface_resolver.py +1 -1
- reconcile/utils/membershipsources/models.py +19 -22
- reconcile/utils/metrics.py +13 -15
- reconcile/utils/mr/base.py +7 -11
- reconcile/utils/mr/glitchtip_access_reporter.py +2 -2
- reconcile/utils/mr/notificator.py +1 -2
- reconcile/utils/oc.py +38 -38
- reconcile/utils/oc_connection_parameters.py +24 -25
- reconcile/utils/oc_filters.py +2 -3
- reconcile/utils/oc_map.py +9 -15
- reconcile/utils/ocm/addons.py +7 -10
- reconcile/utils/ocm/base.py +38 -39
- reconcile/utils/ocm/clusters.py +6 -9
- reconcile/utils/ocm/label_sources.py +1 -2
- reconcile/utils/ocm/labels.py +3 -6
- reconcile/utils/ocm/ocm.py +11 -14
- reconcile/utils/ocm/products.py +1 -3
- reconcile/utils/ocm/search_filters.py +16 -17
- reconcile/utils/ocm/service_log.py +2 -3
- reconcile/utils/ocm/sre_capability_labels.py +4 -8
- reconcile/utils/ocm/subscriptions.py +1 -3
- reconcile/utils/ocm/syncsets.py +2 -4
- reconcile/utils/ocm/upgrades.py +5 -9
- reconcile/utils/ocm_base_client.py +13 -16
- reconcile/utils/openshift_resource.py +5 -11
- reconcile/utils/output.py +2 -3
- reconcile/utils/pagerduty_api.py +4 -5
- reconcile/utils/prometheus.py +2 -2
- reconcile/utils/promotion_state.py +4 -5
- reconcile/utils/promtool.py +2 -8
- reconcile/utils/quay_api.py +12 -22
- reconcile/utils/raw_github_api.py +3 -5
- reconcile/utils/rosa/rosa_cli.py +6 -6
- reconcile/utils/rosa/session.py +6 -7
- reconcile/utils/runtime/desired_state_diff.py +3 -8
- reconcile/utils/runtime/environment.py +4 -7
- reconcile/utils/runtime/integration.py +4 -4
- reconcile/utils/runtime/meta.py +1 -2
- reconcile/utils/runtime/runner.py +7 -10
- reconcile/utils/runtime/sharding.py +22 -27
- reconcile/utils/saasherder/interfaces.py +63 -69
- reconcile/utils/saasherder/models.py +30 -35
- reconcile/utils/saasherder/saasherder.py +39 -54
- reconcile/utils/secret_reader.py +17 -19
- reconcile/utils/slack_api.py +15 -17
- reconcile/utils/smtp_client.py +1 -2
- reconcile/utils/sqs_gateway.py +1 -3
- reconcile/utils/state.py +1 -2
- reconcile/utils/terraform/config_client.py +4 -5
- reconcile/utils/terraform_client.py +12 -8
- reconcile/utils/terrascript/cloudflare_client.py +4 -10
- reconcile/utils/terrascript/cloudflare_resources.py +10 -13
- reconcile/utils/terrascript/models.py +2 -3
- reconcile/utils/terrascript/resources.py +1 -2
- reconcile/utils/terrascript_aws_client.py +50 -38
- reconcile/utils/unleash/client.py +4 -7
- reconcile/utils/unleash/server.py +2 -2
- reconcile/utils/vault.py +8 -11
- reconcile/utils/vaultsecretref.py +2 -3
- reconcile/utils/vcs.py +7 -8
- reconcile/vault_replication.py +4 -8
- reconcile/vpc_peerings_validator.py +4 -9
- release/version.py +6 -7
- tools/app_interface_reporter.py +2 -2
- tools/cli_commands/gpg_encrypt.py +3 -6
- tools/cli_commands/systems_and_tools.py +4 -7
- tools/qontract_cli.py +105 -17
- tools/saas_promotion_state/__init__.py +0 -0
- tools/saas_promotion_state/saas_promotion_state.py +105 -0
- tools/template_validation.py +1 -1
- tools/test/conftest.py +45 -6
- tools/test/test_saas_promotion_state.py +187 -0
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/top_level.txt +0 -0
reconcile/utils/jjb_client.py
CHANGED
@@ -14,10 +14,7 @@ from subprocess import (
|
|
14
14
|
STDOUT,
|
15
15
|
CalledProcessError,
|
16
16
|
)
|
17
|
-
from typing import
|
18
|
-
Any,
|
19
|
-
Optional,
|
20
|
-
)
|
17
|
+
from typing import Any
|
21
18
|
|
22
19
|
import yaml
|
23
20
|
from jenkins_jobs.builder import JenkinsManager
|
@@ -63,7 +60,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
63
60
|
ini = self.secret_reader.read(token)
|
64
61
|
ini = ini.replace('"', "")
|
65
62
|
ini = ini.replace("false", "False")
|
66
|
-
ini_file_path = "{}/{}.ini"
|
63
|
+
ini_file_path = f"{wd}/{name}.ini"
|
67
64
|
with open(ini_file_path, "w", encoding="locale") as f:
|
68
65
|
f.write(ini)
|
69
66
|
f.write("\n")
|
@@ -75,7 +72,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
75
72
|
for c in configs:
|
76
73
|
instance_name = c["instance"]["name"]
|
77
74
|
config = c["config"]
|
78
|
-
config_file_path = "{}/config.yaml"
|
75
|
+
config_file_path = f"{working_dirs[instance_name]}/config.yaml"
|
79
76
|
if config:
|
80
77
|
content = yaml.load(config, Loader=yaml.FullLoader)
|
81
78
|
if c["type"] == "jobs":
|
@@ -99,7 +96,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
99
96
|
config files in the working directories with
|
100
97
|
the supplied configs"""
|
101
98
|
for name, wd in self.working_dirs.items():
|
102
|
-
config_path = "{}/config.yaml"
|
99
|
+
config_path = f"{wd}/config.yaml"
|
103
100
|
with open(config_path, "w", encoding="locale") as f:
|
104
101
|
f.write(configs[name])
|
105
102
|
|
@@ -135,8 +132,8 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
135
132
|
working directories"""
|
136
133
|
configs = {}
|
137
134
|
for name, wd in self.working_dirs.items():
|
138
|
-
config_path = "{}/config.yaml"
|
139
|
-
with open(config_path,
|
135
|
+
config_path = f"{wd}/config.yaml"
|
136
|
+
with open(config_path, encoding="locale") as f:
|
140
137
|
configs[name] = f.read()
|
141
138
|
|
142
139
|
return configs
|
@@ -149,8 +146,8 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
149
146
|
:param fetch_state: subdirectory to use ('desired' or 'current')
|
150
147
|
"""
|
151
148
|
for name, wd in self.working_dirs.items():
|
152
|
-
ini_path = "{}/{}.ini"
|
153
|
-
config_path = "{}/config.yaml"
|
149
|
+
ini_path = f"{wd}/{name}.ini"
|
150
|
+
config_path = f"{wd}/config.yaml"
|
154
151
|
|
155
152
|
output_dir = path.join(io_dir, "jjb", fetch_state, name)
|
156
153
|
args = [
|
@@ -227,8 +224,8 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
227
224
|
|
228
225
|
def update(self) -> None:
|
229
226
|
for name, wd in self.working_dirs.items():
|
230
|
-
ini_path = "{}/{}.ini"
|
231
|
-
config_path = "{}/config.yaml"
|
227
|
+
ini_path = f"{wd}/{name}.ini"
|
228
|
+
config_path = f"{wd}/config.yaml"
|
232
229
|
|
233
230
|
os.environ["PYTHONHTTPSVERIFY"] = self.python_https_verify
|
234
231
|
cmd = ["jenkins-jobs", "--conf", ini_path, "update", config_path]
|
@@ -268,8 +265,8 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
268
265
|
|
269
266
|
@retry(exceptions=(JenkinsJobsException))
|
270
267
|
def get_jobs(self, wd, name):
|
271
|
-
ini_path = "{}/{}.ini"
|
272
|
-
config_path = "{}/config.yaml"
|
268
|
+
ini_path = f"{wd}/{name}.ini"
|
269
|
+
config_path = f"{wd}/config.yaml"
|
273
270
|
|
274
271
|
args = ["--conf", ini_path, "test", config_path]
|
275
272
|
jjb = self.get_jjb(args)
|
@@ -321,7 +318,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
321
318
|
try:
|
322
319
|
repos.add(self.get_repo_url(job))
|
323
320
|
except KeyError:
|
324
|
-
logging.debug("missing github url: {}"
|
321
|
+
logging.debug(f"missing github url: {job_name}")
|
325
322
|
return repos
|
326
323
|
|
327
324
|
def get_admins(self):
|
@@ -393,7 +390,7 @@ class JJB: # pylint: disable=too-many-public-methods
|
|
393
390
|
raise ValueError(f"job with {job_type=} and {repo_url=} not found")
|
394
391
|
|
395
392
|
@staticmethod
|
396
|
-
def get_trigger_phrases_regex(job: dict) ->
|
393
|
+
def get_trigger_phrases_regex(job: dict) -> str | None:
|
397
394
|
for trigger in job["triggers"]:
|
398
395
|
if "gitlab" in trigger:
|
399
396
|
return trigger["gitlab"].get("note-regex")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
import time
|
3
|
-
from typing import
|
3
|
+
from typing import Protocol, TextIO
|
4
4
|
|
5
5
|
from kubernetes.client import ( # type: ignore[attr-defined]
|
6
6
|
ApiClient,
|
@@ -85,7 +85,7 @@ class K8sJobController:
|
|
85
85
|
self.oc = oc
|
86
86
|
self.dry_run = dry_run
|
87
87
|
self.time_module = time_module
|
88
|
-
self._cache:
|
88
|
+
self._cache: dict[str, OpenshiftResource] | None = None
|
89
89
|
|
90
90
|
@property
|
91
91
|
def cache(self) -> dict[str, OpenshiftResource]:
|
@@ -111,7 +111,7 @@ class K8sJobController:
|
|
111
111
|
self._cache = new_cache
|
112
112
|
return self._cache
|
113
113
|
|
114
|
-
def get_job_generation(self, job_name: str) ->
|
114
|
+
def get_job_generation(self, job_name: str) -> str | None:
|
115
115
|
"""
|
116
116
|
Returns the generation annotation for a job.
|
117
117
|
"""
|
@@ -248,7 +248,7 @@ class K8sJobController:
|
|
248
248
|
return True
|
249
249
|
return False
|
250
250
|
|
251
|
-
def _lookup_job_uid(self, job_name: str) ->
|
251
|
+
def _lookup_job_uid(self, job_name: str) -> str | None:
|
252
252
|
job_resource = self.oc.get(
|
253
253
|
self.namespace, "Job", job_name, allow_not_found=True
|
254
254
|
)
|
@@ -256,7 +256,7 @@ class K8sJobController:
|
|
256
256
|
return None
|
257
257
|
return job_resource.get("metadata", {}).get("uid")
|
258
258
|
|
259
|
-
def build_secret(self, job: K8sJob) ->
|
259
|
+
def build_secret(self, job: K8sJob) -> V1Secret | None:
|
260
260
|
secret_data = job.secret_data()
|
261
261
|
script_data = job.scripts()
|
262
262
|
# fail if both dicts have overlapping keys
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import hashlib
|
2
2
|
import inspect
|
3
3
|
from abc import ABC, abstractmethod
|
4
|
-
from enum import
|
4
|
+
from enum import IntFlag, StrEnum
|
5
5
|
from typing import Any
|
6
6
|
|
7
7
|
from deepdiff import DeepHash
|
@@ -19,7 +19,7 @@ from kubernetes.client import (
|
|
19
19
|
)
|
20
20
|
|
21
21
|
|
22
|
-
class JobStatus(
|
22
|
+
class JobStatus(StrEnum):
|
23
23
|
SUCCESS: str = "SUCCESS"
|
24
24
|
ERROR: str = "ERROR"
|
25
25
|
IN_PROGRESS: str = "IN_PROGRESS"
|
reconcile/utils/jsonpath.py
CHANGED
@@ -4,7 +4,6 @@ from functools import (
|
|
4
4
|
reduce,
|
5
5
|
)
|
6
6
|
from itertools import zip_longest
|
7
|
-
from typing import Optional
|
8
7
|
|
9
8
|
import jsonpath_ng
|
10
9
|
import jsonpath_ng.ext.filter
|
@@ -54,11 +53,11 @@ def narrow_jsonpath_node(
|
|
54
53
|
if path_2.fields == ("*",):
|
55
54
|
return path_1
|
56
55
|
elif isinstance(path_1, jsonpath_ng.Index) and isinstance(
|
57
|
-
path_2,
|
56
|
+
path_2, jsonpath_ng.Slice | jsonpath_ng.ext.filter.Filter
|
58
57
|
):
|
59
58
|
return path_1
|
60
59
|
elif isinstance(
|
61
|
-
path_1,
|
60
|
+
path_1, jsonpath_ng.Slice | jsonpath_ng.ext.filter.Filter
|
62
61
|
) and isinstance(path_2, jsonpath_ng.Index):
|
63
62
|
return path_2
|
64
63
|
elif isinstance(path_1, jsonpath_ng.ext.filter.Filter) and isinstance(
|
@@ -119,7 +118,7 @@ def apply_constraint_to_path(
|
|
119
118
|
path: jsonpath_ng.JSONPath,
|
120
119
|
path_constraint: jsonpath_ng.JSONPath,
|
121
120
|
min_common_prefix_length: int = 1,
|
122
|
-
) ->
|
121
|
+
) -> jsonpath_ng.JSONPath | None:
|
123
122
|
"""
|
124
123
|
Narrow the `path` with a more specific `path_constraint`.
|
125
124
|
e.g. if the path constraints a slice `[*]` and the constraints a
|
@@ -148,7 +147,7 @@ def apply_constraint_to_path(
|
|
148
147
|
|
149
148
|
def remove_prefix_from_path(
|
150
149
|
path: jsonpath_ng.JSONPath, prefix: jsonpath_ng.JSONPath
|
151
|
-
) ->
|
150
|
+
) -> jsonpath_ng.JSONPath | None:
|
152
151
|
path_parts = jsonpath_parts(path, ignore_root=True)
|
153
152
|
prefix_parts = jsonpath_parts(prefix, ignore_root=True)
|
154
153
|
|
reconcile/utils/jump_host.py
CHANGED
@@ -4,7 +4,6 @@ import shutil
|
|
4
4
|
import tempfile
|
5
5
|
import threading
|
6
6
|
from dataclasses import dataclass
|
7
|
-
from typing import Optional
|
8
7
|
|
9
8
|
from sshtunnel import SSHTunnelForwarder
|
10
9
|
|
@@ -27,9 +26,9 @@ class JumphostParameters:
|
|
27
26
|
hostname: str
|
28
27
|
known_hosts: str
|
29
28
|
user: str
|
30
|
-
port:
|
31
|
-
remote_port:
|
32
|
-
local_port:
|
29
|
+
port: int | None
|
30
|
+
remote_port: int | None
|
31
|
+
local_port: int | None
|
33
32
|
key: str
|
34
33
|
|
35
34
|
|
@@ -60,7 +59,7 @@ class JumpHostSSH(JumpHostBase):
|
|
60
59
|
tunnel_lock = threading.Lock()
|
61
60
|
|
62
61
|
def __init__(
|
63
|
-
self, parameters: JumphostParameters, gql_api:
|
62
|
+
self, parameters: JumphostParameters, gql_api: gql.GqlApi | None = None
|
64
63
|
):
|
65
64
|
JumpHostBase.__init__(self, parameters=parameters)
|
66
65
|
|
@@ -75,7 +74,7 @@ class JumpHostSSH(JumpHostBase):
|
|
75
74
|
self._remote_port = parameters.remote_port
|
76
75
|
|
77
76
|
@property
|
78
|
-
def local_port(self) ->
|
77
|
+
def local_port(self) -> int | None:
|
79
78
|
return self._local_port
|
80
79
|
|
81
80
|
@staticmethod
|
@@ -102,7 +101,7 @@ class JumpHostSSH(JumpHostBase):
|
|
102
101
|
self.known_hosts_file = known_hosts_file
|
103
102
|
|
104
103
|
def get_ssh_base_cmd(self) -> list[str]:
|
105
|
-
user_host = "{}@{
|
104
|
+
user_host = f"{self._user}@{self._hostname}"
|
106
105
|
|
107
106
|
return [
|
108
107
|
"ssh",
|
@@ -115,7 +114,7 @@ class JumpHostSSH(JumpHostBase):
|
|
115
114
|
"-o",
|
116
115
|
"StrictHostKeyChecking=yes",
|
117
116
|
"-o",
|
118
|
-
"UserKnownHostsFile={
|
117
|
+
f"UserKnownHostsFile={self.known_hosts_file}",
|
119
118
|
"-i",
|
120
119
|
self._identity_file,
|
121
120
|
"-p",
|
reconcile/utils/keycloak.py
CHANGED
@@ -1,9 +1,5 @@
|
|
1
|
-
from
|
2
|
-
|
3
|
-
Iterable,
|
4
|
-
Optional,
|
5
|
-
Sequence,
|
6
|
-
)
|
1
|
+
from collections.abc import Iterable, Sequence
|
2
|
+
from typing import Any
|
7
3
|
|
8
4
|
import requests
|
9
5
|
from pydantic import BaseModel
|
@@ -31,7 +27,7 @@ class SSOClient(BaseModel):
|
|
31
27
|
|
32
28
|
class KeycloakInstance(BaseModel):
|
33
29
|
url: str
|
34
|
-
initial_access_token:
|
30
|
+
initial_access_token: str | None = None
|
35
31
|
|
36
32
|
|
37
33
|
class KeycloakAPI:
|
reconcile/utils/ldap_client.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
from collections import defaultdict
|
2
2
|
from collections.abc import Iterable
|
3
|
-
from typing import Optional
|
4
3
|
|
5
4
|
from ldap3 import (
|
6
5
|
ALL,
|
@@ -30,7 +29,7 @@ class LdapClient:
|
|
30
29
|
self.connection.unbind()
|
31
30
|
|
32
31
|
def get_users(self, uids: Iterable[str]) -> set[str]:
|
33
|
-
user_filter = "".join(
|
32
|
+
user_filter = "".join(f"(uid={u})" for u in uids)
|
34
33
|
_, _, results, _ = self.connection.search(
|
35
34
|
self.base_dn, f"(&(objectclass=person)(|{user_filter}))", attributes=["uid"]
|
36
35
|
)
|
@@ -66,7 +65,7 @@ class LdapClient:
|
|
66
65
|
|
67
66
|
@classmethod
|
68
67
|
def from_params(
|
69
|
-
cls, server_url: str, user:
|
68
|
+
cls, server_url: str, user: str | None, password: str | None, base_dn: str
|
70
69
|
) -> "LdapClient":
|
71
70
|
connection = Connection(
|
72
71
|
Server(server_url, get_info=ALL),
|
@@ -3,11 +3,7 @@ import logging
|
|
3
3
|
import os
|
4
4
|
import subprocess
|
5
5
|
from collections.abc import Mapping
|
6
|
-
from typing import
|
7
|
-
Any,
|
8
|
-
Optional,
|
9
|
-
Tuple,
|
10
|
-
)
|
6
|
+
from typing import Any
|
11
7
|
|
12
8
|
|
13
9
|
def state_rm_access_key(working_dirs, account, user):
|
@@ -15,13 +11,13 @@ def state_rm_access_key(working_dirs, account, user):
|
|
15
11
|
init_result = subprocess.run(["terraform", "init"], check=False, cwd=wd)
|
16
12
|
if init_result.returncode != 0:
|
17
13
|
return False
|
18
|
-
resource = "aws_iam_access_key.{}"
|
14
|
+
resource = f"aws_iam_access_key.{user}"
|
19
15
|
result = subprocess.run(["terraform", "state", "rm", resource], check=False, cwd=wd)
|
20
16
|
return result.returncode == 0
|
21
17
|
|
22
18
|
|
23
19
|
def _compute_terraform_env(
|
24
|
-
env:
|
20
|
+
env: Mapping[str, str] | None = None,
|
25
21
|
) -> Mapping[str, str]:
|
26
22
|
default_env = os.environ.copy()
|
27
23
|
return default_env if env is None else {**default_env, **env}
|
@@ -30,8 +26,8 @@ def _compute_terraform_env(
|
|
30
26
|
def _terraform_command(
|
31
27
|
args: list[str],
|
32
28
|
working_dir: str,
|
33
|
-
env:
|
34
|
-
) ->
|
29
|
+
env: Mapping[str, str] | None = None,
|
30
|
+
) -> tuple[int, str, str]:
|
35
31
|
result = subprocess.run(
|
36
32
|
args,
|
37
33
|
capture_output=True,
|
@@ -66,8 +62,8 @@ def show_json(working_dir: str, path: str) -> dict[str, Any]:
|
|
66
62
|
|
67
63
|
def init(
|
68
64
|
working_dir: str,
|
69
|
-
env:
|
70
|
-
) ->
|
65
|
+
env: Mapping[str, str] | None = None,
|
66
|
+
) -> tuple[int, str, str]:
|
71
67
|
"""
|
72
68
|
Run terraform init -input=false -no-color.
|
73
69
|
|
@@ -84,8 +80,8 @@ def init(
|
|
84
80
|
|
85
81
|
def output(
|
86
82
|
working_dir: str,
|
87
|
-
env:
|
88
|
-
) ->
|
83
|
+
env: Mapping[str, str] | None = None,
|
84
|
+
) -> tuple[int, str, str]:
|
89
85
|
"""
|
90
86
|
Run terraform output -json.
|
91
87
|
|
@@ -103,8 +99,8 @@ def output(
|
|
103
99
|
def plan(
|
104
100
|
working_dir: str,
|
105
101
|
out: str,
|
106
|
-
env:
|
107
|
-
) ->
|
102
|
+
env: Mapping[str, str] | None = None,
|
103
|
+
) -> tuple[int, str, str]:
|
108
104
|
"""
|
109
105
|
Run terraform plan -out=<out> -input=false -no-color.
|
110
106
|
|
@@ -123,8 +119,8 @@ def plan(
|
|
123
119
|
def apply(
|
124
120
|
working_dir: str,
|
125
121
|
dir_or_plan: str,
|
126
|
-
env:
|
127
|
-
) ->
|
122
|
+
env: Mapping[str, str] | None = None,
|
123
|
+
) -> tuple[int, str, str]:
|
128
124
|
"""
|
129
125
|
Run terraform apply -input=false -no-color <dir_or_plan>.
|
130
126
|
|
@@ -1,11 +1,8 @@
|
|
1
|
-
from collections.abc import Sequence
|
1
|
+
from collections.abc import Callable, Sequence
|
2
2
|
from typing import (
|
3
3
|
Any,
|
4
|
-
Callable,
|
5
|
-
Optional,
|
6
4
|
Protocol,
|
7
5
|
TypeVar,
|
8
|
-
Union,
|
9
6
|
)
|
10
7
|
|
11
8
|
from pydantic import (
|
@@ -34,7 +31,7 @@ class Bot(Protocol):
|
|
34
31
|
def name(self) -> str: ...
|
35
32
|
|
36
33
|
@property
|
37
|
-
def org_username(self) ->
|
34
|
+
def org_username(self) -> str | None: ...
|
38
35
|
|
39
36
|
def dict(self, *, by_alias: bool = False) -> dict[str, Any]: ...
|
40
37
|
|
@@ -50,21 +47,21 @@ class RoleWithMemberships(Protocol):
|
|
50
47
|
def bots(self) -> Sequence[Bot]: ...
|
51
48
|
|
52
49
|
@property
|
53
|
-
def member_sources(self) ->
|
50
|
+
def member_sources(self) -> Sequence[RoleMembershipSource] | None: ...
|
54
51
|
|
55
52
|
|
56
53
|
class RoleUser(BaseModel):
|
57
54
|
name: str
|
58
55
|
org_username: str
|
59
|
-
github_username:
|
60
|
-
quay_username:
|
61
|
-
slack_username:
|
62
|
-
pagerduty_username:
|
63
|
-
aws_username:
|
64
|
-
cloudflare_user:
|
65
|
-
public_gpg_key:
|
66
|
-
tag_on_cluster_updates:
|
67
|
-
tag_on_merge_requests:
|
56
|
+
github_username: str | None
|
57
|
+
quay_username: str | None
|
58
|
+
slack_username: str | None
|
59
|
+
pagerduty_username: str | None
|
60
|
+
aws_username: str | None
|
61
|
+
cloudflare_user: str | None
|
62
|
+
public_gpg_key: str | None
|
63
|
+
tag_on_cluster_updates: bool | None = False
|
64
|
+
tag_on_merge_requests: bool | None = False
|
68
65
|
|
69
66
|
class Config:
|
70
67
|
extra = Extra.ignore
|
@@ -72,18 +69,18 @@ class RoleUser(BaseModel):
|
|
72
69
|
|
73
70
|
class RoleBot(BaseModel):
|
74
71
|
name: str
|
75
|
-
description:
|
76
|
-
org_username:
|
77
|
-
github_username:
|
78
|
-
gitlab_username:
|
79
|
-
openshift_serviceaccount:
|
80
|
-
quay_username:
|
72
|
+
description: str | None
|
73
|
+
org_username: str | None
|
74
|
+
github_username: str | None
|
75
|
+
gitlab_username: str | None
|
76
|
+
openshift_serviceaccount: str | None
|
77
|
+
quay_username: str | None
|
81
78
|
|
82
79
|
class Config:
|
83
80
|
extra = Extra.ignore
|
84
81
|
|
85
82
|
|
86
|
-
RoleMember =
|
83
|
+
RoleMember = RoleUser | RoleBot
|
87
84
|
|
88
85
|
ProviderGroup = tuple[str, str]
|
89
86
|
|
reconcile/utils/metrics.py
CHANGED
@@ -12,8 +12,6 @@ from collections.abc import (
|
|
12
12
|
from types import TracebackType
|
13
13
|
from typing import (
|
14
14
|
Any,
|
15
|
-
Optional,
|
16
|
-
Type,
|
17
15
|
TypeVar,
|
18
16
|
)
|
19
17
|
|
@@ -190,10 +188,10 @@ class MetricsContainer:
|
|
190
188
|
def __init__(
|
191
189
|
self,
|
192
190
|
) -> None:
|
193
|
-
self._gauges: dict[
|
191
|
+
self._gauges: dict[type[GaugeMetric], dict[Sequence[str], float]] = defaultdict(
|
194
192
|
dict
|
195
193
|
)
|
196
|
-
self._counters: dict[
|
194
|
+
self._counters: dict[type[CounterMetric], dict[Sequence[str], float]] = (
|
197
195
|
defaultdict(dict)
|
198
196
|
)
|
199
197
|
|
@@ -236,7 +234,7 @@ class MetricsContainer:
|
|
236
234
|
|
237
235
|
T = TypeVar("T", bound=BaseMetric)
|
238
236
|
|
239
|
-
def get_metric_value(self, metric_class:
|
237
|
+
def get_metric_value(self, metric_class: type[T], **kwargs: Any) -> float | None:
|
240
238
|
"""
|
241
239
|
Finds a unique match for the metrics class and labels, and returns its value.
|
242
240
|
If more than one match is found, a ValueError is raised.
|
@@ -252,7 +250,7 @@ class MetricsContainer:
|
|
252
250
|
return None
|
253
251
|
|
254
252
|
def get_metrics(
|
255
|
-
self, metric_class:
|
253
|
+
self, metric_class: type[T], **kwargs: Any
|
256
254
|
) -> list[tuple[T, float]]:
|
257
255
|
"""
|
258
256
|
Returns all metrics of the given class from this container and all its scopes,
|
@@ -383,7 +381,7 @@ class _MetricsContext:
|
|
383
381
|
|
384
382
|
def __init__(
|
385
383
|
self,
|
386
|
-
scope:
|
384
|
+
scope: Hashable | None,
|
387
385
|
parent: MetricsContainer,
|
388
386
|
aggregate_counters: bool,
|
389
387
|
):
|
@@ -408,9 +406,9 @@ class _MetricsContext:
|
|
408
406
|
|
409
407
|
def __exit__(
|
410
408
|
self,
|
411
|
-
exc_type:
|
412
|
-
exc_value:
|
413
|
-
traceback:
|
409
|
+
exc_type: type[BaseException] | None,
|
410
|
+
exc_value: BaseException | None,
|
411
|
+
traceback: TracebackType | None,
|
414
412
|
) -> None:
|
415
413
|
if self.scope:
|
416
414
|
self.parent._scopes[self.scope] = self.container
|
@@ -420,8 +418,8 @@ class _MetricsContext:
|
|
420
418
|
|
421
419
|
|
422
420
|
def transactional_metrics(
|
423
|
-
scope:
|
424
|
-
parent_container:
|
421
|
+
scope: Hashable | None = None,
|
422
|
+
parent_container: MetricsContainer | None = None,
|
425
423
|
aggregate_counters: bool = True,
|
426
424
|
) -> _MetricsContext:
|
427
425
|
"""
|
@@ -562,9 +560,9 @@ class ErrorRateMetricSet:
|
|
562
560
|
|
563
561
|
def __exit__(
|
564
562
|
self: ERMS,
|
565
|
-
exc_type:
|
566
|
-
exc_value:
|
567
|
-
traceback:
|
563
|
+
exc_type: type[BaseException] | None,
|
564
|
+
exc_value: BaseException | None,
|
565
|
+
traceback: TracebackType | None,
|
568
566
|
) -> None:
|
569
567
|
if exc_value:
|
570
568
|
self.fail(exc_value)
|
reconcile/utils/mr/base.py
CHANGED
@@ -4,11 +4,7 @@ from abc import (
|
|
4
4
|
ABC,
|
5
5
|
abstractmethod,
|
6
6
|
)
|
7
|
-
from typing import
|
8
|
-
Any,
|
9
|
-
Optional,
|
10
|
-
Union,
|
11
|
-
)
|
7
|
+
from typing import Any
|
12
8
|
from uuid import uuid4
|
13
9
|
|
14
10
|
from gitlab.exceptions import GitlabError
|
@@ -36,7 +32,7 @@ class MergeRequestProcessingError(Exception):
|
|
36
32
|
"""
|
37
33
|
|
38
34
|
|
39
|
-
MRClient =
|
35
|
+
MRClient = GitLabApi | SQSGateway
|
40
36
|
|
41
37
|
|
42
38
|
class MergeRequestBase(ABC):
|
@@ -211,7 +207,7 @@ class MergeRequestBase(ABC):
|
|
211
207
|
from_=gitlab_cli.main_branch, to=self.branch
|
212
208
|
)["diffs"]
|
213
209
|
|
214
|
-
def submit(self, cli: MRClient) ->
|
210
|
+
def submit(self, cli: MRClient) -> Any | None:
|
215
211
|
if isinstance(cli, GitLabApi):
|
216
212
|
return self.submit_to_gitlab(gitlab_cli=cli)
|
217
213
|
|
@@ -226,10 +222,10 @@ def app_interface_email(
|
|
226
222
|
name: str,
|
227
223
|
subject: str,
|
228
224
|
body: str,
|
229
|
-
users:
|
230
|
-
aliases:
|
231
|
-
aws_accounts:
|
232
|
-
apps:
|
225
|
+
users: list[str] | None = None,
|
226
|
+
aliases: list[str] | None = None,
|
227
|
+
aws_accounts: list[str] | None = None,
|
228
|
+
apps: list[str] | None = None,
|
233
229
|
) -> str:
|
234
230
|
"""Render app-interface-email template."""
|
235
231
|
with open(EMAIL_TEMPLATE, encoding="locale") as file_obj:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from collections.abc import Sequence
|
3
|
-
from datetime import
|
3
|
+
from datetime import UTC, date
|
4
4
|
from datetime import datetime as dt
|
5
5
|
from pathlib import Path
|
6
6
|
|
@@ -60,7 +60,7 @@ class UpdateGlitchtipAccessReport(MergeRequestBase):
|
|
60
60
|
self._glitchtip_access_revalidation_workbook = str(
|
61
61
|
glitchtip_access_revalidation_workbook
|
62
62
|
)
|
63
|
-
self._isodate = dt.now(tz=
|
63
|
+
self._isodate = dt.now(tz=UTC).isoformat()
|
64
64
|
self._dry_run = dry_run
|
65
65
|
|
66
66
|
@property
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from datetime import datetime
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Optional
|
5
4
|
|
6
5
|
from pydantic import BaseModel
|
7
6
|
|
@@ -32,7 +31,7 @@ class CreateAppInterfaceNotificator(MergeRequestBase):
|
|
32
31
|
def __init__(
|
33
32
|
self,
|
34
33
|
notification: Notification,
|
35
|
-
labels:
|
34
|
+
labels: list[str] | None = None,
|
36
35
|
email_base_path: Path = Path("data") / "app-interface" / "emails",
|
37
36
|
dry_run: bool = False,
|
38
37
|
):
|