paasta-tools 1.30.9__py3-none-any.whl → 1.35.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of paasta-tools might be problematic. Click here for more details.
- paasta_tools/__init__.py +1 -1
- paasta_tools/api/api_docs/swagger.json +5 -0
- paasta_tools/cli/cmds/autoscale.py +2 -0
- paasta_tools/cli/cmds/check.py +2 -0
- paasta_tools/cli/cmds/cook_image.py +2 -0
- paasta_tools/cli/cmds/get_docker_image.py +2 -0
- paasta_tools/cli/cmds/get_image_version.py +2 -0
- paasta_tools/cli/cmds/get_latest_deployment.py +2 -0
- paasta_tools/cli/cmds/info.py +5 -1
- paasta_tools/cli/cmds/itest.py +2 -0
- paasta_tools/cli/cmds/list_namespaces.py +2 -0
- paasta_tools/cli/cmds/local_run.py +116 -24
- paasta_tools/cli/cmds/logs.py +2 -0
- paasta_tools/cli/cmds/mark_for_deployment.py +12 -2
- paasta_tools/cli/cmds/mesh_status.py +2 -1
- paasta_tools/cli/cmds/push_to_registry.py +2 -0
- paasta_tools/cli/cmds/remote_run.py +10 -0
- paasta_tools/cli/cmds/rollback.py +5 -1
- paasta_tools/cli/cmds/secret.py +4 -2
- paasta_tools/cli/cmds/security_check.py +2 -0
- paasta_tools/cli/cmds/spark_run.py +4 -0
- paasta_tools/cli/cmds/status.py +35 -8
- paasta_tools/cli/cmds/validate.py +296 -19
- paasta_tools/cli/cmds/wait_for_deployment.py +2 -0
- paasta_tools/cli/schemas/autoscaling_schema.json +3 -2
- paasta_tools/cli/schemas/eks_schema.json +23 -1
- paasta_tools/cli/schemas/smartstack_schema.json +12 -0
- paasta_tools/cli/utils.py +2 -1
- paasta_tools/contrib/paasta_update_soa_memcpu.py +10 -14
- paasta_tools/generate_deployments_for_service.py +2 -0
- paasta_tools/instance/hpa_metrics_parser.py +3 -5
- paasta_tools/instance/kubernetes.py +58 -25
- paasta_tools/kubernetes/application/controller_wrappers.py +23 -2
- paasta_tools/kubernetes/remote_run.py +2 -2
- paasta_tools/kubernetes_tools.py +37 -66
- paasta_tools/long_running_service_tools.py +8 -1
- paasta_tools/paastaapi/model/kubernetes_version.py +3 -0
- paasta_tools/setup_prometheus_adapter_config.py +82 -0
- paasta_tools/tron_tools.py +3 -0
- paasta_tools/utils.py +26 -9
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/generate_deployments_for_service.py +2 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/paasta_update_soa_memcpu.py +10 -14
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/setup_prometheus_adapter_config.py +82 -0
- {paasta_tools-1.30.9.dist-info → paasta_tools-1.35.8.dist-info}/METADATA +4 -4
- {paasta_tools-1.30.9.dist-info → paasta_tools-1.35.8.dist-info}/RECORD +98 -98
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/apply_external_resources.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/bounce_log_latency_parser.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_autoscaler_max_instances.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_cassandracluster_services_replication.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_flink_services_health.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_kubernetes_api.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_kubernetes_services_replication.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_manual_oapi_changes.sh +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_oom_events.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_orphans.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/check_spark_jobs.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/cleanup_kubernetes_cr.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/cleanup_kubernetes_crd.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/cleanup_kubernetes_jobs.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/create_dynamodb_table.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/create_paasta_playground.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/delete_kubernetes_deployments.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/emit_allocated_cpu_metrics.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/generate_all_deployments +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/generate_authenticating_services.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/generate_services_file.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/generate_services_yaml.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/get_running_task_allocation.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/habitat_fixer.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/ide_helper.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/is_pod_healthy_in_proxy.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/is_pod_healthy_in_smartstack.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/kill_bad_containers.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/kubernetes_remove_evicted_pods.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/mass-deploy-tag.sh +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/mock_patch_checker.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/paasta_cleanup_remote_run_resources.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/paasta_cleanup_stale_nodes.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/paasta_deploy_tron_jobs +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/paasta_execute_docker_command.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/paasta_secrets_sync.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/paasta_tabcomplete.sh +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/render_template.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/rightsizer_soaconfigs_update.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/service_shard_remove.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/service_shard_update.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/setup_istio_mesh.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/setup_kubernetes_cr.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/setup_kubernetes_crd.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/setup_kubernetes_internal_crd.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/setup_kubernetes_job.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/shared_ip_check.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/synapse_srv_namespaces_fact.py +0 -0
- {paasta_tools-1.30.9.data → paasta_tools-1.35.8.data}/scripts/timeouts_metrics_prom.py +0 -0
- {paasta_tools-1.30.9.dist-info → paasta_tools-1.35.8.dist-info}/WHEEL +0 -0
- {paasta_tools-1.30.9.dist-info → paasta_tools-1.35.8.dist-info}/entry_points.txt +0 -0
- {paasta_tools-1.30.9.dist-info → paasta_tools-1.35.8.dist-info}/licenses/LICENSE +0 -0
- {paasta_tools-1.30.9.dist-info → paasta_tools-1.35.8.dist-info}/top_level.txt +0 -0
paasta_tools/__init__.py
CHANGED
|
@@ -1788,6 +1788,11 @@
|
|
|
1788
1788
|
"KubernetesVersion": {
|
|
1789
1789
|
"type": "object",
|
|
1790
1790
|
"properties": {
|
|
1791
|
+
"container_port": {
|
|
1792
|
+
"description": "Port the container is expecting to receive traffic on",
|
|
1793
|
+
"type": "integer",
|
|
1794
|
+
"format": "int32"
|
|
1795
|
+
},
|
|
1791
1796
|
"type": {
|
|
1792
1797
|
"description": "Type of version (ReplicaSet or ControllerRevision)",
|
|
1793
1798
|
"type": "string"
|
|
@@ -48,6 +48,8 @@ def add_subparser(subparsers):
|
|
|
48
48
|
"-s",
|
|
49
49
|
"--service",
|
|
50
50
|
help="Service that you want to autoscale. Like 'example_service'.",
|
|
51
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
52
|
+
type=lambda x: x.rstrip("/"),
|
|
51
53
|
).completer = lazy_choices_completer(list_services)
|
|
52
54
|
autoscale_parser.add_argument(
|
|
53
55
|
"-i",
|
paasta_tools/cli/cmds/check.py
CHANGED
|
@@ -53,6 +53,8 @@ def add_subparser(subparsers):
|
|
|
53
53
|
"-s",
|
|
54
54
|
"--service",
|
|
55
55
|
help="The name of the service you wish to inspect. Defaults to autodetect.",
|
|
56
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
57
|
+
type=lambda x: x.rstrip("/"),
|
|
56
58
|
).completer = lazy_choices_completer(list_services)
|
|
57
59
|
check_parser.add_argument(
|
|
58
60
|
"-y",
|
|
@@ -48,6 +48,8 @@ def add_subparser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
48
48
|
'"services-", as included in a Jenkins job name, '
|
|
49
49
|
"will be stripped."
|
|
50
50
|
),
|
|
51
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
52
|
+
type=lambda x: x.rstrip("/"),
|
|
51
53
|
required=True,
|
|
52
54
|
)
|
|
53
55
|
list_parser.add_argument(
|
|
@@ -34,6 +34,8 @@ def add_subparser(subparsers):
|
|
|
34
34
|
"--service",
|
|
35
35
|
help="Name of the service which you want to get the docker image for.",
|
|
36
36
|
required=True,
|
|
37
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
38
|
+
type=lambda x: x.rstrip("/"),
|
|
37
39
|
).completer = lazy_choices_completer(list_services)
|
|
38
40
|
list_parser.add_argument(
|
|
39
41
|
"-i",
|
|
@@ -54,6 +54,8 @@ def add_subparser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
54
54
|
"--service",
|
|
55
55
|
help="Name of the service which you want to get the image version for.",
|
|
56
56
|
required=True,
|
|
57
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
58
|
+
type=lambda x: x.rstrip("/"),
|
|
57
59
|
)
|
|
58
60
|
arg_service.completer = lazy_choices_completer(list_services) # type: ignore
|
|
59
61
|
parser.add_argument(
|
|
@@ -33,6 +33,8 @@ def add_subparser(subparsers):
|
|
|
33
33
|
"--service",
|
|
34
34
|
help="Name of the service which you want to get the latest deployment for.",
|
|
35
35
|
required=True,
|
|
36
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
37
|
+
type=lambda x: x.rstrip("/"),
|
|
36
38
|
).completer = lazy_choices_completer(list_services)
|
|
37
39
|
list_parser.add_argument(
|
|
38
40
|
"-i",
|
paasta_tools/cli/cmds/info.py
CHANGED
|
@@ -51,7 +51,11 @@ def add_subparser(subparsers):
|
|
|
51
51
|
),
|
|
52
52
|
)
|
|
53
53
|
list_parser.add_argument(
|
|
54
|
-
"-s",
|
|
54
|
+
"-s",
|
|
55
|
+
"--service",
|
|
56
|
+
help="The name of the service you wish to inspect",
|
|
57
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
58
|
+
type=lambda x: x.rstrip("/"),
|
|
55
59
|
).completer = lazy_choices_completer(list_services)
|
|
56
60
|
list_parser.add_argument(
|
|
57
61
|
"-d",
|
paasta_tools/cli/cmds/itest.py
CHANGED
|
@@ -41,6 +41,8 @@ def add_subparser(subparsers):
|
|
|
41
41
|
help="Test and build docker image for this service. Leading "
|
|
42
42
|
'"services-", as included in a Jenkins job name, '
|
|
43
43
|
"will be stripped.",
|
|
44
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
45
|
+
type=lambda x: x.rstrip("/"),
|
|
44
46
|
required=True,
|
|
45
47
|
)
|
|
46
48
|
list_parser.add_argument(
|
|
@@ -31,6 +31,8 @@ def add_subparser(subparsers) -> None:
|
|
|
31
31
|
"--service",
|
|
32
32
|
help="Name of the service which you want to list the namespaces for.",
|
|
33
33
|
required=True,
|
|
34
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
35
|
+
type=lambda x: x.rstrip("/"),
|
|
34
36
|
).completer = lazy_choices_completer(list_services)
|
|
35
37
|
# Most services likely don't need to filter by cluster/instance, and can add namespaces from all instances
|
|
36
38
|
list_parser.add_argument(
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
|
+
import base64
|
|
15
16
|
import datetime
|
|
16
17
|
import json
|
|
17
18
|
import os
|
|
@@ -31,7 +32,9 @@ from urllib.parse import urlparse
|
|
|
31
32
|
import boto3
|
|
32
33
|
import requests
|
|
33
34
|
from docker import errors
|
|
35
|
+
from docker.api.client import APIClient
|
|
34
36
|
from mypy_extensions import TypedDict
|
|
37
|
+
from service_configuration_lib import read_service_configuration
|
|
35
38
|
|
|
36
39
|
from paasta_tools.adhoc_tools import get_default_interactive_config
|
|
37
40
|
from paasta_tools.cli.authentication import get_service_auth_token
|
|
@@ -325,7 +328,11 @@ def add_subparser(subparsers):
|
|
|
325
328
|
),
|
|
326
329
|
)
|
|
327
330
|
list_parser.add_argument(
|
|
328
|
-
"-s",
|
|
331
|
+
"-s",
|
|
332
|
+
"--service",
|
|
333
|
+
help="The name of the service you wish to inspect",
|
|
334
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
335
|
+
type=lambda x: x.rstrip("/"),
|
|
329
336
|
).completer = lazy_choices_completer(list_services)
|
|
330
337
|
list_parser.add_argument(
|
|
331
338
|
"-c",
|
|
@@ -612,26 +619,83 @@ class LostContainerException(Exception):
|
|
|
612
619
|
pass
|
|
613
620
|
|
|
614
621
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
622
|
+
class DockerAuthConfig(TypedDict):
|
|
623
|
+
username: str
|
|
624
|
+
password: str
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
def get_readonly_docker_registry_auth_config(
|
|
628
|
+
docker_url: str,
|
|
629
|
+
) -> DockerAuthConfig | None:
|
|
630
|
+
system_paasta_config = load_system_paasta_config()
|
|
631
|
+
config_path = system_paasta_config.get_readonly_docker_registry_auth_file()
|
|
632
|
+
|
|
633
|
+
try:
|
|
634
|
+
with open(config_path) as f:
|
|
635
|
+
docker_config = json.load(f)
|
|
636
|
+
except Exception:
|
|
637
|
+
print(
|
|
638
|
+
PaastaColors.yellow(
|
|
639
|
+
"Warning: unable to load read-only docker registry credentials."
|
|
640
|
+
),
|
|
641
|
+
file=sys.stderr,
|
|
642
|
+
)
|
|
643
|
+
# the best we can do is try to pull with whatever auth the user has configured locally
|
|
644
|
+
# i.e., root-owned docker config in /root/.docker/config.json
|
|
645
|
+
return None
|
|
646
|
+
registry = docker_url.split("/")[0]
|
|
647
|
+
|
|
648
|
+
# find matching auth config - our usual ro config will have at least two entries
|
|
649
|
+
# at the time this comment was written
|
|
650
|
+
auths = docker_config
|
|
651
|
+
for auth_url, auth_data in auths.items():
|
|
652
|
+
if registry in auth_url:
|
|
653
|
+
# Decode the base64 auth string if present
|
|
654
|
+
if "auth" in auth_data:
|
|
655
|
+
auth_string = base64.b64decode(auth_data["auth"]).decode("utf-8")
|
|
656
|
+
username, password = auth_string.split(":", 1)
|
|
657
|
+
return {"username": username, "password": password}
|
|
658
|
+
|
|
659
|
+
# we'll hit this for registries like docker-dev or extra-private internal registries
|
|
660
|
+
return None
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
def docker_pull_image(docker_client: APIClient, docker_url: str) -> None:
|
|
664
|
+
"""Pull an image using the docker-py library with read-only registry credentials"""
|
|
620
665
|
print(
|
|
621
|
-
"Please wait while the image (
|
|
622
|
-
% docker_url,
|
|
666
|
+
f"Please wait while the image ({docker_url}) is pulled (times out after 30m)...",
|
|
623
667
|
file=sys.stderr,
|
|
624
668
|
)
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
669
|
+
|
|
670
|
+
auth_config = get_readonly_docker_registry_auth_config(docker_url)
|
|
671
|
+
if not auth_config:
|
|
672
|
+
print(
|
|
673
|
+
PaastaColors.yellow(
|
|
674
|
+
"Warning: No read-only docker registry credentials found, attempting to pull without them."
|
|
675
|
+
),
|
|
676
|
+
file=sys.stderr,
|
|
677
|
+
)
|
|
678
|
+
|
|
679
|
+
try:
|
|
680
|
+
with Timeout(
|
|
681
|
+
seconds=1800,
|
|
682
|
+
error_message=f"Timed out pulling docker image from {docker_url}",
|
|
683
|
+
):
|
|
684
|
+
# this is slightly funky since pull() returns the output line-by-line, but as a dict
|
|
685
|
+
# ...that we then need to format back to the usual `docker pull` output
|
|
686
|
+
# :p
|
|
687
|
+
for line in docker_client.pull(
|
|
688
|
+
docker_url, auth_config=auth_config, stream=True, decode=True
|
|
689
|
+
):
|
|
690
|
+
# not all lines have an 'id' key :(
|
|
691
|
+
id_prefix = f"{line['id']}: " if "id" in line else ""
|
|
692
|
+
print(f"{id_prefix}{line['status']}", file=sys.stderr)
|
|
693
|
+
except Exception as e:
|
|
694
|
+
print(
|
|
695
|
+
f"\nPull failed. Error: {e}",
|
|
696
|
+
file=sys.stderr,
|
|
697
|
+
)
|
|
698
|
+
sys.exit(1)
|
|
635
699
|
|
|
636
700
|
|
|
637
701
|
def get_container_id(docker_client, container_name):
|
|
@@ -1226,7 +1290,7 @@ def configure_and_run_docker_container(
|
|
|
1226
1290
|
return 1
|
|
1227
1291
|
|
|
1228
1292
|
if pull_image:
|
|
1229
|
-
docker_pull_image(docker_url)
|
|
1293
|
+
docker_pull_image(docker_client, docker_url)
|
|
1230
1294
|
|
|
1231
1295
|
for volume in instance_config.get_volumes(
|
|
1232
1296
|
system_paasta_config.get_volumes(),
|
|
@@ -1302,10 +1366,40 @@ def docker_config_available():
|
|
|
1302
1366
|
)
|
|
1303
1367
|
|
|
1304
1368
|
|
|
1369
|
+
def should_reexec_as_root(
|
|
1370
|
+
service: str, skip_secrets: bool, action: str, soa_dir: str = DEFAULT_SOA_DIR
|
|
1371
|
+
) -> bool:
|
|
1372
|
+
# local-run can't pull secrets from Vault in prod without a root-owned token
|
|
1373
|
+
need_vault_token = not skip_secrets and action == "pull"
|
|
1374
|
+
|
|
1375
|
+
# there are some special teams with their own private docker registries and no ro creds
|
|
1376
|
+
# however, we don't know what registry is to be used without loading the service config
|
|
1377
|
+
service_info = read_service_configuration(service, soa_dir)
|
|
1378
|
+
# technically folks can set the standard registry as a value here, but atm no one is doing that :p
|
|
1379
|
+
registry_override = service_info.get("docker_registry")
|
|
1380
|
+
# note: we could also have a list of registries that have ro creds, but this seems fine for now
|
|
1381
|
+
uses_private_registry = (
|
|
1382
|
+
registry_override
|
|
1383
|
+
and registry_override
|
|
1384
|
+
in load_system_paasta_config().get_private_docker_registries()
|
|
1385
|
+
)
|
|
1386
|
+
need_docker_config = uses_private_registry and action == "pull"
|
|
1387
|
+
|
|
1388
|
+
return (need_vault_token or need_docker_config) and os.geteuid() != 0
|
|
1389
|
+
|
|
1390
|
+
|
|
1305
1391
|
def paasta_local_run(args):
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1392
|
+
service = figure_out_service_name(args, soa_dir=args.yelpsoa_config_root)
|
|
1393
|
+
if should_reexec_as_root(
|
|
1394
|
+
service, args.skip_secrets, args.action, args.yelpsoa_config_root
|
|
1395
|
+
):
|
|
1396
|
+
# XXX: we should re-architect this to not need sudo, but for now,
|
|
1397
|
+
# re-exec ourselves with sudo to get access to the paasta vault token
|
|
1398
|
+
# NOTE: once we do that, we can also remove the venv check above :)
|
|
1399
|
+
print(
|
|
1400
|
+
"Re-executing paasta local-run --pull with sudo for Vault/Docker registry access..."
|
|
1401
|
+
)
|
|
1402
|
+
os.execvp("sudo", ["sudo", "-H", "/usr/bin/paasta"] + sys.argv[1:])
|
|
1309
1403
|
if args.action == "build" and not makefile_responds_to("cook-image"):
|
|
1310
1404
|
print(
|
|
1311
1405
|
"A local Makefile with a 'cook-image' target is required for --build",
|
|
@@ -1332,8 +1426,6 @@ def paasta_local_run(args):
|
|
|
1332
1426
|
|
|
1333
1427
|
local_run_config = system_paasta_config.get_local_run_config()
|
|
1334
1428
|
|
|
1335
|
-
service = figure_out_service_name(args, soa_dir=args.yelpsoa_config_root)
|
|
1336
|
-
|
|
1337
1429
|
if args.cluster:
|
|
1338
1430
|
cluster = args.cluster
|
|
1339
1431
|
else:
|
paasta_tools/cli/cmds/logs.py
CHANGED
|
@@ -117,6 +117,8 @@ def add_subparser(subparsers) -> None:
|
|
|
117
117
|
"-s",
|
|
118
118
|
"--service",
|
|
119
119
|
help="The name of the service you wish to inspect. Defaults to autodetect.",
|
|
120
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
121
|
+
type=lambda x: x.rstrip("/"),
|
|
120
122
|
).completer = lazy_choices_completer(list_services)
|
|
121
123
|
status_parser.add_argument(
|
|
122
124
|
"-c",
|
|
@@ -157,6 +157,8 @@ def add_subparser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
157
157
|
help="Name of the service which you wish to mark for deployment. Leading "
|
|
158
158
|
'"services-" will be stripped.',
|
|
159
159
|
required=True,
|
|
160
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
161
|
+
type=lambda x: x.rstrip("/"),
|
|
160
162
|
)
|
|
161
163
|
arg_service.completer = lazy_choices_completer(list_services) # type: ignore
|
|
162
164
|
list_parser.add_argument(
|
|
@@ -1264,7 +1266,15 @@ class MarkForDeploymentProcess(RollbackSlackDeploymentProcess):
|
|
|
1264
1266
|
self.ping_authors()
|
|
1265
1267
|
|
|
1266
1268
|
def send_manual_rollback_instructions(self) -> None:
|
|
1267
|
-
|
|
1269
|
+
# NOTE: new deploy groups are not exactly a particularly frequent occurrence, but
|
|
1270
|
+
# we want to prevent sending messages that look like
|
|
1271
|
+
# `If you need to roll back manually, run: paasta rollback --service $S --deploy-group $G --commit None`
|
|
1272
|
+
# since that's not actually valid/actionable.
|
|
1273
|
+
# thus the seemingly out-of-nowhere old_git_sha check: new deploy groups won't have value set there.
|
|
1274
|
+
if (
|
|
1275
|
+
self.deployment_version != self.old_deployment_version
|
|
1276
|
+
and self.old_git_sha is not None
|
|
1277
|
+
):
|
|
1268
1278
|
extra_rollback_args = ""
|
|
1269
1279
|
if self.old_deployment_version.image_version:
|
|
1270
1280
|
extra_rollback_args = (
|
|
@@ -1843,7 +1853,7 @@ async def wait_for_deployment(
|
|
|
1843
1853
|
system_paasta_config.get_mark_for_deployment_default_time_before_first_diagnosis()
|
|
1844
1854
|
)
|
|
1845
1855
|
|
|
1846
|
-
with progressbar.ProgressBar(
|
|
1856
|
+
with progressbar.ProgressBar(max_value=total_instances) as bar:
|
|
1847
1857
|
instance_done_futures = []
|
|
1848
1858
|
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
1849
1859
|
for cluster, instance_configs in instance_configs_per_cluster.items():
|
|
@@ -44,9 +44,10 @@ def add_subparser(subparsers) -> None:
|
|
|
44
44
|
mesh_status_parser.add_argument(
|
|
45
45
|
"-s",
|
|
46
46
|
"--service",
|
|
47
|
-
type=str,
|
|
48
47
|
help="The name of the service you wish to inspect",
|
|
49
48
|
required=True,
|
|
49
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
50
|
+
type=lambda x: x.rstrip("/"),
|
|
50
51
|
).completer = lazy_choices_completer(list_services)
|
|
51
52
|
mesh_status_parser.add_argument(
|
|
52
53
|
"-i",
|
|
@@ -62,6 +62,8 @@ def add_subparser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
62
62
|
help='Name of service for which you wish to upload a docker image. Leading "services-", '
|
|
63
63
|
"as included in a Jenkins job name, will be stripped.",
|
|
64
64
|
required=True,
|
|
65
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
66
|
+
type=lambda x: x.rstrip("/"),
|
|
65
67
|
)
|
|
66
68
|
list_parser.add_argument(
|
|
67
69
|
"-c",
|
|
@@ -295,11 +295,20 @@ def paasta_remote_run_stop(
|
|
|
295
295
|
|
|
296
296
|
|
|
297
297
|
def add_common_args_to_parser(parser: argparse.ArgumentParser):
|
|
298
|
+
def _validate_service_name(name: str) -> str:
|
|
299
|
+
# remove trailing slash if present for folks tab-completing directories
|
|
300
|
+
if name.rstrip("/") not in _list_services_and_toolboxes():
|
|
301
|
+
raise ValueError(f"{name} is not a known service name")
|
|
302
|
+
return name
|
|
303
|
+
|
|
298
304
|
service_arg = parser.add_argument(
|
|
299
305
|
"-s",
|
|
300
306
|
"--service",
|
|
301
307
|
help="The name of the service you wish to inspect. Required.",
|
|
302
308
|
required=True,
|
|
309
|
+
# not using `choices` for validation to avoid the help text
|
|
310
|
+
# for the command being incredibly large
|
|
311
|
+
type=_validate_service_name,
|
|
303
312
|
)
|
|
304
313
|
service_arg.completer = lazy_choices_completer(_list_services_and_toolboxes) # type: ignore
|
|
305
314
|
instance_or_toolbox = parser.add_mutually_exclusive_group()
|
|
@@ -323,6 +332,7 @@ def add_common_args_to_parser(parser: argparse.ArgumentParser):
|
|
|
323
332
|
"--cluster",
|
|
324
333
|
help="The name of the cluster you wish to run your task on. Required.",
|
|
325
334
|
required=True,
|
|
335
|
+
choices=list_clusters(),
|
|
326
336
|
)
|
|
327
337
|
cluster_arg.completer = lazy_choices_completer(list_clusters) # type: ignore
|
|
328
338
|
|
|
@@ -107,7 +107,11 @@ def add_subparser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
107
107
|
)
|
|
108
108
|
|
|
109
109
|
arg_service = list_parser.add_argument(
|
|
110
|
-
"-s",
|
|
110
|
+
"-s",
|
|
111
|
+
"--service",
|
|
112
|
+
help='Name of the service to rollback (e.g. "service1")',
|
|
113
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
114
|
+
type=lambda x: x.rstrip("/"),
|
|
111
115
|
)
|
|
112
116
|
arg_service.completer = lazy_choices_completer(list_services) # type: ignore
|
|
113
117
|
list_parser.add_argument(
|
paasta_tools/cli/cmds/secret.py
CHANGED
|
@@ -212,7 +212,7 @@ def _add_vault_auth_args(parser: argparse.ArgumentParser):
|
|
|
212
212
|
dest="vault_auth_method",
|
|
213
213
|
required=False,
|
|
214
214
|
default="token",
|
|
215
|
-
choices=["token", "
|
|
215
|
+
choices=["token", "okta"],
|
|
216
216
|
)
|
|
217
217
|
parser.add_argument(
|
|
218
218
|
"--vault-token-file",
|
|
@@ -246,6 +246,8 @@ def _add_common_args(parser: argparse.ArgumentParser, allow_shared: bool = True)
|
|
|
246
246
|
"--service",
|
|
247
247
|
required=not allow_shared,
|
|
248
248
|
help="The name of the service on which you wish to act",
|
|
249
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
250
|
+
type=lambda x: x.rstrip("/"),
|
|
249
251
|
).completer = lazy_choices_completer(list_services)
|
|
250
252
|
|
|
251
253
|
if allow_shared:
|
|
@@ -456,7 +458,7 @@ def paasta_secret(args):
|
|
|
456
458
|
"vault_token_file": args.vault_token_file,
|
|
457
459
|
# best solution so far is to change the below string to "token",
|
|
458
460
|
# so that token file is picked up from argparse
|
|
459
|
-
"vault_auth_method": "
|
|
461
|
+
"vault_auth_method": "okta", # must use Okta to get 2FA push
|
|
460
462
|
},
|
|
461
463
|
)
|
|
462
464
|
secret_provider.write_secret(
|
|
@@ -28,6 +28,8 @@ def add_subparser(subparsers):
|
|
|
28
28
|
help='Name of service for which you wish to check. Leading "services-", as included in a '
|
|
29
29
|
"Jenkins job name, will be stripped.",
|
|
30
30
|
required=True,
|
|
31
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
32
|
+
type=lambda x: x.rstrip("/"),
|
|
31
33
|
)
|
|
32
34
|
list_parser.add_argument(
|
|
33
35
|
"-c", "--commit", help="Git sha of the image to check", required=True
|
|
@@ -238,6 +238,8 @@ def add_subparser(subparsers):
|
|
|
238
238
|
"--service",
|
|
239
239
|
help="The name of the service from which the Spark image is built.",
|
|
240
240
|
default=DEFAULT_SPARK_SERVICE,
|
|
241
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
242
|
+
type=lambda x: x.rstrip("/"),
|
|
241
243
|
).completer = lazy_choices_completer(list_services)
|
|
242
244
|
|
|
243
245
|
list_parser.add_argument(
|
|
@@ -897,6 +899,8 @@ def configure_and_run_docker_container(
|
|
|
897
899
|
)
|
|
898
900
|
) # type:ignore
|
|
899
901
|
environment.update(extra_driver_envs)
|
|
902
|
+
if "jupyter-lab" == args.cmd:
|
|
903
|
+
environment["SPARK_DRIVER_TYPE"] = "jupyter"
|
|
900
904
|
|
|
901
905
|
if args.use_service_auth_token:
|
|
902
906
|
environment["YELP_SVC_AUTHZ_TOKEN"] = get_service_auth_token()
|
paasta_tools/cli/cmds/status.py
CHANGED
|
@@ -203,7 +203,11 @@ def add_subparser(
|
|
|
203
203
|
|
|
204
204
|
def add_instance_filter_arguments(status_parser, verb: str = "inspect") -> None:
|
|
205
205
|
status_parser.add_argument(
|
|
206
|
-
"-s",
|
|
206
|
+
"-s",
|
|
207
|
+
"--service",
|
|
208
|
+
help=f"The name of the service you wish to {verb}",
|
|
209
|
+
# strip any potential trailing / for folks tab-completing directories
|
|
210
|
+
type=lambda x: x.rstrip("/"),
|
|
207
211
|
).completer = lazy_choices_completer(list_services)
|
|
208
212
|
status_parser.add_argument(
|
|
209
213
|
"-c",
|
|
@@ -891,7 +895,7 @@ def _print_flink_status_from_job_manager(
|
|
|
891
895
|
|
|
892
896
|
# Print Flink Costs Link
|
|
893
897
|
output.append(
|
|
894
|
-
f" Flink Cost: https://
|
|
898
|
+
f" Flink Cost: https://app.cloudzero.com/explorer?activeCostType=invoiced_amortized_cost&partitions=costcontext%3AResource%20Summary&dateRange=Last%2030%20Days&costcontext%3AKube%20Paasta%20Cluster={cluster}&costcontext%3APaasta%20Instance={instance}&costcontext%3APaasta%20Service={service}&showRightFlyout=filters"
|
|
895
899
|
)
|
|
896
900
|
|
|
897
901
|
output.append(f"{OUTPUT_HORIZONTAL_RULE}")
|
|
@@ -917,11 +921,13 @@ def _print_flink_status_from_job_manager(
|
|
|
917
921
|
else f"{pod_evicted_count}"
|
|
918
922
|
)
|
|
919
923
|
|
|
924
|
+
pods_total_count = pod_running_count + pod_evicted_count + pod_other_count
|
|
920
925
|
output.append(
|
|
921
926
|
" Pods:"
|
|
922
927
|
f" {pod_running_count} running,"
|
|
923
928
|
f" {evicted} evicted,"
|
|
924
|
-
f" {pod_other_count} other"
|
|
929
|
+
f" {pod_other_count} other,"
|
|
930
|
+
f" {pods_total_count} total"
|
|
925
931
|
)
|
|
926
932
|
|
|
927
933
|
if not should_job_info_be_shown(status["state"]):
|
|
@@ -944,12 +950,19 @@ def _print_flink_status_from_job_manager(
|
|
|
944
950
|
output.append(str(e))
|
|
945
951
|
return 1
|
|
946
952
|
|
|
953
|
+
jobs_total_count = (
|
|
954
|
+
overview.jobs_running
|
|
955
|
+
+ overview.jobs_finished
|
|
956
|
+
+ overview.jobs_failed
|
|
957
|
+
+ overview.jobs_cancelled
|
|
958
|
+
)
|
|
947
959
|
output.append(
|
|
948
960
|
" Jobs:"
|
|
949
961
|
f" {overview.jobs_running} running,"
|
|
950
962
|
f" {overview.jobs_finished} finished,"
|
|
951
963
|
f" {overview.jobs_failed} failed,"
|
|
952
|
-
f" {overview.jobs_cancelled} cancelled"
|
|
964
|
+
f" {overview.jobs_cancelled} cancelled,"
|
|
965
|
+
f" {jobs_total_count} total"
|
|
953
966
|
)
|
|
954
967
|
output.append(
|
|
955
968
|
" "
|
|
@@ -1313,7 +1326,9 @@ def get_version_table_entry(
|
|
|
1313
1326
|
for state in ReplicaState
|
|
1314
1327
|
if state in replica_state_counts
|
|
1315
1328
|
]
|
|
1316
|
-
entry.append(
|
|
1329
|
+
entry.append(
|
|
1330
|
+
f" Replica States: {' / '.join(replica_state_display)} / {replica_state_counts.total()} total"
|
|
1331
|
+
)
|
|
1317
1332
|
if not verbose:
|
|
1318
1333
|
unhealthy_replicas = [
|
|
1319
1334
|
(state, pod) for state, pod in replica_states if state.is_unhealthy()
|
|
@@ -1321,13 +1336,23 @@ def get_version_table_entry(
|
|
|
1321
1336
|
if unhealthy_replicas:
|
|
1322
1337
|
entry.append(" Unhealthy Replicas:")
|
|
1323
1338
|
replica_table = create_replica_table(
|
|
1324
|
-
unhealthy_replicas,
|
|
1339
|
+
unhealthy_replicas,
|
|
1340
|
+
service,
|
|
1341
|
+
instance,
|
|
1342
|
+
cluster,
|
|
1343
|
+
version.container_port,
|
|
1344
|
+
verbose,
|
|
1325
1345
|
)
|
|
1326
1346
|
for line in replica_table:
|
|
1327
1347
|
entry.append(f" {line}")
|
|
1328
1348
|
else:
|
|
1329
1349
|
replica_table = create_replica_table(
|
|
1330
|
-
replica_states,
|
|
1350
|
+
replica_states,
|
|
1351
|
+
service,
|
|
1352
|
+
instance,
|
|
1353
|
+
cluster,
|
|
1354
|
+
version.container_port,
|
|
1355
|
+
verbose,
|
|
1331
1356
|
)
|
|
1332
1357
|
for line in replica_table:
|
|
1333
1358
|
entry.append(f" {line}")
|
|
@@ -1467,6 +1492,7 @@ def create_replica_table(
|
|
|
1467
1492
|
service: str,
|
|
1468
1493
|
instance: str,
|
|
1469
1494
|
cluster: str,
|
|
1495
|
+
container_port: int,
|
|
1470
1496
|
verbose: int = 0,
|
|
1471
1497
|
) -> List[str]:
|
|
1472
1498
|
header = ["ID", "IP/Port", "Host deployed to", "Started at what localtime", "State"]
|
|
@@ -1474,9 +1500,10 @@ def create_replica_table(
|
|
|
1474
1500
|
for state, pod in pods:
|
|
1475
1501
|
start_datetime = datetime.fromtimestamp(pod.create_timestamp)
|
|
1476
1502
|
humanized_start_time = humanize.naturaltime(start_datetime)
|
|
1503
|
+
|
|
1477
1504
|
row = [
|
|
1478
1505
|
pod.name,
|
|
1479
|
-
f"{pod.ip}:
|
|
1506
|
+
f"{pod.ip}:{container_port}" if pod.ip else "None",
|
|
1480
1507
|
pod.host or "None",
|
|
1481
1508
|
humanized_start_time,
|
|
1482
1509
|
state.formatted_message,
|