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,76 @@
|
|
|
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
|
+
"""
|
|
16
|
+
PaaSTA resource utilization, etc.
|
|
17
|
+
"""
|
|
18
|
+
from a_sync import block
|
|
19
|
+
from pyramid.response import Response
|
|
20
|
+
from pyramid.view import view_config
|
|
21
|
+
|
|
22
|
+
from paasta_tools.mesos_tools import get_mesos_master
|
|
23
|
+
from paasta_tools.metrics import metastatus_lib
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def parse_filters(filters):
|
|
27
|
+
# The swagger config verifies that the data is in this format
|
|
28
|
+
# "pattern": "(.*):(.*,)*(.*)"
|
|
29
|
+
if filters is None:
|
|
30
|
+
return {}
|
|
31
|
+
f = {s[0]: s[1] for s in [e.split(":") for e in filters]}
|
|
32
|
+
f = {k: v.split(",") for k, v in f.items()}
|
|
33
|
+
return f
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@view_config(route_name="resources.utilization", request_method="GET", renderer="json")
|
|
37
|
+
def resources_utilization(request):
|
|
38
|
+
master = get_mesos_master()
|
|
39
|
+
mesos_state = block(master.state)
|
|
40
|
+
|
|
41
|
+
groupings = request.swagger_data.get("groupings", ["superregion"])
|
|
42
|
+
# swagger actually makes the key None if it's not set
|
|
43
|
+
if groupings is None:
|
|
44
|
+
groupings = ["superregion"]
|
|
45
|
+
grouping_function = metastatus_lib.key_func_for_attribute_multi(groupings)
|
|
46
|
+
sorting_function = metastatus_lib.sort_func_for_attributes(groupings)
|
|
47
|
+
|
|
48
|
+
filters = request.swagger_data.get("filter", [])
|
|
49
|
+
filters = parse_filters(filters)
|
|
50
|
+
filter_funcs = [
|
|
51
|
+
metastatus_lib.make_filter_slave_func(attr, vals)
|
|
52
|
+
for attr, vals in filters.items()
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
resource_info_dict = metastatus_lib.get_resource_utilization_by_grouping(
|
|
56
|
+
grouping_func=grouping_function,
|
|
57
|
+
mesos_state=mesos_state,
|
|
58
|
+
filters=filter_funcs,
|
|
59
|
+
sort_func=sorting_function,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
response_body = []
|
|
63
|
+
for k, v in resource_info_dict.items():
|
|
64
|
+
group = {"groupings": {}}
|
|
65
|
+
for grouping, value in k:
|
|
66
|
+
group["groupings"][grouping] = value
|
|
67
|
+
for resource, value in v["total"]._asdict().items():
|
|
68
|
+
group[resource] = {"total": value}
|
|
69
|
+
for resource, value in v["free"]._asdict().items():
|
|
70
|
+
group[resource]["free"] = value
|
|
71
|
+
for resource in v["free"]._fields:
|
|
72
|
+
group[resource]["used"] = group[resource]["total"] - group[resource]["free"]
|
|
73
|
+
|
|
74
|
+
response_body.append(group)
|
|
75
|
+
|
|
76
|
+
return Response(json_body=response_body, status_code=200)
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
"""
|
|
16
|
+
PaaSTA service list (instances) etc.
|
|
17
|
+
"""
|
|
18
|
+
from pyramid.view import view_config
|
|
19
|
+
|
|
20
|
+
from paasta_tools.api import settings
|
|
21
|
+
from paasta_tools.utils import get_services_for_cluster
|
|
22
|
+
from paasta_tools.utils import list_all_instances_for_service
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@view_config(route_name="service.list", request_method="GET", renderer="json")
|
|
26
|
+
def list_instances(request):
|
|
27
|
+
service = request.swagger_data.get("service")
|
|
28
|
+
instances = list_all_instances_for_service(service, clusters=[settings.cluster])
|
|
29
|
+
return {"instances": list(instances)}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@view_config(route_name="services", request_method="GET", renderer="json")
|
|
33
|
+
def list_services_for_cluster(request):
|
|
34
|
+
services_for_cluster = get_services_for_cluster(cluster=settings.cluster)
|
|
35
|
+
return {"services": services_for_cluster}
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
"""
|
|
16
|
+
PaaSTA service list (instances) etc.
|
|
17
|
+
"""
|
|
18
|
+
from pyramid.view import view_config
|
|
19
|
+
|
|
20
|
+
from paasta_tools import __version__
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@view_config(route_name="version", request_method="GET", renderer="json")
|
|
24
|
+
def version(request):
|
|
25
|
+
return __version__
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/opt/venvs/paasta-tools/bin/python
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
from filecmp import cmp
|
|
5
|
+
from shutil import copy
|
|
6
|
+
from subprocess import CalledProcessError
|
|
7
|
+
from subprocess import run
|
|
8
|
+
from traceback import print_exc
|
|
9
|
+
|
|
10
|
+
APPLIED_DIRECTORY = ".applied"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# This script expects the KUBECONFIG environment variable to be set correctly
|
|
14
|
+
def main(puppet_resource_root: str) -> int:
|
|
15
|
+
exit_code = 0
|
|
16
|
+
applied_resource_root = os.path.join(puppet_resource_root, APPLIED_DIRECTORY)
|
|
17
|
+
|
|
18
|
+
# Loop through everything in the puppet resource path
|
|
19
|
+
for root, dirs, files in os.walk(puppet_resource_root):
|
|
20
|
+
# modifying the 'dirs' variable in-place will update the order that os.walk visits things
|
|
21
|
+
if APPLIED_DIRECTORY in dirs:
|
|
22
|
+
dirs.remove(APPLIED_DIRECTORY)
|
|
23
|
+
dirs.sort() # Need to apply things in the correct order
|
|
24
|
+
|
|
25
|
+
# Check to see if there's a difference between what Puppet created and
|
|
26
|
+
# what's been previously applied
|
|
27
|
+
for filename in sorted([f for f in files if f.endswith(".yaml")]):
|
|
28
|
+
path = os.path.join(root, filename)
|
|
29
|
+
applied_path = os.path.join(
|
|
30
|
+
applied_resource_root, os.path.relpath(path, puppet_resource_root)
|
|
31
|
+
)
|
|
32
|
+
print(f"comparing {path} and {applied_path}")
|
|
33
|
+
if not os.path.exists(applied_path) or not cmp(
|
|
34
|
+
path, applied_path, shallow=False
|
|
35
|
+
):
|
|
36
|
+
# This is idempotent; if something gets out of sync and a resource gets applied
|
|
37
|
+
# a second time, kubectl just won't make any changes
|
|
38
|
+
try:
|
|
39
|
+
run(["kubectl", "apply", "-f", path], check=True)
|
|
40
|
+
os.makedirs(os.path.dirname(applied_path), exist_ok=True)
|
|
41
|
+
copy(path, applied_path)
|
|
42
|
+
except CalledProcessError:
|
|
43
|
+
print(f"There was a problem applying {path}:\n")
|
|
44
|
+
print_exc(
|
|
45
|
+
file=sys.stdout
|
|
46
|
+
) # keep all messages on the same stream so they're in order
|
|
47
|
+
exit_code = 1
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
# Loop through all the files that have been previously applied and see
|
|
51
|
+
# if Puppet has removed any of them
|
|
52
|
+
for root, dirs, files in os.walk(applied_resource_root):
|
|
53
|
+
dirs.sort(reverse=True) # for deleting things, we need to go in reverse order
|
|
54
|
+
for filename in sorted([f for f in files if f.endswith(".yaml")], reverse=True):
|
|
55
|
+
path = os.path.join(root, filename)
|
|
56
|
+
puppet_path = os.path.join(
|
|
57
|
+
puppet_resource_root, os.path.relpath(path, applied_resource_root)
|
|
58
|
+
)
|
|
59
|
+
if not os.path.exists(puppet_path):
|
|
60
|
+
print(f"Deleting resource {path}...")
|
|
61
|
+
try:
|
|
62
|
+
run(
|
|
63
|
+
["kubectl", "delete", "--ignore-not-found=true", "-f", path],
|
|
64
|
+
check=True,
|
|
65
|
+
)
|
|
66
|
+
os.remove(path)
|
|
67
|
+
except CalledProcessError:
|
|
68
|
+
print(f"There was a problem deleting {path}:\n")
|
|
69
|
+
print_exc(
|
|
70
|
+
file=sys.stdout
|
|
71
|
+
) # keep all messages on the same stream so they're in order
|
|
72
|
+
exit_code = 1
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
return exit_code
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
if __name__ == "__main__":
|
|
79
|
+
sys.exit(main(sys.argv[1]))
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import functools
|
|
3
|
+
import time
|
|
4
|
+
import weakref
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from typing import AsyncIterable
|
|
7
|
+
from typing import Awaitable
|
|
8
|
+
from typing import Callable
|
|
9
|
+
from typing import Dict
|
|
10
|
+
from typing import List
|
|
11
|
+
from typing import Optional
|
|
12
|
+
from typing import TypeVar
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
T = TypeVar("T")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# NOTE: this method is not thread-safe due to lack of locking while checking
|
|
19
|
+
# and updating the cache
|
|
20
|
+
def async_ttl_cache(
|
|
21
|
+
ttl: Optional[float] = 300,
|
|
22
|
+
cleanup_self: bool = False,
|
|
23
|
+
*,
|
|
24
|
+
cache: Optional[Dict] = None,
|
|
25
|
+
) -> Callable[
|
|
26
|
+
[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]] # wrapped # inner
|
|
27
|
+
]:
|
|
28
|
+
async def call_or_get_from_cache(cache, async_func, args_for_key, args, kwargs):
|
|
29
|
+
# Please note that anything which is put into `key` will be in the
|
|
30
|
+
# cache forever, potentially causing memory leaks. The most common
|
|
31
|
+
# case is the `self` arg pointing to a huge object. To mitigate that
|
|
32
|
+
# we're using `args_for_key`, which is supposed not contain any huge
|
|
33
|
+
# objects.
|
|
34
|
+
key = functools._make_key(args_for_key, kwargs, typed=False)
|
|
35
|
+
try:
|
|
36
|
+
future, last_update = cache[key]
|
|
37
|
+
if ttl is not None and time.time() - last_update > ttl:
|
|
38
|
+
raise KeyError
|
|
39
|
+
except KeyError:
|
|
40
|
+
future = asyncio.ensure_future(async_func(*args, **kwargs))
|
|
41
|
+
# set the timestamp to +infinity so that we always wait on the in-flight request.
|
|
42
|
+
cache[key] = (future, float("Inf"))
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
value = await future
|
|
46
|
+
except Exception:
|
|
47
|
+
# Only update the cache if it's the same future we awaited and
|
|
48
|
+
# it hasn't already been updated by another coroutine
|
|
49
|
+
# Note also that we use get() in case the key was deleted from the
|
|
50
|
+
# cache by another coroutine
|
|
51
|
+
if cache.get(key) == (future, float("Inf")):
|
|
52
|
+
del cache[key]
|
|
53
|
+
raise
|
|
54
|
+
else:
|
|
55
|
+
if cache.get(key) == (future, float("Inf")):
|
|
56
|
+
cache[key] = (future, time.time())
|
|
57
|
+
return value
|
|
58
|
+
|
|
59
|
+
if cleanup_self:
|
|
60
|
+
instance_caches: Dict = cache if cache is not None else defaultdict(dict)
|
|
61
|
+
|
|
62
|
+
def on_delete(w):
|
|
63
|
+
del instance_caches[w]
|
|
64
|
+
|
|
65
|
+
def outer(wrapped):
|
|
66
|
+
@functools.wraps(wrapped)
|
|
67
|
+
async def inner(self, *args, **kwargs):
|
|
68
|
+
w = weakref.ref(self, on_delete)
|
|
69
|
+
self_cache = instance_caches[w]
|
|
70
|
+
return await call_or_get_from_cache(
|
|
71
|
+
self_cache, wrapped, args, (self,) + args, kwargs
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return inner
|
|
75
|
+
|
|
76
|
+
else:
|
|
77
|
+
cache2: Dict = (
|
|
78
|
+
cache if cache is not None else {}
|
|
79
|
+
) # Should be Dict[Any, T] but that doesn't work.
|
|
80
|
+
|
|
81
|
+
def outer(wrapped):
|
|
82
|
+
@functools.wraps(wrapped)
|
|
83
|
+
async def inner(*args, **kwargs):
|
|
84
|
+
return await call_or_get_from_cache(cache2, wrapped, args, args, kwargs)
|
|
85
|
+
|
|
86
|
+
return inner
|
|
87
|
+
|
|
88
|
+
return outer
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
async def aiter_to_list(
|
|
92
|
+
aiter: AsyncIterable[T],
|
|
93
|
+
) -> List[T]:
|
|
94
|
+
return [x async for x in aiter]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def async_timeout(
|
|
98
|
+
seconds: int = 10,
|
|
99
|
+
) -> Callable[
|
|
100
|
+
[Callable[..., Awaitable[T]]], Callable[..., Awaitable[T]] # wrapped # inner
|
|
101
|
+
]:
|
|
102
|
+
def outer(wrapped):
|
|
103
|
+
@functools.wraps(wrapped)
|
|
104
|
+
async def inner(*args, **kwargs):
|
|
105
|
+
return await asyncio.wait_for(wrapped(*args, **kwargs), timeout=seconds)
|
|
106
|
+
|
|
107
|
+
return inner
|
|
108
|
+
|
|
109
|
+
return outer
|
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# Copyright 2015-2019 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 logging
|
|
16
|
+
import time
|
|
17
|
+
from collections import namedtuple
|
|
18
|
+
|
|
19
|
+
from kazoo.exceptions import NoNodeError
|
|
20
|
+
|
|
21
|
+
from paasta_tools.long_running_service_tools import ZK_PAUSE_AUTOSCALE_PATH
|
|
22
|
+
from paasta_tools.utils import ZookeeperPool
|
|
23
|
+
|
|
24
|
+
ServiceAutoscalingInfo = namedtuple(
|
|
25
|
+
"ServiceAutoscalingInfo",
|
|
26
|
+
[
|
|
27
|
+
"current_instances",
|
|
28
|
+
"max_instances",
|
|
29
|
+
"min_instances",
|
|
30
|
+
"current_utilization",
|
|
31
|
+
"target_instances",
|
|
32
|
+
],
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
SERVICE_METRICS_PROVIDER_KEY = "metrics_providers"
|
|
37
|
+
DECISION_POLICY_KEY = "decision_policy"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
log = logging.getLogger(__name__)
|
|
41
|
+
log.addHandler(logging.NullHandler())
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def autoscaling_is_paused():
|
|
45
|
+
with ZookeeperPool() as zk:
|
|
46
|
+
try:
|
|
47
|
+
pause_until = zk.get(ZK_PAUSE_AUTOSCALE_PATH)[0].decode("utf8")
|
|
48
|
+
pause_until = float(pause_until)
|
|
49
|
+
except (NoNodeError, ValueError, AttributeError):
|
|
50
|
+
pause_until = 0
|
|
51
|
+
|
|
52
|
+
remaining = pause_until - time.time()
|
|
53
|
+
if remaining >= 0:
|
|
54
|
+
log.debug("Autoscaling is paused for {} more seconds".format(str(remaining)))
|
|
55
|
+
return True
|
|
56
|
+
else:
|
|
57
|
+
return False
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from paasta_tools.autoscaling.utils import get_autoscaling_component
|
|
2
|
+
from paasta_tools.autoscaling.utils import register_autoscaling_component
|
|
3
|
+
from paasta_tools.long_running_service_tools import (
|
|
4
|
+
DEFAULT_UWSGI_AUTOSCALING_MOVING_AVERAGE_WINDOW,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
FORECAST_POLICY_KEY = "forecast_policy"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_forecast_policy(name):
|
|
12
|
+
"""
|
|
13
|
+
Returns a forecast policy matching the given name. Only used by decision policies that try to forecast load, like
|
|
14
|
+
the proportional decision policy.
|
|
15
|
+
"""
|
|
16
|
+
return get_autoscaling_component(name, FORECAST_POLICY_KEY)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@register_autoscaling_component("current", FORECAST_POLICY_KEY)
|
|
20
|
+
def current_value_forecast_policy(historical_load, **kwargs):
|
|
21
|
+
"""A prediction policy that assumes that the value any time in the future will be the same as the current value.
|
|
22
|
+
|
|
23
|
+
:param historical_load: a list of (timestamp, value)s, where timestamp is a unix timestamp and value is load.
|
|
24
|
+
"""
|
|
25
|
+
return historical_load[-1][1]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def window_historical_load(historical_load, window_begin, window_end):
|
|
29
|
+
"""Filter historical_load down to just the datapoints lying between times window_begin and window_end, inclusive."""
|
|
30
|
+
filtered = []
|
|
31
|
+
for timestamp, value in historical_load:
|
|
32
|
+
if timestamp >= window_begin and timestamp <= window_end:
|
|
33
|
+
filtered.append((timestamp, value))
|
|
34
|
+
return filtered
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def trailing_window_historical_load(historical_load, window_size):
|
|
38
|
+
window_end, _ = historical_load[-1]
|
|
39
|
+
window_begin = window_end - window_size
|
|
40
|
+
return window_historical_load(historical_load, window_begin, window_end)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@register_autoscaling_component("moving_average", FORECAST_POLICY_KEY)
|
|
44
|
+
def moving_average_forecast_policy(
|
|
45
|
+
historical_load,
|
|
46
|
+
moving_average_window_seconds=DEFAULT_UWSGI_AUTOSCALING_MOVING_AVERAGE_WINDOW,
|
|
47
|
+
**kwargs,
|
|
48
|
+
):
|
|
49
|
+
"""Does a simple average of all historical load data points within the moving average window. Weights all data
|
|
50
|
+
points within the window equally."""
|
|
51
|
+
|
|
52
|
+
windowed_data = trailing_window_historical_load(
|
|
53
|
+
historical_load, moving_average_window_seconds
|
|
54
|
+
)
|
|
55
|
+
windowed_values = [value for timestamp, value in windowed_data]
|
|
56
|
+
return sum(windowed_values) / len(windowed_values)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@register_autoscaling_component("linreg", FORECAST_POLICY_KEY)
|
|
60
|
+
def linreg_forecast_policy(
|
|
61
|
+
historical_load,
|
|
62
|
+
linreg_window_seconds,
|
|
63
|
+
linreg_extrapolation_seconds,
|
|
64
|
+
linreg_default_slope=0,
|
|
65
|
+
**kwargs,
|
|
66
|
+
):
|
|
67
|
+
"""Does a linear regression on the load data within the last linreg_window_seconds. For every time delta in
|
|
68
|
+
linreg_extrapolation_seconds, forecasts the value at that time delta from now, and returns the maximum of these
|
|
69
|
+
predicted values. (With linear extrapolation, it doesn't make sense to forecast at more than two points, as the max
|
|
70
|
+
load will always be at the first or last time delta.)
|
|
71
|
+
|
|
72
|
+
:param linreg_window_seconds: Consider all data from this many seconds ago until now.
|
|
73
|
+
:param linreg_extrapolation_seconds: A list of floats representing a number of seconds in the future at which to
|
|
74
|
+
predict the load. The highest prediction will be returned.
|
|
75
|
+
:param linreg_default_slope: If there is only one data point within the window, the equation for slope is undefined,
|
|
76
|
+
so we use this value (expressed in load/second) for prediction instead. Default is
|
|
77
|
+
0.
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
window = trailing_window_historical_load(historical_load, linreg_window_seconds)
|
|
82
|
+
|
|
83
|
+
loads = [load for timestamp, load in window]
|
|
84
|
+
times = [timestamp for timestamp, load in window]
|
|
85
|
+
|
|
86
|
+
mean_time = sum(times) / len(times)
|
|
87
|
+
mean_load = sum(loads) / len(loads)
|
|
88
|
+
|
|
89
|
+
if len(window) > 1:
|
|
90
|
+
slope = sum((t - mean_time) * (l - mean_load) for t, l in window) / sum(
|
|
91
|
+
(t - mean_time) ** 2 for t in times
|
|
92
|
+
)
|
|
93
|
+
else:
|
|
94
|
+
slope = linreg_default_slope
|
|
95
|
+
|
|
96
|
+
intercept = mean_load - slope * mean_time
|
|
97
|
+
|
|
98
|
+
def predict(timestamp):
|
|
99
|
+
return slope * timestamp + intercept
|
|
100
|
+
|
|
101
|
+
if isinstance(linreg_extrapolation_seconds, (int, float)):
|
|
102
|
+
linreg_extrapolation_seconds = [linreg_extrapolation_seconds]
|
|
103
|
+
|
|
104
|
+
now, _ = historical_load[-1]
|
|
105
|
+
forecasted_values = [predict(now + delta) for delta in linreg_extrapolation_seconds]
|
|
106
|
+
return max(forecasted_values)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
from paasta_tools.kubernetes.application.controller_wrappers import (
|
|
3
|
+
get_application_wrapper,
|
|
4
|
+
)
|
|
5
|
+
from paasta_tools.kubernetes_tools import KubeClient
|
|
6
|
+
from paasta_tools.kubernetes_tools import KubernetesDeploymentConfig
|
|
7
|
+
from paasta_tools.paasta_service_config_loader import PaastaServiceConfigLoader
|
|
8
|
+
from paasta_tools.utils import get_services_for_cluster
|
|
9
|
+
from paasta_tools.utils import load_system_paasta_config
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> None:
|
|
13
|
+
system_paasta_config = load_system_paasta_config()
|
|
14
|
+
|
|
15
|
+
kube_client = KubeClient()
|
|
16
|
+
|
|
17
|
+
services = {
|
|
18
|
+
service
|
|
19
|
+
for service, instance in get_services_for_cluster(
|
|
20
|
+
cluster=system_paasta_config.get_cluster(), instance_type="kubernetes"
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
for service in services:
|
|
25
|
+
pscl = PaastaServiceConfigLoader(service=service, load_deployments=False)
|
|
26
|
+
for instance_config in pscl.instance_configs(
|
|
27
|
+
cluster=system_paasta_config.get_cluster(),
|
|
28
|
+
instance_type_class=KubernetesDeploymentConfig,
|
|
29
|
+
):
|
|
30
|
+
max_instances = instance_config.get_max_instances()
|
|
31
|
+
if max_instances is not None:
|
|
32
|
+
formatted_application = instance_config.format_kubernetes_app()
|
|
33
|
+
formatted_application.spec.replicas = max_instances
|
|
34
|
+
wrapper = get_application_wrapper(formatted_application)
|
|
35
|
+
wrapper.soa_config = instance_config
|
|
36
|
+
print(f"Scaling up {service}.{instance_config.instance}")
|
|
37
|
+
wrapper.update(kube_client)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == "__main__":
|
|
41
|
+
main()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
import pytz
|
|
6
|
+
from tzlocal import get_localzone as tzlocal_get_localzone
|
|
7
|
+
|
|
8
|
+
import paasta_tools.paastaapi.models as paastamodels
|
|
9
|
+
from paasta_tools.api import client
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_localzone():
|
|
13
|
+
if "TZ" in os.environ:
|
|
14
|
+
return pytz.timezone(os.environ["TZ"])
|
|
15
|
+
else:
|
|
16
|
+
return tzlocal_get_localzone()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def print_paused_message(pause_time):
|
|
20
|
+
local_tz = get_localzone()
|
|
21
|
+
paused_readable = local_tz.localize(datetime.fromtimestamp(pause_time)).strftime(
|
|
22
|
+
"%F %H:%M:%S %Z"
|
|
23
|
+
)
|
|
24
|
+
print(f"Service autoscaler is paused until {paused_readable}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_service_autoscale_pause_time(cluster):
|
|
28
|
+
api = client.get_paasta_oapi_client(cluster=cluster, http_res=True)
|
|
29
|
+
if not api:
|
|
30
|
+
print("Could not connect to paasta api. Maybe you misspelled the cluster?")
|
|
31
|
+
return 1
|
|
32
|
+
pause_time, status, _ = api.default.get_service_autoscaler_pause(
|
|
33
|
+
_return_http_data_only=False
|
|
34
|
+
)
|
|
35
|
+
if status == 500:
|
|
36
|
+
print("Could not connect to zookeeper server")
|
|
37
|
+
return 2
|
|
38
|
+
|
|
39
|
+
pause_time = float(pause_time)
|
|
40
|
+
if pause_time < time.time():
|
|
41
|
+
print("Service autoscaler is not paused")
|
|
42
|
+
else:
|
|
43
|
+
print_paused_message(pause_time)
|
|
44
|
+
|
|
45
|
+
return 0
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def update_service_autoscale_pause_time(cluster, mins):
|
|
49
|
+
api = client.get_paasta_oapi_client(cluster=cluster, http_res=True)
|
|
50
|
+
if not api:
|
|
51
|
+
print("Could not connect to paasta api. Maybe you misspelled the cluster?")
|
|
52
|
+
return 1
|
|
53
|
+
res, status, _ = api.default.update_service_autoscaler_pause(
|
|
54
|
+
paastamodels.InlineObject(minutes=int(mins)), _return_http_data_only=False
|
|
55
|
+
)
|
|
56
|
+
if status == 500:
|
|
57
|
+
print("Could not connect to zookeeper server")
|
|
58
|
+
return 2
|
|
59
|
+
|
|
60
|
+
print(f"Service autoscaler is paused for {mins} minutes")
|
|
61
|
+
return 0
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def delete_service_autoscale_pause_time(cluster):
|
|
65
|
+
api = client.get_paasta_oapi_client(cluster=cluster, http_res=True)
|
|
66
|
+
if not api:
|
|
67
|
+
print("Could not connect to paasta api. Maybe you misspelled the cluster?")
|
|
68
|
+
return 1
|
|
69
|
+
res, status, _ = api.default.delete_service_autoscaler_pause(
|
|
70
|
+
_return_http_data_only=False
|
|
71
|
+
)
|
|
72
|
+
if status == 500:
|
|
73
|
+
print("Could not connect to zookeeper server")
|
|
74
|
+
return 2
|
|
75
|
+
|
|
76
|
+
print("Service autoscaler is unpaused")
|
|
77
|
+
return 0
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
from collections import defaultdict
|
|
16
|
+
from typing import Callable
|
|
17
|
+
from typing import Dict
|
|
18
|
+
from typing import List
|
|
19
|
+
from typing import Optional
|
|
20
|
+
from typing import TypedDict
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_autoscaling_components: Dict[str, Dict[str, Callable]] = defaultdict(dict)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def register_autoscaling_component(name, method_type):
|
|
27
|
+
def outer(autoscaling_method):
|
|
28
|
+
_autoscaling_components[method_type][name] = autoscaling_method
|
|
29
|
+
return autoscaling_method
|
|
30
|
+
|
|
31
|
+
return outer
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_autoscaling_component(name, method_type):
|
|
35
|
+
return _autoscaling_components[method_type][name]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MetricsProviderDict(TypedDict, total=False):
|
|
39
|
+
type: str
|
|
40
|
+
decision_policy: str
|
|
41
|
+
setpoint: float
|
|
42
|
+
desired_active_requests_per_replica: int
|
|
43
|
+
forecast_policy: Optional[str]
|
|
44
|
+
moving_average_window_seconds: Optional[int]
|
|
45
|
+
use_resource_metrics: bool
|
|
46
|
+
prometheus_adapter_config: Optional[dict]
|
|
47
|
+
max_instances_alert_threshold: float
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class AutoscalingParamsDict(TypedDict, total=False):
|
|
51
|
+
metrics_providers: List[MetricsProviderDict]
|
|
52
|
+
scaledown_policies: Optional[dict]
|