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,106 @@
|
|
|
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
|
+
Client interface for the Paasta rest api.
|
|
17
|
+
"""
|
|
18
|
+
import logging
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from typing import Optional
|
|
21
|
+
from typing import Type
|
|
22
|
+
from urllib.parse import ParseResult
|
|
23
|
+
from urllib.parse import urlparse
|
|
24
|
+
|
|
25
|
+
import paasta_tools.paastaapi.apis as paastaapis
|
|
26
|
+
from paasta_tools import paastaapi
|
|
27
|
+
from paasta_tools.utils import load_system_paasta_config
|
|
28
|
+
from paasta_tools.utils import SystemPaastaConfig
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
log = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class PaastaOApiClient:
|
|
36
|
+
autoscaler: paastaapis.AutoscalerApi
|
|
37
|
+
default: paastaapis.DefaultApi
|
|
38
|
+
resources: paastaapis.ResourcesApi
|
|
39
|
+
service: paastaapis.ServiceApi
|
|
40
|
+
remote_run: paastaapis.RemoteRunApi
|
|
41
|
+
api_error: Type[paastaapi.ApiException]
|
|
42
|
+
connection_error: Type[paastaapi.ApiException]
|
|
43
|
+
timeout_error: Type[paastaapi.ApiException]
|
|
44
|
+
request_error: Type[paastaapi.ApiException]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_paasta_oapi_client_by_url(
|
|
48
|
+
parsed_url: ParseResult,
|
|
49
|
+
cert_file: Optional[str] = None,
|
|
50
|
+
key_file: Optional[str] = None,
|
|
51
|
+
ssl_ca_cert: Optional[str] = None,
|
|
52
|
+
auth_token: str = "",
|
|
53
|
+
) -> PaastaOApiClient:
|
|
54
|
+
server_variables = dict(scheme=parsed_url.scheme, host=parsed_url.netloc)
|
|
55
|
+
config = paastaapi.Configuration(
|
|
56
|
+
server_variables=server_variables,
|
|
57
|
+
discard_unknown_keys=True,
|
|
58
|
+
)
|
|
59
|
+
config.cert_file = cert_file
|
|
60
|
+
config.key_file = key_file
|
|
61
|
+
config.ssl_ca_cert = ssl_ca_cert
|
|
62
|
+
|
|
63
|
+
client = paastaapi.ApiClient(configuration=config)
|
|
64
|
+
# PAASTA-18005: Adds default timeout to paastaapi client
|
|
65
|
+
client.rest_client.pool_manager.connection_pool_kw[
|
|
66
|
+
"timeout"
|
|
67
|
+
] = load_system_paasta_config().get_api_client_timeout()
|
|
68
|
+
# SEC-19555: support auth in PaaSTA APIs
|
|
69
|
+
if auth_token:
|
|
70
|
+
client.set_default_header("Authorization", f"Bearer {auth_token}")
|
|
71
|
+
return PaastaOApiClient(
|
|
72
|
+
autoscaler=paastaapis.AutoscalerApi(client),
|
|
73
|
+
default=paastaapis.DefaultApi(client),
|
|
74
|
+
resources=paastaapis.ResourcesApi(client),
|
|
75
|
+
service=paastaapis.ServiceApi(client),
|
|
76
|
+
remote_run=paastaapis.RemoteRunApi(client),
|
|
77
|
+
api_error=paastaapi.ApiException,
|
|
78
|
+
connection_error=paastaapi.ApiException,
|
|
79
|
+
timeout_error=paastaapi.ApiException,
|
|
80
|
+
request_error=paastaapi.ApiException,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_paasta_oapi_client(
|
|
85
|
+
cluster: str = None,
|
|
86
|
+
system_paasta_config: SystemPaastaConfig = None,
|
|
87
|
+
http_res: bool = False,
|
|
88
|
+
auth_token: str = "",
|
|
89
|
+
) -> Optional[PaastaOApiClient]:
|
|
90
|
+
if not system_paasta_config:
|
|
91
|
+
system_paasta_config = load_system_paasta_config()
|
|
92
|
+
|
|
93
|
+
if not cluster:
|
|
94
|
+
cluster = system_paasta_config.get_cluster()
|
|
95
|
+
|
|
96
|
+
api_endpoints = system_paasta_config.get_api_endpoints()
|
|
97
|
+
if cluster not in api_endpoints:
|
|
98
|
+
log.error("Cluster %s not in paasta-api endpoints config", cluster)
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
parsed = urlparse(api_endpoints[cluster])
|
|
102
|
+
cert_file = key_file = ssl_ca_cert = None
|
|
103
|
+
|
|
104
|
+
return get_paasta_oapi_client_by_url(
|
|
105
|
+
parsed, cert_file, key_file, ssl_ca_cert, auth_token
|
|
106
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Copyright 2015-2016 Yelp Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
"""
|
|
15
|
+
Settings of the paasta-api server.
|
|
16
|
+
"""
|
|
17
|
+
import os
|
|
18
|
+
from typing import Optional
|
|
19
|
+
|
|
20
|
+
from paasta_tools import utils
|
|
21
|
+
from paasta_tools.kubernetes_tools import KubeClient
|
|
22
|
+
from paasta_tools.utils import DEFAULT_SOA_DIR
|
|
23
|
+
from paasta_tools.utils import SystemPaastaConfig
|
|
24
|
+
|
|
25
|
+
soa_dir: str = os.environ.get("PAASTA_API_SOA_DIR", DEFAULT_SOA_DIR)
|
|
26
|
+
|
|
27
|
+
# The following `type: ignore` mypy hints are there because variables below de
|
|
28
|
+
# juro have `Optional[T]` type, but de facto are always initialized to a value
|
|
29
|
+
# of the corresponding type after the application is started.
|
|
30
|
+
cluster: str = None # type: ignore
|
|
31
|
+
hostname: str = utils.get_hostname()
|
|
32
|
+
kubernetes_client: Optional[KubeClient] = None
|
|
33
|
+
system_paasta_config: Optional[SystemPaastaConfig]
|
|
@@ -0,0 +1,125 @@
|
|
|
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 json
|
|
16
|
+
import logging
|
|
17
|
+
import os
|
|
18
|
+
from typing import NamedTuple
|
|
19
|
+
from typing import Optional
|
|
20
|
+
|
|
21
|
+
import cachetools.func
|
|
22
|
+
import pyramid
|
|
23
|
+
import requests
|
|
24
|
+
from pyramid.config import Configurator
|
|
25
|
+
from pyramid.httpexceptions import HTTPForbidden
|
|
26
|
+
from pyramid.registry import Registry
|
|
27
|
+
from pyramid.request import Request
|
|
28
|
+
from pyramid.response import Response
|
|
29
|
+
|
|
30
|
+
from paasta_tools.api.tweens import Handler
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
AUTH_CACHE_SIZE = 50000
|
|
35
|
+
AUTH_CACHE_TTL = 30 * 60
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class AuthorizationOutcome(NamedTuple):
|
|
39
|
+
authorized: bool
|
|
40
|
+
reason: str
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class AuthTweenFactory:
|
|
44
|
+
def __init__(self, handler: Handler, registry: Registry) -> None:
|
|
45
|
+
self.handler = handler
|
|
46
|
+
self.registry = registry
|
|
47
|
+
self.enforce = bool(os.getenv("PAASTA_API_AUTH_ENFORCE", ""))
|
|
48
|
+
self.endpoint = os.getenv("PAASTA_API_AUTH_ENDPOINT")
|
|
49
|
+
self.session = requests.Session()
|
|
50
|
+
|
|
51
|
+
def __call__(self, request: Request) -> Response:
|
|
52
|
+
"""
|
|
53
|
+
Extracts relevant metadata from request, and checks if it is authorized
|
|
54
|
+
"""
|
|
55
|
+
token = request.headers.get("Authorization", "").strip()
|
|
56
|
+
token = token.split()[-1] if token else "" # removes "Bearer" prefix
|
|
57
|
+
auth_outcome = self.is_request_authorized(
|
|
58
|
+
request.path,
|
|
59
|
+
token,
|
|
60
|
+
request.method,
|
|
61
|
+
request.swagger_data.get("service", None),
|
|
62
|
+
)
|
|
63
|
+
if self.enforce and not auth_outcome.authorized:
|
|
64
|
+
return HTTPForbidden(
|
|
65
|
+
body=json.dumps({"reason": auth_outcome.reason}),
|
|
66
|
+
headers={"X-Auth-Failure-Reason": auth_outcome.reason},
|
|
67
|
+
content_type="application/json",
|
|
68
|
+
charset="utf-8",
|
|
69
|
+
)
|
|
70
|
+
return self.handler(request)
|
|
71
|
+
|
|
72
|
+
@cachetools.func.ttl_cache(maxsize=AUTH_CACHE_SIZE, ttl=AUTH_CACHE_TTL)
|
|
73
|
+
def is_request_authorized(
|
|
74
|
+
self,
|
|
75
|
+
path: str,
|
|
76
|
+
token: str,
|
|
77
|
+
method: str,
|
|
78
|
+
service: Optional[str],
|
|
79
|
+
) -> AuthorizationOutcome:
|
|
80
|
+
"""Check if API request is authorized
|
|
81
|
+
|
|
82
|
+
:param str path: API path
|
|
83
|
+
:param str token: authentication token
|
|
84
|
+
:param str method: http method
|
|
85
|
+
:return: auth outcome
|
|
86
|
+
"""
|
|
87
|
+
try:
|
|
88
|
+
response = self.session.post(
|
|
89
|
+
url=self.endpoint,
|
|
90
|
+
json={
|
|
91
|
+
"input": {
|
|
92
|
+
"path": path,
|
|
93
|
+
"backend": "paasta",
|
|
94
|
+
"token": token,
|
|
95
|
+
"method": method,
|
|
96
|
+
"service": service,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
timeout=2,
|
|
100
|
+
).json()
|
|
101
|
+
except Exception as e:
|
|
102
|
+
logger.exception(f"Issue communicating with auth endpoint: {e}")
|
|
103
|
+
return AuthorizationOutcome(False, "Auth backend error")
|
|
104
|
+
|
|
105
|
+
auth_result_allowed = response.get("result", {}).get("allowed")
|
|
106
|
+
if auth_result_allowed is None:
|
|
107
|
+
return AuthorizationOutcome(False, "Malformed auth response")
|
|
108
|
+
|
|
109
|
+
if not auth_result_allowed:
|
|
110
|
+
reason = response["result"].get("reason", "Denied")
|
|
111
|
+
return AuthorizationOutcome(False, reason)
|
|
112
|
+
|
|
113
|
+
reason = response["result"].get("reason", "Ok")
|
|
114
|
+
return AuthorizationOutcome(True, reason)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def includeme(config: Configurator):
|
|
118
|
+
if os.getenv("PAASTA_API_AUTH_ENDPOINT"):
|
|
119
|
+
config.add_tween(
|
|
120
|
+
"paasta_tools.api.tweens.auth.AuthTweenFactory",
|
|
121
|
+
under=(
|
|
122
|
+
pyramid.tweens.INGRESS,
|
|
123
|
+
"pyramid_swagger.tween.validation_tween_factory",
|
|
124
|
+
),
|
|
125
|
+
)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Copyright 2015-2016 Yelp Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
"""
|
|
15
|
+
Creates a tween that cprofiles requests
|
|
16
|
+
"""
|
|
17
|
+
import pyramid
|
|
18
|
+
import pytz
|
|
19
|
+
|
|
20
|
+
from paasta_tools.api import settings as api_settings
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
# hackily patch pytz, since yelp_lib (used by yelp_profiling) type checks
|
|
24
|
+
# using an older version of pytz where tzinfo didn't exist yet. this needs to
|
|
25
|
+
# happen before importing `yelp_profiling` since it is used at import time.
|
|
26
|
+
pytz.BaseTzInfo = pytz.tzinfo.BaseTzInfo # type: ignore
|
|
27
|
+
import yelp_profiling
|
|
28
|
+
from yelp_profiling.cprofile import CProfileConfig
|
|
29
|
+
from yelp_profiling.cprofile import CProfileContextManager
|
|
30
|
+
from yelp_profiling.tweens import YelpSOARequestProcessor
|
|
31
|
+
|
|
32
|
+
class PaastaCProfileConfig(CProfileConfig):
|
|
33
|
+
"""Paasta API version of yelp_profiling's CProfileConfig. Instead of reading
|
|
34
|
+
from srv-configs, this reads configs from /etc/paasta.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, pyramid_settings):
|
|
38
|
+
super().__init__(pyramid_settings)
|
|
39
|
+
self._cprofile_config = (
|
|
40
|
+
api_settings.system_paasta_config.get_api_profiling_config()
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def enabled(self):
|
|
45
|
+
return self._cprofile_config.get("cprofile_sampling_enabled", False)
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def output_prefix(self):
|
|
49
|
+
return self._cprofile_config.get("cprofile_output_prefix", "cprofile")
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def scribe_log_name(self):
|
|
53
|
+
return self._cprofile_config.get(
|
|
54
|
+
"cprofile_scribe_log", "tmp_paasta_api_cprofiles"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def default_probability(self):
|
|
59
|
+
return self._cprofile_config.get("cprofile_sampling_probability", 0)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def path_probabilities(self):
|
|
63
|
+
probabilities = {"patterns": []}
|
|
64
|
+
probabilities.update(
|
|
65
|
+
self._cprofile_config.get("cprofile_path_probabilities", {})
|
|
66
|
+
)
|
|
67
|
+
return probabilities
|
|
68
|
+
|
|
69
|
+
except ImportError:
|
|
70
|
+
yelp_profiling = None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def includeme(config):
|
|
74
|
+
if yelp_profiling is not None:
|
|
75
|
+
config.add_tween(
|
|
76
|
+
"paasta_tools.api.tweens.profiling.cprofile_tween_factory",
|
|
77
|
+
under=pyramid.tweens.INGRESS,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def cprofile_tween_factory(handler, registry):
|
|
82
|
+
"""Tween for profiling API requests and sending them to scribe.
|
|
83
|
+
|
|
84
|
+
yelp_profiling does define a tween, but it is designed more for PaaSTA
|
|
85
|
+
services. So, we need to define our own.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def cprofile_tween(request):
|
|
89
|
+
if yelp_profiling is None:
|
|
90
|
+
return handler(request)
|
|
91
|
+
|
|
92
|
+
config = PaastaCProfileConfig(registry.settings)
|
|
93
|
+
processor = YelpSOARequestProcessor(config, registry)
|
|
94
|
+
context_manager = CProfileContextManager(config, processor)
|
|
95
|
+
|
|
96
|
+
# uses the config and processor to decide whether or not to cprofile
|
|
97
|
+
# the request
|
|
98
|
+
with context_manager(request):
|
|
99
|
+
processor.begin_request(request)
|
|
100
|
+
status_code = 500
|
|
101
|
+
try:
|
|
102
|
+
response = handler(request)
|
|
103
|
+
status_code = response.status_code
|
|
104
|
+
return response
|
|
105
|
+
finally:
|
|
106
|
+
processor.end_request(request, status_code)
|
|
107
|
+
|
|
108
|
+
return cprofile_tween
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Copyright 2015-2016 Yelp Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
"""
|
|
15
|
+
Creates a tween that logs information about requests.
|
|
16
|
+
"""
|
|
17
|
+
import json
|
|
18
|
+
import traceback
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
|
|
21
|
+
import pyramid
|
|
22
|
+
import pytz
|
|
23
|
+
|
|
24
|
+
from paasta_tools.api import settings
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
import clog
|
|
28
|
+
except ImportError:
|
|
29
|
+
clog = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
DEFAULT_REQUEST_LOG_NAME = "tmp_paasta_api_requests"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def includeme(config):
|
|
36
|
+
if clog is not None:
|
|
37
|
+
config.add_tween(
|
|
38
|
+
"paasta_tools.api.tweens.request_logger.request_logger_tween_factory",
|
|
39
|
+
under=pyramid.tweens.INGRESS,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class request_logger_tween_factory:
|
|
44
|
+
"""Tween that logs information about requests"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, handler, registry):
|
|
47
|
+
self.handler = handler
|
|
48
|
+
self.registry = registry
|
|
49
|
+
self.log_name = registry.settings.get(
|
|
50
|
+
"request_log_name",
|
|
51
|
+
DEFAULT_REQUEST_LOG_NAME,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def _log(
|
|
55
|
+
self,
|
|
56
|
+
timestamp=None,
|
|
57
|
+
level="INFO",
|
|
58
|
+
additional_fields=None,
|
|
59
|
+
):
|
|
60
|
+
if clog is not None:
|
|
61
|
+
# `settings` values are set by paasta_tools.api.api:setup_paasta_api
|
|
62
|
+
if not timestamp:
|
|
63
|
+
timestamp = datetime.now(pytz.utc)
|
|
64
|
+
dct = {
|
|
65
|
+
"human_timestamp": timestamp.strftime("%Y-%m-%dT%H:%M:%S%Z"),
|
|
66
|
+
"unix_timestamp": timestamp.timestamp(),
|
|
67
|
+
"hostname": settings.hostname,
|
|
68
|
+
"level": level,
|
|
69
|
+
"cluster": settings.cluster,
|
|
70
|
+
}
|
|
71
|
+
if additional_fields is not None:
|
|
72
|
+
dct.update(additional_fields)
|
|
73
|
+
line = json.dumps(dct, sort_keys=True)
|
|
74
|
+
clog.log_line(self.log_name, line)
|
|
75
|
+
|
|
76
|
+
def __call__(self, request):
|
|
77
|
+
start_time = datetime.now(pytz.utc) # start clock for response time
|
|
78
|
+
request_fields = {
|
|
79
|
+
"path": request.path,
|
|
80
|
+
"params": request.params.mixed(),
|
|
81
|
+
"client_addr": request.client_addr,
|
|
82
|
+
"http_method": request.method,
|
|
83
|
+
"headers": dict(request.headers), # incls user agent
|
|
84
|
+
}
|
|
85
|
+
response_fields = {}
|
|
86
|
+
log_level = "INFO"
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
response = self.handler(request)
|
|
90
|
+
|
|
91
|
+
response_fields["status_code"] = response.status_int
|
|
92
|
+
if 300 <= response.status_int < 400:
|
|
93
|
+
log_level = "WARNING"
|
|
94
|
+
elif 400 <= response.status_int < 600:
|
|
95
|
+
log_level = "ERROR"
|
|
96
|
+
response_fields["body"] = response.body.decode("utf-8")
|
|
97
|
+
|
|
98
|
+
return response
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
log_level = "ERROR"
|
|
102
|
+
response_fields.update(
|
|
103
|
+
{
|
|
104
|
+
"status_code": 500,
|
|
105
|
+
"exc_type": type(e).__name__,
|
|
106
|
+
"exc_info": traceback.format_exc(),
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
raise
|
|
110
|
+
|
|
111
|
+
finally:
|
|
112
|
+
response_time_ms = (
|
|
113
|
+
datetime.now(pytz.utc) - start_time
|
|
114
|
+
).total_seconds() * 1000
|
|
115
|
+
response_fields["response_time_ms"] = response_time_ms
|
|
116
|
+
|
|
117
|
+
self._log(
|
|
118
|
+
timestamp=start_time,
|
|
119
|
+
level=log_level,
|
|
120
|
+
additional_fields={
|
|
121
|
+
"request": request_fields,
|
|
122
|
+
"response": response_fields,
|
|
123
|
+
},
|
|
124
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Copyright 2015-2016 Yelp Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
@@ -0,0 +1,100 @@
|
|
|
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.response import Response
|
|
19
|
+
from pyramid.view import view_config
|
|
20
|
+
|
|
21
|
+
from paasta_tools.api import settings
|
|
22
|
+
from paasta_tools.api.views.exception import ApiFailure
|
|
23
|
+
from paasta_tools.cli.utils import get_instance_config
|
|
24
|
+
from paasta_tools.kubernetes_tools import KubernetesDeploymentConfig
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@view_config(route_name="service.autoscaler.get", request_method="GET", renderer="json")
|
|
28
|
+
def get_autoscaler_count(request):
|
|
29
|
+
service = request.swagger_data.get("service")
|
|
30
|
+
instance = request.swagger_data.get("instance")
|
|
31
|
+
cluster = settings.cluster
|
|
32
|
+
soa_dir = settings.soa_dir
|
|
33
|
+
|
|
34
|
+
instance_config = get_instance_config(service, instance, cluster, soa_dir)
|
|
35
|
+
if not isinstance(instance_config, (KubernetesDeploymentConfig)):
|
|
36
|
+
error_message = (
|
|
37
|
+
f"Autoscaling is not supported for {service}.{instance} because instance type is not "
|
|
38
|
+
f"kubernetes."
|
|
39
|
+
)
|
|
40
|
+
raise ApiFailure(error_message, 501)
|
|
41
|
+
|
|
42
|
+
response_body = {
|
|
43
|
+
"desired_instances": instance_config.get_instances(),
|
|
44
|
+
"calculated_instances": instance_config.get_instances(with_limit=False),
|
|
45
|
+
}
|
|
46
|
+
return Response(json_body=response_body, status_code=200)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@view_config(
|
|
50
|
+
route_name="service.autoscaler.post", request_method="POST", renderer="json"
|
|
51
|
+
)
|
|
52
|
+
def update_autoscaler_count(request):
|
|
53
|
+
service = request.swagger_data.get("service")
|
|
54
|
+
instance = request.swagger_data.get("instance")
|
|
55
|
+
cluster = settings.cluster
|
|
56
|
+
soa_dir = settings.soa_dir
|
|
57
|
+
desired_instances = request.swagger_data.get("json_body")["desired_instances"]
|
|
58
|
+
if not isinstance(desired_instances, int):
|
|
59
|
+
error_message = 'The provided body does not have an integer value for "desired_instances": {}'.format(
|
|
60
|
+
request.swagger_data.get("json_body")
|
|
61
|
+
)
|
|
62
|
+
raise ApiFailure(error_message, 500)
|
|
63
|
+
|
|
64
|
+
instance_config = get_instance_config(service, instance, cluster, soa_dir, True)
|
|
65
|
+
if not isinstance(instance_config, (KubernetesDeploymentConfig)):
|
|
66
|
+
error_message = (
|
|
67
|
+
f"Autoscaling is not supported for {service}.{instance} because instance type is not "
|
|
68
|
+
f"kubernetes."
|
|
69
|
+
)
|
|
70
|
+
raise ApiFailure(error_message, 501)
|
|
71
|
+
|
|
72
|
+
max_instances = instance_config.get_max_instances()
|
|
73
|
+
if max_instances is None:
|
|
74
|
+
error_message = f"Autoscaling is not enabled for {service}.{instance}"
|
|
75
|
+
raise ApiFailure(error_message, 404)
|
|
76
|
+
min_instances = instance_config.get_min_instances()
|
|
77
|
+
|
|
78
|
+
status = "SUCCESS"
|
|
79
|
+
if desired_instances > max_instances:
|
|
80
|
+
desired_instances = max_instances
|
|
81
|
+
status = (
|
|
82
|
+
"WARNING desired_instances is greater than max_instances %d" % max_instances
|
|
83
|
+
)
|
|
84
|
+
elif desired_instances < min_instances:
|
|
85
|
+
desired_instances = min_instances
|
|
86
|
+
status = (
|
|
87
|
+
"WARNING desired_instances is less than min_instances %d" % min_instances
|
|
88
|
+
)
|
|
89
|
+
try:
|
|
90
|
+
if isinstance(instance_config, KubernetesDeploymentConfig):
|
|
91
|
+
instance_config.set_autoscaled_instances(
|
|
92
|
+
instance_count=desired_instances, kube_client=settings.kubernetes_client
|
|
93
|
+
)
|
|
94
|
+
else:
|
|
95
|
+
instance_config.set_autoscaled_instances(instance_count=desired_instances)
|
|
96
|
+
except Exception as err:
|
|
97
|
+
raise ApiFailure(err, 500)
|
|
98
|
+
|
|
99
|
+
response_body = {"desired_instances": desired_instances, "status": status}
|
|
100
|
+
return Response(json_body=response_body, status_code=202)
|
|
@@ -0,0 +1,45 @@
|
|
|
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 API error handling.
|
|
17
|
+
"""
|
|
18
|
+
import logging
|
|
19
|
+
|
|
20
|
+
from pyramid.response import Response
|
|
21
|
+
from pyramid.view import view_config
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
log = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ApiFailure(Exception):
|
|
28
|
+
def __init__(self, msg, err):
|
|
29
|
+
self.msg = msg
|
|
30
|
+
self.err = err
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@view_config(context=ApiFailure)
|
|
34
|
+
def api_failure_response(exc, request):
|
|
35
|
+
"""Construct an HTTP response with an error status code. This happens when
|
|
36
|
+
the API service has to stop on a 'hard' error. In contrast, the API service
|
|
37
|
+
continues to produce results on a 'soft' error. It will place a 'message'
|
|
38
|
+
field in the output. Multiple 'soft' errors are concatenated in the same
|
|
39
|
+
'message' field when errors happen in the same hierarchy.
|
|
40
|
+
"""
|
|
41
|
+
log.error(exc.msg)
|
|
42
|
+
|
|
43
|
+
response = Response("ERROR: %s" % exc.msg)
|
|
44
|
+
response.status_int = exc.err
|
|
45
|
+
return response
|