qontract-reconcile 0.10.1rc883__py3-none-any.whl → 0.10.1rc885__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.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/RECORD +276 -276
- 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 +2 -2
- 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 +9 -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 +2 -5
- 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 +2 -5
- reconcile/glitchtip_project_alerts/integration.py +3 -6
- reconcile/glitchtip_project_dsn/integration.py +4 -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 +27 -29
- 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 +3 -4
- 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 +2 -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/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/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 +32 -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 +37 -53
- 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 +30 -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 +12 -17
- tools/template_validation.py +1 -1
- tools/test/conftest.py +3 -6
- {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,3 @@
|
|
1
|
-
from typing import Optional
|
2
|
-
|
3
1
|
from reconcile.utils.glitchtip.models import (
|
4
2
|
Organization,
|
5
3
|
Project,
|
@@ -60,7 +58,7 @@ class GlitchtipClient(ApiBase):
|
|
60
58
|
]
|
61
59
|
|
62
60
|
def create_project(
|
63
|
-
self, organization_slug: str, team_slug: str, name: str, platform:
|
61
|
+
self, organization_slug: str, team_slug: str, name: str, platform: str | None
|
64
62
|
) -> Project:
|
65
63
|
"""Create a project."""
|
66
64
|
return Project(
|
@@ -75,7 +73,7 @@ class GlitchtipClient(ApiBase):
|
|
75
73
|
organization_slug: str,
|
76
74
|
slug: str,
|
77
75
|
name: str,
|
78
|
-
platform:
|
76
|
+
platform: str | None,
|
79
77
|
event_throttle_rate: int,
|
80
78
|
) -> Project:
|
81
79
|
"""Update a project."""
|
@@ -3,10 +3,7 @@ from __future__ import annotations
|
|
3
3
|
import re
|
4
4
|
from collections.abc import MutableMapping
|
5
5
|
from enum import Enum
|
6
|
-
from typing import
|
7
|
-
Any,
|
8
|
-
Optional,
|
9
|
-
)
|
6
|
+
from typing import Any
|
10
7
|
|
11
8
|
from pydantic import (
|
12
9
|
BaseModel,
|
@@ -26,7 +23,7 @@ def slugify(value: str) -> str:
|
|
26
23
|
|
27
24
|
|
28
25
|
class User(BaseModel):
|
29
|
-
pk:
|
26
|
+
pk: int | None = Field(None, alias="id")
|
30
27
|
email: str
|
31
28
|
role: str
|
32
29
|
pending: bool = False
|
@@ -44,7 +41,7 @@ class User(BaseModel):
|
|
44
41
|
|
45
42
|
|
46
43
|
class Team(BaseModel):
|
47
|
-
pk:
|
44
|
+
pk: int | None = Field(None, alias="id")
|
48
45
|
name: str = ""
|
49
46
|
slug: str = ""
|
50
47
|
users: list[User] = []
|
@@ -89,7 +86,7 @@ class RecipientType(Enum):
|
|
89
86
|
|
90
87
|
|
91
88
|
class ProjectAlertRecipient(BaseModel):
|
92
|
-
pk:
|
89
|
+
pk: int | None
|
93
90
|
recipient_type: RecipientType = Field(..., alias="recipientType")
|
94
91
|
url: str = ""
|
95
92
|
|
@@ -118,7 +115,7 @@ class ProjectAlertRecipient(BaseModel):
|
|
118
115
|
|
119
116
|
|
120
117
|
class ProjectAlert(BaseModel):
|
121
|
-
pk:
|
118
|
+
pk: int | None
|
122
119
|
name: str
|
123
120
|
timespan_minutes: int
|
124
121
|
quantity: int
|
@@ -148,10 +145,10 @@ class ProjectAlert(BaseModel):
|
|
148
145
|
|
149
146
|
|
150
147
|
class Project(BaseModel):
|
151
|
-
pk:
|
148
|
+
pk: int | None = Field(None, alias="id")
|
152
149
|
name: str
|
153
150
|
slug: str = ""
|
154
|
-
platform:
|
151
|
+
platform: str | None
|
155
152
|
teams: list[Team] = []
|
156
153
|
alerts: list[ProjectAlert] = []
|
157
154
|
event_throttle_rate: int = Field(0, alias="eventThrottleRate")
|
@@ -189,7 +186,7 @@ class Project(BaseModel):
|
|
189
186
|
|
190
187
|
|
191
188
|
class Organization(BaseModel):
|
192
|
-
pk:
|
189
|
+
pk: int | None = Field(None, alias="id")
|
193
190
|
name: str
|
194
191
|
slug: str = ""
|
195
192
|
projects: list[Project] = []
|
reconcile/utils/gql.py
CHANGED
@@ -2,15 +2,10 @@ import logging
|
|
2
2
|
import textwrap
|
3
3
|
import threading
|
4
4
|
from datetime import (
|
5
|
+
UTC,
|
5
6
|
datetime,
|
6
|
-
timezone,
|
7
|
-
)
|
8
|
-
from typing import (
|
9
|
-
Any,
|
10
|
-
Dict,
|
11
|
-
Optional,
|
12
|
-
Union,
|
13
7
|
)
|
8
|
+
from typing import Any
|
14
9
|
from urllib.parse import urlparse
|
15
10
|
|
16
11
|
import requests
|
@@ -83,9 +78,7 @@ class GqlApiErrorForbiddenSchema(Exception):
|
|
83
78
|
|
84
79
|
class GqlGetResourceError(Exception):
|
85
80
|
def __init__(self, path, msg):
|
86
|
-
super().__init__(
|
87
|
-
"Error getting resource from path {}: {}".format(path, str(msg))
|
88
|
-
)
|
81
|
+
super().__init__(f"Error getting resource from path {path}: {str(msg)}")
|
89
82
|
|
90
83
|
|
91
84
|
class GqlApi:
|
@@ -95,11 +88,11 @@ class GqlApi:
|
|
95
88
|
def __init__(
|
96
89
|
self,
|
97
90
|
url: str,
|
98
|
-
token:
|
91
|
+
token: str | None = None,
|
99
92
|
int_name=None,
|
100
93
|
validate_schemas=False,
|
101
|
-
commit:
|
102
|
-
commit_timestamp:
|
94
|
+
commit: str | None = None,
|
95
|
+
commit_timestamp: str | None = None,
|
103
96
|
) -> None:
|
104
97
|
self.url = url
|
105
98
|
self.token = token
|
@@ -143,15 +136,15 @@ class GqlApi:
|
|
143
136
|
@retry(exceptions=GqlApiError, max_attempts=5, hook=capture_and_forget)
|
144
137
|
def query(
|
145
138
|
self, query: str, variables=None, skip_validation=False
|
146
|
-
) ->
|
139
|
+
) -> dict[str, Any] | None:
|
147
140
|
try:
|
148
141
|
result = self.client.execute(
|
149
142
|
gql(query), variables, get_execution_result=True
|
150
143
|
).formatted
|
151
144
|
except requests.exceptions.ConnectionError as e:
|
152
|
-
raise GqlApiError("Could not connect to GraphQL server ({})"
|
145
|
+
raise GqlApiError(f"Could not connect to GraphQL server ({e})")
|
153
146
|
except TransportQueryError as e:
|
154
|
-
raise GqlApiError("`error` returned with GraphQL response {}"
|
147
|
+
raise GqlApiError(f"`error` returned with GraphQL response {e}")
|
155
148
|
except AssertionError:
|
156
149
|
raise GqlApiError("`data` field missing from GraphQL response payload")
|
157
150
|
except Exception as e:
|
@@ -247,16 +240,14 @@ class GqlApi:
|
|
247
240
|
return list(self._queried_schemas)
|
248
241
|
|
249
242
|
@property
|
250
|
-
def commit_timestamp_utc(self) ->
|
243
|
+
def commit_timestamp_utc(self) -> str | None:
|
251
244
|
if self.commit_timestamp:
|
252
|
-
return datetime.fromtimestamp(
|
253
|
-
int(self.commit_timestamp), timezone.utc
|
254
|
-
).isoformat()
|
245
|
+
return datetime.fromtimestamp(int(self.commit_timestamp), UTC).isoformat()
|
255
246
|
return None
|
256
247
|
|
257
248
|
|
258
249
|
class GqlApiSingleton:
|
259
|
-
gql_api:
|
250
|
+
gql_api: GqlApi | None = None
|
260
251
|
gqlapi_lock = threading.Lock()
|
261
252
|
|
262
253
|
@classmethod
|
@@ -288,11 +279,11 @@ class GqlApiSingleton:
|
|
288
279
|
|
289
280
|
def init(
|
290
281
|
url: str,
|
291
|
-
token:
|
282
|
+
token: str | None = None,
|
292
283
|
integration=None,
|
293
284
|
validate_schemas=False,
|
294
|
-
commit:
|
295
|
-
commit_timestamp:
|
285
|
+
commit: str | None = None,
|
286
|
+
commit_timestamp: str | None = None,
|
296
287
|
):
|
297
288
|
return GqlApiSingleton.create(
|
298
289
|
url,
|
@@ -319,12 +310,12 @@ class PersistentRequestsHTTPTransport(RequestsHTTPTransport):
|
|
319
310
|
self,
|
320
311
|
session: requests.Session,
|
321
312
|
url: str,
|
322
|
-
headers:
|
323
|
-
cookies:
|
324
|
-
auth:
|
313
|
+
headers: dict[str, Any] | None = None,
|
314
|
+
cookies: dict[str, Any] | RequestsCookieJar | None = None,
|
315
|
+
auth: AuthBase | None = None,
|
325
316
|
use_json: bool = True,
|
326
|
-
timeout:
|
327
|
-
verify:
|
317
|
+
timeout: int | None = None,
|
318
|
+
verify: bool | str = True,
|
328
319
|
retries: int = 0,
|
329
320
|
method: str = "POST",
|
330
321
|
**kwargs: Any,
|
@@ -398,8 +389,8 @@ def init_from_config(
|
|
398
389
|
|
399
390
|
|
400
391
|
def _get_gql_server_and_token(
|
401
|
-
autodetect_sha: bool = False, sha:
|
402
|
-
) -> tuple[str, str,
|
392
|
+
autodetect_sha: bool = False, sha: str | None = None
|
393
|
+
) -> tuple[str, str, str | None, str | None]:
|
403
394
|
config = get_config()
|
404
395
|
|
405
396
|
server_url = urlparse(config["graphql"]["server"])
|
@@ -425,7 +416,7 @@ def get_api() -> GqlApi:
|
|
425
416
|
|
426
417
|
|
427
418
|
def get_api_for_sha(
|
428
|
-
sha: str, integration:
|
419
|
+
sha: str, integration: str | None = None, validate_schemas: bool = True
|
429
420
|
) -> GqlApi:
|
430
421
|
server, token, commit, timestamp = _get_gql_server_and_token(
|
431
422
|
autodetect_sha=False, sha=sha
|
@@ -442,8 +433,8 @@ def get_api_for_sha(
|
|
442
433
|
|
443
434
|
def get_api_for_server(
|
444
435
|
server: str,
|
445
|
-
token:
|
446
|
-
integration:
|
436
|
+
token: str | None,
|
437
|
+
integration: str | None = None,
|
447
438
|
validate_schemas: bool = True,
|
448
439
|
) -> GqlApi:
|
449
440
|
return GqlApi(
|
@@ -458,7 +449,7 @@ def get_api_for_server(
|
|
458
449
|
|
459
450
|
@retry(exceptions=requests.exceptions.HTTPError, max_attempts=5)
|
460
451
|
def get_diff(
|
461
|
-
old_sha: str, file_type:
|
452
|
+
old_sha: str, file_type: str | None = None, file_path: str | None = None
|
462
453
|
) -> dict[str, Any]:
|
463
454
|
config = get_config()
|
464
455
|
|
reconcile/utils/grouping.py
CHANGED
reconcile/utils/imap_client.py
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
import imaplib
|
2
|
-
from typing import
|
3
|
-
Any,
|
4
|
-
Union,
|
5
|
-
)
|
2
|
+
from typing import Any
|
6
3
|
|
7
4
|
from reconcile.utils.secret_reader import SecretReader
|
8
5
|
|
@@ -15,7 +12,7 @@ class ImapClient:
|
|
15
12
|
self.password: str = imap_config["password"]
|
16
13
|
self.port: int = int(imap_config["port"])
|
17
14
|
self.timeout: int = settings["imap"].get("timeout", 30)
|
18
|
-
self._server:
|
15
|
+
self._server: imaplib.IMAP4_SSL | None = None
|
19
16
|
|
20
17
|
def __enter__(self) -> "ImapClient":
|
21
18
|
self._server = imaplib.IMAP4_SSL(
|
@@ -1,6 +1,5 @@
|
|
1
1
|
from typing import (
|
2
2
|
Any,
|
3
|
-
Optional,
|
4
3
|
Self,
|
5
4
|
)
|
6
5
|
|
@@ -61,7 +60,7 @@ class InternalGroupsApi:
|
|
61
60
|
|
62
61
|
@retry(exceptions=(TokenExpiredError,), max_attempts=2)
|
63
62
|
def _request(
|
64
|
-
self, method: str, url: str, json:
|
63
|
+
self, method: str, url: str, json: dict[Any, Any] | None = None
|
65
64
|
) -> Response:
|
66
65
|
try:
|
67
66
|
return self._client.request(
|
@@ -1,7 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from enum import
|
4
|
-
from typing import Optional
|
3
|
+
from enum import StrEnum
|
5
4
|
|
6
5
|
from pydantic import (
|
7
6
|
BaseModel,
|
@@ -9,7 +8,7 @@ from pydantic import (
|
|
9
8
|
)
|
10
9
|
|
11
10
|
|
12
|
-
class EntityType(
|
11
|
+
class EntityType(StrEnum):
|
13
12
|
USER = "user"
|
14
13
|
SERVICE_ACCOUNT = "serviceaccount"
|
15
14
|
DELETED_USER = "deleteduser"
|
@@ -35,17 +34,17 @@ class Group(BaseModel):
|
|
35
34
|
contact_list: str = Field(..., alias="contactList")
|
36
35
|
owners: list[Entity]
|
37
36
|
display_name: str = Field(..., alias="displayName")
|
38
|
-
notes:
|
39
|
-
rover_group_member_query:
|
40
|
-
rover_group_inclusions:
|
37
|
+
notes: str | None = None
|
38
|
+
rover_group_member_query: str | None = Field(None, alias="roverGroupMemberQuery")
|
39
|
+
rover_group_inclusions: list[Entity] | None = Field(
|
41
40
|
None, alias="roverGroupInclusions"
|
42
41
|
)
|
43
|
-
rover_group_exclusions:
|
42
|
+
rover_group_exclusions: list[Entity] | None = Field(
|
44
43
|
None, alias="roverGroupExclusions"
|
45
44
|
)
|
46
45
|
members: list[Entity] = []
|
47
|
-
member_of:
|
48
|
-
namespace:
|
46
|
+
member_of: list[str] | None = Field(None, alias="memberOf")
|
47
|
+
namespace: str | None = None
|
49
48
|
|
50
49
|
def __eq__(self, other: object) -> bool:
|
51
50
|
if not isinstance(other, Group):
|
reconcile/utils/jenkins_api.py
CHANGED
@@ -108,7 +108,7 @@ class JenkinsApi:
|
|
108
108
|
res.raise_for_status()
|
109
109
|
|
110
110
|
def get_all_roles(self):
|
111
|
-
url = "{}/role-strategy/strategy/getAllRoles"
|
111
|
+
url = f"{self.url}/role-strategy/strategy/getAllRoles"
|
112
112
|
res = requests.get(
|
113
113
|
url, verify=self.ssl_verify, auth=(self.user, self.password), timeout=60
|
114
114
|
)
|
@@ -117,7 +117,7 @@ class JenkinsApi:
|
|
117
117
|
return res.json()
|
118
118
|
|
119
119
|
def assign_role_to_user(self, role, user):
|
120
|
-
url = "{}/role-strategy/strategy/assignRole"
|
120
|
+
url = f"{self.url}/role-strategy/strategy/assignRole"
|
121
121
|
data = {"type": "globalRoles", "roleName": role, "sid": user}
|
122
122
|
res = requests.post(
|
123
123
|
url,
|
@@ -130,7 +130,7 @@ class JenkinsApi:
|
|
130
130
|
res.raise_for_status()
|
131
131
|
|
132
132
|
def unassign_role_from_user(self, role, user):
|
133
|
-
url = "{}/role-strategy/strategy/unassignRole"
|
133
|
+
url = f"{self.url}/role-strategy/strategy/unassignRole"
|
134
134
|
data = {"type": "globalRoles", "roleName": role, "sid": user}
|
135
135
|
res = requests.post(
|
136
136
|
url,
|
@@ -143,7 +143,7 @@ class JenkinsApi:
|
|
143
143
|
res.raise_for_status()
|
144
144
|
|
145
145
|
def safe_restart(self, force_restart=False):
|
146
|
-
url = "{}/safeRestart"
|
146
|
+
url = f"{self.url}/safeRestart"
|
147
147
|
if self.should_restart or force_restart:
|
148
148
|
logging.debug(
|
149
149
|
"performing safe restart. "
|
@@ -2,7 +2,7 @@ import hashlib
|
|
2
2
|
import json
|
3
3
|
import re
|
4
4
|
from collections.abc import Iterable
|
5
|
-
from typing import Any
|
5
|
+
from typing import Any
|
6
6
|
from urllib import parse
|
7
7
|
|
8
8
|
import jinja2
|
@@ -20,7 +20,7 @@ def json_to_dict(input: str) -> Any:
|
|
20
20
|
return data
|
21
21
|
|
22
22
|
|
23
|
-
def urlescape(string: str, safe: str = "/", encoding:
|
23
|
+
def urlescape(string: str, safe: str = "/", encoding: str | None = None) -> str:
|
24
24
|
"""Jinja2 filter that is a simple wrapper around urllib's URL quoting
|
25
25
|
functions that takes a string value and makes it safe for use as URL
|
26
26
|
components escaping any reserved characters using URL encoding. See:
|
@@ -37,7 +37,7 @@ def urlescape(string: str, safe: str = "/", encoding: Optional[str] = None) -> s
|
|
37
37
|
return parse.quote(string, safe=safe, encoding=encoding)
|
38
38
|
|
39
39
|
|
40
|
-
def urlunescape(string: str, encoding:
|
40
|
+
def urlunescape(string: str, encoding: str | None = None) -> str:
|
41
41
|
"""Jinja2 filter that is a simple wrapper around urllib's URL unquoting
|
42
42
|
functions that takes an URL-encoded string value and unescapes it
|
43
43
|
replacing any URL-encoded values with their character equivalent. See:
|
@@ -78,7 +78,7 @@ def hash_list(input: Iterable) -> str:
|
|
78
78
|
lst = list(input)
|
79
79
|
str_lst = []
|
80
80
|
for el in lst:
|
81
|
-
if isinstance(el,
|
81
|
+
if isinstance(el, list | dict):
|
82
82
|
raise RuntimeError(
|
83
83
|
f"jinja2 hash_list function received non-primitive value {el}. All values received {lst}"
|
84
84
|
)
|
reconcile/utils/jinja2/utils.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from functools import cache
|
2
|
-
from typing import Any
|
2
|
+
from typing import Any
|
3
3
|
|
4
4
|
import jinja2
|
5
5
|
from jinja2.sandbox import SandboxedEnvironment
|
@@ -66,9 +66,9 @@ def lookup_github_file_content(
|
|
66
66
|
repo: str,
|
67
67
|
path: str,
|
68
68
|
ref: str,
|
69
|
-
tvars:
|
70
|
-
settings:
|
71
|
-
secret_reader:
|
69
|
+
tvars: dict[str, Any] | None = None,
|
70
|
+
settings: dict[str, Any] | None = None,
|
71
|
+
secret_reader: SecretReaderBase | None = None,
|
72
72
|
) -> str:
|
73
73
|
if tvars is not None:
|
74
74
|
repo = process_jinja2_template(
|
@@ -98,7 +98,7 @@ def lookup_s3_object(
|
|
98
98
|
account_name: str,
|
99
99
|
bucket_name: str,
|
100
100
|
path: str,
|
101
|
-
region_name:
|
101
|
+
region_name: str | None = None,
|
102
102
|
) -> str:
|
103
103
|
settings = queries.get_app_interface_settings()
|
104
104
|
accounts = queries.get_aws_accounts(name=account_name)
|
@@ -118,12 +118,12 @@ def lookup_s3_object(
|
|
118
118
|
def lookup_secret(
|
119
119
|
path: str,
|
120
120
|
key: str,
|
121
|
-
version:
|
122
|
-
tvars:
|
121
|
+
version: str | None = None,
|
122
|
+
tvars: dict[str, Any] | None = None,
|
123
123
|
allow_not_found: bool = False,
|
124
|
-
settings:
|
125
|
-
secret_reader:
|
126
|
-
) ->
|
124
|
+
settings: dict[str, Any] | None = None,
|
125
|
+
secret_reader: SecretReaderBase | None = None,
|
126
|
+
) -> str | None:
|
127
127
|
if tvars is not None:
|
128
128
|
path = process_jinja2_template(
|
129
129
|
body=path, vars=tvars, settings=settings, secret_reader=secret_reader
|
@@ -150,10 +150,10 @@ def lookup_secret(
|
|
150
150
|
|
151
151
|
def process_jinja2_template(
|
152
152
|
body: str,
|
153
|
-
vars:
|
153
|
+
vars: dict[str, Any] | None = None,
|
154
154
|
extra_curly: bool = False,
|
155
|
-
settings:
|
156
|
-
secret_reader:
|
155
|
+
settings: dict[str, Any] | None = None,
|
156
|
+
secret_reader: SecretReaderBase | None = None,
|
157
157
|
) -> Any:
|
158
158
|
if vars is None:
|
159
159
|
vars = {}
|
@@ -196,10 +196,10 @@ def process_jinja2_template(
|
|
196
196
|
|
197
197
|
def process_extracurlyjinja2_template(
|
198
198
|
body: str,
|
199
|
-
vars:
|
199
|
+
vars: dict[str, Any] | None = None,
|
200
200
|
extra_curly: bool = True,
|
201
|
-
settings:
|
202
|
-
secret_reader:
|
201
|
+
settings: dict[str, Any] | None = None,
|
202
|
+
secret_reader: SecretReaderBase | None = None,
|
203
203
|
) -> Any:
|
204
204
|
if vars is None:
|
205
205
|
vars = {}
|
reconcile/utils/jira_client.py
CHANGED
@@ -8,7 +8,6 @@ from collections.abc import (
|
|
8
8
|
)
|
9
9
|
from typing import (
|
10
10
|
Any,
|
11
|
-
Optional,
|
12
11
|
Protocol,
|
13
12
|
)
|
14
13
|
|
@@ -57,11 +56,11 @@ class JiraClient:
|
|
57
56
|
|
58
57
|
def __init__(
|
59
58
|
self,
|
60
|
-
jira_board:
|
61
|
-
settings:
|
62
|
-
jira_api:
|
63
|
-
project:
|
64
|
-
server:
|
59
|
+
jira_board: Mapping[str, Any] | None = None,
|
60
|
+
settings: Mapping | None = None,
|
61
|
+
jira_api: JIRA | None = None,
|
62
|
+
project: str | None = None,
|
63
|
+
server: str | None = None,
|
65
64
|
):
|
66
65
|
"""
|
67
66
|
Note: jira_board and settings is to be deprecated. Use JiraClient.create() instead.
|
@@ -89,7 +88,7 @@ class JiraClient:
|
|
89
88
|
self.my_permissions = functools.lru_cache(maxsize=None)(self._my_permissions)
|
90
89
|
|
91
90
|
def _deprecated_init(
|
92
|
-
self, jira_board: Mapping[str, Any], settings:
|
91
|
+
self, jira_board: Mapping[str, Any], settings: Mapping | None
|
93
92
|
) -> None:
|
94
93
|
secret_reader = SecretReader(settings=settings)
|
95
94
|
self.project = jira_board["name"]
|
@@ -114,7 +113,7 @@ class JiraClient:
|
|
114
113
|
project_name: str,
|
115
114
|
token: str,
|
116
115
|
server_url: str,
|
117
|
-
jira_watcher_settings:
|
116
|
+
jira_watcher_settings: JiraWatcherSettings | None = None,
|
118
117
|
) -> JiraClient:
|
119
118
|
read_timeout = JiraClient.DEFAULT_READ_TIMEOUT
|
120
119
|
connect_timeout = JiraClient.DEFAULT_CONNECT_TIMEOUT
|
@@ -130,12 +129,12 @@ class JiraClient:
|
|
130
129
|
server=server_url,
|
131
130
|
)
|
132
131
|
|
133
|
-
def get_issues(self, fields:
|
132
|
+
def get_issues(self, fields: Mapping | None = None) -> list[Issue]:
|
134
133
|
block_size = 100
|
135
134
|
block_num = 0
|
136
135
|
|
137
136
|
all_issues: list[Issue] = []
|
138
|
-
jql = "project={
|
137
|
+
jql = f"project={self.project}"
|
139
138
|
kwargs: dict[str, Any] = {}
|
140
139
|
if fields:
|
141
140
|
kwargs["fields"] = ",".join(fields)
|
@@ -163,7 +162,7 @@ class JiraClient:
|
|
163
162
|
self,
|
164
163
|
summary: str,
|
165
164
|
body: str,
|
166
|
-
labels:
|
165
|
+
labels: Iterable[str] | None = None,
|
167
166
|
links: Iterable[str] = (),
|
168
167
|
) -> Issue:
|
169
168
|
"""Create an issue in our project with the given labels."""
|
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")
|