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,44 @@
|
|
|
1
|
+
import errno
|
|
2
|
+
import fcntl
|
|
3
|
+
import os.path
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
MAC_ADDRESS_PREFIX = ("02", "52")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MacAddressException(Exception):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def reserve_unique_mac_address(lock_directory):
|
|
14
|
+
"""Pick and reserve a unique mac address for a container
|
|
15
|
+
returns (mac_address, lockfile)
|
|
16
|
+
where the mac address is a string in the form of 00:00:00:00:00:00
|
|
17
|
+
and lockfile is a file object that holds an exclusive lock
|
|
18
|
+
"""
|
|
19
|
+
for x in range(100):
|
|
20
|
+
random_hex = "{:08x}".format(random.getrandbits(32))
|
|
21
|
+
mac_address = ":".join(
|
|
22
|
+
MAC_ADDRESS_PREFIX
|
|
23
|
+
+ (random_hex[0:2], random_hex[2:4], random_hex[4:6], random_hex[6:8])
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
lock_filepath = os.path.join(lock_directory, mac_address)
|
|
27
|
+
lock_file = obtain_lock(lock_filepath)
|
|
28
|
+
if lock_file is not None:
|
|
29
|
+
return (mac_address, lock_file)
|
|
30
|
+
|
|
31
|
+
raise MacAddressException("Unable to pick unique MAC address")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def obtain_lock(lock_filepath):
|
|
35
|
+
"""Open and obtain a flock on the parameter. Returns a file if successful, None if not"""
|
|
36
|
+
lock_file = open(lock_filepath, "w")
|
|
37
|
+
try:
|
|
38
|
+
fcntl.flock(lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
39
|
+
return lock_file
|
|
40
|
+
except IOError as err:
|
|
41
|
+
if err.errno != errno.EAGAIN:
|
|
42
|
+
raise
|
|
43
|
+
lock_file.close()
|
|
44
|
+
return None
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,46 @@
|
|
|
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 copy
|
|
17
|
+
import errno
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
DEFAULTS = {
|
|
22
|
+
"debug": "false",
|
|
23
|
+
"log_file": None,
|
|
24
|
+
"log_level": "warning",
|
|
25
|
+
"master": "localhost:5050",
|
|
26
|
+
"max_workers": 5,
|
|
27
|
+
"scheme": "http",
|
|
28
|
+
"response_timeout": 5,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def load_mesos_config(config_path, profile="default"):
|
|
33
|
+
on_disk = {}
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
with open(config_path, "rt") as f:
|
|
37
|
+
on_disk = json.load(f)[profile]
|
|
38
|
+
except ValueError as e:
|
|
39
|
+
raise ValueError("Invalid JSON: {} in {}".format(str(e), config_path))
|
|
40
|
+
except IOError as e:
|
|
41
|
+
if e.errno != errno.ENOENT:
|
|
42
|
+
raise
|
|
43
|
+
|
|
44
|
+
config = copy.deepcopy(DEFAULTS)
|
|
45
|
+
config.update(on_disk)
|
|
46
|
+
return config
|
|
@@ -0,0 +1,60 @@
|
|
|
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 asyncio
|
|
17
|
+
import itertools
|
|
18
|
+
|
|
19
|
+
from . import exceptions
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async def get_files_for_tasks(task_list, file_list, max_workers):
|
|
23
|
+
no_files_found = True
|
|
24
|
+
|
|
25
|
+
async def process(task_fname):
|
|
26
|
+
task, fname = task_fname
|
|
27
|
+
try:
|
|
28
|
+
fobj = await task.file(fname)
|
|
29
|
+
except exceptions.SlaveDoesNotExist:
|
|
30
|
+
if task is None:
|
|
31
|
+
print(f"(Unknown Task):{fname} (Slave no longer exists)")
|
|
32
|
+
else:
|
|
33
|
+
print(f"{task['id']}:{task_fname} (Slave no longer exists)")
|
|
34
|
+
raise exceptions.SkipResult
|
|
35
|
+
|
|
36
|
+
if await fobj.exists():
|
|
37
|
+
return fobj
|
|
38
|
+
|
|
39
|
+
elements = itertools.chain(
|
|
40
|
+
*[[(task, fname) for fname in file_list] for task in task_list]
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
futures = [asyncio.ensure_future(process(element)) for element in elements]
|
|
44
|
+
|
|
45
|
+
if futures:
|
|
46
|
+
for result in asyncio.as_completed(futures):
|
|
47
|
+
try:
|
|
48
|
+
result = await result
|
|
49
|
+
if result:
|
|
50
|
+
no_files_found = False
|
|
51
|
+
yield result
|
|
52
|
+
except exceptions.SkipResult:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
if no_files_found:
|
|
56
|
+
raise exceptions.FileNotFoundForTaskException(
|
|
57
|
+
"None of the tasks in {} contain the files in list {}".format(
|
|
58
|
+
",".join([task["id"] for task in task_list]), ",".join(file_list)
|
|
59
|
+
)
|
|
60
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
|
|
17
|
+
|
|
18
|
+
class MasterNotAvailableException(Exception):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MasterTemporarilyNotAvailableException(Exception):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class NoSlavesAvailableError(Exception):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MultipleSlavesForIDError(Exception):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class TaskNotFoundException(Exception):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FileNotFoundForTaskException(Exception):
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class MultipleTasksForIDError(Exception):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class FileDoesNotExist(Exception):
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class MissingExecutor(Exception):
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class SlaveDoesNotExist(Exception):
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class SkipResult(Exception):
|
|
59
|
+
pass
|
|
@@ -0,0 +1,77 @@
|
|
|
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
|
+
|
|
17
|
+
|
|
18
|
+
class Framework:
|
|
19
|
+
def __init__(self, items):
|
|
20
|
+
self.__items = items
|
|
21
|
+
|
|
22
|
+
def __getitem__(self, name):
|
|
23
|
+
return self.__items[name]
|
|
24
|
+
|
|
25
|
+
def __str__(self):
|
|
26
|
+
return f"{self.name}:{self.id}"
|
|
27
|
+
|
|
28
|
+
def get(self, name, default=None):
|
|
29
|
+
try:
|
|
30
|
+
return self[name]
|
|
31
|
+
except KeyError:
|
|
32
|
+
return default
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def id(self):
|
|
36
|
+
return self["id"]
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def name(self):
|
|
40
|
+
return self["name"]
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def hostname(self):
|
|
44
|
+
return self["hostname"]
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def active(self):
|
|
48
|
+
return self["active"]
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def task_count(self):
|
|
52
|
+
return len(self["tasks"])
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def user(self):
|
|
56
|
+
return self["user"]
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def cpu_allocated(self):
|
|
60
|
+
return self._resource_allocated("cpus")
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def mem_allocated(self):
|
|
64
|
+
return self._resource_allocated("mem")
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def disk_allocated(self):
|
|
68
|
+
return self._resource_allocated("disk")
|
|
69
|
+
|
|
70
|
+
def _resource_allocated(self, resource):
|
|
71
|
+
return self["resources"][resource]
|
|
72
|
+
|
|
73
|
+
def __eq__(self, other):
|
|
74
|
+
return self.__items == other.__items
|
|
75
|
+
|
|
76
|
+
def __ne__(self, other):
|
|
77
|
+
return not self.__eq__
|
|
@@ -0,0 +1,48 @@
|
|
|
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 logging
|
|
18
|
+
import sys
|
|
19
|
+
import time
|
|
20
|
+
|
|
21
|
+
debug = logging.debug
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def fatal(msg, code=1):
|
|
25
|
+
print(msg + "\n")
|
|
26
|
+
logging.error(msg)
|
|
27
|
+
sys.exit(code)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def fn(f, *args, **kwargs):
|
|
31
|
+
logging.debug("{}: {} {}".format(repr(f), args, kwargs))
|
|
32
|
+
return f(*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def duration(fn):
|
|
36
|
+
@functools.wraps(fn)
|
|
37
|
+
def timer(*args, **kwargs):
|
|
38
|
+
start = time.time()
|
|
39
|
+
try:
|
|
40
|
+
return fn(*args, **kwargs)
|
|
41
|
+
finally:
|
|
42
|
+
debug(
|
|
43
|
+
"duration: {}.{}: {:2.2f}s".format(
|
|
44
|
+
fn.__module__, fn.__name__, time.time() - start
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
return timer
|
|
@@ -0,0 +1,306 @@
|
|
|
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 fnmatch
|
|
17
|
+
import itertools
|
|
18
|
+
import json
|
|
19
|
+
import logging
|
|
20
|
+
import os
|
|
21
|
+
import re
|
|
22
|
+
from typing import List
|
|
23
|
+
from urllib.parse import urljoin
|
|
24
|
+
from urllib.parse import urlparse
|
|
25
|
+
|
|
26
|
+
import aiohttp
|
|
27
|
+
from kazoo.handlers.threading import KazooTimeoutError
|
|
28
|
+
from kazoo.retry import KazooRetry
|
|
29
|
+
from mypy_extensions import TypedDict
|
|
30
|
+
from retry import retry
|
|
31
|
+
|
|
32
|
+
from . import exceptions
|
|
33
|
+
from . import framework
|
|
34
|
+
from . import log
|
|
35
|
+
from . import mesos_file
|
|
36
|
+
from . import slave
|
|
37
|
+
from . import task
|
|
38
|
+
from . import util
|
|
39
|
+
from . import zookeeper
|
|
40
|
+
from paasta_tools.async_utils import async_ttl_cache
|
|
41
|
+
from paasta_tools.utils import get_user_agent
|
|
42
|
+
|
|
43
|
+
ZOOKEEPER_TIMEOUT = 1
|
|
44
|
+
|
|
45
|
+
INVALID_PATH = "{0} does not have a valid path. Did you forget /mesos?"
|
|
46
|
+
|
|
47
|
+
MISSING_MASTER = """unable to connect to a master at {0}.
|
|
48
|
+
|
|
49
|
+
Try running `mesos config master zk://localhost:2181/mesos`. See the README for
|
|
50
|
+
more examples."""
|
|
51
|
+
|
|
52
|
+
MULTIPLE_SLAVES = "There are multiple slaves with that id. Please choose one: "
|
|
53
|
+
|
|
54
|
+
logger = logging.getLogger(__name__)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class MesosState(TypedDict):
|
|
58
|
+
slaves: List
|
|
59
|
+
frameworks: List
|
|
60
|
+
orphan_tasks: List
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
MesosMetrics = TypedDict(
|
|
64
|
+
"MesosMetrics",
|
|
65
|
+
{
|
|
66
|
+
"master/cpus_total": int,
|
|
67
|
+
"master/cpus_used": int,
|
|
68
|
+
"master/disk_total": int,
|
|
69
|
+
"master/disk_used": int,
|
|
70
|
+
"master/gpus_total": int,
|
|
71
|
+
"master/gpus_used": int,
|
|
72
|
+
"master/mem_total": int,
|
|
73
|
+
"master/mem_used": int,
|
|
74
|
+
"master/tasks_running": int,
|
|
75
|
+
"master/tasks_staging": int,
|
|
76
|
+
"master/tasks_starting": int,
|
|
77
|
+
"master/slaves_active": int,
|
|
78
|
+
"master/slaves_inactive": int,
|
|
79
|
+
},
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class MesosMaster:
|
|
84
|
+
def __init__(self, config):
|
|
85
|
+
self.config = config
|
|
86
|
+
|
|
87
|
+
def __str__(self):
|
|
88
|
+
return "<master: {}>".format(self.key())
|
|
89
|
+
|
|
90
|
+
def key(self):
|
|
91
|
+
return self.config["master"]
|
|
92
|
+
|
|
93
|
+
@util.CachedProperty(ttl=5)
|
|
94
|
+
def host(self):
|
|
95
|
+
return "{}://{}".format(
|
|
96
|
+
self.config["scheme"], self.resolve(self.config["master"])
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@util.CachedProperty(ttl=5)
|
|
100
|
+
def cache_host(self):
|
|
101
|
+
host_url = urlparse(self.host)
|
|
102
|
+
replaced = host_url._replace(netloc=host_url.hostname + ":5055")
|
|
103
|
+
return replaced.geturl()
|
|
104
|
+
|
|
105
|
+
async def _request(
|
|
106
|
+
self, url: str, method: str = "GET", cached: bool = False, **kwargs
|
|
107
|
+
) -> aiohttp.ClientResponse:
|
|
108
|
+
headers = {"User-Agent": get_user_agent()}
|
|
109
|
+
|
|
110
|
+
if cached and self.config.get("use_mesos_cache", False):
|
|
111
|
+
# TODO: fall back to original host if this fails?
|
|
112
|
+
host = self.cache_host
|
|
113
|
+
else:
|
|
114
|
+
host = self.host
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
async with aiohttp.ClientSession(
|
|
118
|
+
conn_timeout=self.config["response_timeout"],
|
|
119
|
+
read_timeout=self.config["response_timeout"],
|
|
120
|
+
) as session:
|
|
121
|
+
async with session.request(
|
|
122
|
+
method=method, url=urljoin(host, url), headers=headers, **kwargs
|
|
123
|
+
) as resp:
|
|
124
|
+
# if nobody awaits resp.text() or resp.json() before we exit the session context manager, then the
|
|
125
|
+
# http connection gets closed before we read the response; then later calls to resp.text/json will
|
|
126
|
+
# fail.
|
|
127
|
+
await resp.text()
|
|
128
|
+
return resp
|
|
129
|
+
|
|
130
|
+
except aiohttp.client_exceptions.ClientConnectionError:
|
|
131
|
+
raise exceptions.MasterNotAvailableException(MISSING_MASTER.format(host))
|
|
132
|
+
except aiohttp.client_exceptions.TooManyRedirects:
|
|
133
|
+
raise exceptions.MasterTemporarilyNotAvailableException(
|
|
134
|
+
(
|
|
135
|
+
"Unable to connect to master at %s, likely due to "
|
|
136
|
+
"an ongoing leader election"
|
|
137
|
+
)
|
|
138
|
+
% host
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
async def fetch(self, url, **kwargs):
|
|
142
|
+
return await self._request(url, **kwargs)
|
|
143
|
+
|
|
144
|
+
async def post(self, url, **kwargs):
|
|
145
|
+
return await self._request(url, method="POST", **kwargs)
|
|
146
|
+
|
|
147
|
+
def _file_resolver(self, cfg):
|
|
148
|
+
return self.resolve(open(cfg[6:], "r+").read().strip())
|
|
149
|
+
|
|
150
|
+
@retry(KazooTimeoutError, tries=5, delay=0.5, logger=logger)
|
|
151
|
+
def _zookeeper_resolver(self, cfg):
|
|
152
|
+
hosts, path = cfg[5:].split("/", 1)
|
|
153
|
+
path = "/" + path
|
|
154
|
+
|
|
155
|
+
retry = KazooRetry(max_tries=10)
|
|
156
|
+
with zookeeper.client(
|
|
157
|
+
hosts=hosts, read_only=True, connection_retry=retry, command_retry=retry
|
|
158
|
+
) as zk:
|
|
159
|
+
|
|
160
|
+
def master_id(key):
|
|
161
|
+
return int(key.split("_")[-1])
|
|
162
|
+
|
|
163
|
+
def get_masters():
|
|
164
|
+
return [x for x in zk.get_children(path) if re.search(r"\d+", x)]
|
|
165
|
+
|
|
166
|
+
leader = sorted(get_masters(), key=lambda x: master_id(x))
|
|
167
|
+
|
|
168
|
+
if len(leader) == 0:
|
|
169
|
+
raise exceptions.MasterNotAvailableException(
|
|
170
|
+
f"cannot find any masters at {cfg}"
|
|
171
|
+
)
|
|
172
|
+
data, stat = zk.get(os.path.join(path, leader[0]))
|
|
173
|
+
|
|
174
|
+
if not data:
|
|
175
|
+
exceptions.MasterNotAvailableException(
|
|
176
|
+
"Cannot retrieve valid MasterInfo data from ZooKeeper"
|
|
177
|
+
)
|
|
178
|
+
else:
|
|
179
|
+
data = data.decode("utf8")
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
parsed = json.loads(data)
|
|
183
|
+
if parsed and "address" in parsed:
|
|
184
|
+
ip = parsed["address"].get("ip")
|
|
185
|
+
port = parsed["address"].get("port")
|
|
186
|
+
if ip and port:
|
|
187
|
+
return f"{ip}:{port}"
|
|
188
|
+
except ValueError as parse_error:
|
|
189
|
+
log.debug(
|
|
190
|
+
"[WARN] No JSON content, probably connecting to older "
|
|
191
|
+
"Mesos version. Reason: {}".format(parse_error)
|
|
192
|
+
)
|
|
193
|
+
raise exceptions.MasterNotAvailableException(
|
|
194
|
+
"Failed to parse mesos master ip from ZK"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
@log.duration
|
|
198
|
+
def resolve(self, cfg):
|
|
199
|
+
"""Resolve the URL to the mesos master.
|
|
200
|
+
|
|
201
|
+
The value of cfg should be one of:
|
|
202
|
+
- host:port
|
|
203
|
+
- zk://host1:port1,host2:port2/path
|
|
204
|
+
- zk://username:password@host1:port1/path
|
|
205
|
+
- file:///path/to/file (where file contains one of the above)
|
|
206
|
+
"""
|
|
207
|
+
if cfg.startswith("zk:"):
|
|
208
|
+
return self._zookeeper_resolver(cfg)
|
|
209
|
+
elif cfg.startswith("file:"):
|
|
210
|
+
return self._file_resolver(cfg)
|
|
211
|
+
else:
|
|
212
|
+
return cfg
|
|
213
|
+
|
|
214
|
+
@async_ttl_cache(ttl=15, cleanup_self=True)
|
|
215
|
+
async def state(self) -> MesosState:
|
|
216
|
+
return await (await self.fetch("/master/state.json", cached=True)).json()
|
|
217
|
+
|
|
218
|
+
async def state_summary(self) -> MesosState:
|
|
219
|
+
return await (await self.fetch("/master/state-summary")).json()
|
|
220
|
+
|
|
221
|
+
@async_ttl_cache(ttl=None, cleanup_self=True)
|
|
222
|
+
async def slave(self, fltr):
|
|
223
|
+
lst = await self.slaves(fltr)
|
|
224
|
+
|
|
225
|
+
log.debug(f"master.slave({fltr})")
|
|
226
|
+
|
|
227
|
+
if len(lst) == 0:
|
|
228
|
+
raise exceptions.SlaveDoesNotExist(f"Slave {fltr} no longer exists.")
|
|
229
|
+
|
|
230
|
+
elif len(lst) > 1:
|
|
231
|
+
raise exceptions.MultipleSlavesForIDError(
|
|
232
|
+
"Multiple slaves matching filter {}. {}".format(
|
|
233
|
+
fltr, ",".join([slave.id for slave in lst])
|
|
234
|
+
)
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
return lst[0]
|
|
238
|
+
|
|
239
|
+
async def slaves(self, fltr=""):
|
|
240
|
+
return [
|
|
241
|
+
slave.MesosSlave(self.config, x)
|
|
242
|
+
for x in (await self.state())["slaves"]
|
|
243
|
+
if fltr == x["id"]
|
|
244
|
+
]
|
|
245
|
+
|
|
246
|
+
async def _task_list(self, active_only=False):
|
|
247
|
+
keys = ["tasks"]
|
|
248
|
+
if not active_only:
|
|
249
|
+
keys.append("completed_tasks")
|
|
250
|
+
return itertools.chain(
|
|
251
|
+
*[util.merge(x, *keys) for x in await self._framework_list(active_only)]
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
async def task(self, fltr):
|
|
255
|
+
lst = await self.tasks(fltr)
|
|
256
|
+
|
|
257
|
+
if len(lst) == 0:
|
|
258
|
+
raise exceptions.TaskNotFoundException(
|
|
259
|
+
"Cannot find a task with filter %s" % fltr
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
elif len(lst) > 1:
|
|
263
|
+
raise exceptions.MultipleTasksForIDError(
|
|
264
|
+
"Multiple tasks matching filter {}. {}".format(
|
|
265
|
+
fltr, ",".join([task.id for task in lst])
|
|
266
|
+
)
|
|
267
|
+
)
|
|
268
|
+
return lst[0]
|
|
269
|
+
|
|
270
|
+
async def orphan_tasks(self):
|
|
271
|
+
return (await self.state())["orphan_tasks"]
|
|
272
|
+
|
|
273
|
+
# XXX - need to filter on task state as well as id
|
|
274
|
+
async def tasks(self, fltr="", active_only=False):
|
|
275
|
+
return [
|
|
276
|
+
task.Task(self, x)
|
|
277
|
+
for x in await self._task_list(active_only)
|
|
278
|
+
if fltr in x["id"] or fnmatch.fnmatch(x["id"], fltr)
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
async def framework(self, fwid):
|
|
282
|
+
return list(filter(lambda x: x.id == fwid, await self.frameworks()))[0]
|
|
283
|
+
|
|
284
|
+
async def _framework_list(self, active_only=False):
|
|
285
|
+
keys = ["frameworks"]
|
|
286
|
+
if not active_only:
|
|
287
|
+
keys.append("completed_frameworks")
|
|
288
|
+
return util.merge(await self._frameworks(), *keys)
|
|
289
|
+
|
|
290
|
+
@async_ttl_cache(ttl=15, cleanup_self=True)
|
|
291
|
+
async def _frameworks(self):
|
|
292
|
+
return await (await self.fetch("/master/frameworks", cached=True)).json()
|
|
293
|
+
|
|
294
|
+
async def frameworks(self, active_only=False):
|
|
295
|
+
return [framework.Framework(f) for f in await self._framework_list(active_only)]
|
|
296
|
+
|
|
297
|
+
async def teardown(self, framework_id):
|
|
298
|
+
return await self.post("/master/teardown", data="frameworkId=%s" % framework_id)
|
|
299
|
+
|
|
300
|
+
async def metrics_snapshot(self) -> MesosMetrics:
|
|
301
|
+
return await (await self.fetch("/metrics/snapshot")).json()
|
|
302
|
+
|
|
303
|
+
@property # type: ignore
|
|
304
|
+
@util.memoize
|
|
305
|
+
def log(self):
|
|
306
|
+
return mesos_file.File(self, path="/master/log")
|