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,277 @@
|
|
|
1
|
+
# Copyright 2015-2017 Yelp Inc.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
# See the License for the specific language governing permissions and
|
|
12
|
+
# limitations under the License.
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
import sys
|
|
17
|
+
from typing import Any
|
|
18
|
+
from typing import Dict
|
|
19
|
+
from typing import List
|
|
20
|
+
from typing import Optional
|
|
21
|
+
from typing import Sequence
|
|
22
|
+
from typing import Union
|
|
23
|
+
|
|
24
|
+
from paasta_tools.secret_providers import SecretProvider
|
|
25
|
+
from paasta_tools.utils import SecretVolume
|
|
26
|
+
|
|
27
|
+
SECRET_REGEX = r"^(SHARED_)?SECRET\([A-Za-z0-9_-]*\)$"
|
|
28
|
+
SHARED_SECRET_SERVICE = "_shared"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def is_secret_ref(env_var_val: str) -> bool:
|
|
32
|
+
pattern = re.compile(SECRET_REGEX)
|
|
33
|
+
try:
|
|
34
|
+
match = pattern.match(env_var_val)
|
|
35
|
+
except TypeError:
|
|
36
|
+
# it can't be a secret ref if it isn't a string
|
|
37
|
+
return False
|
|
38
|
+
return match is not None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def is_shared_secret(env_var_val: str) -> bool:
|
|
42
|
+
return env_var_val.startswith("SHARED_")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def is_shared_secret_from_secret_name(soa_dir: str, secret_name: str) -> bool:
|
|
46
|
+
"""Alternative way of figuring if a secret is shared, directly from the secret_name."""
|
|
47
|
+
secret_path = os.path.join(
|
|
48
|
+
soa_dir, SHARED_SECRET_SERVICE, "secrets", f"{secret_name}.json"
|
|
49
|
+
)
|
|
50
|
+
return os.path.isfile(secret_path)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_hmac_for_secret(
|
|
54
|
+
env_var_val: str, service: str, soa_dir: str, secret_environment: str
|
|
55
|
+
) -> Optional[str]:
|
|
56
|
+
secret_name = get_secret_name_from_ref(env_var_val)
|
|
57
|
+
if is_shared_secret(env_var_val):
|
|
58
|
+
service = SHARED_SECRET_SERVICE
|
|
59
|
+
secret_path = os.path.join(soa_dir, service, "secrets", f"{secret_name}.json")
|
|
60
|
+
try:
|
|
61
|
+
with open(secret_path, "r") as json_secret_file:
|
|
62
|
+
secret_file = json.load(json_secret_file)
|
|
63
|
+
try:
|
|
64
|
+
return secret_file["environments"][secret_environment]["signature"]
|
|
65
|
+
except KeyError:
|
|
66
|
+
print(
|
|
67
|
+
"Failed to get secret signature at environments:{}:signature in json"
|
|
68
|
+
" file".format(secret_environment),
|
|
69
|
+
file=sys.stderr,
|
|
70
|
+
)
|
|
71
|
+
return None
|
|
72
|
+
except IOError:
|
|
73
|
+
print(f"Failed to open json secret at {secret_path}", file=sys.stderr)
|
|
74
|
+
return None
|
|
75
|
+
except json.decoder.JSONDecodeError:
|
|
76
|
+
print(f"Failed to deserialise json secret at {secret_path}", file=sys.stderr)
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_secret_name_from_ref(env_var_val: str) -> str:
|
|
81
|
+
"""
|
|
82
|
+
:param env_var_val: Expect value is in form of "SECRET(<secret-name>)"
|
|
83
|
+
"""
|
|
84
|
+
return env_var_val.split("(")[1][:-1]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_secret_provider(
|
|
88
|
+
secret_provider_name: str,
|
|
89
|
+
soa_dir: str,
|
|
90
|
+
service_name: str,
|
|
91
|
+
cluster_names: List[str],
|
|
92
|
+
secret_provider_kwargs: Dict[str, Any],
|
|
93
|
+
) -> SecretProvider:
|
|
94
|
+
SecretProvider = __import__(
|
|
95
|
+
secret_provider_name, fromlist=["SecretProvider"]
|
|
96
|
+
).SecretProvider
|
|
97
|
+
return SecretProvider(
|
|
98
|
+
soa_dir=soa_dir,
|
|
99
|
+
service_name=service_name,
|
|
100
|
+
cluster_names=cluster_names,
|
|
101
|
+
**secret_provider_kwargs,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_secret_hashes(
|
|
106
|
+
environment_variables: Dict[str, str],
|
|
107
|
+
secret_environment: str,
|
|
108
|
+
service: str,
|
|
109
|
+
soa_dir: str,
|
|
110
|
+
) -> Dict[str, str]:
|
|
111
|
+
|
|
112
|
+
secret_hashes = {}
|
|
113
|
+
for env_var_val in environment_variables.values():
|
|
114
|
+
if is_secret_ref(env_var_val):
|
|
115
|
+
secret_hashes[env_var_val] = get_hmac_for_secret(
|
|
116
|
+
env_var_val=env_var_val,
|
|
117
|
+
service=service,
|
|
118
|
+
soa_dir=soa_dir,
|
|
119
|
+
secret_environment=secret_environment,
|
|
120
|
+
)
|
|
121
|
+
return secret_hashes
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def decrypt_secret_environment_for_service(
|
|
125
|
+
secret_env_vars: Dict[str, str],
|
|
126
|
+
service_name: str,
|
|
127
|
+
secret_provider_name: str,
|
|
128
|
+
soa_dir: str,
|
|
129
|
+
cluster_name: str,
|
|
130
|
+
secret_provider_kwargs: Dict[str, Any],
|
|
131
|
+
) -> Dict[str, str]:
|
|
132
|
+
if not secret_env_vars:
|
|
133
|
+
return {}
|
|
134
|
+
|
|
135
|
+
secret_provider = get_secret_provider(
|
|
136
|
+
secret_provider_name=secret_provider_name,
|
|
137
|
+
soa_dir=soa_dir,
|
|
138
|
+
service_name=service_name,
|
|
139
|
+
cluster_names=[cluster_name],
|
|
140
|
+
secret_provider_kwargs=secret_provider_kwargs,
|
|
141
|
+
)
|
|
142
|
+
return secret_provider.decrypt_environment(secret_env_vars)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def decrypt_secret_environment_variables(
|
|
146
|
+
secret_provider_name: str,
|
|
147
|
+
environment: Dict[str, str],
|
|
148
|
+
soa_dir: str,
|
|
149
|
+
service_name: str,
|
|
150
|
+
cluster_name: str,
|
|
151
|
+
secret_provider_kwargs: Dict[str, Any],
|
|
152
|
+
) -> Dict[str, str]:
|
|
153
|
+
decrypted_secrets = {}
|
|
154
|
+
service_secret_env = {}
|
|
155
|
+
shared_secret_env = {}
|
|
156
|
+
for k, v in environment.items():
|
|
157
|
+
if is_secret_ref(v):
|
|
158
|
+
if is_shared_secret(v):
|
|
159
|
+
shared_secret_env[k] = v
|
|
160
|
+
else:
|
|
161
|
+
service_secret_env[k] = v
|
|
162
|
+
secret_provider_kwargs["vault_num_uses"] = len(service_secret_env) + len(
|
|
163
|
+
shared_secret_env
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
decrypted_secrets.update(
|
|
167
|
+
decrypt_secret_environment_for_service(
|
|
168
|
+
service_secret_env,
|
|
169
|
+
service_name,
|
|
170
|
+
secret_provider_name,
|
|
171
|
+
soa_dir,
|
|
172
|
+
cluster_name,
|
|
173
|
+
secret_provider_kwargs,
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
decrypted_secrets.update(
|
|
177
|
+
decrypt_secret_environment_for_service(
|
|
178
|
+
shared_secret_env,
|
|
179
|
+
SHARED_SECRET_SERVICE,
|
|
180
|
+
secret_provider_name,
|
|
181
|
+
soa_dir,
|
|
182
|
+
cluster_name,
|
|
183
|
+
secret_provider_kwargs,
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
return decrypted_secrets
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def decrypt_secret_volumes(
|
|
190
|
+
secret_provider_name: str,
|
|
191
|
+
secret_volumes_config: Sequence[SecretVolume],
|
|
192
|
+
soa_dir: str,
|
|
193
|
+
service_name: str,
|
|
194
|
+
cluster_name: str,
|
|
195
|
+
secret_provider_kwargs: Dict[str, Any],
|
|
196
|
+
) -> Dict[str, Union[str, bytes]]:
|
|
197
|
+
secret_volumes = {}
|
|
198
|
+
# The config might look one of two ways:
|
|
199
|
+
# Implicit full path consisting of the container path and the secret name:
|
|
200
|
+
# secret_volumes:
|
|
201
|
+
# - container_path: /nail/foo
|
|
202
|
+
# secret_name: the_secret_1
|
|
203
|
+
# - container_path: /nail/bar
|
|
204
|
+
# secret_name: the_secret_2
|
|
205
|
+
#
|
|
206
|
+
# This ^ should result in two files (/nail/foo/the_secret_1, /nail/foo/the_secret_2)
|
|
207
|
+
#
|
|
208
|
+
# OR
|
|
209
|
+
#
|
|
210
|
+
# Multiple files within a folder with explicit path names
|
|
211
|
+
# secret_volumes:
|
|
212
|
+
# - container_path: /nail/foo
|
|
213
|
+
# items:
|
|
214
|
+
# - key: the_secret_1
|
|
215
|
+
# path: bar.yaml
|
|
216
|
+
# - key: the_secret_2
|
|
217
|
+
# path: baz.yaml
|
|
218
|
+
#
|
|
219
|
+
# This ^ should result in 2 files (/nail/foo/bar.yaml, /nail/foo/baz.yaml)
|
|
220
|
+
# We need to support both cases
|
|
221
|
+
for secret_volume in secret_volumes_config:
|
|
222
|
+
if not secret_volume.get("items"):
|
|
223
|
+
secret_contents = decrypt_secret(
|
|
224
|
+
secret_provider_name=secret_provider_name,
|
|
225
|
+
soa_dir=soa_dir,
|
|
226
|
+
service_name=service_name,
|
|
227
|
+
cluster_name=cluster_name,
|
|
228
|
+
secret_provider_kwargs=secret_provider_kwargs,
|
|
229
|
+
secret_name=secret_volume["secret_name"],
|
|
230
|
+
decode=False,
|
|
231
|
+
)
|
|
232
|
+
# Index by container path => the actual secret contents, to be used downstream to create local files and mount into the container
|
|
233
|
+
secret_volumes[
|
|
234
|
+
os.path.join(
|
|
235
|
+
secret_volume["container_path"], secret_volume["secret_name"]
|
|
236
|
+
)
|
|
237
|
+
] = secret_contents
|
|
238
|
+
else:
|
|
239
|
+
for item in secret_volume["items"]:
|
|
240
|
+
secret_contents = decrypt_secret(
|
|
241
|
+
secret_provider_name=secret_provider_name,
|
|
242
|
+
soa_dir=soa_dir,
|
|
243
|
+
service_name=service_name,
|
|
244
|
+
cluster_name=cluster_name,
|
|
245
|
+
secret_provider_kwargs=secret_provider_kwargs,
|
|
246
|
+
secret_name=item["key"],
|
|
247
|
+
decode=False,
|
|
248
|
+
)
|
|
249
|
+
# Index by container path => the actual secret contents, to be used downstream to create local files and mount into the container
|
|
250
|
+
secret_volumes[
|
|
251
|
+
os.path.join(secret_volume["container_path"], item["path"])
|
|
252
|
+
] = secret_contents
|
|
253
|
+
|
|
254
|
+
return secret_volumes
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def decrypt_secret(
|
|
258
|
+
secret_provider_name: str,
|
|
259
|
+
soa_dir: str,
|
|
260
|
+
service_name: str,
|
|
261
|
+
cluster_name: str,
|
|
262
|
+
secret_provider_kwargs: Dict[str, Any],
|
|
263
|
+
secret_name: str,
|
|
264
|
+
decode: bool = True,
|
|
265
|
+
) -> Union[str, bytes]:
|
|
266
|
+
secret_provider = get_secret_provider(
|
|
267
|
+
secret_provider_name=secret_provider_name,
|
|
268
|
+
soa_dir=soa_dir,
|
|
269
|
+
service_name=service_name,
|
|
270
|
+
cluster_names=[cluster_name],
|
|
271
|
+
secret_provider_kwargs=secret_provider_kwargs,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
if decode:
|
|
275
|
+
return secret_provider.decrypt_secret(secret_name)
|
|
276
|
+
else:
|
|
277
|
+
return secret_provider.decrypt_secret_raw(secret_name)
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# Copyright 2015-2018 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
|
+
Usage: ./setup_kubernetes_services.py <service.instance>
|
|
17
|
+
|
|
18
|
+
Command line options:
|
|
19
|
+
|
|
20
|
+
- -c, --cluster: PAASTA cluster
|
|
21
|
+
- -v, --verbose: Verbose output
|
|
22
|
+
"""
|
|
23
|
+
import argparse
|
|
24
|
+
import logging
|
|
25
|
+
import os
|
|
26
|
+
import sys
|
|
27
|
+
import time
|
|
28
|
+
from functools import partial
|
|
29
|
+
from typing import AbstractSet
|
|
30
|
+
from typing import Iterator
|
|
31
|
+
from typing import Mapping
|
|
32
|
+
from typing import Set
|
|
33
|
+
|
|
34
|
+
import kubernetes.client as k8s
|
|
35
|
+
|
|
36
|
+
from paasta_tools import yaml_tools as yaml
|
|
37
|
+
from paasta_tools.kubernetes_tools import ensure_namespace
|
|
38
|
+
from paasta_tools.kubernetes_tools import KubeClient
|
|
39
|
+
from paasta_tools.kubernetes_tools import limit_size_with_hash
|
|
40
|
+
from paasta_tools.kubernetes_tools import paasta_prefixed
|
|
41
|
+
from paasta_tools.kubernetes_tools import registration_label
|
|
42
|
+
from paasta_tools.kubernetes_tools import sanitise_kubernetes_name
|
|
43
|
+
from paasta_tools.utils import DEFAULT_SOA_DIR
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
log = logging.getLogger(__name__)
|
|
47
|
+
|
|
48
|
+
UNIFIED_K8S_SVC_NAME = "paasta-routing"
|
|
49
|
+
UNIFIED_SVC_PORT = 1337
|
|
50
|
+
PAASTA_SVC_PORT = 8888
|
|
51
|
+
PAASTA_NAMESPACE = "paasta"
|
|
52
|
+
ANNOTATIONS = {paasta_prefixed("managed_by"): "setup_istio_mesh"}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def parse_args() -> argparse.Namespace:
|
|
56
|
+
parser = argparse.ArgumentParser(description="Creates Kubernetes services.")
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"-v",
|
|
59
|
+
"--verbose",
|
|
60
|
+
action="store_true",
|
|
61
|
+
dest="verbose",
|
|
62
|
+
default=False,
|
|
63
|
+
)
|
|
64
|
+
parser.add_argument(
|
|
65
|
+
"--dry-run",
|
|
66
|
+
action="store_true",
|
|
67
|
+
dest="dry_run",
|
|
68
|
+
default=False,
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"-l",
|
|
72
|
+
"--rate-limit",
|
|
73
|
+
dest="rate_limit",
|
|
74
|
+
default=0,
|
|
75
|
+
metavar="LIMIT",
|
|
76
|
+
type=float,
|
|
77
|
+
help="Maximum number of write calls to k8s per second. Default is 0 (no limit).",
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"-d",
|
|
81
|
+
"--soa-dir",
|
|
82
|
+
dest="soa_dir",
|
|
83
|
+
default=DEFAULT_SOA_DIR,
|
|
84
|
+
metavar="LIMIT",
|
|
85
|
+
type=str,
|
|
86
|
+
help=f"Directory with service declarations. Default is {DEFAULT_SOA_DIR}",
|
|
87
|
+
)
|
|
88
|
+
args = parser.parse_args()
|
|
89
|
+
return args
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def load_smartstack_namespaces(soa_dir: str = DEFAULT_SOA_DIR) -> Mapping:
|
|
93
|
+
namespaces = {}
|
|
94
|
+
|
|
95
|
+
_, dirs, _ = next(os.walk(soa_dir))
|
|
96
|
+
for dir in dirs:
|
|
97
|
+
file_path = f"{soa_dir}/{dir}/smartstack.yaml"
|
|
98
|
+
if not os.path.isfile(file_path):
|
|
99
|
+
continue
|
|
100
|
+
try:
|
|
101
|
+
with open(file_path) as f:
|
|
102
|
+
svc_namespaces = yaml.safe_load(f)
|
|
103
|
+
for (ns, details) in svc_namespaces.items():
|
|
104
|
+
namespaces[f"{dir}.{ns}"] = details
|
|
105
|
+
except Exception as err:
|
|
106
|
+
log.warn(f"Failed to load namespaces for {dir}: {err}")
|
|
107
|
+
|
|
108
|
+
return namespaces
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def sanitise_kubernetes_service_name(name: str) -> str:
|
|
112
|
+
return limit_size_with_hash(sanitise_kubernetes_name(name).replace(".", "---"))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_existing_kubernetes_service_names(kube_client: KubeClient) -> Set[str]:
|
|
116
|
+
service_objects = kube_client.core.list_namespaced_service(PAASTA_NAMESPACE)
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
item.metadata.name
|
|
120
|
+
for item in service_objects.items
|
|
121
|
+
if item.metadata.annotations
|
|
122
|
+
if item.metadata.annotations.get(paasta_prefixed("managed_by"))
|
|
123
|
+
== "setup_istio_mesh"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def get_existing_kubernetes_virtual_services(kube_client: KubeClient) -> Set[str]:
|
|
128
|
+
virtual_service_objects = kube_client.custom.list_namespaced_custom_object(
|
|
129
|
+
"networking.istio.io", "v1beta1", PAASTA_NAMESPACE, "virtualservices"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
return {item["metadata"]["name"] for item in virtual_service_objects["items"]}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def setup_paasta_routing(kube_client: KubeClient, namespaces: Mapping) -> Iterator:
|
|
136
|
+
# Add smartstack ports for routing, Clients can connect to this
|
|
137
|
+
# Directly without need of setting x-yelp-svc header
|
|
138
|
+
# Add port 1337 for envoy unified listener.
|
|
139
|
+
# Clients can connect to this listenner and set x-yelp-svc header for routing
|
|
140
|
+
port_list = sorted(
|
|
141
|
+
val["proxy_port"] for val in namespaces.values() if val.get("proxy_port")
|
|
142
|
+
)
|
|
143
|
+
ports = [
|
|
144
|
+
k8s.V1ServicePort(
|
|
145
|
+
name=f"p{port}",
|
|
146
|
+
port=port,
|
|
147
|
+
protocol="TCP",
|
|
148
|
+
target_port=PAASTA_SVC_PORT,
|
|
149
|
+
app_protocol="http",
|
|
150
|
+
)
|
|
151
|
+
for port in [1337, *port_list]
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
service_meta = k8s.V1ObjectMeta(name=UNIFIED_K8S_SVC_NAME, annotations=ANNOTATIONS)
|
|
155
|
+
service_spec = k8s.V1ServiceSpec(ports=ports)
|
|
156
|
+
service_object = k8s.V1APIService(metadata=service_meta, spec=service_spec)
|
|
157
|
+
yield partial(
|
|
158
|
+
kube_client.core.create_namespaced_service, PAASTA_NAMESPACE, service_object
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
sorted_namespaces = sorted(namespaces.keys())
|
|
162
|
+
x_yelp_svc_routes = [
|
|
163
|
+
dict(
|
|
164
|
+
match=[dict(headers={"x-yelp-svc": dict(exact=mesh_ns)})],
|
|
165
|
+
delegate=dict(
|
|
166
|
+
name=sanitise_kubernetes_service_name(mesh_ns),
|
|
167
|
+
namespace=PAASTA_NAMESPACE,
|
|
168
|
+
),
|
|
169
|
+
)
|
|
170
|
+
for mesh_ns in sorted_namespaces
|
|
171
|
+
]
|
|
172
|
+
port_routes = [
|
|
173
|
+
dict(
|
|
174
|
+
match=[dict(port=namespaces[mesh_ns]["proxy_port"])],
|
|
175
|
+
delegate=dict(
|
|
176
|
+
name=sanitise_kubernetes_service_name(mesh_ns),
|
|
177
|
+
namespace=PAASTA_NAMESPACE,
|
|
178
|
+
),
|
|
179
|
+
)
|
|
180
|
+
for mesh_ns in sorted_namespaces
|
|
181
|
+
if namespaces[mesh_ns].get("proxy_port")
|
|
182
|
+
]
|
|
183
|
+
virtual_service = dict(
|
|
184
|
+
apiVersion="networking.istio.io/v1alpha3",
|
|
185
|
+
kind="VirtualService",
|
|
186
|
+
metadata=dict(
|
|
187
|
+
name="paasta-routing",
|
|
188
|
+
namespace=PAASTA_NAMESPACE,
|
|
189
|
+
),
|
|
190
|
+
spec=dict(
|
|
191
|
+
hosts=["paasta-routing", "169.254.255.254"],
|
|
192
|
+
http=x_yelp_svc_routes + port_routes,
|
|
193
|
+
),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
yield partial(
|
|
197
|
+
kube_client.custom.create_namespaced_custom_object,
|
|
198
|
+
"networking.istio.io",
|
|
199
|
+
"v1alpha3",
|
|
200
|
+
PAASTA_NAMESPACE,
|
|
201
|
+
"virtualservices",
|
|
202
|
+
virtual_service,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def setup_paasta_namespace_services(
|
|
207
|
+
kube_client: KubeClient,
|
|
208
|
+
paasta_namespaces: AbstractSet,
|
|
209
|
+
existing_namespace_services: Set[str],
|
|
210
|
+
existing_virtual_services: Set[str],
|
|
211
|
+
) -> Iterator:
|
|
212
|
+
for namespace in paasta_namespaces:
|
|
213
|
+
service = sanitise_kubernetes_service_name(namespace)
|
|
214
|
+
if service not in existing_namespace_services:
|
|
215
|
+
log.info(f"Creating k8s service {service} because it does not exist yet.")
|
|
216
|
+
|
|
217
|
+
service_meta = k8s.V1ObjectMeta(name=service, annotations=ANNOTATIONS)
|
|
218
|
+
port_spec = k8s.V1ServicePort(
|
|
219
|
+
name="http", port=PAASTA_SVC_PORT, protocol="TCP", app_protocol="http"
|
|
220
|
+
)
|
|
221
|
+
service_spec = k8s.V1ServiceSpec(
|
|
222
|
+
selector={registration_label(namespace): "true"}, ports=[port_spec]
|
|
223
|
+
)
|
|
224
|
+
service_object = k8s.V1APIService(metadata=service_meta, spec=service_spec)
|
|
225
|
+
yield partial(
|
|
226
|
+
kube_client.core.create_namespaced_service,
|
|
227
|
+
PAASTA_NAMESPACE,
|
|
228
|
+
service_object,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
if service not in existing_virtual_services:
|
|
232
|
+
log.info(
|
|
233
|
+
f"Creating istio virtualservice {service} because it does not exist yet."
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
route = dict(
|
|
237
|
+
destination=dict(host=service, port=dict(number=PAASTA_SVC_PORT))
|
|
238
|
+
)
|
|
239
|
+
virtual_service = dict(
|
|
240
|
+
apiVersion="networking.istio.io/v1alpha3",
|
|
241
|
+
kind="VirtualService",
|
|
242
|
+
metadata=dict(name=service, namespace=PAASTA_NAMESPACE),
|
|
243
|
+
spec=dict(http=[dict(route=[route])]),
|
|
244
|
+
)
|
|
245
|
+
yield partial(
|
|
246
|
+
kube_client.custom.create_namespaced_custom_object,
|
|
247
|
+
"networking.istio.io",
|
|
248
|
+
"v1alpha3",
|
|
249
|
+
PAASTA_NAMESPACE,
|
|
250
|
+
"virtualservices",
|
|
251
|
+
virtual_service,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def cleanup_paasta_namespace_services(
|
|
256
|
+
kube_client: KubeClient,
|
|
257
|
+
paasta_namespaces: AbstractSet,
|
|
258
|
+
existing_namespace_services: Set[str],
|
|
259
|
+
existing_virtual_services: Set[str],
|
|
260
|
+
) -> Iterator:
|
|
261
|
+
declared_services = {
|
|
262
|
+
sanitise_kubernetes_service_name(ns) for ns in paasta_namespaces
|
|
263
|
+
}
|
|
264
|
+
for service in existing_namespace_services:
|
|
265
|
+
if service == UNIFIED_K8S_SVC_NAME or service in declared_services:
|
|
266
|
+
continue
|
|
267
|
+
log.info(f"Garbage collecting K8s Service {service}")
|
|
268
|
+
yield partial(
|
|
269
|
+
kube_client.core.delete_namespaced_service, service, PAASTA_NAMESPACE
|
|
270
|
+
)
|
|
271
|
+
for service in existing_virtual_services:
|
|
272
|
+
if service == UNIFIED_K8S_SVC_NAME or service in declared_services:
|
|
273
|
+
continue
|
|
274
|
+
log.info(f"Garbage collecting Istio VS {service}")
|
|
275
|
+
yield partial(
|
|
276
|
+
kube_client.custom.delete_namespaced_custom_object,
|
|
277
|
+
"networking.istio.io",
|
|
278
|
+
"v1beta1",
|
|
279
|
+
PAASTA_NAMESPACE,
|
|
280
|
+
"virtualservices",
|
|
281
|
+
service,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def process_kube_services(
|
|
286
|
+
kube_client: KubeClient, soa_dir: str = DEFAULT_SOA_DIR
|
|
287
|
+
) -> Iterator:
|
|
288
|
+
|
|
289
|
+
existing_namespace_services = get_existing_kubernetes_service_names(kube_client)
|
|
290
|
+
existing_virtual_services = get_existing_kubernetes_virtual_services(kube_client)
|
|
291
|
+
|
|
292
|
+
namespaces = load_smartstack_namespaces(soa_dir)
|
|
293
|
+
|
|
294
|
+
should_setup_unified = (
|
|
295
|
+
UNIFIED_K8S_SVC_NAME not in existing_namespace_services
|
|
296
|
+
or UNIFIED_K8S_SVC_NAME not in existing_virtual_services
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
if should_setup_unified:
|
|
300
|
+
log.info(f"Creating {UNIFIED_K8S_SVC_NAME} because it does not exist yet.")
|
|
301
|
+
yield from setup_paasta_routing(
|
|
302
|
+
kube_client=kube_client,
|
|
303
|
+
namespaces=namespaces,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
yield from setup_paasta_namespace_services(
|
|
307
|
+
kube_client,
|
|
308
|
+
namespaces.keys(),
|
|
309
|
+
existing_namespace_services,
|
|
310
|
+
existing_virtual_services,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
yield from cleanup_paasta_namespace_services(
|
|
314
|
+
kube_client,
|
|
315
|
+
namespaces.keys(),
|
|
316
|
+
existing_namespace_services,
|
|
317
|
+
existing_virtual_services,
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def setup_istio_mesh(
|
|
322
|
+
kube_client: KubeClient,
|
|
323
|
+
rate_limit: int = 0,
|
|
324
|
+
soa_dir: str = DEFAULT_SOA_DIR,
|
|
325
|
+
) -> bool:
|
|
326
|
+
delay = 0 if rate_limit == 0 else 1.0 / float(rate_limit)
|
|
327
|
+
took = delay
|
|
328
|
+
success = True
|
|
329
|
+
for fn in process_kube_services(kube_client=kube_client, soa_dir=soa_dir):
|
|
330
|
+
time.sleep(max(0, delay - took))
|
|
331
|
+
try:
|
|
332
|
+
log.debug(f"Calling yielded {fn.func}({fn.args})")
|
|
333
|
+
start = time.time()
|
|
334
|
+
result = fn()
|
|
335
|
+
took = time.time() - start
|
|
336
|
+
log.debug(f"Result: {result}, took {took}s")
|
|
337
|
+
except Exception:
|
|
338
|
+
success = False
|
|
339
|
+
log.exception(f"Failed calling {fn.func}({fn.args})")
|
|
340
|
+
return success
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def main() -> None:
|
|
344
|
+
args = parse_args()
|
|
345
|
+
logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
|
|
346
|
+
kube_client = KubeClient()
|
|
347
|
+
ensure_namespace(kube_client, namespace=PAASTA_NAMESPACE)
|
|
348
|
+
success = setup_istio_mesh(kube_client, args.rate_limit, args.soa_dir)
|
|
349
|
+
sys.exit(0 if success else 1)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
if __name__ == "__main__":
|
|
353
|
+
main()
|