paasta-tools 1.21.3__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.
- k8s_itests/__init__.py +0 -0
- k8s_itests/test_autoscaling.py +23 -0
- k8s_itests/utils.py +38 -0
- paasta_tools/__init__.py +20 -0
- paasta_tools/adhoc_tools.py +142 -0
- paasta_tools/api/__init__.py +13 -0
- paasta_tools/api/api.py +330 -0
- paasta_tools/api/api_docs/swagger.json +2323 -0
- paasta_tools/api/client.py +106 -0
- paasta_tools/api/settings.py +33 -0
- paasta_tools/api/tweens/__init__.py +6 -0
- paasta_tools/api/tweens/auth.py +125 -0
- paasta_tools/api/tweens/profiling.py +108 -0
- paasta_tools/api/tweens/request_logger.py +124 -0
- paasta_tools/api/views/__init__.py +13 -0
- paasta_tools/api/views/autoscaler.py +100 -0
- paasta_tools/api/views/exception.py +45 -0
- paasta_tools/api/views/flink.py +73 -0
- paasta_tools/api/views/instance.py +395 -0
- paasta_tools/api/views/pause_autoscaler.py +71 -0
- paasta_tools/api/views/remote_run.py +113 -0
- paasta_tools/api/views/resources.py +76 -0
- paasta_tools/api/views/service.py +35 -0
- paasta_tools/api/views/version.py +25 -0
- paasta_tools/apply_external_resources.py +79 -0
- paasta_tools/async_utils.py +109 -0
- paasta_tools/autoscaling/__init__.py +0 -0
- paasta_tools/autoscaling/autoscaling_service_lib.py +57 -0
- paasta_tools/autoscaling/forecasting.py +106 -0
- paasta_tools/autoscaling/max_all_k8s_services.py +41 -0
- paasta_tools/autoscaling/pause_service_autoscaler.py +77 -0
- paasta_tools/autoscaling/utils.py +52 -0
- paasta_tools/bounce_lib.py +184 -0
- paasta_tools/broadcast_log_to_services.py +62 -0
- paasta_tools/cassandracluster_tools.py +210 -0
- paasta_tools/check_autoscaler_max_instances.py +212 -0
- paasta_tools/check_cassandracluster_services_replication.py +35 -0
- paasta_tools/check_flink_services_health.py +203 -0
- paasta_tools/check_kubernetes_api.py +57 -0
- paasta_tools/check_kubernetes_services_replication.py +141 -0
- paasta_tools/check_oom_events.py +244 -0
- paasta_tools/check_services_replication_tools.py +324 -0
- paasta_tools/check_spark_jobs.py +234 -0
- paasta_tools/cleanup_kubernetes_cr.py +138 -0
- paasta_tools/cleanup_kubernetes_crd.py +145 -0
- paasta_tools/cleanup_kubernetes_jobs.py +344 -0
- paasta_tools/cleanup_tron_namespaces.py +96 -0
- paasta_tools/cli/__init__.py +13 -0
- paasta_tools/cli/authentication.py +85 -0
- paasta_tools/cli/cli.py +260 -0
- paasta_tools/cli/cmds/__init__.py +13 -0
- paasta_tools/cli/cmds/autoscale.py +143 -0
- paasta_tools/cli/cmds/check.py +334 -0
- paasta_tools/cli/cmds/cook_image.py +147 -0
- paasta_tools/cli/cmds/get_docker_image.py +76 -0
- paasta_tools/cli/cmds/get_image_version.py +172 -0
- paasta_tools/cli/cmds/get_latest_deployment.py +93 -0
- paasta_tools/cli/cmds/info.py +155 -0
- paasta_tools/cli/cmds/itest.py +117 -0
- paasta_tools/cli/cmds/list.py +66 -0
- paasta_tools/cli/cmds/list_clusters.py +42 -0
- paasta_tools/cli/cmds/list_deploy_queue.py +171 -0
- paasta_tools/cli/cmds/list_namespaces.py +84 -0
- paasta_tools/cli/cmds/local_run.py +1396 -0
- paasta_tools/cli/cmds/logs.py +1601 -0
- paasta_tools/cli/cmds/mark_for_deployment.py +1988 -0
- paasta_tools/cli/cmds/mesh_status.py +174 -0
- paasta_tools/cli/cmds/pause_service_autoscaler.py +107 -0
- paasta_tools/cli/cmds/push_to_registry.py +275 -0
- paasta_tools/cli/cmds/remote_run.py +252 -0
- paasta_tools/cli/cmds/rollback.py +347 -0
- paasta_tools/cli/cmds/secret.py +549 -0
- paasta_tools/cli/cmds/security_check.py +59 -0
- paasta_tools/cli/cmds/spark_run.py +1400 -0
- paasta_tools/cli/cmds/start_stop_restart.py +401 -0
- paasta_tools/cli/cmds/status.py +2302 -0
- paasta_tools/cli/cmds/validate.py +1012 -0
- paasta_tools/cli/cmds/wait_for_deployment.py +275 -0
- paasta_tools/cli/fsm/__init__.py +13 -0
- paasta_tools/cli/fsm/autosuggest.py +82 -0
- paasta_tools/cli/fsm/template/README.md +8 -0
- paasta_tools/cli/fsm/template/cookiecutter.json +7 -0
- paasta_tools/cli/fsm/template/{{cookiecutter.service}}/kubernetes-PROD.yaml +91 -0
- paasta_tools/cli/fsm/template/{{cookiecutter.service}}/monitoring.yaml +20 -0
- paasta_tools/cli/fsm/template/{{cookiecutter.service}}/service.yaml +8 -0
- paasta_tools/cli/fsm/template/{{cookiecutter.service}}/smartstack.yaml +6 -0
- paasta_tools/cli/fsm_cmd.py +121 -0
- paasta_tools/cli/paasta_tabcomplete.sh +23 -0
- paasta_tools/cli/schemas/adhoc_schema.json +199 -0
- paasta_tools/cli/schemas/autoscaling_schema.json +91 -0
- paasta_tools/cli/schemas/autotuned_defaults/cassandracluster_schema.json +37 -0
- paasta_tools/cli/schemas/autotuned_defaults/kubernetes_schema.json +89 -0
- paasta_tools/cli/schemas/deploy_schema.json +173 -0
- paasta_tools/cli/schemas/eks_schema.json +970 -0
- paasta_tools/cli/schemas/kubernetes_schema.json +970 -0
- paasta_tools/cli/schemas/rollback_schema.json +160 -0
- paasta_tools/cli/schemas/service_schema.json +25 -0
- paasta_tools/cli/schemas/smartstack_schema.json +322 -0
- paasta_tools/cli/schemas/tron_schema.json +699 -0
- paasta_tools/cli/utils.py +1118 -0
- paasta_tools/clusterman.py +21 -0
- paasta_tools/config_utils.py +385 -0
- paasta_tools/contrib/__init__.py +0 -0
- paasta_tools/contrib/bounce_log_latency_parser.py +68 -0
- paasta_tools/contrib/check_manual_oapi_changes.sh +24 -0
- paasta_tools/contrib/check_orphans.py +306 -0
- paasta_tools/contrib/create_dynamodb_table.py +35 -0
- paasta_tools/contrib/create_paasta_playground.py +105 -0
- paasta_tools/contrib/emit_allocated_cpu_metrics.py +50 -0
- paasta_tools/contrib/get_running_task_allocation.py +346 -0
- paasta_tools/contrib/habitat_fixer.py +86 -0
- paasta_tools/contrib/ide_helper.py +316 -0
- paasta_tools/contrib/is_pod_healthy_in_proxy.py +139 -0
- paasta_tools/contrib/is_pod_healthy_in_smartstack.py +50 -0
- paasta_tools/contrib/kill_bad_containers.py +109 -0
- paasta_tools/contrib/mass-deploy-tag.sh +44 -0
- paasta_tools/contrib/mock_patch_checker.py +86 -0
- paasta_tools/contrib/paasta_update_soa_memcpu.py +520 -0
- paasta_tools/contrib/render_template.py +129 -0
- paasta_tools/contrib/rightsizer_soaconfigs_update.py +348 -0
- paasta_tools/contrib/service_shard_remove.py +157 -0
- paasta_tools/contrib/service_shard_update.py +373 -0
- paasta_tools/contrib/shared_ip_check.py +77 -0
- paasta_tools/contrib/timeouts_metrics_prom.py +64 -0
- paasta_tools/delete_kubernetes_deployments.py +89 -0
- paasta_tools/deployment_utils.py +44 -0
- paasta_tools/docker_wrapper.py +234 -0
- paasta_tools/docker_wrapper_imports.py +13 -0
- paasta_tools/drain_lib.py +351 -0
- paasta_tools/dump_locally_running_services.py +71 -0
- paasta_tools/eks_tools.py +119 -0
- paasta_tools/envoy_tools.py +373 -0
- paasta_tools/firewall.py +504 -0
- paasta_tools/firewall_logging.py +154 -0
- paasta_tools/firewall_update.py +172 -0
- paasta_tools/flink_tools.py +345 -0
- paasta_tools/flinkeks_tools.py +90 -0
- paasta_tools/frameworks/__init__.py +0 -0
- paasta_tools/frameworks/adhoc_scheduler.py +71 -0
- paasta_tools/frameworks/constraints.py +87 -0
- paasta_tools/frameworks/native_scheduler.py +652 -0
- paasta_tools/frameworks/native_service_config.py +301 -0
- paasta_tools/frameworks/task_store.py +245 -0
- paasta_tools/generate_all_deployments +9 -0
- paasta_tools/generate_authenticating_services.py +94 -0
- paasta_tools/generate_deployments_for_service.py +255 -0
- paasta_tools/generate_services_file.py +114 -0
- paasta_tools/generate_services_yaml.py +30 -0
- paasta_tools/hacheck.py +76 -0
- paasta_tools/instance/__init__.py +0 -0
- paasta_tools/instance/hpa_metrics_parser.py +122 -0
- paasta_tools/instance/kubernetes.py +1362 -0
- paasta_tools/iptables.py +240 -0
- paasta_tools/kafkacluster_tools.py +143 -0
- paasta_tools/kubernetes/__init__.py +0 -0
- paasta_tools/kubernetes/application/__init__.py +0 -0
- paasta_tools/kubernetes/application/controller_wrappers.py +476 -0
- paasta_tools/kubernetes/application/tools.py +90 -0
- paasta_tools/kubernetes/bin/__init__.py +0 -0
- paasta_tools/kubernetes/bin/kubernetes_remove_evicted_pods.py +164 -0
- paasta_tools/kubernetes/bin/paasta_cleanup_remote_run_resources.py +135 -0
- paasta_tools/kubernetes/bin/paasta_cleanup_stale_nodes.py +181 -0
- paasta_tools/kubernetes/bin/paasta_secrets_sync.py +758 -0
- paasta_tools/kubernetes/remote_run.py +558 -0
- paasta_tools/kubernetes_tools.py +4679 -0
- paasta_tools/list_kubernetes_service_instances.py +128 -0
- paasta_tools/list_tron_namespaces.py +60 -0
- paasta_tools/long_running_service_tools.py +678 -0
- paasta_tools/mac_address.py +44 -0
- paasta_tools/marathon_dashboard.py +0 -0
- paasta_tools/mesos/__init__.py +0 -0
- paasta_tools/mesos/cfg.py +46 -0
- paasta_tools/mesos/cluster.py +60 -0
- paasta_tools/mesos/exceptions.py +59 -0
- paasta_tools/mesos/framework.py +77 -0
- paasta_tools/mesos/log.py +48 -0
- paasta_tools/mesos/master.py +306 -0
- paasta_tools/mesos/mesos_file.py +169 -0
- paasta_tools/mesos/parallel.py +52 -0
- paasta_tools/mesos/slave.py +115 -0
- paasta_tools/mesos/task.py +94 -0
- paasta_tools/mesos/util.py +69 -0
- paasta_tools/mesos/zookeeper.py +37 -0
- paasta_tools/mesos_maintenance.py +848 -0
- paasta_tools/mesos_tools.py +1051 -0
- paasta_tools/metrics/__init__.py +0 -0
- paasta_tools/metrics/metastatus_lib.py +1110 -0
- paasta_tools/metrics/metrics_lib.py +217 -0
- paasta_tools/monitoring/__init__.py +13 -0
- paasta_tools/monitoring/check_k8s_api_performance.py +110 -0
- paasta_tools/monitoring_tools.py +652 -0
- paasta_tools/monkrelaycluster_tools.py +146 -0
- paasta_tools/nrtsearchservice_tools.py +143 -0
- paasta_tools/nrtsearchserviceeks_tools.py +68 -0
- paasta_tools/oom_logger.py +321 -0
- paasta_tools/paasta_deploy_tron_jobs +3 -0
- paasta_tools/paasta_execute_docker_command.py +123 -0
- paasta_tools/paasta_native_serviceinit.py +21 -0
- paasta_tools/paasta_service_config_loader.py +201 -0
- paasta_tools/paastaapi/__init__.py +29 -0
- paasta_tools/paastaapi/api/__init__.py +3 -0
- paasta_tools/paastaapi/api/autoscaler_api.py +302 -0
- paasta_tools/paastaapi/api/default_api.py +569 -0
- paasta_tools/paastaapi/api/remote_run_api.py +604 -0
- paasta_tools/paastaapi/api/resources_api.py +157 -0
- paasta_tools/paastaapi/api/service_api.py +1736 -0
- paasta_tools/paastaapi/api_client.py +818 -0
- paasta_tools/paastaapi/apis/__init__.py +22 -0
- paasta_tools/paastaapi/configuration.py +455 -0
- paasta_tools/paastaapi/exceptions.py +137 -0
- paasta_tools/paastaapi/model/__init__.py +5 -0
- paasta_tools/paastaapi/model/adhoc_launch_history.py +176 -0
- paasta_tools/paastaapi/model/autoscaler_count_msg.py +176 -0
- paasta_tools/paastaapi/model/deploy_queue.py +178 -0
- paasta_tools/paastaapi/model/deploy_queue_service_instance.py +194 -0
- paasta_tools/paastaapi/model/envoy_backend.py +185 -0
- paasta_tools/paastaapi/model/envoy_location.py +184 -0
- paasta_tools/paastaapi/model/envoy_status.py +181 -0
- paasta_tools/paastaapi/model/flink_cluster_overview.py +188 -0
- paasta_tools/paastaapi/model/flink_config.py +173 -0
- paasta_tools/paastaapi/model/flink_job.py +186 -0
- paasta_tools/paastaapi/model/flink_job_details.py +192 -0
- paasta_tools/paastaapi/model/flink_jobs.py +175 -0
- paasta_tools/paastaapi/model/float_and_error.py +173 -0
- paasta_tools/paastaapi/model/hpa_metric.py +176 -0
- paasta_tools/paastaapi/model/inline_object.py +170 -0
- paasta_tools/paastaapi/model/inline_response200.py +170 -0
- paasta_tools/paastaapi/model/inline_response2001.py +170 -0
- paasta_tools/paastaapi/model/instance_bounce_status.py +200 -0
- paasta_tools/paastaapi/model/instance_mesh_status.py +186 -0
- paasta_tools/paastaapi/model/instance_status.py +220 -0
- paasta_tools/paastaapi/model/instance_status_adhoc.py +187 -0
- paasta_tools/paastaapi/model/instance_status_cassandracluster.py +173 -0
- paasta_tools/paastaapi/model/instance_status_flink.py +173 -0
- paasta_tools/paastaapi/model/instance_status_kafkacluster.py +173 -0
- paasta_tools/paastaapi/model/instance_status_kubernetes.py +263 -0
- paasta_tools/paastaapi/model/instance_status_kubernetes_autoscaling_status.py +187 -0
- paasta_tools/paastaapi/model/instance_status_kubernetes_v2.py +197 -0
- paasta_tools/paastaapi/model/instance_status_tron.py +204 -0
- paasta_tools/paastaapi/model/instance_tasks.py +182 -0
- paasta_tools/paastaapi/model/integer_and_error.py +173 -0
- paasta_tools/paastaapi/model/kubernetes_container.py +178 -0
- paasta_tools/paastaapi/model/kubernetes_container_v2.py +219 -0
- paasta_tools/paastaapi/model/kubernetes_healthcheck.py +176 -0
- paasta_tools/paastaapi/model/kubernetes_pod.py +201 -0
- paasta_tools/paastaapi/model/kubernetes_pod_event.py +176 -0
- paasta_tools/paastaapi/model/kubernetes_pod_v2.py +213 -0
- paasta_tools/paastaapi/model/kubernetes_replica_set.py +185 -0
- paasta_tools/paastaapi/model/kubernetes_version.py +202 -0
- paasta_tools/paastaapi/model/remote_run_outcome.py +189 -0
- paasta_tools/paastaapi/model/remote_run_start.py +185 -0
- paasta_tools/paastaapi/model/remote_run_stop.py +176 -0
- paasta_tools/paastaapi/model/remote_run_token.py +173 -0
- paasta_tools/paastaapi/model/resource.py +187 -0
- paasta_tools/paastaapi/model/resource_item.py +187 -0
- paasta_tools/paastaapi/model/resource_value.py +176 -0
- paasta_tools/paastaapi/model/smartstack_backend.py +191 -0
- paasta_tools/paastaapi/model/smartstack_location.py +181 -0
- paasta_tools/paastaapi/model/smartstack_status.py +181 -0
- paasta_tools/paastaapi/model/task_tail_lines.py +176 -0
- paasta_tools/paastaapi/model_utils.py +1879 -0
- paasta_tools/paastaapi/models/__init__.py +62 -0
- paasta_tools/paastaapi/rest.py +287 -0
- paasta_tools/prune_completed_pods.py +220 -0
- paasta_tools/puppet_service_tools.py +59 -0
- paasta_tools/py.typed +1 -0
- paasta_tools/remote_git.py +127 -0
- paasta_tools/run-paasta-api-in-dev-mode.py +57 -0
- paasta_tools/run-paasta-api-playground.py +51 -0
- paasta_tools/secret_providers/__init__.py +66 -0
- paasta_tools/secret_providers/vault.py +214 -0
- paasta_tools/secret_tools.py +277 -0
- paasta_tools/setup_istio_mesh.py +353 -0
- paasta_tools/setup_kubernetes_cr.py +412 -0
- paasta_tools/setup_kubernetes_crd.py +138 -0
- paasta_tools/setup_kubernetes_internal_crd.py +154 -0
- paasta_tools/setup_kubernetes_job.py +353 -0
- paasta_tools/setup_prometheus_adapter_config.py +1028 -0
- paasta_tools/setup_tron_namespace.py +248 -0
- paasta_tools/slack.py +75 -0
- paasta_tools/smartstack_tools.py +676 -0
- paasta_tools/spark_tools.py +283 -0
- paasta_tools/synapse_srv_namespaces_fact.py +42 -0
- paasta_tools/tron/__init__.py +0 -0
- paasta_tools/tron/client.py +158 -0
- paasta_tools/tron/tron_command_context.py +194 -0
- paasta_tools/tron/tron_timeutils.py +101 -0
- paasta_tools/tron_tools.py +1448 -0
- paasta_tools/utils.py +4307 -0
- paasta_tools/yaml_tools.py +44 -0
- paasta_tools-1.21.3.data/scripts/apply_external_resources.py +79 -0
- paasta_tools-1.21.3.data/scripts/bounce_log_latency_parser.py +68 -0
- paasta_tools-1.21.3.data/scripts/check_autoscaler_max_instances.py +212 -0
- paasta_tools-1.21.3.data/scripts/check_cassandracluster_services_replication.py +35 -0
- paasta_tools-1.21.3.data/scripts/check_flink_services_health.py +203 -0
- paasta_tools-1.21.3.data/scripts/check_kubernetes_api.py +57 -0
- paasta_tools-1.21.3.data/scripts/check_kubernetes_services_replication.py +141 -0
- paasta_tools-1.21.3.data/scripts/check_manual_oapi_changes.sh +24 -0
- paasta_tools-1.21.3.data/scripts/check_oom_events.py +244 -0
- paasta_tools-1.21.3.data/scripts/check_orphans.py +306 -0
- paasta_tools-1.21.3.data/scripts/check_spark_jobs.py +234 -0
- paasta_tools-1.21.3.data/scripts/cleanup_kubernetes_cr.py +138 -0
- paasta_tools-1.21.3.data/scripts/cleanup_kubernetes_crd.py +145 -0
- paasta_tools-1.21.3.data/scripts/cleanup_kubernetes_jobs.py +344 -0
- paasta_tools-1.21.3.data/scripts/create_dynamodb_table.py +35 -0
- paasta_tools-1.21.3.data/scripts/create_paasta_playground.py +105 -0
- paasta_tools-1.21.3.data/scripts/delete_kubernetes_deployments.py +89 -0
- paasta_tools-1.21.3.data/scripts/emit_allocated_cpu_metrics.py +50 -0
- paasta_tools-1.21.3.data/scripts/generate_all_deployments +9 -0
- paasta_tools-1.21.3.data/scripts/generate_authenticating_services.py +94 -0
- paasta_tools-1.21.3.data/scripts/generate_deployments_for_service.py +255 -0
- paasta_tools-1.21.3.data/scripts/generate_services_file.py +114 -0
- paasta_tools-1.21.3.data/scripts/generate_services_yaml.py +30 -0
- paasta_tools-1.21.3.data/scripts/get_running_task_allocation.py +346 -0
- paasta_tools-1.21.3.data/scripts/habitat_fixer.py +86 -0
- paasta_tools-1.21.3.data/scripts/ide_helper.py +316 -0
- paasta_tools-1.21.3.data/scripts/is_pod_healthy_in_proxy.py +139 -0
- paasta_tools-1.21.3.data/scripts/is_pod_healthy_in_smartstack.py +50 -0
- paasta_tools-1.21.3.data/scripts/kill_bad_containers.py +109 -0
- paasta_tools-1.21.3.data/scripts/kubernetes_remove_evicted_pods.py +164 -0
- paasta_tools-1.21.3.data/scripts/mass-deploy-tag.sh +44 -0
- paasta_tools-1.21.3.data/scripts/mock_patch_checker.py +86 -0
- paasta_tools-1.21.3.data/scripts/paasta_cleanup_remote_run_resources.py +135 -0
- paasta_tools-1.21.3.data/scripts/paasta_cleanup_stale_nodes.py +181 -0
- paasta_tools-1.21.3.data/scripts/paasta_deploy_tron_jobs +3 -0
- paasta_tools-1.21.3.data/scripts/paasta_execute_docker_command.py +123 -0
- paasta_tools-1.21.3.data/scripts/paasta_secrets_sync.py +758 -0
- paasta_tools-1.21.3.data/scripts/paasta_tabcomplete.sh +23 -0
- paasta_tools-1.21.3.data/scripts/paasta_update_soa_memcpu.py +520 -0
- paasta_tools-1.21.3.data/scripts/render_template.py +129 -0
- paasta_tools-1.21.3.data/scripts/rightsizer_soaconfigs_update.py +348 -0
- paasta_tools-1.21.3.data/scripts/service_shard_remove.py +157 -0
- paasta_tools-1.21.3.data/scripts/service_shard_update.py +373 -0
- paasta_tools-1.21.3.data/scripts/setup_istio_mesh.py +353 -0
- paasta_tools-1.21.3.data/scripts/setup_kubernetes_cr.py +412 -0
- paasta_tools-1.21.3.data/scripts/setup_kubernetes_crd.py +138 -0
- paasta_tools-1.21.3.data/scripts/setup_kubernetes_internal_crd.py +154 -0
- paasta_tools-1.21.3.data/scripts/setup_kubernetes_job.py +353 -0
- paasta_tools-1.21.3.data/scripts/setup_prometheus_adapter_config.py +1028 -0
- paasta_tools-1.21.3.data/scripts/shared_ip_check.py +77 -0
- paasta_tools-1.21.3.data/scripts/synapse_srv_namespaces_fact.py +42 -0
- paasta_tools-1.21.3.data/scripts/timeouts_metrics_prom.py +64 -0
- paasta_tools-1.21.3.dist-info/LICENSE +201 -0
- paasta_tools-1.21.3.dist-info/METADATA +74 -0
- paasta_tools-1.21.3.dist-info/RECORD +348 -0
- paasta_tools-1.21.3.dist-info/WHEEL +5 -0
- paasta_tools-1.21.3.dist-info/entry_points.txt +20 -0
- paasta_tools-1.21.3.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# Copyright 2015-2017 Yelp Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import argparse
|
|
16
|
+
import shutil
|
|
17
|
+
import time
|
|
18
|
+
from typing import List
|
|
19
|
+
|
|
20
|
+
from paasta_tools.cli.utils import get_paasta_oapi_api_clustername
|
|
21
|
+
from paasta_tools.cli.utils import get_paasta_oapi_client_with_auth
|
|
22
|
+
from paasta_tools.cli.utils import lazy_choices_completer
|
|
23
|
+
from paasta_tools.cli.utils import run_interactive_cli
|
|
24
|
+
from paasta_tools.kubernetes.remote_run import TOOLBOX_MOCK_SERVICE
|
|
25
|
+
from paasta_tools.paastaapi.model.remote_run_start import RemoteRunStart
|
|
26
|
+
from paasta_tools.paastaapi.model.remote_run_stop import RemoteRunStop
|
|
27
|
+
from paasta_tools.utils import get_username
|
|
28
|
+
from paasta_tools.utils import list_all_instances_for_service
|
|
29
|
+
from paasta_tools.utils import list_clusters
|
|
30
|
+
from paasta_tools.utils import list_services
|
|
31
|
+
from paasta_tools.utils import load_system_paasta_config
|
|
32
|
+
from paasta_tools.utils import SystemPaastaConfig
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
KUBECTL_CMD_TEMPLATE = (
|
|
36
|
+
"{kubectl_wrapper} --token {token} exec -it -n {namespace} {pod} -- /bin/bash"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _list_services_and_toolboxes() -> List[str]:
|
|
41
|
+
try:
|
|
42
|
+
toolbox_instances = list_all_instances_for_service(
|
|
43
|
+
TOOLBOX_MOCK_SERVICE, instance_type="adhoc"
|
|
44
|
+
)
|
|
45
|
+
except Exception:
|
|
46
|
+
toolbox_instances = set()
|
|
47
|
+
# NOTE: API authorization is enforced by service, and we want different rules
|
|
48
|
+
# for each toolbox, so we combine service and instance in this case to properly
|
|
49
|
+
# allow that to happen.
|
|
50
|
+
return list(list_services()) + sorted(
|
|
51
|
+
f"{TOOLBOX_MOCK_SERVICE}-{instance}" for instance in toolbox_instances
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def paasta_remote_run_start(
|
|
56
|
+
args: argparse.Namespace,
|
|
57
|
+
system_paasta_config: SystemPaastaConfig,
|
|
58
|
+
) -> int:
|
|
59
|
+
client = get_paasta_oapi_client_with_auth(
|
|
60
|
+
cluster=get_paasta_oapi_api_clustername(cluster=args.cluster, is_eks=True),
|
|
61
|
+
system_paasta_config=system_paasta_config,
|
|
62
|
+
)
|
|
63
|
+
if not client:
|
|
64
|
+
print("Cannot get a paasta-api client")
|
|
65
|
+
return 1
|
|
66
|
+
|
|
67
|
+
user = get_username()
|
|
68
|
+
start_response = client.remote_run.remote_run_start(
|
|
69
|
+
args.service,
|
|
70
|
+
args.instance,
|
|
71
|
+
RemoteRunStart(
|
|
72
|
+
user=user,
|
|
73
|
+
interactive=args.interactive,
|
|
74
|
+
recreate=args.recreate,
|
|
75
|
+
max_duration=args.max_duration,
|
|
76
|
+
toolbox=args.toolbox,
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
if start_response.status >= 300:
|
|
80
|
+
print(f"Error from PaaSTA APIs while starting job: {start_response.message}")
|
|
81
|
+
return 1
|
|
82
|
+
|
|
83
|
+
print(
|
|
84
|
+
f"Triggered remote-run job for {args.service}. Waiting for pod to come online..."
|
|
85
|
+
)
|
|
86
|
+
start_time = time.time()
|
|
87
|
+
while time.time() - start_time < args.timeout:
|
|
88
|
+
poll_response = client.remote_run.remote_run_poll(
|
|
89
|
+
service=args.service,
|
|
90
|
+
instance=args.instance,
|
|
91
|
+
job_name=start_response.job_name,
|
|
92
|
+
user=user,
|
|
93
|
+
toolbox=args.toolbox,
|
|
94
|
+
)
|
|
95
|
+
if poll_response.status == 200:
|
|
96
|
+
print("")
|
|
97
|
+
break
|
|
98
|
+
print(f"\rStatus: {poll_response.message}", end="")
|
|
99
|
+
time.sleep(10)
|
|
100
|
+
else:
|
|
101
|
+
print("Timed out while waiting for job to start")
|
|
102
|
+
return 1
|
|
103
|
+
|
|
104
|
+
if not args.interactive and not args.toolbox:
|
|
105
|
+
print("Successfully started remote-run job")
|
|
106
|
+
return 0
|
|
107
|
+
|
|
108
|
+
print("Pod ready, establishing interactive session...")
|
|
109
|
+
|
|
110
|
+
if args.toolbox:
|
|
111
|
+
# NOTE: we only do this for toolbox containers since those images are built with interactive
|
|
112
|
+
# access in mind, and SSH sessions provide better auditability of user actions.
|
|
113
|
+
# I.e., being `nobody` is fine in a normal remote-run, but in toolbox containers
|
|
114
|
+
# we will require knowing the real user (and some tools may need that too).
|
|
115
|
+
exec_command = f"ssh -A {poll_response.pod_address}"
|
|
116
|
+
else:
|
|
117
|
+
token_response = client.remote_run.remote_run_token(
|
|
118
|
+
args.service, args.instance, user
|
|
119
|
+
)
|
|
120
|
+
kubectl_wrapper = f"kubectl-eks-{args.cluster}"
|
|
121
|
+
if not shutil.which(kubectl_wrapper):
|
|
122
|
+
kubectl_wrapper = f"kubectl-{args.cluster}"
|
|
123
|
+
exec_command = KUBECTL_CMD_TEMPLATE.format(
|
|
124
|
+
kubectl_wrapper=kubectl_wrapper,
|
|
125
|
+
namespace=poll_response.namespace,
|
|
126
|
+
pod=poll_response.pod_name,
|
|
127
|
+
token=token_response.token,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
run_interactive_cli(exec_command)
|
|
131
|
+
return 0
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def paasta_remote_run_stop(
|
|
135
|
+
args: argparse.Namespace,
|
|
136
|
+
system_paasta_config: SystemPaastaConfig,
|
|
137
|
+
) -> int:
|
|
138
|
+
client = get_paasta_oapi_client_with_auth(
|
|
139
|
+
cluster=get_paasta_oapi_api_clustername(cluster=args.cluster, is_eks=True),
|
|
140
|
+
system_paasta_config=system_paasta_config,
|
|
141
|
+
)
|
|
142
|
+
if not client:
|
|
143
|
+
print("Cannot get a paasta-api client")
|
|
144
|
+
return 1
|
|
145
|
+
response = client.remote_run.remote_run_stop(
|
|
146
|
+
args.service,
|
|
147
|
+
args.instance,
|
|
148
|
+
RemoteRunStop(user=get_username(), toolbox=args.toolbox),
|
|
149
|
+
)
|
|
150
|
+
print(response.message)
|
|
151
|
+
return 0 if response.status < 300 else 1
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def add_common_args_to_parser(parser: argparse.ArgumentParser):
|
|
155
|
+
service_arg = parser.add_argument(
|
|
156
|
+
"-s",
|
|
157
|
+
"--service",
|
|
158
|
+
help="The name of the service you wish to inspect. Required.",
|
|
159
|
+
required=True,
|
|
160
|
+
)
|
|
161
|
+
service_arg.completer = lazy_choices_completer(_list_services_and_toolboxes) # type: ignore
|
|
162
|
+
instance_or_toolbox = parser.add_mutually_exclusive_group()
|
|
163
|
+
instance_or_toolbox.add_argument(
|
|
164
|
+
"-i",
|
|
165
|
+
"--instance",
|
|
166
|
+
help=(
|
|
167
|
+
"Simulate a docker run for a particular instance of the "
|
|
168
|
+
"service, like 'main' or 'canary'. Required."
|
|
169
|
+
),
|
|
170
|
+
default="main",
|
|
171
|
+
)
|
|
172
|
+
instance_or_toolbox.add_argument(
|
|
173
|
+
"--toolbox",
|
|
174
|
+
help="The selected service is a 'toolbox' container",
|
|
175
|
+
action="store_true",
|
|
176
|
+
default=False,
|
|
177
|
+
)
|
|
178
|
+
cluster_arg = parser.add_argument(
|
|
179
|
+
"-c",
|
|
180
|
+
"--cluster",
|
|
181
|
+
help="The name of the cluster you wish to run your task on. Required.",
|
|
182
|
+
required=True,
|
|
183
|
+
)
|
|
184
|
+
cluster_arg.completer = lazy_choices_completer(list_clusters) # type: ignore
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def add_subparser(subparsers: argparse._SubParsersAction) -> None:
|
|
188
|
+
remote_run_parser = subparsers.add_parser(
|
|
189
|
+
"remote-run",
|
|
190
|
+
help="Run services / jobs remotely",
|
|
191
|
+
description="'paasta remote-run' runs services / jobs remotely",
|
|
192
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
193
|
+
)
|
|
194
|
+
subparsers = remote_run_parser.add_subparsers(dest="remote_run_command")
|
|
195
|
+
start_parser = subparsers.add_parser(
|
|
196
|
+
"start",
|
|
197
|
+
help="Start or connect to a remote-run job",
|
|
198
|
+
description="Starts or connects to a remote-run-job",
|
|
199
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
200
|
+
)
|
|
201
|
+
start_parser.add_argument(
|
|
202
|
+
"-I",
|
|
203
|
+
"--interactive",
|
|
204
|
+
help=(
|
|
205
|
+
"Run container in interactive mode. If interactive is set the "
|
|
206
|
+
'default command will be "bash" unless otherwise set by the "--cmd" flag'
|
|
207
|
+
),
|
|
208
|
+
action="store_true",
|
|
209
|
+
default=False,
|
|
210
|
+
)
|
|
211
|
+
start_parser.add_argument(
|
|
212
|
+
"-m",
|
|
213
|
+
"--max-duration",
|
|
214
|
+
help=(
|
|
215
|
+
"Amount of time in seconds after which the job is "
|
|
216
|
+
"automatically stopped (capped by the API backend)"
|
|
217
|
+
),
|
|
218
|
+
type=int,
|
|
219
|
+
default=1800,
|
|
220
|
+
)
|
|
221
|
+
start_parser.add_argument(
|
|
222
|
+
"-r",
|
|
223
|
+
"--recreate",
|
|
224
|
+
help="Recreate remote-run job if already existing",
|
|
225
|
+
action="store_true",
|
|
226
|
+
default=False,
|
|
227
|
+
)
|
|
228
|
+
start_parser.add_argument(
|
|
229
|
+
"-t",
|
|
230
|
+
"--timeout",
|
|
231
|
+
help="Maximum time to wait for a job to start, in seconds",
|
|
232
|
+
type=int,
|
|
233
|
+
default=600,
|
|
234
|
+
)
|
|
235
|
+
stop_parser = subparsers.add_parser(
|
|
236
|
+
"stop",
|
|
237
|
+
help="Stop your remote-run job if it exists",
|
|
238
|
+
description="Stop your remote-run job if it exists",
|
|
239
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
240
|
+
)
|
|
241
|
+
add_common_args_to_parser(start_parser)
|
|
242
|
+
add_common_args_to_parser(stop_parser)
|
|
243
|
+
remote_run_parser.set_defaults(command=paasta_remote_run)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def paasta_remote_run(args: argparse.Namespace) -> int:
|
|
247
|
+
system_paasta_config = load_system_paasta_config()
|
|
248
|
+
if args.remote_run_command == "start":
|
|
249
|
+
return paasta_remote_run_start(args, system_paasta_config)
|
|
250
|
+
elif args.remote_run_command == "stop":
|
|
251
|
+
return paasta_remote_run_stop(args, system_paasta_config)
|
|
252
|
+
raise ValueError(f"Unsupported subcommand: {args.remote_run_command}")
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# Copyright 2015-2016 Yelp Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
import argparse
|
|
16
|
+
from typing import Collection
|
|
17
|
+
from typing import Dict
|
|
18
|
+
from typing import Generator
|
|
19
|
+
from typing import Mapping
|
|
20
|
+
from typing import Tuple
|
|
21
|
+
|
|
22
|
+
from humanize import naturaltime
|
|
23
|
+
|
|
24
|
+
from paasta_tools.cli.cmds.mark_for_deployment import can_user_deploy_service
|
|
25
|
+
from paasta_tools.cli.cmds.mark_for_deployment import get_deploy_info
|
|
26
|
+
from paasta_tools.cli.cmds.mark_for_deployment import mark_for_deployment
|
|
27
|
+
from paasta_tools.cli.utils import extract_tags
|
|
28
|
+
from paasta_tools.cli.utils import figure_out_service_name
|
|
29
|
+
from paasta_tools.cli.utils import lazy_choices_completer
|
|
30
|
+
from paasta_tools.cli.utils import list_deploy_groups
|
|
31
|
+
from paasta_tools.cli.utils import validate_full_git_sha
|
|
32
|
+
from paasta_tools.cli.utils import validate_given_deploy_groups
|
|
33
|
+
from paasta_tools.deployment_utils import get_currently_deployed_version
|
|
34
|
+
from paasta_tools.remote_git import list_remote_refs
|
|
35
|
+
from paasta_tools.utils import _log_audit
|
|
36
|
+
from paasta_tools.utils import datetime_from_utc_to_local
|
|
37
|
+
from paasta_tools.utils import DEFAULT_SOA_DIR
|
|
38
|
+
from paasta_tools.utils import DeploymentVersion
|
|
39
|
+
from paasta_tools.utils import format_table
|
|
40
|
+
from paasta_tools.utils import get_git_url
|
|
41
|
+
from paasta_tools.utils import list_services
|
|
42
|
+
from paasta_tools.utils import PaastaColors
|
|
43
|
+
from paasta_tools.utils import parse_timestamp
|
|
44
|
+
from paasta_tools.utils import RollbackTypes
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def add_subparser(subparsers: argparse._SubParsersAction) -> None:
|
|
48
|
+
list_parser = subparsers.add_parser(
|
|
49
|
+
"rollback",
|
|
50
|
+
help="Rollback a docker image to a previous deploy",
|
|
51
|
+
description=(
|
|
52
|
+
"'paasta rollback' is a human-friendly tool for marking a particular "
|
|
53
|
+
"docker image for deployment, which invokes a bounce. While the command "
|
|
54
|
+
"is called 'rollback', it can be used to roll forward or back, as long "
|
|
55
|
+
"as there is a docker image available for the input Git SHA."
|
|
56
|
+
),
|
|
57
|
+
epilog=(
|
|
58
|
+
"This rollback command uses the Git control plane, which requires network "
|
|
59
|
+
"connectivity as well as authorization to the Git repo.\n\n"
|
|
60
|
+
+ PaastaColors.yellow(
|
|
61
|
+
"WARNING: You MUST manually revert changes in Git and go through the normal push process after using this command.\n"
|
|
62
|
+
)
|
|
63
|
+
+ PaastaColors.yellow(
|
|
64
|
+
"WARNING: Failing to do so means that Jenkins will redeploy the latest code on the next scheduled build!"
|
|
65
|
+
)
|
|
66
|
+
),
|
|
67
|
+
# we manually format the epilog to add newlines + give it an attention-grabbing color
|
|
68
|
+
# re: reverting changes in Git post-rollback
|
|
69
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
70
|
+
)
|
|
71
|
+
arg_commit = list_parser.add_argument(
|
|
72
|
+
"-k",
|
|
73
|
+
"--commit",
|
|
74
|
+
help="Git SHA to mark for rollback. "
|
|
75
|
+
"A commit to rollback to is required for paasta rollback to run. However if one is not provided, "
|
|
76
|
+
"paasta rollback will instead output a list of valid git shas to rollback to.",
|
|
77
|
+
required=False,
|
|
78
|
+
)
|
|
79
|
+
arg_commit.completer = lazy_choices_completer(list_previously_deployed_shas) # type: ignore
|
|
80
|
+
arg_version = list_parser.add_argument(
|
|
81
|
+
"-i",
|
|
82
|
+
"--image-version",
|
|
83
|
+
help="Extra version metadata to mark for rollback. "
|
|
84
|
+
"If your service has enabled no-commit redeploys, both a commit and the extra metadata is required for paasta rollback to run. However if one is not provided, "
|
|
85
|
+
"paasta rollback will instead output a list of valid versions to rollback to.",
|
|
86
|
+
required=False,
|
|
87
|
+
default=None,
|
|
88
|
+
)
|
|
89
|
+
arg_version.completer = lazy_choices_completer(list_previously_deployed_image_versions) # type: ignore
|
|
90
|
+
arg_deploy_group = list_parser.add_argument(
|
|
91
|
+
"-l",
|
|
92
|
+
"--deploy-groups",
|
|
93
|
+
help="Mark one or more deploy groups to roll back (e.g. "
|
|
94
|
+
'"all.main", "all.main,all.canary"). If no deploy groups specified,'
|
|
95
|
+
"no deploy groups for that service are rolled back. To rollback all deploy groups "
|
|
96
|
+
"use the flag -a or --all-deploy-groups",
|
|
97
|
+
default="",
|
|
98
|
+
required=False,
|
|
99
|
+
)
|
|
100
|
+
arg_deploy_group.completer = lazy_choices_completer(list_deploy_groups) # type: ignore
|
|
101
|
+
list_parser.add_argument(
|
|
102
|
+
"-a",
|
|
103
|
+
"--all-deploy-groups",
|
|
104
|
+
help="Rollback all deploy groups for the service",
|
|
105
|
+
action="store_true",
|
|
106
|
+
required=False,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
arg_service = list_parser.add_argument(
|
|
110
|
+
"-s", "--service", help='Name of the service to rollback (e.g. "service1")'
|
|
111
|
+
)
|
|
112
|
+
arg_service.completer = lazy_choices_completer(list_services) # type: ignore
|
|
113
|
+
list_parser.add_argument(
|
|
114
|
+
"-y",
|
|
115
|
+
"-d",
|
|
116
|
+
"--soa-dir",
|
|
117
|
+
dest="soa_dir",
|
|
118
|
+
metavar="SOA_DIR",
|
|
119
|
+
default=DEFAULT_SOA_DIR,
|
|
120
|
+
help="define a different soa config directory",
|
|
121
|
+
)
|
|
122
|
+
list_parser.add_argument(
|
|
123
|
+
"-f",
|
|
124
|
+
"--force",
|
|
125
|
+
help=("Do not check if Git SHA was marked for deployment previously."),
|
|
126
|
+
action="store_true",
|
|
127
|
+
)
|
|
128
|
+
list_parser.set_defaults(command=paasta_rollback)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def list_previously_deployed_shas(
|
|
132
|
+
parsed_args: argparse.Namespace, **kwargs: None
|
|
133
|
+
) -> Generator[str, None, None]:
|
|
134
|
+
service = parsed_args.service
|
|
135
|
+
soa_dir = parsed_args.soa_dir
|
|
136
|
+
deploy_groups = {
|
|
137
|
+
deploy_group
|
|
138
|
+
for deploy_group in parsed_args.deploy_groups.split(",")
|
|
139
|
+
if deploy_group
|
|
140
|
+
}
|
|
141
|
+
return (
|
|
142
|
+
version.sha
|
|
143
|
+
for version in get_versions_for_service(service, deploy_groups, soa_dir)
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def list_previously_deployed_image_versions(
|
|
148
|
+
parsed_args: argparse.Namespace, **kwargs: None
|
|
149
|
+
) -> Generator[str, None, None]:
|
|
150
|
+
service = parsed_args.service
|
|
151
|
+
soa_dir = parsed_args.soa_dir
|
|
152
|
+
deploy_groups = {
|
|
153
|
+
deploy_group
|
|
154
|
+
for deploy_group in parsed_args.deploy_groups.split(",")
|
|
155
|
+
if deploy_group
|
|
156
|
+
}
|
|
157
|
+
return (
|
|
158
|
+
version.image_version
|
|
159
|
+
for version in get_versions_for_service(service, deploy_groups, soa_dir)
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def get_versions_for_service(
|
|
164
|
+
service: str, deploy_groups: Collection[str], soa_dir: str
|
|
165
|
+
) -> Mapping[DeploymentVersion, Tuple[str, str]]:
|
|
166
|
+
"""Returns a dictionary of 2-tuples of the form (timestamp, deploy_group) for each version tuple of (deploy sha, image_version)"""
|
|
167
|
+
if service is None:
|
|
168
|
+
return {}
|
|
169
|
+
git_url = get_git_url(service=service, soa_dir=soa_dir)
|
|
170
|
+
all_deploy_groups = list_deploy_groups(service=service, soa_dir=soa_dir)
|
|
171
|
+
deploy_groups, _ = validate_given_deploy_groups(all_deploy_groups, deploy_groups)
|
|
172
|
+
previously_deployed_versions: Dict[DeploymentVersion, Tuple[str, str]] = {}
|
|
173
|
+
for ref, sha in list_remote_refs(git_url).items():
|
|
174
|
+
regex_match = extract_tags(ref)
|
|
175
|
+
try:
|
|
176
|
+
deploy_group = regex_match["deploy_group"]
|
|
177
|
+
tstamp = regex_match["tstamp"]
|
|
178
|
+
image_version = regex_match["image_version"]
|
|
179
|
+
except KeyError:
|
|
180
|
+
pass
|
|
181
|
+
else:
|
|
182
|
+
# Now we filter and dedup by picking the most recent sha for a deploy group
|
|
183
|
+
# Note that all strings are greater than ''
|
|
184
|
+
if deploy_group in deploy_groups:
|
|
185
|
+
version = DeploymentVersion(sha=sha, image_version=image_version)
|
|
186
|
+
tstamp_so_far = previously_deployed_versions.get(version, ("all", ""))[
|
|
187
|
+
1
|
|
188
|
+
]
|
|
189
|
+
if tstamp > tstamp_so_far:
|
|
190
|
+
previously_deployed_versions[version] = (tstamp, deploy_group)
|
|
191
|
+
return previously_deployed_versions
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def list_previous_versions(
|
|
195
|
+
service: str,
|
|
196
|
+
deploy_groups: Collection[str],
|
|
197
|
+
any_given_deploy_groups: bool,
|
|
198
|
+
versions: Mapping[DeploymentVersion, Tuple],
|
|
199
|
+
) -> None:
|
|
200
|
+
def format_timestamp(tstamp: str) -> str:
|
|
201
|
+
return naturaltime(datetime_from_utc_to_local(parse_timestamp(tstamp)))
|
|
202
|
+
|
|
203
|
+
print("Below is a list of recent commits:")
|
|
204
|
+
# Latest 10 versions sorted by deployment time
|
|
205
|
+
list_of_versions = sorted(versions.items(), key=lambda x: x[1], reverse=True)[:10]
|
|
206
|
+
rows = [("Timestamp -- UTC", "Human time", "deploy_group", "Version")]
|
|
207
|
+
for version, (timestamp, deploy_group) in list_of_versions:
|
|
208
|
+
rows.extend(
|
|
209
|
+
[(timestamp, format_timestamp(timestamp), deploy_group, repr(version))]
|
|
210
|
+
)
|
|
211
|
+
for line in format_table(rows):
|
|
212
|
+
print(line)
|
|
213
|
+
if len(list_of_versions) >= 2:
|
|
214
|
+
version, (timestamp, deploy_group) = list_of_versions[1]
|
|
215
|
+
deploy_groups_arg_line = (
|
|
216
|
+
"-l %s " % ",".join(deploy_groups) if any_given_deploy_groups else ""
|
|
217
|
+
)
|
|
218
|
+
version_arg = (
|
|
219
|
+
f" --image-version {version.image_version}" if version.image_version else ""
|
|
220
|
+
)
|
|
221
|
+
print(
|
|
222
|
+
"\nFor example, to use the second to last version from {} used on {}, run:".format(
|
|
223
|
+
format_timestamp(timestamp), PaastaColors.bold(deploy_group)
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
print(
|
|
227
|
+
PaastaColors.bold(
|
|
228
|
+
f" paasta rollback -s {service} {deploy_groups_arg_line}-k {version.sha}{version_arg}"
|
|
229
|
+
)
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def paasta_rollback(args: argparse.Namespace) -> int:
|
|
234
|
+
"""Call mark_for_deployment with rollback parameters
|
|
235
|
+
:param args: contains all the arguments passed onto the script: service,
|
|
236
|
+
deploy groups and sha. These arguments will be verified and passed onto
|
|
237
|
+
mark_for_deployment.
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
soa_dir = args.soa_dir
|
|
241
|
+
service = figure_out_service_name(args, soa_dir)
|
|
242
|
+
|
|
243
|
+
deploy_info = get_deploy_info(service=service, soa_dir=args.soa_dir)
|
|
244
|
+
if not can_user_deploy_service(deploy_info, service):
|
|
245
|
+
return 1
|
|
246
|
+
|
|
247
|
+
git_url = get_git_url(service, soa_dir)
|
|
248
|
+
|
|
249
|
+
if args.all_deploy_groups:
|
|
250
|
+
given_deploy_groups = list_deploy_groups(service=service, soa_dir=soa_dir)
|
|
251
|
+
else:
|
|
252
|
+
given_deploy_groups = {
|
|
253
|
+
deploy_group
|
|
254
|
+
for deploy_group in args.deploy_groups.split(",")
|
|
255
|
+
if deploy_group
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
all_deploy_groups = list_deploy_groups(service=service, soa_dir=soa_dir)
|
|
259
|
+
deploy_groups, invalid = validate_given_deploy_groups(
|
|
260
|
+
all_deploy_groups, given_deploy_groups
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
if len(invalid) > 0:
|
|
264
|
+
print(
|
|
265
|
+
PaastaColors.yellow(
|
|
266
|
+
"These deploy groups are not valid and will be skipped: %s.\n"
|
|
267
|
+
% (",").join(invalid)
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
if len(deploy_groups) == 0 and not args.all_deploy_groups:
|
|
272
|
+
print(
|
|
273
|
+
PaastaColors.red(
|
|
274
|
+
"ERROR: No valid deploy groups specified for %s.\n Use the flag -a to rollback all valid deploy groups for this service"
|
|
275
|
+
% (service)
|
|
276
|
+
)
|
|
277
|
+
)
|
|
278
|
+
return 1
|
|
279
|
+
|
|
280
|
+
versions = get_versions_for_service(service, deploy_groups, soa_dir)
|
|
281
|
+
commit = args.commit
|
|
282
|
+
image_version = args.image_version
|
|
283
|
+
new_version = DeploymentVersion(sha=commit, image_version=image_version)
|
|
284
|
+
if not commit:
|
|
285
|
+
print("Please specify a commit to mark for rollback (-k, --commit).")
|
|
286
|
+
list_previous_versions(
|
|
287
|
+
service, deploy_groups, bool(given_deploy_groups), versions
|
|
288
|
+
)
|
|
289
|
+
return 1
|
|
290
|
+
elif new_version not in versions and not args.force:
|
|
291
|
+
print(
|
|
292
|
+
PaastaColors.red(
|
|
293
|
+
f"This version {new_version} has never been deployed before."
|
|
294
|
+
)
|
|
295
|
+
)
|
|
296
|
+
print("Please double check it or use --force to skip this verification.\n")
|
|
297
|
+
list_previous_versions(
|
|
298
|
+
service, deploy_groups, bool(given_deploy_groups), versions
|
|
299
|
+
)
|
|
300
|
+
return 1
|
|
301
|
+
|
|
302
|
+
try:
|
|
303
|
+
validate_full_git_sha(args.commit)
|
|
304
|
+
except argparse.ArgumentTypeError as e:
|
|
305
|
+
print(PaastaColors.red(f"Error: {e}"))
|
|
306
|
+
return 1
|
|
307
|
+
|
|
308
|
+
# TODO: Add similar check for when image_version is empty and no-commit redeploys is enforced for requested deploy_group
|
|
309
|
+
|
|
310
|
+
returncode = 0
|
|
311
|
+
|
|
312
|
+
for deploy_group in deploy_groups:
|
|
313
|
+
rolled_back_from = get_currently_deployed_version(service, deploy_group)
|
|
314
|
+
returncode |= mark_for_deployment(
|
|
315
|
+
git_url=git_url,
|
|
316
|
+
service=service,
|
|
317
|
+
deploy_group=deploy_group,
|
|
318
|
+
commit=commit,
|
|
319
|
+
image_version=image_version,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
# we could also gate this by the return code from m-f-d, but we probably care more about someone wanting to
|
|
323
|
+
# rollback than we care about if the underlying machinery was successfully able to complete the request
|
|
324
|
+
if rolled_back_from != new_version:
|
|
325
|
+
audit_action_details = {
|
|
326
|
+
"rolled_back_from": str(rolled_back_from),
|
|
327
|
+
"rolled_back_to": str(new_version),
|
|
328
|
+
"rollback_type": RollbackTypes.USER_INITIATED_ROLLBACK.value,
|
|
329
|
+
"deploy_group": deploy_group,
|
|
330
|
+
}
|
|
331
|
+
_log_audit(
|
|
332
|
+
action="rollback", action_details=audit_action_details, service=service
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
if returncode == 0:
|
|
336
|
+
print(
|
|
337
|
+
PaastaColors.yellow(
|
|
338
|
+
f"WARNING: You MUST manually revert changes in Git! Use 'git revert {rolled_back_from.sha}', and go through the normal push process. "
|
|
339
|
+
)
|
|
340
|
+
)
|
|
341
|
+
print(
|
|
342
|
+
PaastaColors.yellow(
|
|
343
|
+
f"WARNING: Failing to do so means that Jenkins will redeploy the latest code on the next scheduled build!"
|
|
344
|
+
)
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
return returncode
|