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,169 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
from . import exceptions
|
|
19
|
+
from paasta_tools.async_utils import async_ttl_cache
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class File:
|
|
23
|
+
|
|
24
|
+
chunk_size = 1024
|
|
25
|
+
|
|
26
|
+
def __init__(self, host, task=None, path=None):
|
|
27
|
+
self.host = host
|
|
28
|
+
self.task = task
|
|
29
|
+
self.path = path
|
|
30
|
+
|
|
31
|
+
if self.task is None:
|
|
32
|
+
self._host_path = self.path
|
|
33
|
+
else:
|
|
34
|
+
self._host_path = None # Defer until later (_fetch) so we don't make HTTP requests in __init__.
|
|
35
|
+
|
|
36
|
+
self._offset = 0
|
|
37
|
+
|
|
38
|
+
# Used during fetch, class level so the dict isn't constantly alloc'd
|
|
39
|
+
self._params = {
|
|
40
|
+
"path": self._host_path,
|
|
41
|
+
"offset": -1,
|
|
42
|
+
"length": self.chunk_size,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
def __eq__(self, y):
|
|
46
|
+
return self.key() == y.key()
|
|
47
|
+
|
|
48
|
+
def __hash__(self):
|
|
49
|
+
return hash(self.__str__())
|
|
50
|
+
|
|
51
|
+
def __repr__(self):
|
|
52
|
+
return f"<open file '{self.path}', for '{self._where}'>"
|
|
53
|
+
|
|
54
|
+
def __str__(self):
|
|
55
|
+
return f"{self._where}:{self.path}"
|
|
56
|
+
|
|
57
|
+
def key(self):
|
|
58
|
+
return "{}:{}".format(self.host.key(), self._host_path)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def _where(self):
|
|
62
|
+
return self.task["id"] if self.task is not None else self.host.key()
|
|
63
|
+
|
|
64
|
+
async def _fetch(self):
|
|
65
|
+
# fill in path if it wasn't set in __init__
|
|
66
|
+
if self._params["path"] is None:
|
|
67
|
+
self._params["path"] = os.path.join(await self.task.directory(), self.path)
|
|
68
|
+
|
|
69
|
+
resp = await self.host.fetch("/files/read.json", params=self._params)
|
|
70
|
+
if resp.status == 404:
|
|
71
|
+
raise exceptions.FileDoesNotExist("No such file or directory.")
|
|
72
|
+
return await resp.json()
|
|
73
|
+
|
|
74
|
+
async def exists(self):
|
|
75
|
+
try:
|
|
76
|
+
await self.size()
|
|
77
|
+
return True
|
|
78
|
+
except exceptions.FileDoesNotExist:
|
|
79
|
+
return False
|
|
80
|
+
except exceptions.SlaveDoesNotExist:
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
# When reading a file, it is common to first check whether it exists, then
|
|
84
|
+
# look at the size to determine where to seek. Instead of requiring
|
|
85
|
+
# multiple requests to the slave, the size is cached for a very short
|
|
86
|
+
# period of time.
|
|
87
|
+
@async_ttl_cache(ttl=0.5, cleanup_self=True)
|
|
88
|
+
async def size(self):
|
|
89
|
+
return (await self._fetch())["offset"]
|
|
90
|
+
|
|
91
|
+
async def seek(self, offset, whence=os.SEEK_SET):
|
|
92
|
+
if whence == os.SEEK_SET:
|
|
93
|
+
self._offset = 0 + offset
|
|
94
|
+
elif whence == os.SEEK_CUR:
|
|
95
|
+
self._offset += offset
|
|
96
|
+
elif whence == os.SEEK_END:
|
|
97
|
+
self._offset = await self.size() + offset
|
|
98
|
+
|
|
99
|
+
def tell(self):
|
|
100
|
+
return self._offset
|
|
101
|
+
|
|
102
|
+
def _length(self, start, size):
|
|
103
|
+
if size and self.tell() - start + self.chunk_size > size:
|
|
104
|
+
return size - (self.tell() - start)
|
|
105
|
+
return self.chunk_size
|
|
106
|
+
|
|
107
|
+
async def _get_chunk(self, loc, size=None):
|
|
108
|
+
if size is None:
|
|
109
|
+
size = self.chunk_size
|
|
110
|
+
|
|
111
|
+
await self.seek(loc, os.SEEK_SET)
|
|
112
|
+
self._params["offset"] = loc
|
|
113
|
+
self._params["length"] = size
|
|
114
|
+
|
|
115
|
+
data = (await self._fetch())["data"]
|
|
116
|
+
await self.seek(len(data), os.SEEK_CUR)
|
|
117
|
+
return data
|
|
118
|
+
|
|
119
|
+
async def _read(self, size=None):
|
|
120
|
+
start = self.tell()
|
|
121
|
+
|
|
122
|
+
def pre(x):
|
|
123
|
+
return x == ""
|
|
124
|
+
|
|
125
|
+
def post(x):
|
|
126
|
+
return size and (self.tell() - start) >= size
|
|
127
|
+
|
|
128
|
+
blob = None
|
|
129
|
+
while blob != "" and not (size and (self.tell() - start) >= size):
|
|
130
|
+
blob = await self._get_chunk(self.tell(), size=self._length(start, size))
|
|
131
|
+
yield blob
|
|
132
|
+
|
|
133
|
+
async def _read_reverse(self, size=None):
|
|
134
|
+
fsize = await self.size()
|
|
135
|
+
if not size:
|
|
136
|
+
size = fsize
|
|
137
|
+
|
|
138
|
+
def next_block():
|
|
139
|
+
current = fsize
|
|
140
|
+
while (current - self.chunk_size) > (fsize - size):
|
|
141
|
+
current -= self.chunk_size
|
|
142
|
+
yield current
|
|
143
|
+
|
|
144
|
+
for pos in next_block():
|
|
145
|
+
yield await self._get_chunk(pos)
|
|
146
|
+
|
|
147
|
+
yield await self._get_chunk(fsize - size, size % self.chunk_size)
|
|
148
|
+
|
|
149
|
+
async def _readlines(self, size=None):
|
|
150
|
+
last = ""
|
|
151
|
+
async for blob in self._read(size):
|
|
152
|
+
|
|
153
|
+
# This is not streaming and assumes small chunk sizes
|
|
154
|
+
blob_lines = (last + blob).split("\n")
|
|
155
|
+
for line in blob_lines[: len(blob_lines) - 1]:
|
|
156
|
+
yield line
|
|
157
|
+
|
|
158
|
+
last = blob_lines[-1]
|
|
159
|
+
|
|
160
|
+
async def _readlines_reverse(self, size=None):
|
|
161
|
+
buf = ""
|
|
162
|
+
async for blob in self._read_reverse(size):
|
|
163
|
+
|
|
164
|
+
blob_lines = (blob + buf).split("\n")
|
|
165
|
+
for line in reversed(blob_lines[1:]):
|
|
166
|
+
yield line
|
|
167
|
+
|
|
168
|
+
buf = blob_lines[0]
|
|
169
|
+
yield buf
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
import concurrent.futures
|
|
17
|
+
import contextlib
|
|
18
|
+
|
|
19
|
+
from . import exceptions
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@contextlib.contextmanager
|
|
23
|
+
def execute(max_workers):
|
|
24
|
+
try:
|
|
25
|
+
executor = concurrent.futures.ThreadPoolExecutor(max_workers=max_workers)
|
|
26
|
+
yield executor
|
|
27
|
+
except KeyboardInterrupt:
|
|
28
|
+
# Threads in the ThreadPoolExecutor are created with
|
|
29
|
+
# daemon=True. There is, therefore, an atexit function registered
|
|
30
|
+
# that allows all the currently running threads to stop before
|
|
31
|
+
# allowing the interpreter to stop. Because we don't care whether
|
|
32
|
+
# the worker threads exit cleanly or not, we force shutdown to be
|
|
33
|
+
# immediate.
|
|
34
|
+
concurrent.futures.thread._threads_queues.clear()
|
|
35
|
+
raise
|
|
36
|
+
finally:
|
|
37
|
+
executor.shutdown(wait=False)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def stream(fn, elements, workers):
|
|
41
|
+
"""Yield the results of fn as jobs complete."""
|
|
42
|
+
jobs = []
|
|
43
|
+
|
|
44
|
+
with execute(workers) as executor:
|
|
45
|
+
for elem in elements:
|
|
46
|
+
jobs.append(executor.submit(fn, elem))
|
|
47
|
+
|
|
48
|
+
for job in concurrent.futures.as_completed(jobs):
|
|
49
|
+
try:
|
|
50
|
+
yield job.result()
|
|
51
|
+
except exceptions.SkipResult:
|
|
52
|
+
pass
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
from urllib.parse import urljoin
|
|
17
|
+
|
|
18
|
+
import aiohttp
|
|
19
|
+
|
|
20
|
+
from . import exceptions
|
|
21
|
+
from . import mesos_file
|
|
22
|
+
from . import util
|
|
23
|
+
from paasta_tools.async_utils import async_ttl_cache
|
|
24
|
+
from paasta_tools.utils import get_user_agent
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MesosSlave:
|
|
28
|
+
def __init__(self, config, items):
|
|
29
|
+
self.config = config
|
|
30
|
+
self.__items = items
|
|
31
|
+
|
|
32
|
+
def __getitem__(self, name):
|
|
33
|
+
return self.__items[name]
|
|
34
|
+
|
|
35
|
+
def __str__(self):
|
|
36
|
+
return self.key()
|
|
37
|
+
|
|
38
|
+
def key(self):
|
|
39
|
+
return self["pid"].split("@")[-1]
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def host(self):
|
|
43
|
+
return "{}://{}:{}".format(
|
|
44
|
+
self.config["scheme"], self["hostname"], self["pid"].split(":")[-1]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
async def fetch(self, url, **kwargs) -> aiohttp.ClientResponse:
|
|
48
|
+
headers = {"User-Agent": get_user_agent()}
|
|
49
|
+
async with aiohttp.ClientSession(
|
|
50
|
+
conn_timeout=self.config["response_timeout"],
|
|
51
|
+
read_timeout=self.config["response_timeout"],
|
|
52
|
+
) as session:
|
|
53
|
+
try:
|
|
54
|
+
async with session.get(
|
|
55
|
+
urljoin(self.host, url), headers=headers, **kwargs
|
|
56
|
+
) as response:
|
|
57
|
+
await response.text()
|
|
58
|
+
return response
|
|
59
|
+
except aiohttp.ClientConnectionError:
|
|
60
|
+
raise exceptions.SlaveDoesNotExist(
|
|
61
|
+
f"Unable to connect to the slave at {self.host}"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@async_ttl_cache(ttl=5, cleanup_self=True)
|
|
65
|
+
async def state(self):
|
|
66
|
+
return await (await self.fetch("/slave(1)/state.json")).json()
|
|
67
|
+
|
|
68
|
+
async def frameworks(self):
|
|
69
|
+
return util.merge(await self.state(), "frameworks", "completed_frameworks")
|
|
70
|
+
|
|
71
|
+
async def task_executor(self, task_id):
|
|
72
|
+
for fw in await self.frameworks():
|
|
73
|
+
for exc in util.merge(fw, "executors", "completed_executors"):
|
|
74
|
+
if task_id in list(
|
|
75
|
+
map(
|
|
76
|
+
lambda x: x["id"],
|
|
77
|
+
util.merge(exc, "completed_tasks", "tasks", "queued_tasks"),
|
|
78
|
+
)
|
|
79
|
+
):
|
|
80
|
+
return exc
|
|
81
|
+
raise exceptions.MissingExecutor("No executor has a task by that id")
|
|
82
|
+
|
|
83
|
+
async def file_list(self, path):
|
|
84
|
+
# The sandbox does not exist on the slave.
|
|
85
|
+
if path == "":
|
|
86
|
+
return []
|
|
87
|
+
|
|
88
|
+
resp = self.fetch("/files/browse.json", params={"path": path})
|
|
89
|
+
if resp.status_code == 404:
|
|
90
|
+
return []
|
|
91
|
+
return await resp.json()
|
|
92
|
+
|
|
93
|
+
def file(self, task, path):
|
|
94
|
+
return mesos_file.File(self, task, path)
|
|
95
|
+
|
|
96
|
+
@async_ttl_cache(ttl=30, cleanup_self=True)
|
|
97
|
+
async def stats(self):
|
|
98
|
+
return await (await self.fetch("/monitor/statistics.json")).json()
|
|
99
|
+
|
|
100
|
+
def executor_stats(self, _id):
|
|
101
|
+
return list(filter(lambda x: x["executor_id"]))
|
|
102
|
+
|
|
103
|
+
async def task_stats(self, _id):
|
|
104
|
+
stats = list(filter(lambda x: x["executor_id"] == _id, await self.stats()))
|
|
105
|
+
|
|
106
|
+
# Tasks that are not yet in a RUNNING state have no stats.
|
|
107
|
+
if len(stats) == 0:
|
|
108
|
+
return {}
|
|
109
|
+
else:
|
|
110
|
+
return stats[0]["statistics"]
|
|
111
|
+
|
|
112
|
+
@property # type: ignore
|
|
113
|
+
@util.memoize
|
|
114
|
+
def log(self):
|
|
115
|
+
return mesos_file.File(self, path="/slave/log")
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
import os
|
|
17
|
+
import re
|
|
18
|
+
|
|
19
|
+
import a_sync
|
|
20
|
+
|
|
21
|
+
from . import exceptions
|
|
22
|
+
from . import framework
|
|
23
|
+
from . import mesos_file
|
|
24
|
+
from paasta_tools.async_utils import async_ttl_cache
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Task:
|
|
28
|
+
|
|
29
|
+
cmd_re = re.compile(r"\(Command: (.+)\)")
|
|
30
|
+
|
|
31
|
+
def __init__(self, master, items):
|
|
32
|
+
self.master = master
|
|
33
|
+
self.__items = items
|
|
34
|
+
|
|
35
|
+
def __str__(self):
|
|
36
|
+
return "{}:{}".format(a_sync.block(self.slave), self["id"])
|
|
37
|
+
|
|
38
|
+
def __getitem__(self, name):
|
|
39
|
+
return self.__items[name]
|
|
40
|
+
|
|
41
|
+
async def executor(self):
|
|
42
|
+
return await (await self.slave()).task_executor(self["id"])
|
|
43
|
+
|
|
44
|
+
async def framework(self):
|
|
45
|
+
return framework.Framework(await self.master.framework(self["framework_id"]))
|
|
46
|
+
|
|
47
|
+
@async_ttl_cache(cleanup_self=True)
|
|
48
|
+
async def directory(self):
|
|
49
|
+
try:
|
|
50
|
+
return (await self.executor())["directory"]
|
|
51
|
+
except exceptions.MissingExecutor:
|
|
52
|
+
return ""
|
|
53
|
+
|
|
54
|
+
@async_ttl_cache(cleanup_self=True)
|
|
55
|
+
async def slave(self):
|
|
56
|
+
return await self.master.slave(self["slave_id"])
|
|
57
|
+
|
|
58
|
+
async def file(self, path):
|
|
59
|
+
return mesos_file.File(await self.slave(), self, path)
|
|
60
|
+
|
|
61
|
+
async def file_list(self, path):
|
|
62
|
+
return await (await self.slave()).file_list(os.path.join(self.directory, path))
|
|
63
|
+
|
|
64
|
+
async def stats(self):
|
|
65
|
+
try:
|
|
66
|
+
return await (await self.slave()).task_stats(self["id"])
|
|
67
|
+
except exceptions.MissingExecutor:
|
|
68
|
+
return {}
|
|
69
|
+
|
|
70
|
+
async def cpu_time(self):
|
|
71
|
+
st = await self.stats()
|
|
72
|
+
secs = st.get("cpus_user_time_secs", 0) + st.get("cpus_system_time_secs", 0)
|
|
73
|
+
return secs
|
|
74
|
+
|
|
75
|
+
async def cpu_limit(self):
|
|
76
|
+
return (await self.stats()).get("cpus_limit", 0)
|
|
77
|
+
|
|
78
|
+
async def mem_limit(self):
|
|
79
|
+
return (await self.stats()).get("mem_limit_bytes", 0)
|
|
80
|
+
|
|
81
|
+
async def rss(self):
|
|
82
|
+
return (await self.stats()).get("mem_rss_bytes", 0)
|
|
83
|
+
|
|
84
|
+
async def command(self):
|
|
85
|
+
try:
|
|
86
|
+
result = self.cmd_re.search((await self.executor())["name"])
|
|
87
|
+
except exceptions.MissingExecutor:
|
|
88
|
+
result = None
|
|
89
|
+
if not result:
|
|
90
|
+
return "none"
|
|
91
|
+
return result.group(1)
|
|
92
|
+
|
|
93
|
+
async def user(self):
|
|
94
|
+
return (await self.framework()).user
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
import functools
|
|
17
|
+
import itertools
|
|
18
|
+
import time
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def merge(obj, *keys):
|
|
22
|
+
return itertools.chain(*[obj[k] for k in keys])
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class CachedProperty:
|
|
26
|
+
def __init__(self, ttl=300):
|
|
27
|
+
self.ttl = ttl
|
|
28
|
+
|
|
29
|
+
def __call__(self, fget, doc=None):
|
|
30
|
+
self.fget = fget
|
|
31
|
+
self.__doc__ = doc or fget.__doc__
|
|
32
|
+
self.__name__ = fget.__name__
|
|
33
|
+
self.__module__ = fget.__module__
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
def __get__(self, inst, owner):
|
|
37
|
+
try:
|
|
38
|
+
value, last_update = inst._cache[self.__name__]
|
|
39
|
+
if self.ttl > 0 and time.time() - last_update > self.ttl:
|
|
40
|
+
raise AttributeError
|
|
41
|
+
except (KeyError, AttributeError):
|
|
42
|
+
value = self.fget(inst)
|
|
43
|
+
try:
|
|
44
|
+
cache = inst._cache
|
|
45
|
+
except AttributeError:
|
|
46
|
+
cache = inst._cache = {}
|
|
47
|
+
cache[self.__name__] = (value, time.time())
|
|
48
|
+
return value
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def memoize(obj):
|
|
52
|
+
cache = obj.cache = {}
|
|
53
|
+
|
|
54
|
+
@functools.wraps(obj)
|
|
55
|
+
def memoizer(*args, **kwargs):
|
|
56
|
+
key = str(args) + str(kwargs)
|
|
57
|
+
if key not in cache:
|
|
58
|
+
cache[key] = obj(*args, **kwargs)
|
|
59
|
+
return cache[key]
|
|
60
|
+
|
|
61
|
+
return memoizer
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def humanize_bytes(b):
|
|
65
|
+
abbrevs = ((1 << 30, "GB"), (1 << 20, "MB"), (1 << 10, "kB"), (1, "B"))
|
|
66
|
+
for factor, suffix in abbrevs:
|
|
67
|
+
if b >= factor:
|
|
68
|
+
break
|
|
69
|
+
return "%.*f %s" % (2, b / float(factor), suffix)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
|
3
|
+
# distributed with this work for additional information
|
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
|
6
|
+
# "License"); you may not use this file except in compliance
|
|
7
|
+
# with the License. You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
import contextlib
|
|
17
|
+
|
|
18
|
+
import kazoo.client
|
|
19
|
+
import kazoo.exceptions
|
|
20
|
+
import kazoo.handlers.threading
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
TIMEOUT = 1
|
|
24
|
+
|
|
25
|
+
# Helper for testing
|
|
26
|
+
client_class = kazoo.client.KazooClient
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@contextlib.contextmanager
|
|
30
|
+
def client(*args, **kwargs):
|
|
31
|
+
zk = client_class(*args, **kwargs)
|
|
32
|
+
zk.start(timeout=TIMEOUT)
|
|
33
|
+
try:
|
|
34
|
+
yield zk
|
|
35
|
+
finally:
|
|
36
|
+
zk.stop()
|
|
37
|
+
zk.close()
|