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,21 @@
|
|
|
1
|
+
import staticconf
|
|
2
|
+
|
|
3
|
+
CLUSTERMAN_YAML_FILE_PATH = "/nail/srv/configs/clusterman.yaml"
|
|
4
|
+
CLUSTERMAN_METRICS_YAML_FILE_PATH = "/nail/srv/configs/clusterman_metrics.yaml"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_clusterman_metrics():
|
|
8
|
+
try:
|
|
9
|
+
import clusterman_metrics
|
|
10
|
+
import clusterman_metrics.util.costs
|
|
11
|
+
|
|
12
|
+
clusterman_yaml = CLUSTERMAN_YAML_FILE_PATH
|
|
13
|
+
staticconf.YamlConfiguration(
|
|
14
|
+
CLUSTERMAN_METRICS_YAML_FILE_PATH, namespace="clusterman_metrics"
|
|
15
|
+
)
|
|
16
|
+
except (ImportError, FileNotFoundError):
|
|
17
|
+
# our cluster autoscaler is not currently open source, sorry!
|
|
18
|
+
clusterman_metrics = None
|
|
19
|
+
clusterman_yaml = None
|
|
20
|
+
|
|
21
|
+
return clusterman_metrics, clusterman_yaml
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
from tempfile import TemporaryDirectory
|
|
6
|
+
from typing import Any
|
|
7
|
+
from typing import Dict
|
|
8
|
+
from typing import List
|
|
9
|
+
from typing import Optional
|
|
10
|
+
from typing import Set
|
|
11
|
+
from typing import Tuple
|
|
12
|
+
|
|
13
|
+
import ruamel.yaml as yaml
|
|
14
|
+
|
|
15
|
+
from paasta_tools.cli.cmds.validate import validate_schema
|
|
16
|
+
from paasta_tools.utils import AUTO_SOACONFIG_SUBDIR
|
|
17
|
+
from paasta_tools.utils import DEFAULT_SOA_DIR
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
log = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
# Must have a schema defined
|
|
23
|
+
KNOWN_CONFIG_TYPES = (
|
|
24
|
+
"kubernetes",
|
|
25
|
+
"deploy",
|
|
26
|
+
"smartstack",
|
|
27
|
+
"cassandracluster",
|
|
28
|
+
"eks",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# this could use a better name - but basically, this is for pairs of instance types
|
|
32
|
+
# where you generally want to check both types (i.e.,g a status-quo and migration
|
|
33
|
+
# instance type)
|
|
34
|
+
INSTANCE_TYPE_COUNTERPARTS = {"eks": "kubernetes", "kubernetes": "eks"}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def my_represent_none(self, data):
|
|
38
|
+
return self.represent_scalar("tag:yaml.org,2002:null", "null")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def write_auto_config_data(
|
|
42
|
+
service: str,
|
|
43
|
+
extra_info: str,
|
|
44
|
+
data: Dict[str, Any],
|
|
45
|
+
soa_dir: str = DEFAULT_SOA_DIR,
|
|
46
|
+
sub_dir: Optional[str] = None,
|
|
47
|
+
comment: Optional[str] = None,
|
|
48
|
+
) -> Optional[str]:
|
|
49
|
+
"""
|
|
50
|
+
Replaces the contents of an automated config file for a service, or creates the file if it does not exist.
|
|
51
|
+
|
|
52
|
+
Returns the filename of the modified file, or None if no file was written.
|
|
53
|
+
"""
|
|
54
|
+
yaml.YAML().representer.add_representer(type(None), my_represent_none)
|
|
55
|
+
service_dir = f"{soa_dir}/{service}"
|
|
56
|
+
if not os.path.exists(service_dir):
|
|
57
|
+
log.warning(
|
|
58
|
+
f"Service {service} does not exist in configs, skipping auto config update"
|
|
59
|
+
)
|
|
60
|
+
return None
|
|
61
|
+
subdir = f"{service_dir}/{sub_dir}" if sub_dir else service_dir
|
|
62
|
+
if not os.path.exists(subdir):
|
|
63
|
+
os.mkdir(subdir)
|
|
64
|
+
filename = f"{subdir}/{extra_info}.yaml"
|
|
65
|
+
|
|
66
|
+
with open(filename, "w") as f:
|
|
67
|
+
# TODO: this can be collapsed into one codeblock. It is separated as two
|
|
68
|
+
# because doing content.update(data) results in losing comments from `data`
|
|
69
|
+
# we should be able to handle adding a header comment and yaml with comments in it
|
|
70
|
+
# without this if/else block
|
|
71
|
+
if comment:
|
|
72
|
+
content = (
|
|
73
|
+
yaml.round_trip_load(
|
|
74
|
+
comment.format(
|
|
75
|
+
# this is a bit of a hack, but we've decided to not rename files back to kubernetes-*
|
|
76
|
+
# files. while we still need to update things to reference the eks files directly, there's
|
|
77
|
+
# still a couple of places where we still need kubernetes-* files (e.g., unmigrated operators)
|
|
78
|
+
# so for now let's just assume that autotuned things will always actually have their human-managed
|
|
79
|
+
# config in eks-* files
|
|
80
|
+
regular_filename=f"{service}/{extra_info.replace('kubernetes-', 'eks-')}.yaml",
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
if comment
|
|
84
|
+
else {}
|
|
85
|
+
)
|
|
86
|
+
content.update(data)
|
|
87
|
+
else:
|
|
88
|
+
# avoids content.update to preserve comments in `data`
|
|
89
|
+
content = data
|
|
90
|
+
|
|
91
|
+
f.write(yaml.round_trip_dump(content))
|
|
92
|
+
return filename
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _commit_files(files: List[str], message: str) -> bool:
|
|
96
|
+
"""
|
|
97
|
+
Stages the given files and creates a commit with the given message.
|
|
98
|
+
|
|
99
|
+
Returns True if a new commit was created, False if the files are unchanged.
|
|
100
|
+
"""
|
|
101
|
+
subprocess.check_call(["git", "add"] + files)
|
|
102
|
+
# Skip commit if no changes are staged
|
|
103
|
+
result_code = subprocess.call(["git", "diff-index", "--quiet", "--cached", "HEAD"])
|
|
104
|
+
if result_code == 0:
|
|
105
|
+
return False
|
|
106
|
+
else:
|
|
107
|
+
subprocess.check_call(["git", "commit", "--no-verify", "--message", message])
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class PushNotFastForwardError(Exception):
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ValidationError(Exception):
|
|
116
|
+
pass
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _push_to_remote(branch: str) -> None:
|
|
120
|
+
try:
|
|
121
|
+
subprocess.check_output(
|
|
122
|
+
("git", "push", "origin", branch), stderr=subprocess.STDOUT
|
|
123
|
+
)
|
|
124
|
+
except subprocess.CalledProcessError as e:
|
|
125
|
+
if "Updates were rejected" in str(e.stdout):
|
|
126
|
+
raise PushNotFastForwardError()
|
|
127
|
+
else:
|
|
128
|
+
log.error(f"Push to {branch} failed with:\n {e.stdout}")
|
|
129
|
+
raise
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def validate_auto_config_file(filepath: str, schema_subdir: str):
|
|
133
|
+
basename = os.path.basename(filepath)
|
|
134
|
+
for file_type in KNOWN_CONFIG_TYPES:
|
|
135
|
+
schema_path = f"{schema_subdir}/{file_type}" if schema_subdir else file_type
|
|
136
|
+
if basename.startswith(file_type):
|
|
137
|
+
return bool(validate_schema(filepath, schema_path))
|
|
138
|
+
else:
|
|
139
|
+
logging.info(f"{filepath} is invalid because it has no validator defined")
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class AutoConfigUpdater:
|
|
144
|
+
"""
|
|
145
|
+
Helper class for updating automated paasta configs.
|
|
146
|
+
|
|
147
|
+
Usage:
|
|
148
|
+
|
|
149
|
+
updater = AutoConfigUpdater('about_me', 'git@git.me:my_configs', branch='test')
|
|
150
|
+
# The context manager clones the repo into a local temp directory, then
|
|
151
|
+
# cleans up afterwards.
|
|
152
|
+
with updater:
|
|
153
|
+
# The updater replaces the content of files, so get the existing data
|
|
154
|
+
# first if you want to update it
|
|
155
|
+
data = updater.get_existing_configs('service_foo', 'conf_file')
|
|
156
|
+
data["new_key"] = "g_minor"
|
|
157
|
+
|
|
158
|
+
# Now write the new data
|
|
159
|
+
updater.write_configs('service_foo', 'conf_file', data)
|
|
160
|
+
|
|
161
|
+
# Edit more files...
|
|
162
|
+
|
|
163
|
+
# Once you're done editing files, commit. If all files pass validation,
|
|
164
|
+
# the updater will commit the changes and push them to the desired branch
|
|
165
|
+
# on the remote.
|
|
166
|
+
updater.commit_to_remote(extra_message="Adding some extra context.")
|
|
167
|
+
|
|
168
|
+
Raises PushNotFastForwardError if the updated branch does not include changes in the
|
|
169
|
+
remote branch.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
def __init__(
|
|
173
|
+
self,
|
|
174
|
+
config_source: str,
|
|
175
|
+
git_remote: str,
|
|
176
|
+
branch: str = "master",
|
|
177
|
+
working_dir: Optional[str] = None,
|
|
178
|
+
do_clone: bool = True,
|
|
179
|
+
validation_schema_path: str = "",
|
|
180
|
+
):
|
|
181
|
+
self.config_source = config_source
|
|
182
|
+
self.git_remote = git_remote
|
|
183
|
+
self.branch = branch
|
|
184
|
+
self.working_dir = working_dir
|
|
185
|
+
self.do_clone = do_clone
|
|
186
|
+
self.files_changed: Set[str] = set()
|
|
187
|
+
self.validation_schema_path = validation_schema_path
|
|
188
|
+
self.tmp_dir = None
|
|
189
|
+
|
|
190
|
+
def __enter__(self):
|
|
191
|
+
if self.do_clone:
|
|
192
|
+
self.tmp_dir = TemporaryDirectory(dir=self.working_dir)
|
|
193
|
+
self.working_dir = self.tmp_dir.name
|
|
194
|
+
subprocess.check_call(["git", "clone", self.git_remote, self.working_dir])
|
|
195
|
+
self.pwd = os.getcwd()
|
|
196
|
+
os.chdir(self.working_dir)
|
|
197
|
+
if self.branch != "master":
|
|
198
|
+
if self._remote_branch_exists():
|
|
199
|
+
subprocess.check_call(["git", "fetch", "origin", self.branch])
|
|
200
|
+
subprocess.check_call(
|
|
201
|
+
["git", "checkout", "-b", self.branch, f"origin/{self.branch}"]
|
|
202
|
+
)
|
|
203
|
+
else:
|
|
204
|
+
subprocess.check_call(["git", "checkout", "-b", self.branch])
|
|
205
|
+
return self
|
|
206
|
+
|
|
207
|
+
def __exit__(self, type, value, traceback):
|
|
208
|
+
os.chdir(self.pwd)
|
|
209
|
+
if self.tmp_dir:
|
|
210
|
+
self.tmp_dir.cleanup()
|
|
211
|
+
|
|
212
|
+
def _remote_branch_exists(self) -> bool:
|
|
213
|
+
return (
|
|
214
|
+
subprocess.run(
|
|
215
|
+
["git", "ls-remote", "--exit-code", "--heads", "origin", self.branch],
|
|
216
|
+
).returncode
|
|
217
|
+
== 0
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
def write_configs(
|
|
221
|
+
self,
|
|
222
|
+
service: str,
|
|
223
|
+
extra_info: str,
|
|
224
|
+
configs: Dict[str, Any],
|
|
225
|
+
sub_dir: Optional[str] = None,
|
|
226
|
+
comment: Optional[str] = None,
|
|
227
|
+
):
|
|
228
|
+
result = write_auto_config_data(
|
|
229
|
+
service,
|
|
230
|
+
extra_info,
|
|
231
|
+
configs,
|
|
232
|
+
soa_dir=self.working_dir,
|
|
233
|
+
sub_dir=sub_dir,
|
|
234
|
+
comment=comment,
|
|
235
|
+
)
|
|
236
|
+
if result:
|
|
237
|
+
self.files_changed.add(result)
|
|
238
|
+
|
|
239
|
+
def get_existing_configs(
|
|
240
|
+
self, service: str, file_name: str, sub_dir: Optional[str] = None
|
|
241
|
+
) -> Dict[str, Any]:
|
|
242
|
+
config_file_path = f"{sub_dir}/{file_name}" if sub_dir else file_name
|
|
243
|
+
config_file_abs_path = os.path.join(
|
|
244
|
+
os.path.abspath(self.working_dir),
|
|
245
|
+
service,
|
|
246
|
+
config_file_path + ".yaml",
|
|
247
|
+
)
|
|
248
|
+
try:
|
|
249
|
+
return yaml.round_trip_load(open(config_file_abs_path))
|
|
250
|
+
except FileNotFoundError:
|
|
251
|
+
return {}
|
|
252
|
+
|
|
253
|
+
def validate(self):
|
|
254
|
+
return_code = True
|
|
255
|
+
for filepath in self.files_changed:
|
|
256
|
+
# We don't short circuit after a failure so the caller gets info on all the failures
|
|
257
|
+
return_code = (
|
|
258
|
+
validate_auto_config_file(filepath, self.validation_schema_path)
|
|
259
|
+
and return_code
|
|
260
|
+
)
|
|
261
|
+
return return_code
|
|
262
|
+
|
|
263
|
+
def commit_to_remote(self, extra_message: str = ""):
|
|
264
|
+
if not self.validate():
|
|
265
|
+
log.error("Files failed validation, not committing changes")
|
|
266
|
+
raise ValidationError
|
|
267
|
+
|
|
268
|
+
# TODO: more identifying information, like hostname or paasta_tools version?
|
|
269
|
+
message = f"Update to configs from {self.config_source}"
|
|
270
|
+
if extra_message:
|
|
271
|
+
message = f"{message}\n\n{extra_message}"
|
|
272
|
+
|
|
273
|
+
if _commit_files(list(self.files_changed), message):
|
|
274
|
+
_push_to_remote(self.branch)
|
|
275
|
+
else:
|
|
276
|
+
log.info("No files changed, no push required.")
|
|
277
|
+
|
|
278
|
+
def _clamp_recommendations(
|
|
279
|
+
self, merged_recommendation: Dict[str, Any], config: Dict[str, Any]
|
|
280
|
+
) -> Dict[str, Any]:
|
|
281
|
+
clamped_recomendation = copy.deepcopy(merged_recommendation)
|
|
282
|
+
for limit_type, limits in config.get("autotune_limits", {}).items():
|
|
283
|
+
log.debug(f"Processing {limit_type} autotune limits...")
|
|
284
|
+
min_value = limits.get("min")
|
|
285
|
+
max_value = limits.get("max")
|
|
286
|
+
unclamped_resource_value = clamped_recomendation.get(limit_type)
|
|
287
|
+
|
|
288
|
+
# no autotune data present, but min value present
|
|
289
|
+
if not unclamped_resource_value and min_value:
|
|
290
|
+
# use the min value since this is likely an autogenerated service where we know we have a given minimum CPU
|
|
291
|
+
# that we'd like to allocate
|
|
292
|
+
log.debug(
|
|
293
|
+
f"No {limit_type} autotune data found, using autotune limit lower bound ({min_value})."
|
|
294
|
+
)
|
|
295
|
+
clamped_recomendation[limit_type] = min_value
|
|
296
|
+
|
|
297
|
+
# otherwise, we can do some pretty rote clamping of resource values
|
|
298
|
+
elif unclamped_resource_value is not None:
|
|
299
|
+
if min_value and unclamped_resource_value < min_value:
|
|
300
|
+
log.debug(
|
|
301
|
+
f"{limit_type} autotune config under configured limit ({min_value}), using autotune limit lower bound."
|
|
302
|
+
)
|
|
303
|
+
clamped_recomendation[limit_type] = min_value
|
|
304
|
+
if max_value and unclamped_resource_value > max_value:
|
|
305
|
+
log.debug(
|
|
306
|
+
f"{limit_type} autotune config over configured limit ({min_value}), using autotune limit upper bound."
|
|
307
|
+
)
|
|
308
|
+
clamped_recomendation[limit_type] = max_value
|
|
309
|
+
else:
|
|
310
|
+
log.debug(
|
|
311
|
+
f"No {limit_type} autotune data or limits found, will continue using PaaSTA defaults."
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
return clamped_recomendation
|
|
315
|
+
|
|
316
|
+
def merge_recommendations(
|
|
317
|
+
self, recs: Dict[Tuple[str, str], Dict[str, Any]]
|
|
318
|
+
) -> Dict[Tuple[str, str], Dict[str, Any]]:
|
|
319
|
+
"""
|
|
320
|
+
:param recs: Dictionary of (service, instance_type_cluster) -> recommendations.
|
|
321
|
+
NOTE: instance_type_cluster is something like "kubernetes-pnw-prod".
|
|
322
|
+
:returns: a dictionary of the same format, with the previous recommendations merged in and autotune_limits applied.
|
|
323
|
+
"""
|
|
324
|
+
merged_recs = {}
|
|
325
|
+
for (
|
|
326
|
+
service,
|
|
327
|
+
instance_type_cluster,
|
|
328
|
+
), recommendations_by_instance in recs.items():
|
|
329
|
+
log.info(f"Starting to process {service}/{instance_type_cluster}.yaml...")
|
|
330
|
+
log.debug(
|
|
331
|
+
f"Getting current autotune configs for {service}/{instance_type_cluster}.yaml"
|
|
332
|
+
)
|
|
333
|
+
existing_recommendations = self.get_existing_configs(
|
|
334
|
+
service=service,
|
|
335
|
+
file_name=instance_type_cluster,
|
|
336
|
+
sub_dir=AUTO_SOACONFIG_SUBDIR,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
log.debug(
|
|
340
|
+
f"Getting current configs for {service}/{instance_type_cluster}.yaml..."
|
|
341
|
+
)
|
|
342
|
+
# i'm so sorry.
|
|
343
|
+
# basically, we need to make sure that for every autotuned service, we load both kubernetes-
|
|
344
|
+
# and eks- files for the existing configs, as there are services that at any given time will
|
|
345
|
+
# only exist on one of these or may have a mix (and the csv file that we get fakes the current
|
|
346
|
+
# cluster type)
|
|
347
|
+
# NOTE: if an instance appears in both files, the counterpart will always "win" - this
|
|
348
|
+
# should only be possible while an instance is being migrated from one instance type to
|
|
349
|
+
# another
|
|
350
|
+
instance_type, _ = instance_type_cluster.split("-", maxsplit=1)
|
|
351
|
+
existing_configs = {
|
|
352
|
+
# if we upgrate to py3.9 before getting rid of this code, this should use PEP-584-style dict merging
|
|
353
|
+
**self.get_existing_configs(
|
|
354
|
+
service=service,
|
|
355
|
+
file_name=instance_type_cluster,
|
|
356
|
+
),
|
|
357
|
+
**self.get_existing_configs(
|
|
358
|
+
service=service,
|
|
359
|
+
file_name=instance_type_cluster.replace(
|
|
360
|
+
instance_type, INSTANCE_TYPE_COUNTERPARTS.get(instance_type, "")
|
|
361
|
+
),
|
|
362
|
+
),
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
for instance_name, recommendation in recommendations_by_instance.items():
|
|
366
|
+
if instance_name not in existing_configs:
|
|
367
|
+
log.debug(
|
|
368
|
+
f"Skipping config merge for {instance_name} as it no longer exists in {instance_type_cluster}.yaml."
|
|
369
|
+
)
|
|
370
|
+
continue
|
|
371
|
+
|
|
372
|
+
log.debug(
|
|
373
|
+
f"Merging recommendations for {instance_name} in {service}/{AUTO_SOACONFIG_SUBDIR}/{instance_type_cluster}.yaml..."
|
|
374
|
+
)
|
|
375
|
+
existing_recommendations.setdefault(instance_name, {})
|
|
376
|
+
existing_recommendations[instance_name].update(recommendation)
|
|
377
|
+
|
|
378
|
+
existing_recommendations[instance_name] = self._clamp_recommendations(
|
|
379
|
+
merged_recommendation=existing_recommendations[instance_name],
|
|
380
|
+
config=existing_configs[instance_name],
|
|
381
|
+
)
|
|
382
|
+
merged_recs[(service, instance_type_cluster)] = existing_recommendations
|
|
383
|
+
log.info(f"Done processing {service}/{instance_type_cluster}.yaml.")
|
|
384
|
+
|
|
385
|
+
return merged_recs
|
|
File without changes
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env python3.8
|
|
2
|
+
import itertools
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_datetime_from_ts(ts):
|
|
10
|
+
tformat = "%Y-%m-%dT%H:%M:%S.%f"
|
|
11
|
+
return datetime.strptime(ts, tformat)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_deploy_durations_from_file(filename):
|
|
15
|
+
"""
|
|
16
|
+
filename: path to a file to be parsed for datetime data
|
|
17
|
+
The expected input is a paasta service log for the deploy events
|
|
18
|
+
The way I've been fetching them is by running 'internal logreader command' | grep deploy | grep event > filename
|
|
19
|
+
"""
|
|
20
|
+
file_object = open(filename, "r")
|
|
21
|
+
data = sorted(
|
|
22
|
+
[json.loads(line.rstrip("\n")) for line in file_object],
|
|
23
|
+
key=lambda x: get_datetime_from_ts(x["timestamp"]),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
timedeltas = defaultdict(list)
|
|
27
|
+
last_time = dict()
|
|
28
|
+
instance_bitvector = defaultdict(bool) # defaults to False
|
|
29
|
+
|
|
30
|
+
for datum in data:
|
|
31
|
+
time = get_datetime_from_ts(datum["timestamp"])
|
|
32
|
+
instance = datum["instance"]
|
|
33
|
+
if "in progress" in datum["message"] and not instance_bitvector[instance]:
|
|
34
|
+
instance_bitvector[instance] = True
|
|
35
|
+
last_time[instance] = time
|
|
36
|
+
elif "finishing" in datum["message"]:
|
|
37
|
+
instance_bitvector[instance] = False
|
|
38
|
+
timedeltas[instance].append(time - last_time[instance])
|
|
39
|
+
|
|
40
|
+
return timedeltas
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def display_bounce_info(timedeltas):
|
|
44
|
+
"""
|
|
45
|
+
timedeltas: iterable of timedelta objects
|
|
46
|
+
"""
|
|
47
|
+
std = list(sorted(timedeltas))
|
|
48
|
+
print("Median time to bounce: {} seconds".format(std[len(std) / 2]))
|
|
49
|
+
print("10% time to bounce: {}".format(std[len(std) / 10]))
|
|
50
|
+
print("90% time to bounce: {}".format(std[len(std) * 9 / 10]))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def main(filenames):
|
|
54
|
+
for filename in filenames:
|
|
55
|
+
print(filename)
|
|
56
|
+
print("=========================")
|
|
57
|
+
timedeltas = get_deploy_durations_from_file(filename)
|
|
58
|
+
for instance, tdlist in timedeltas.items():
|
|
59
|
+
if timedeltas:
|
|
60
|
+
print("Instance: %s" % instance)
|
|
61
|
+
display_bounce_info(tdlist)
|
|
62
|
+
print("Overall:")
|
|
63
|
+
display_bounce_info(itertools.chain.from_iterable(timedeltas.values()))
|
|
64
|
+
print("=========================")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if __name__ == "__main__":
|
|
68
|
+
main(filenames=sys.argv[1:])
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
diff_names=$(git diff origin/master --name-only)
|
|
5
|
+
schema_touched=$(echo "$diff_names" | grep 'paasta_tools/api/api_docs/oapi.yaml')
|
|
6
|
+
api_touched=$(echo "$diff_names" | grep 'paasta_tools/paastaapi')
|
|
7
|
+
|
|
8
|
+
# this case will only be hit as part of `make test` or someone running pre-commit on
|
|
9
|
+
# all files manually since we've chosen to only run this hook on changes to the schema
|
|
10
|
+
# file
|
|
11
|
+
if [ ! -z "$api_touched" -a -z "$schema_touched" ]; then
|
|
12
|
+
echo "paasta_tools/paastaapi must not be modified manually" >&2
|
|
13
|
+
echo "Please revert your changes:" >&2
|
|
14
|
+
echo -e "$api_touched" >&2
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
make openapi-codegen &>/dev/null
|
|
19
|
+
diff=$(git diff --name-only | grep paasta_tools/paastaapi)
|
|
20
|
+
if [ ! -z "$diff" ]; then
|
|
21
|
+
echo "paasta_tools/paastaapi codegen has a diff, either commit the changes or fix oapi.yaml:" >&2
|
|
22
|
+
echo -e "$diff" >&2
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|