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/acs/notifiers.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import json
|
2
|
-
from typing import Any
|
2
|
+
from typing import Any
|
3
3
|
|
4
4
|
from pydantic import BaseModel
|
5
5
|
|
@@ -35,9 +35,9 @@ class JiraNotifier(BaseModel):
|
|
35
35
|
name: str
|
36
36
|
board: str
|
37
37
|
url: str
|
38
|
-
issue_type:
|
38
|
+
issue_type: str | None
|
39
39
|
severity_priority_mappings: list[SeverityPriorityMapping]
|
40
|
-
custom_fields:
|
40
|
+
custom_fields: dict[str, Any] | None
|
41
41
|
|
42
42
|
@staticmethod
|
43
43
|
def from_api(notifier: dict[str, Any]) -> "JiraNotifier":
|
reconcile/utils/acs/policies.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Any
|
1
|
+
from typing import Any
|
2
2
|
|
3
3
|
from pydantic import BaseModel
|
4
4
|
|
@@ -11,7 +11,7 @@ class Scope(BaseModel):
|
|
11
11
|
"""
|
12
12
|
|
13
13
|
cluster: str
|
14
|
-
namespace:
|
14
|
+
namespace: str | None
|
15
15
|
|
16
16
|
|
17
17
|
class PolicyCondition(BaseModel):
|
@@ -23,7 +23,7 @@ class PolicyCondition(BaseModel):
|
|
23
23
|
"""
|
24
24
|
|
25
25
|
field_name: str
|
26
|
-
negate:
|
26
|
+
negate: bool | None
|
27
27
|
values: list[str]
|
28
28
|
|
29
29
|
|
@@ -93,7 +93,7 @@ class AggregatedDiffRunner:
|
|
93
93
|
|
94
94
|
def register(self, on, action, cond=None):
|
95
95
|
if on not in self.diff.keys():
|
96
|
-
raise Exception("Unknown diff key for 'on': {}"
|
96
|
+
raise Exception(f"Unknown diff key for 'on': {on}")
|
97
97
|
self.actions.append((on, action, cond))
|
98
98
|
|
99
99
|
def run(self):
|
reconcile/utils/amtool.py
CHANGED
@@ -2,7 +2,6 @@ import re
|
|
2
2
|
import tempfile
|
3
3
|
from collections.abc import Mapping
|
4
4
|
from subprocess import (
|
5
|
-
PIPE,
|
6
5
|
CalledProcessError,
|
7
6
|
run,
|
8
7
|
)
|
@@ -62,7 +61,7 @@ def version() -> AmtoolResult:
|
|
62
61
|
|
63
62
|
def _run_cmd(cmd: list[str]) -> AmtoolResult:
|
64
63
|
try:
|
65
|
-
result = run(cmd,
|
64
|
+
result = run(cmd, capture_output=True, check=True)
|
66
65
|
except CalledProcessError as e:
|
67
66
|
msg = f'Error running amtool command [{" ".join(cmd)}]'
|
68
67
|
if e.stdout:
|
reconcile/utils/aws_api.py
CHANGED
@@ -15,8 +15,6 @@ from typing import (
|
|
15
15
|
TYPE_CHECKING,
|
16
16
|
Any,
|
17
17
|
Literal,
|
18
|
-
Optional,
|
19
|
-
Union,
|
20
18
|
)
|
21
19
|
|
22
20
|
import botocore
|
@@ -83,7 +81,7 @@ class MissingARNError(Exception):
|
|
83
81
|
pass
|
84
82
|
|
85
83
|
|
86
|
-
KeyStatus =
|
84
|
+
KeyStatus = Literal["Active"] | Literal["Inactive"]
|
87
85
|
|
88
86
|
GOVCLOUD_PARTITION = "aws-us-gov"
|
89
87
|
|
@@ -191,7 +189,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
191
189
|
self,
|
192
190
|
session: Session,
|
193
191
|
service_name,
|
194
|
-
region_name:
|
192
|
+
region_name: str | None = None,
|
195
193
|
):
|
196
194
|
region = region_name if region_name else session.region_name
|
197
195
|
client = session.client(
|
@@ -205,49 +203,49 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
205
203
|
@staticmethod
|
206
204
|
# pylint: disable=method-hidden
|
207
205
|
def _get_session_resource(
|
208
|
-
session: Session, service_name, region_name:
|
206
|
+
session: Session, service_name, region_name: str | None = None
|
209
207
|
):
|
210
208
|
region = region_name if region_name else session.region_name
|
211
209
|
return session.resource(service_name, region_name=region)
|
212
210
|
|
213
211
|
def _account_ec2_client(
|
214
|
-
self, account_name: str, region_name:
|
212
|
+
self, account_name: str, region_name: str | None = None
|
215
213
|
) -> EC2Client:
|
216
214
|
session = self.get_session(account_name)
|
217
215
|
return self.get_session_client(session, "ec2", region_name)
|
218
216
|
|
219
217
|
def _account_ec2_resource(
|
220
|
-
self, account_name: str, region_name:
|
218
|
+
self, account_name: str, region_name: str | None = None
|
221
219
|
) -> EC2ServiceResource:
|
222
220
|
session = self.get_session(account_name)
|
223
221
|
return self._get_session_resource(session, "ec2", region_name)
|
224
222
|
|
225
223
|
def _account_route53_client(
|
226
|
-
self, account_name: str, region_name:
|
224
|
+
self, account_name: str, region_name: str | None = None
|
227
225
|
) -> Route53Client:
|
228
226
|
session = self.get_session(account_name)
|
229
227
|
return self.get_session_client(session, "route53", region_name)
|
230
228
|
|
231
229
|
def _account_rds_client(
|
232
|
-
self, account_name: str, region_name:
|
230
|
+
self, account_name: str, region_name: str | None = None
|
233
231
|
) -> RDSClient:
|
234
232
|
session = self.get_session(account_name)
|
235
233
|
return self.get_session_client(session, "rds", region_name)
|
236
234
|
|
237
235
|
def _account_cloudwatch_client(
|
238
|
-
self, account_name: str, region_name:
|
236
|
+
self, account_name: str, region_name: str | None = None
|
239
237
|
):
|
240
238
|
session = self.get_session(account_name)
|
241
239
|
return self.get_session_client(session, "logs", region_name)
|
242
240
|
|
243
241
|
def _account_organizations_client(
|
244
|
-
self, account_name: str, region_name:
|
242
|
+
self, account_name: str, region_name: str | None = None
|
245
243
|
) -> OrganizationsClient:
|
246
244
|
session = self.get_session(account_name)
|
247
245
|
return self.get_session_client(session, "organizations", region_name)
|
248
246
|
|
249
247
|
def _account_s3_client(
|
250
|
-
self, account_name: str, region_name:
|
248
|
+
self, account_name: str, region_name: str | None = None
|
251
249
|
) -> S3Client:
|
252
250
|
session = self.get_session(account_name)
|
253
251
|
return self.get_session_client(session, "s3", region_name)
|
@@ -493,7 +491,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
493
491
|
|
494
492
|
@staticmethod
|
495
493
|
def resource_has_special_name(account, type, resource):
|
496
|
-
skip_msg = "[{}] skipping {} "
|
494
|
+
skip_msg = f"[{account}] skipping {type} " + "({} related) {}"
|
497
495
|
|
498
496
|
ignore_names = {
|
499
497
|
"production": ["prod"],
|
@@ -510,7 +508,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
510
508
|
return False
|
511
509
|
|
512
510
|
def resource_has_special_tags(self, account, type, resource, tags):
|
513
|
-
skip_msg = "[{}] skipping {} "
|
511
|
+
skip_msg = f"[{account}] skipping {type} " + "({}={}) {}"
|
514
512
|
|
515
513
|
ignore_tags = {
|
516
514
|
"ENV": ["prod", "stage", "staging"],
|
@@ -616,8 +614,8 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
616
614
|
if managed_by_integration_tag[0] == "terraform_resources":
|
617
615
|
return "service_account"
|
618
616
|
|
619
|
-
huh =
|
620
|
-
managed_by_integration_tag[0]
|
617
|
+
huh = (
|
618
|
+
f"unrecognized managed_by_integration tag: {managed_by_integration_tag[0]}"
|
621
619
|
)
|
622
620
|
raise InvalidResourceTypeError(huh)
|
623
621
|
|
@@ -813,7 +811,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
813
811
|
@staticmethod
|
814
812
|
def _get_account_assume_data(
|
815
813
|
account: awsh.Account,
|
816
|
-
) -> tuple[str,
|
814
|
+
) -> tuple[str, str | None, str]:
|
817
815
|
"""
|
818
816
|
returns mandatory data to be able to assume a role with this account:
|
819
817
|
(account_name, assume_role, assume_region)
|
@@ -823,7 +821,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
823
821
|
ok = all(elem in account.keys() for elem in required_keys)
|
824
822
|
if not ok:
|
825
823
|
account_name = account.get("name")
|
826
|
-
raise KeyError("[{}] account is missing required keys"
|
824
|
+
raise KeyError(f"[{account_name}] account is missing required keys")
|
827
825
|
return (account["name"], account.get("assume_role"), account["assume_region"])
|
828
826
|
|
829
827
|
@staticmethod
|
@@ -863,7 +861,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
863
861
|
def _get_assumed_role_client(
|
864
862
|
self,
|
865
863
|
account_name: str,
|
866
|
-
assume_role:
|
864
|
+
assume_role: str | None,
|
867
865
|
assume_region: str,
|
868
866
|
client_type="ec2",
|
869
867
|
) -> EC2Client:
|
@@ -893,7 +891,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
893
891
|
# filters a list of aws resources according to tags
|
894
892
|
@staticmethod
|
895
893
|
def filter_on_tags(
|
896
|
-
items: Iterable[Any], tags:
|
894
|
+
items: Iterable[Any], tags: Mapping[str, str] | None = None
|
897
895
|
) -> list[Any]:
|
898
896
|
if tags is None:
|
899
897
|
tags = {}
|
@@ -1054,7 +1052,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1054
1052
|
account: Mapping[str, Any],
|
1055
1053
|
owner_account: Mapping[str, Any],
|
1056
1054
|
regex: str,
|
1057
|
-
region:
|
1055
|
+
region: str | None = None,
|
1058
1056
|
) -> list[dict[str, Any]]:
|
1059
1057
|
ec2 = self._account_ec2_client(account["name"], region_name=region)
|
1060
1058
|
images = self.get_account_amis(ec2, owner=owner_account["uid"])
|
@@ -1065,7 +1063,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1065
1063
|
account: Mapping[str, Any],
|
1066
1064
|
share_account_uid: str,
|
1067
1065
|
image_id: str,
|
1068
|
-
region:
|
1066
|
+
region: str | None = None,
|
1069
1067
|
):
|
1070
1068
|
ec2 = self._account_ec2_resource(account["name"], region)
|
1071
1069
|
image = ec2.Image(image_id)
|
@@ -1100,8 +1098,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1100
1098
|
client = self._account_cloudwatch_client(account_name, region_name=region_name)
|
1101
1099
|
paginator = client.get_paginator("describe_log_groups")
|
1102
1100
|
for page in paginator.paginate():
|
1103
|
-
|
1104
|
-
yield log_group
|
1101
|
+
yield from page["logGroups"]
|
1105
1102
|
|
1106
1103
|
def get_cloudwatch_log_group_tags(
|
1107
1104
|
self,
|
@@ -1175,7 +1172,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1175
1172
|
|
1176
1173
|
@staticmethod
|
1177
1174
|
# pylint: disable=method-hidden
|
1178
|
-
def get_vpc_default_sg_id(vpc_id: str, ec2: EC2Client) ->
|
1175
|
+
def get_vpc_default_sg_id(vpc_id: str, ec2: EC2Client) -> str | None:
|
1179
1176
|
vpc_security_groups = ec2.describe_security_groups(
|
1180
1177
|
Filters=[
|
1181
1178
|
{"Name": "vpc-id", "Values": [vpc_id]},
|
@@ -1196,7 +1193,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1196
1193
|
|
1197
1194
|
def get_tgw_default_route_table_id(
|
1198
1195
|
self, ec2: EC2Client, tgw_id: str, tags: Mapping[str, str]
|
1199
|
-
) ->
|
1196
|
+
) -> str | None:
|
1200
1197
|
tgws = self.get_transit_gateways(ec2)
|
1201
1198
|
tgws = self.filter_on_tags(tgws, tags)
|
1202
1199
|
# we know the party TGW exists, so we can be
|
@@ -1555,7 +1552,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1555
1552
|
|
1556
1553
|
def get_image_id(
|
1557
1554
|
self, account_name: str, region_name: str, tags: Iterable[AmiTag]
|
1558
|
-
) ->
|
1555
|
+
) -> str | None:
|
1559
1556
|
"""
|
1560
1557
|
Get AMI ID matching the specified criteria.
|
1561
1558
|
|
@@ -1584,7 +1581,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1584
1581
|
self,
|
1585
1582
|
account_name: str,
|
1586
1583
|
db_instance_name: str,
|
1587
|
-
region_name:
|
1584
|
+
region_name: str | None = None,
|
1588
1585
|
) -> DBInstanceMessageTypeDef:
|
1589
1586
|
"""
|
1590
1587
|
Describe a single RDS instance.
|
@@ -1606,7 +1603,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1606
1603
|
account_name: str,
|
1607
1604
|
engine: str,
|
1608
1605
|
engine_version: str,
|
1609
|
-
region_name:
|
1606
|
+
region_name: str | None = None,
|
1610
1607
|
) -> list[UpgradeTargetTypeDef]:
|
1611
1608
|
"""
|
1612
1609
|
Get a list version of the database engine that a DB instance can be upgraded to.
|
@@ -1640,7 +1637,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1640
1637
|
account_name: str,
|
1641
1638
|
bucket_name: str,
|
1642
1639
|
path: str,
|
1643
|
-
region_name:
|
1640
|
+
region_name: str | None = None,
|
1644
1641
|
) -> str:
|
1645
1642
|
s3 = self._account_s3_client(account_name, region_name=region_name)
|
1646
1643
|
return (
|
@@ -1648,7 +1645,7 @@ class AWSApi: # pylint: disable=too-many-public-methods
|
|
1648
1645
|
)
|
1649
1646
|
|
1650
1647
|
|
1651
|
-
def aws_config_file_path() ->
|
1648
|
+
def aws_config_file_path() -> str | None:
|
1652
1649
|
config_file_path = os.path.expanduser(
|
1653
1650
|
os.environ.get("AWS_CONFIG_FILE", "~/.aws/config")
|
1654
1651
|
)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
if TYPE_CHECKING:
|
4
|
+
from mypy_boto3_account import AccountClient
|
5
|
+
else:
|
6
|
+
AccountClient = object
|
7
|
+
|
8
|
+
|
9
|
+
class AWSApiAccount:
|
10
|
+
def __init__(self, client: AccountClient) -> None:
|
11
|
+
self.client = client
|
12
|
+
|
13
|
+
def set_security_contact(
|
14
|
+
self, name: str, title: str, email: str, phone_number: str
|
15
|
+
) -> None:
|
16
|
+
"""Set the security contact for the account."""
|
17
|
+
self.client.put_alternate_contact(
|
18
|
+
AlternateContactType="SECURITY",
|
19
|
+
EmailAddress=email,
|
20
|
+
Name=name,
|
21
|
+
Title=title,
|
22
|
+
PhoneNumber=phone_number,
|
23
|
+
)
|
@@ -9,6 +9,7 @@ from boto3 import Session
|
|
9
9
|
from botocore.client import BaseClient
|
10
10
|
from pydantic import BaseModel
|
11
11
|
|
12
|
+
import reconcile.utils.aws_api_typed.account
|
12
13
|
import reconcile.utils.aws_api_typed.dynamodb
|
13
14
|
import reconcile.utils.aws_api_typed.iam
|
14
15
|
import reconcile.utils.aws_api_typed.organization
|
@@ -16,6 +17,7 @@ import reconcile.utils.aws_api_typed.s3
|
|
16
17
|
import reconcile.utils.aws_api_typed.service_quotas
|
17
18
|
import reconcile.utils.aws_api_typed.sts
|
18
19
|
import reconcile.utils.aws_api_typed.support
|
20
|
+
from reconcile.utils.aws_api_typed.account import AWSApiAccount
|
19
21
|
from reconcile.utils.aws_api_typed.dynamodb import AWSApiDynamoDB
|
20
22
|
from reconcile.utils.aws_api_typed.iam import AWSApiIam
|
21
23
|
from reconcile.utils.aws_api_typed.organization import AWSApiOrganizations
|
@@ -26,13 +28,14 @@ from reconcile.utils.aws_api_typed.support import AWSApiSupport
|
|
26
28
|
|
27
29
|
SubApi = TypeVar(
|
28
30
|
"SubApi",
|
31
|
+
AWSApiAccount,
|
32
|
+
AWSApiDynamoDB,
|
29
33
|
AWSApiIam,
|
30
34
|
AWSApiOrganizations,
|
31
35
|
AWSApiS3,
|
32
36
|
AWSApiServiceQuotas,
|
33
37
|
AWSApiSts,
|
34
38
|
AWSApiSupport,
|
35
|
-
AWSApiDynamoDB,
|
36
39
|
)
|
37
40
|
|
38
41
|
|
@@ -168,6 +171,12 @@ class AWSApi:
|
|
168
171
|
def _init_sub_api(self, api_cls: type[SubApi]) -> SubApi:
|
169
172
|
"""Return a new or cached sub api client."""
|
170
173
|
match api_cls:
|
174
|
+
case reconcile.utils.aws_api_typed.account.AWSApiAccount:
|
175
|
+
client = self.session.client("account")
|
176
|
+
api = api_cls(client)
|
177
|
+
case reconcile.utils.aws_api_typed.dynamodb.AWSApiDynamoDB:
|
178
|
+
client = self.session.client("dynamodb")
|
179
|
+
api = api_cls(client)
|
171
180
|
case reconcile.utils.aws_api_typed.iam.AWSApiIam:
|
172
181
|
client = self.session.client("iam")
|
173
182
|
api = api_cls(client)
|
@@ -186,15 +195,22 @@ class AWSApi:
|
|
186
195
|
case reconcile.utils.aws_api_typed.support.AWSApiSupport:
|
187
196
|
client = self.session.client("support")
|
188
197
|
api = api_cls(client)
|
189
|
-
case reconcile.utils.aws_api_typed.dynamodb.AWSApiDynamoDB:
|
190
|
-
client = self.session.client("dynamodb")
|
191
|
-
api = api_cls(client)
|
192
198
|
case _:
|
193
199
|
raise ValueError(f"Unknown API class: {api_cls}")
|
194
200
|
|
195
201
|
self._session_clients.append(client)
|
196
202
|
return api
|
197
203
|
|
204
|
+
@cached_property
|
205
|
+
def account(self) -> AWSApiAccount:
|
206
|
+
"""Return an AWS Acount Api client"""
|
207
|
+
return self._init_sub_api(AWSApiAccount)
|
208
|
+
|
209
|
+
@cached_property
|
210
|
+
def dynamodb(self) -> AWSApiDynamoDB:
|
211
|
+
"""Return an AWS DynamoDB Api client"""
|
212
|
+
return self._init_sub_api(AWSApiDynamoDB)
|
213
|
+
|
198
214
|
@cached_property
|
199
215
|
def iam(self) -> AWSApiIam:
|
200
216
|
"""Return an AWS IAM Api client."""
|
@@ -225,11 +241,6 @@ class AWSApi:
|
|
225
241
|
"""Return an AWS Support Api client."""
|
226
242
|
return self._init_sub_api(AWSApiSupport)
|
227
243
|
|
228
|
-
@cached_property
|
229
|
-
def dynamodb(self) -> AWSApiDynamoDB:
|
230
|
-
"""Return an AWS DynamoDB Api client"""
|
231
|
-
return self._init_sub_api(AWSApiDynamoDB)
|
232
|
-
|
233
244
|
def assume_role(self, account_id: str, role: str) -> AWSApi:
|
234
245
|
"""Return a new AWSApi with the assumed role."""
|
235
246
|
credentials = self.sts.assume_role(account_id=account_id, role=role)
|
reconcile/utils/binary.py
CHANGED
@@ -36,9 +36,7 @@ def binary_version(binary, version_args, search_regex, expected_versions):
|
|
36
36
|
cmd = [binary]
|
37
37
|
cmd.extend(version_args)
|
38
38
|
try:
|
39
|
-
result = subprocess.run(
|
40
|
-
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True
|
41
|
-
)
|
39
|
+
result = subprocess.run(cmd, capture_output=True, check=True)
|
42
40
|
except subprocess.CalledProcessError as e:
|
43
41
|
msg = (
|
44
42
|
f"Could not execute binary '{binary}' "
|
@@ -1,12 +1,11 @@
|
|
1
1
|
from abc import ABC, abstractmethod
|
2
|
-
from typing import Optional
|
3
2
|
|
4
3
|
from pydantic import BaseModel
|
5
4
|
|
6
5
|
|
7
6
|
class ClusterHealth(BaseModel):
|
8
7
|
source: str
|
9
|
-
errors:
|
8
|
+
errors: set[str] | None = None
|
10
9
|
|
11
10
|
def has_health_errors(self) -> bool:
|
12
11
|
return bool(self.errors)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from functools import
|
1
|
+
from functools import cache
|
2
2
|
|
3
3
|
from reconcile.utils.clusterhealth.providerbase import (
|
4
4
|
ClusterHealth,
|
@@ -14,7 +14,7 @@ class TelemeterClusterHealthProvider(ClusterHealthProvider):
|
|
14
14
|
def __init__(self, querier: PrometheusQuerier):
|
15
15
|
self.querier = querier
|
16
16
|
|
17
|
-
@
|
17
|
+
@cache
|
18
18
|
def cluster_health_for_org(self, org_id: str) -> dict[str, ClusterHealth]:
|
19
19
|
vectors_by_cluster = group_by(
|
20
20
|
self.querier.instant_vector_query(telemeter_alert_query(org_id)),
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from typing import (
|
3
3
|
Any,
|
4
|
-
Optional,
|
5
4
|
Self,
|
6
5
|
)
|
7
6
|
|
@@ -27,7 +26,7 @@ class Snitch(BaseModel):
|
|
27
26
|
interval: str
|
28
27
|
alert_type: str
|
29
28
|
alert_email: list[str]
|
30
|
-
vault_data:
|
29
|
+
vault_data: str | None
|
31
30
|
|
32
31
|
def needs_vault_update(self) -> bool:
|
33
32
|
return self.vault_data is not None and self.check_in_url != self.vault_data
|
@@ -1,26 +1,24 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
2
|
from typing import (
|
3
3
|
Any,
|
4
|
-
Optional,
|
5
4
|
Protocol,
|
6
|
-
Union,
|
7
5
|
runtime_checkable,
|
8
6
|
)
|
9
7
|
|
10
8
|
|
11
9
|
class HasIntegrations(Protocol):
|
12
|
-
integrations:
|
10
|
+
integrations: list[str] | None
|
13
11
|
|
14
12
|
|
15
13
|
@runtime_checkable
|
16
14
|
class HasDisableIntegrations(Protocol):
|
17
15
|
@property
|
18
|
-
def disable(self) ->
|
16
|
+
def disable(self) -> HasIntegrations | None:
|
19
17
|
pass
|
20
18
|
|
21
19
|
|
22
20
|
def disabled_integrations(
|
23
|
-
disable_obj:
|
21
|
+
disable_obj: Mapping[str, Any] | HasDisableIntegrations | None,
|
24
22
|
) -> list[str]:
|
25
23
|
"""Returns all disabled integrations"""
|
26
24
|
if not disable_obj:
|
@@ -38,7 +36,7 @@ def disabled_integrations(
|
|
38
36
|
|
39
37
|
def integration_is_enabled(
|
40
38
|
integration: str,
|
41
|
-
disable_obj:
|
39
|
+
disable_obj: Mapping[str, Any] | HasDisableIntegrations | None,
|
42
40
|
) -> bool:
|
43
41
|
"""A convenient method to check whether an integration is enabled or not."""
|
44
42
|
return integration not in disabled_integrations(disable_obj)
|
reconcile/utils/environ.py
CHANGED
@@ -12,7 +12,7 @@ def environ(variables=None):
|
|
12
12
|
def f_environ(*args, **kwargs):
|
13
13
|
for e in variables:
|
14
14
|
if not os.environ.get(e):
|
15
|
-
raise KeyError("Could not find environment variable: {}"
|
15
|
+
raise KeyError(f"Could not find environment variable: {e}")
|
16
16
|
f(*args, **kwargs)
|
17
17
|
|
18
18
|
return f_environ
|
reconcile/utils/expiration.py
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
import datetime
|
2
2
|
from collections.abc import Iterable
|
3
3
|
from typing import (
|
4
|
-
Optional,
|
5
4
|
Protocol,
|
6
5
|
TypeVar,
|
7
|
-
Union,
|
8
6
|
cast,
|
9
7
|
)
|
10
8
|
|
@@ -12,12 +10,10 @@ DATE_FORMAT = "%Y-%m-%d"
|
|
12
10
|
|
13
11
|
|
14
12
|
class FilterableRole(Protocol):
|
15
|
-
expiration_date:
|
13
|
+
expiration_date: str | None
|
16
14
|
|
17
15
|
|
18
|
-
DictsOrRoles = TypeVar(
|
19
|
-
"DictsOrRoles", bound=Union[Iterable[FilterableRole], Iterable[dict]]
|
20
|
-
)
|
16
|
+
DictsOrRoles = TypeVar("DictsOrRoles", bound=Iterable[FilterableRole] | Iterable[dict])
|
21
17
|
|
22
18
|
|
23
19
|
def date_expired(date: str) -> bool:
|
@@ -26,7 +22,7 @@ def date_expired(date: str) -> bool:
|
|
26
22
|
return current_date >= exp_date
|
27
23
|
|
28
24
|
|
29
|
-
def filter(roles:
|
25
|
+
def filter(roles: DictsOrRoles | None) -> DictsOrRoles:
|
30
26
|
"""Filters roles and returns the ones which are not yet expired."""
|
31
27
|
filtered = []
|
32
28
|
for r in roles or []:
|
@@ -7,7 +7,6 @@ from collections.abc import (
|
|
7
7
|
from dataclasses import field
|
8
8
|
from typing import (
|
9
9
|
Any,
|
10
|
-
Optional,
|
11
10
|
cast,
|
12
11
|
)
|
13
12
|
|
@@ -52,7 +51,7 @@ class OutputFormatProcessor:
|
|
52
51
|
|
53
52
|
@dataclass
|
54
53
|
class GenericSecretOutputFormatConfig(OutputFormatProcessor):
|
55
|
-
data:
|
54
|
+
data: str | None = None
|
56
55
|
|
57
56
|
def render(self, vars: Mapping[str, str]) -> dict[str, str]:
|
58
57
|
if self.data:
|
@@ -68,7 +67,7 @@ class GenericSecretOutputFormatConfig(OutputFormatProcessor):
|
|
68
67
|
@dataclass
|
69
68
|
class OutputFormat:
|
70
69
|
provider: str
|
71
|
-
data:
|
70
|
+
data: str | None = None
|
72
71
|
|
73
72
|
@property
|
74
73
|
def _formatter(self) -> OutputFormatProcessor:
|
@@ -144,7 +143,7 @@ class ExternalResourceSpec:
|
|
144
143
|
"app": self.namespace["app"]["name"],
|
145
144
|
}
|
146
145
|
|
147
|
-
def get_secret_field(self, field: str) ->
|
146
|
+
def get_secret_field(self, field: str) -> str | None:
|
148
147
|
return self.secret.get(field)
|
149
148
|
|
150
149
|
def id_object(self) -> "ExternalResourceUniqueKey":
|
@@ -4,10 +4,7 @@ from collections.abc import (
|
|
4
4
|
Mapping,
|
5
5
|
MutableMapping,
|
6
6
|
)
|
7
|
-
from typing import
|
8
|
-
Any,
|
9
|
-
Optional,
|
10
|
-
)
|
7
|
+
from typing import Any
|
11
8
|
|
12
9
|
import anymarkup
|
13
10
|
|
@@ -27,7 +24,7 @@ PROVIDER_CLOUDFLARE = "cloudflare"
|
|
27
24
|
|
28
25
|
|
29
26
|
def get_external_resource_specs(
|
30
|
-
namespace_info: Mapping[str, Any], provision_provider:
|
27
|
+
namespace_info: Mapping[str, Any], provision_provider: str | None = None
|
31
28
|
) -> list[ExternalResourceSpec]:
|
32
29
|
specs: list[ExternalResourceSpec] = []
|
33
30
|
if not managed_external_resources(namespace_info):
|
@@ -121,7 +118,7 @@ class ResourceValueResolver:
|
|
121
118
|
def __init__(
|
122
119
|
self,
|
123
120
|
spec: ExternalResourceSpec,
|
124
|
-
integration_tag:
|
121
|
+
integration_tag: str | None = None,
|
125
122
|
identifier_as_value: bool = False,
|
126
123
|
):
|
127
124
|
"""
|
@@ -207,7 +204,7 @@ class ResourceValueResolver:
|
|
207
204
|
|
208
205
|
@staticmethod
|
209
206
|
def _override_values(
|
210
|
-
values: MutableMapping[str, Any], overrides:
|
207
|
+
values: MutableMapping[str, Any], overrides: str | None
|
211
208
|
) -> None:
|
212
209
|
if overrides is None:
|
213
210
|
return
|
reconcile/utils/filtering.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
from typing import (
|
2
|
-
Optional,
|
3
2
|
TypeVar,
|
4
3
|
)
|
5
4
|
|
@@ -8,7 +7,7 @@ ValueType = TypeVar("ValueType")
|
|
8
7
|
|
9
8
|
|
10
9
|
def remove_none_values_from_dict(
|
11
|
-
a_dict: dict[KeyType,
|
10
|
+
a_dict: dict[KeyType, ValueType | None],
|
12
11
|
) -> dict[KeyType, ValueType]:
|
13
12
|
"""
|
14
13
|
Creates a new dictionary based on the input dictionary but skips items
|
reconcile/utils/git.py
CHANGED
@@ -14,18 +14,14 @@ def clone(repo_url, wd, depth=None, verify=True):
|
|
14
14
|
if depth:
|
15
15
|
cmd += ["--depth", str(depth)]
|
16
16
|
cmd += [repo_url, wd]
|
17
|
-
result = subprocess.run(
|
18
|
-
cmd, cwd=wd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False
|
19
|
-
)
|
17
|
+
result = subprocess.run(cmd, cwd=wd, capture_output=True, check=False)
|
20
18
|
if result.returncode != 0:
|
21
19
|
raise GitError(f"git clone failed: {repo_url}")
|
22
20
|
|
23
21
|
|
24
22
|
def checkout(commit, wd):
|
25
23
|
cmd = ["git", "checkout", commit]
|
26
|
-
result = subprocess.run(
|
27
|
-
cmd, cwd=wd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False
|
28
|
-
)
|
24
|
+
result = subprocess.run(cmd, cwd=wd, capture_output=True, check=False)
|
29
25
|
if result.returncode != 0:
|
30
26
|
raise GitError(f"git checkout failed: {commit}")
|
31
27
|
|
@@ -34,9 +30,7 @@ def is_file_in_git_repo(file_path):
|
|
34
30
|
real_path = os.path.realpath(file_path)
|
35
31
|
dir_path = os.path.dirname(real_path)
|
36
32
|
cmd = ["git", "rev-parse", "--is-inside-work-tree"]
|
37
|
-
result = subprocess.run(
|
38
|
-
cmd, cwd=dir_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False
|
39
|
-
)
|
33
|
+
result = subprocess.run(cmd, cwd=dir_path, capture_output=True, check=False)
|
40
34
|
return result.returncode == 0
|
41
35
|
|
42
36
|
|