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.
Files changed (348) hide show
  1. k8s_itests/__init__.py +0 -0
  2. k8s_itests/test_autoscaling.py +23 -0
  3. k8s_itests/utils.py +38 -0
  4. paasta_tools/__init__.py +20 -0
  5. paasta_tools/adhoc_tools.py +142 -0
  6. paasta_tools/api/__init__.py +13 -0
  7. paasta_tools/api/api.py +330 -0
  8. paasta_tools/api/api_docs/swagger.json +2323 -0
  9. paasta_tools/api/client.py +106 -0
  10. paasta_tools/api/settings.py +33 -0
  11. paasta_tools/api/tweens/__init__.py +6 -0
  12. paasta_tools/api/tweens/auth.py +125 -0
  13. paasta_tools/api/tweens/profiling.py +108 -0
  14. paasta_tools/api/tweens/request_logger.py +124 -0
  15. paasta_tools/api/views/__init__.py +13 -0
  16. paasta_tools/api/views/autoscaler.py +100 -0
  17. paasta_tools/api/views/exception.py +45 -0
  18. paasta_tools/api/views/flink.py +73 -0
  19. paasta_tools/api/views/instance.py +395 -0
  20. paasta_tools/api/views/pause_autoscaler.py +71 -0
  21. paasta_tools/api/views/remote_run.py +113 -0
  22. paasta_tools/api/views/resources.py +76 -0
  23. paasta_tools/api/views/service.py +35 -0
  24. paasta_tools/api/views/version.py +25 -0
  25. paasta_tools/apply_external_resources.py +79 -0
  26. paasta_tools/async_utils.py +109 -0
  27. paasta_tools/autoscaling/__init__.py +0 -0
  28. paasta_tools/autoscaling/autoscaling_service_lib.py +57 -0
  29. paasta_tools/autoscaling/forecasting.py +106 -0
  30. paasta_tools/autoscaling/max_all_k8s_services.py +41 -0
  31. paasta_tools/autoscaling/pause_service_autoscaler.py +77 -0
  32. paasta_tools/autoscaling/utils.py +52 -0
  33. paasta_tools/bounce_lib.py +184 -0
  34. paasta_tools/broadcast_log_to_services.py +62 -0
  35. paasta_tools/cassandracluster_tools.py +210 -0
  36. paasta_tools/check_autoscaler_max_instances.py +212 -0
  37. paasta_tools/check_cassandracluster_services_replication.py +35 -0
  38. paasta_tools/check_flink_services_health.py +203 -0
  39. paasta_tools/check_kubernetes_api.py +57 -0
  40. paasta_tools/check_kubernetes_services_replication.py +141 -0
  41. paasta_tools/check_oom_events.py +244 -0
  42. paasta_tools/check_services_replication_tools.py +324 -0
  43. paasta_tools/check_spark_jobs.py +234 -0
  44. paasta_tools/cleanup_kubernetes_cr.py +138 -0
  45. paasta_tools/cleanup_kubernetes_crd.py +145 -0
  46. paasta_tools/cleanup_kubernetes_jobs.py +344 -0
  47. paasta_tools/cleanup_tron_namespaces.py +96 -0
  48. paasta_tools/cli/__init__.py +13 -0
  49. paasta_tools/cli/authentication.py +85 -0
  50. paasta_tools/cli/cli.py +260 -0
  51. paasta_tools/cli/cmds/__init__.py +13 -0
  52. paasta_tools/cli/cmds/autoscale.py +143 -0
  53. paasta_tools/cli/cmds/check.py +334 -0
  54. paasta_tools/cli/cmds/cook_image.py +147 -0
  55. paasta_tools/cli/cmds/get_docker_image.py +76 -0
  56. paasta_tools/cli/cmds/get_image_version.py +172 -0
  57. paasta_tools/cli/cmds/get_latest_deployment.py +93 -0
  58. paasta_tools/cli/cmds/info.py +155 -0
  59. paasta_tools/cli/cmds/itest.py +117 -0
  60. paasta_tools/cli/cmds/list.py +66 -0
  61. paasta_tools/cli/cmds/list_clusters.py +42 -0
  62. paasta_tools/cli/cmds/list_deploy_queue.py +171 -0
  63. paasta_tools/cli/cmds/list_namespaces.py +84 -0
  64. paasta_tools/cli/cmds/local_run.py +1396 -0
  65. paasta_tools/cli/cmds/logs.py +1601 -0
  66. paasta_tools/cli/cmds/mark_for_deployment.py +1988 -0
  67. paasta_tools/cli/cmds/mesh_status.py +174 -0
  68. paasta_tools/cli/cmds/pause_service_autoscaler.py +107 -0
  69. paasta_tools/cli/cmds/push_to_registry.py +275 -0
  70. paasta_tools/cli/cmds/remote_run.py +252 -0
  71. paasta_tools/cli/cmds/rollback.py +347 -0
  72. paasta_tools/cli/cmds/secret.py +549 -0
  73. paasta_tools/cli/cmds/security_check.py +59 -0
  74. paasta_tools/cli/cmds/spark_run.py +1400 -0
  75. paasta_tools/cli/cmds/start_stop_restart.py +401 -0
  76. paasta_tools/cli/cmds/status.py +2302 -0
  77. paasta_tools/cli/cmds/validate.py +1012 -0
  78. paasta_tools/cli/cmds/wait_for_deployment.py +275 -0
  79. paasta_tools/cli/fsm/__init__.py +13 -0
  80. paasta_tools/cli/fsm/autosuggest.py +82 -0
  81. paasta_tools/cli/fsm/template/README.md +8 -0
  82. paasta_tools/cli/fsm/template/cookiecutter.json +7 -0
  83. paasta_tools/cli/fsm/template/{{cookiecutter.service}}/kubernetes-PROD.yaml +91 -0
  84. paasta_tools/cli/fsm/template/{{cookiecutter.service}}/monitoring.yaml +20 -0
  85. paasta_tools/cli/fsm/template/{{cookiecutter.service}}/service.yaml +8 -0
  86. paasta_tools/cli/fsm/template/{{cookiecutter.service}}/smartstack.yaml +6 -0
  87. paasta_tools/cli/fsm_cmd.py +121 -0
  88. paasta_tools/cli/paasta_tabcomplete.sh +23 -0
  89. paasta_tools/cli/schemas/adhoc_schema.json +199 -0
  90. paasta_tools/cli/schemas/autoscaling_schema.json +91 -0
  91. paasta_tools/cli/schemas/autotuned_defaults/cassandracluster_schema.json +37 -0
  92. paasta_tools/cli/schemas/autotuned_defaults/kubernetes_schema.json +89 -0
  93. paasta_tools/cli/schemas/deploy_schema.json +173 -0
  94. paasta_tools/cli/schemas/eks_schema.json +970 -0
  95. paasta_tools/cli/schemas/kubernetes_schema.json +970 -0
  96. paasta_tools/cli/schemas/rollback_schema.json +160 -0
  97. paasta_tools/cli/schemas/service_schema.json +25 -0
  98. paasta_tools/cli/schemas/smartstack_schema.json +322 -0
  99. paasta_tools/cli/schemas/tron_schema.json +699 -0
  100. paasta_tools/cli/utils.py +1118 -0
  101. paasta_tools/clusterman.py +21 -0
  102. paasta_tools/config_utils.py +385 -0
  103. paasta_tools/contrib/__init__.py +0 -0
  104. paasta_tools/contrib/bounce_log_latency_parser.py +68 -0
  105. paasta_tools/contrib/check_manual_oapi_changes.sh +24 -0
  106. paasta_tools/contrib/check_orphans.py +306 -0
  107. paasta_tools/contrib/create_dynamodb_table.py +35 -0
  108. paasta_tools/contrib/create_paasta_playground.py +105 -0
  109. paasta_tools/contrib/emit_allocated_cpu_metrics.py +50 -0
  110. paasta_tools/contrib/get_running_task_allocation.py +346 -0
  111. paasta_tools/contrib/habitat_fixer.py +86 -0
  112. paasta_tools/contrib/ide_helper.py +316 -0
  113. paasta_tools/contrib/is_pod_healthy_in_proxy.py +139 -0
  114. paasta_tools/contrib/is_pod_healthy_in_smartstack.py +50 -0
  115. paasta_tools/contrib/kill_bad_containers.py +109 -0
  116. paasta_tools/contrib/mass-deploy-tag.sh +44 -0
  117. paasta_tools/contrib/mock_patch_checker.py +86 -0
  118. paasta_tools/contrib/paasta_update_soa_memcpu.py +520 -0
  119. paasta_tools/contrib/render_template.py +129 -0
  120. paasta_tools/contrib/rightsizer_soaconfigs_update.py +348 -0
  121. paasta_tools/contrib/service_shard_remove.py +157 -0
  122. paasta_tools/contrib/service_shard_update.py +373 -0
  123. paasta_tools/contrib/shared_ip_check.py +77 -0
  124. paasta_tools/contrib/timeouts_metrics_prom.py +64 -0
  125. paasta_tools/delete_kubernetes_deployments.py +89 -0
  126. paasta_tools/deployment_utils.py +44 -0
  127. paasta_tools/docker_wrapper.py +234 -0
  128. paasta_tools/docker_wrapper_imports.py +13 -0
  129. paasta_tools/drain_lib.py +351 -0
  130. paasta_tools/dump_locally_running_services.py +71 -0
  131. paasta_tools/eks_tools.py +119 -0
  132. paasta_tools/envoy_tools.py +373 -0
  133. paasta_tools/firewall.py +504 -0
  134. paasta_tools/firewall_logging.py +154 -0
  135. paasta_tools/firewall_update.py +172 -0
  136. paasta_tools/flink_tools.py +345 -0
  137. paasta_tools/flinkeks_tools.py +90 -0
  138. paasta_tools/frameworks/__init__.py +0 -0
  139. paasta_tools/frameworks/adhoc_scheduler.py +71 -0
  140. paasta_tools/frameworks/constraints.py +87 -0
  141. paasta_tools/frameworks/native_scheduler.py +652 -0
  142. paasta_tools/frameworks/native_service_config.py +301 -0
  143. paasta_tools/frameworks/task_store.py +245 -0
  144. paasta_tools/generate_all_deployments +9 -0
  145. paasta_tools/generate_authenticating_services.py +94 -0
  146. paasta_tools/generate_deployments_for_service.py +255 -0
  147. paasta_tools/generate_services_file.py +114 -0
  148. paasta_tools/generate_services_yaml.py +30 -0
  149. paasta_tools/hacheck.py +76 -0
  150. paasta_tools/instance/__init__.py +0 -0
  151. paasta_tools/instance/hpa_metrics_parser.py +122 -0
  152. paasta_tools/instance/kubernetes.py +1362 -0
  153. paasta_tools/iptables.py +240 -0
  154. paasta_tools/kafkacluster_tools.py +143 -0
  155. paasta_tools/kubernetes/__init__.py +0 -0
  156. paasta_tools/kubernetes/application/__init__.py +0 -0
  157. paasta_tools/kubernetes/application/controller_wrappers.py +476 -0
  158. paasta_tools/kubernetes/application/tools.py +90 -0
  159. paasta_tools/kubernetes/bin/__init__.py +0 -0
  160. paasta_tools/kubernetes/bin/kubernetes_remove_evicted_pods.py +164 -0
  161. paasta_tools/kubernetes/bin/paasta_cleanup_remote_run_resources.py +135 -0
  162. paasta_tools/kubernetes/bin/paasta_cleanup_stale_nodes.py +181 -0
  163. paasta_tools/kubernetes/bin/paasta_secrets_sync.py +758 -0
  164. paasta_tools/kubernetes/remote_run.py +558 -0
  165. paasta_tools/kubernetes_tools.py +4679 -0
  166. paasta_tools/list_kubernetes_service_instances.py +128 -0
  167. paasta_tools/list_tron_namespaces.py +60 -0
  168. paasta_tools/long_running_service_tools.py +678 -0
  169. paasta_tools/mac_address.py +44 -0
  170. paasta_tools/marathon_dashboard.py +0 -0
  171. paasta_tools/mesos/__init__.py +0 -0
  172. paasta_tools/mesos/cfg.py +46 -0
  173. paasta_tools/mesos/cluster.py +60 -0
  174. paasta_tools/mesos/exceptions.py +59 -0
  175. paasta_tools/mesos/framework.py +77 -0
  176. paasta_tools/mesos/log.py +48 -0
  177. paasta_tools/mesos/master.py +306 -0
  178. paasta_tools/mesos/mesos_file.py +169 -0
  179. paasta_tools/mesos/parallel.py +52 -0
  180. paasta_tools/mesos/slave.py +115 -0
  181. paasta_tools/mesos/task.py +94 -0
  182. paasta_tools/mesos/util.py +69 -0
  183. paasta_tools/mesos/zookeeper.py +37 -0
  184. paasta_tools/mesos_maintenance.py +848 -0
  185. paasta_tools/mesos_tools.py +1051 -0
  186. paasta_tools/metrics/__init__.py +0 -0
  187. paasta_tools/metrics/metastatus_lib.py +1110 -0
  188. paasta_tools/metrics/metrics_lib.py +217 -0
  189. paasta_tools/monitoring/__init__.py +13 -0
  190. paasta_tools/monitoring/check_k8s_api_performance.py +110 -0
  191. paasta_tools/monitoring_tools.py +652 -0
  192. paasta_tools/monkrelaycluster_tools.py +146 -0
  193. paasta_tools/nrtsearchservice_tools.py +143 -0
  194. paasta_tools/nrtsearchserviceeks_tools.py +68 -0
  195. paasta_tools/oom_logger.py +321 -0
  196. paasta_tools/paasta_deploy_tron_jobs +3 -0
  197. paasta_tools/paasta_execute_docker_command.py +123 -0
  198. paasta_tools/paasta_native_serviceinit.py +21 -0
  199. paasta_tools/paasta_service_config_loader.py +201 -0
  200. paasta_tools/paastaapi/__init__.py +29 -0
  201. paasta_tools/paastaapi/api/__init__.py +3 -0
  202. paasta_tools/paastaapi/api/autoscaler_api.py +302 -0
  203. paasta_tools/paastaapi/api/default_api.py +569 -0
  204. paasta_tools/paastaapi/api/remote_run_api.py +604 -0
  205. paasta_tools/paastaapi/api/resources_api.py +157 -0
  206. paasta_tools/paastaapi/api/service_api.py +1736 -0
  207. paasta_tools/paastaapi/api_client.py +818 -0
  208. paasta_tools/paastaapi/apis/__init__.py +22 -0
  209. paasta_tools/paastaapi/configuration.py +455 -0
  210. paasta_tools/paastaapi/exceptions.py +137 -0
  211. paasta_tools/paastaapi/model/__init__.py +5 -0
  212. paasta_tools/paastaapi/model/adhoc_launch_history.py +176 -0
  213. paasta_tools/paastaapi/model/autoscaler_count_msg.py +176 -0
  214. paasta_tools/paastaapi/model/deploy_queue.py +178 -0
  215. paasta_tools/paastaapi/model/deploy_queue_service_instance.py +194 -0
  216. paasta_tools/paastaapi/model/envoy_backend.py +185 -0
  217. paasta_tools/paastaapi/model/envoy_location.py +184 -0
  218. paasta_tools/paastaapi/model/envoy_status.py +181 -0
  219. paasta_tools/paastaapi/model/flink_cluster_overview.py +188 -0
  220. paasta_tools/paastaapi/model/flink_config.py +173 -0
  221. paasta_tools/paastaapi/model/flink_job.py +186 -0
  222. paasta_tools/paastaapi/model/flink_job_details.py +192 -0
  223. paasta_tools/paastaapi/model/flink_jobs.py +175 -0
  224. paasta_tools/paastaapi/model/float_and_error.py +173 -0
  225. paasta_tools/paastaapi/model/hpa_metric.py +176 -0
  226. paasta_tools/paastaapi/model/inline_object.py +170 -0
  227. paasta_tools/paastaapi/model/inline_response200.py +170 -0
  228. paasta_tools/paastaapi/model/inline_response2001.py +170 -0
  229. paasta_tools/paastaapi/model/instance_bounce_status.py +200 -0
  230. paasta_tools/paastaapi/model/instance_mesh_status.py +186 -0
  231. paasta_tools/paastaapi/model/instance_status.py +220 -0
  232. paasta_tools/paastaapi/model/instance_status_adhoc.py +187 -0
  233. paasta_tools/paastaapi/model/instance_status_cassandracluster.py +173 -0
  234. paasta_tools/paastaapi/model/instance_status_flink.py +173 -0
  235. paasta_tools/paastaapi/model/instance_status_kafkacluster.py +173 -0
  236. paasta_tools/paastaapi/model/instance_status_kubernetes.py +263 -0
  237. paasta_tools/paastaapi/model/instance_status_kubernetes_autoscaling_status.py +187 -0
  238. paasta_tools/paastaapi/model/instance_status_kubernetes_v2.py +197 -0
  239. paasta_tools/paastaapi/model/instance_status_tron.py +204 -0
  240. paasta_tools/paastaapi/model/instance_tasks.py +182 -0
  241. paasta_tools/paastaapi/model/integer_and_error.py +173 -0
  242. paasta_tools/paastaapi/model/kubernetes_container.py +178 -0
  243. paasta_tools/paastaapi/model/kubernetes_container_v2.py +219 -0
  244. paasta_tools/paastaapi/model/kubernetes_healthcheck.py +176 -0
  245. paasta_tools/paastaapi/model/kubernetes_pod.py +201 -0
  246. paasta_tools/paastaapi/model/kubernetes_pod_event.py +176 -0
  247. paasta_tools/paastaapi/model/kubernetes_pod_v2.py +213 -0
  248. paasta_tools/paastaapi/model/kubernetes_replica_set.py +185 -0
  249. paasta_tools/paastaapi/model/kubernetes_version.py +202 -0
  250. paasta_tools/paastaapi/model/remote_run_outcome.py +189 -0
  251. paasta_tools/paastaapi/model/remote_run_start.py +185 -0
  252. paasta_tools/paastaapi/model/remote_run_stop.py +176 -0
  253. paasta_tools/paastaapi/model/remote_run_token.py +173 -0
  254. paasta_tools/paastaapi/model/resource.py +187 -0
  255. paasta_tools/paastaapi/model/resource_item.py +187 -0
  256. paasta_tools/paastaapi/model/resource_value.py +176 -0
  257. paasta_tools/paastaapi/model/smartstack_backend.py +191 -0
  258. paasta_tools/paastaapi/model/smartstack_location.py +181 -0
  259. paasta_tools/paastaapi/model/smartstack_status.py +181 -0
  260. paasta_tools/paastaapi/model/task_tail_lines.py +176 -0
  261. paasta_tools/paastaapi/model_utils.py +1879 -0
  262. paasta_tools/paastaapi/models/__init__.py +62 -0
  263. paasta_tools/paastaapi/rest.py +287 -0
  264. paasta_tools/prune_completed_pods.py +220 -0
  265. paasta_tools/puppet_service_tools.py +59 -0
  266. paasta_tools/py.typed +1 -0
  267. paasta_tools/remote_git.py +127 -0
  268. paasta_tools/run-paasta-api-in-dev-mode.py +57 -0
  269. paasta_tools/run-paasta-api-playground.py +51 -0
  270. paasta_tools/secret_providers/__init__.py +66 -0
  271. paasta_tools/secret_providers/vault.py +214 -0
  272. paasta_tools/secret_tools.py +277 -0
  273. paasta_tools/setup_istio_mesh.py +353 -0
  274. paasta_tools/setup_kubernetes_cr.py +412 -0
  275. paasta_tools/setup_kubernetes_crd.py +138 -0
  276. paasta_tools/setup_kubernetes_internal_crd.py +154 -0
  277. paasta_tools/setup_kubernetes_job.py +353 -0
  278. paasta_tools/setup_prometheus_adapter_config.py +1028 -0
  279. paasta_tools/setup_tron_namespace.py +248 -0
  280. paasta_tools/slack.py +75 -0
  281. paasta_tools/smartstack_tools.py +676 -0
  282. paasta_tools/spark_tools.py +283 -0
  283. paasta_tools/synapse_srv_namespaces_fact.py +42 -0
  284. paasta_tools/tron/__init__.py +0 -0
  285. paasta_tools/tron/client.py +158 -0
  286. paasta_tools/tron/tron_command_context.py +194 -0
  287. paasta_tools/tron/tron_timeutils.py +101 -0
  288. paasta_tools/tron_tools.py +1448 -0
  289. paasta_tools/utils.py +4307 -0
  290. paasta_tools/yaml_tools.py +44 -0
  291. paasta_tools-1.21.3.data/scripts/apply_external_resources.py +79 -0
  292. paasta_tools-1.21.3.data/scripts/bounce_log_latency_parser.py +68 -0
  293. paasta_tools-1.21.3.data/scripts/check_autoscaler_max_instances.py +212 -0
  294. paasta_tools-1.21.3.data/scripts/check_cassandracluster_services_replication.py +35 -0
  295. paasta_tools-1.21.3.data/scripts/check_flink_services_health.py +203 -0
  296. paasta_tools-1.21.3.data/scripts/check_kubernetes_api.py +57 -0
  297. paasta_tools-1.21.3.data/scripts/check_kubernetes_services_replication.py +141 -0
  298. paasta_tools-1.21.3.data/scripts/check_manual_oapi_changes.sh +24 -0
  299. paasta_tools-1.21.3.data/scripts/check_oom_events.py +244 -0
  300. paasta_tools-1.21.3.data/scripts/check_orphans.py +306 -0
  301. paasta_tools-1.21.3.data/scripts/check_spark_jobs.py +234 -0
  302. paasta_tools-1.21.3.data/scripts/cleanup_kubernetes_cr.py +138 -0
  303. paasta_tools-1.21.3.data/scripts/cleanup_kubernetes_crd.py +145 -0
  304. paasta_tools-1.21.3.data/scripts/cleanup_kubernetes_jobs.py +344 -0
  305. paasta_tools-1.21.3.data/scripts/create_dynamodb_table.py +35 -0
  306. paasta_tools-1.21.3.data/scripts/create_paasta_playground.py +105 -0
  307. paasta_tools-1.21.3.data/scripts/delete_kubernetes_deployments.py +89 -0
  308. paasta_tools-1.21.3.data/scripts/emit_allocated_cpu_metrics.py +50 -0
  309. paasta_tools-1.21.3.data/scripts/generate_all_deployments +9 -0
  310. paasta_tools-1.21.3.data/scripts/generate_authenticating_services.py +94 -0
  311. paasta_tools-1.21.3.data/scripts/generate_deployments_for_service.py +255 -0
  312. paasta_tools-1.21.3.data/scripts/generate_services_file.py +114 -0
  313. paasta_tools-1.21.3.data/scripts/generate_services_yaml.py +30 -0
  314. paasta_tools-1.21.3.data/scripts/get_running_task_allocation.py +346 -0
  315. paasta_tools-1.21.3.data/scripts/habitat_fixer.py +86 -0
  316. paasta_tools-1.21.3.data/scripts/ide_helper.py +316 -0
  317. paasta_tools-1.21.3.data/scripts/is_pod_healthy_in_proxy.py +139 -0
  318. paasta_tools-1.21.3.data/scripts/is_pod_healthy_in_smartstack.py +50 -0
  319. paasta_tools-1.21.3.data/scripts/kill_bad_containers.py +109 -0
  320. paasta_tools-1.21.3.data/scripts/kubernetes_remove_evicted_pods.py +164 -0
  321. paasta_tools-1.21.3.data/scripts/mass-deploy-tag.sh +44 -0
  322. paasta_tools-1.21.3.data/scripts/mock_patch_checker.py +86 -0
  323. paasta_tools-1.21.3.data/scripts/paasta_cleanup_remote_run_resources.py +135 -0
  324. paasta_tools-1.21.3.data/scripts/paasta_cleanup_stale_nodes.py +181 -0
  325. paasta_tools-1.21.3.data/scripts/paasta_deploy_tron_jobs +3 -0
  326. paasta_tools-1.21.3.data/scripts/paasta_execute_docker_command.py +123 -0
  327. paasta_tools-1.21.3.data/scripts/paasta_secrets_sync.py +758 -0
  328. paasta_tools-1.21.3.data/scripts/paasta_tabcomplete.sh +23 -0
  329. paasta_tools-1.21.3.data/scripts/paasta_update_soa_memcpu.py +520 -0
  330. paasta_tools-1.21.3.data/scripts/render_template.py +129 -0
  331. paasta_tools-1.21.3.data/scripts/rightsizer_soaconfigs_update.py +348 -0
  332. paasta_tools-1.21.3.data/scripts/service_shard_remove.py +157 -0
  333. paasta_tools-1.21.3.data/scripts/service_shard_update.py +373 -0
  334. paasta_tools-1.21.3.data/scripts/setup_istio_mesh.py +353 -0
  335. paasta_tools-1.21.3.data/scripts/setup_kubernetes_cr.py +412 -0
  336. paasta_tools-1.21.3.data/scripts/setup_kubernetes_crd.py +138 -0
  337. paasta_tools-1.21.3.data/scripts/setup_kubernetes_internal_crd.py +154 -0
  338. paasta_tools-1.21.3.data/scripts/setup_kubernetes_job.py +353 -0
  339. paasta_tools-1.21.3.data/scripts/setup_prometheus_adapter_config.py +1028 -0
  340. paasta_tools-1.21.3.data/scripts/shared_ip_check.py +77 -0
  341. paasta_tools-1.21.3.data/scripts/synapse_srv_namespaces_fact.py +42 -0
  342. paasta_tools-1.21.3.data/scripts/timeouts_metrics_prom.py +64 -0
  343. paasta_tools-1.21.3.dist-info/LICENSE +201 -0
  344. paasta_tools-1.21.3.dist-info/METADATA +74 -0
  345. paasta_tools-1.21.3.dist-info/RECORD +348 -0
  346. paasta_tools-1.21.3.dist-info/WHEEL +5 -0
  347. paasta_tools-1.21.3.dist-info/entry_points.txt +20 -0
  348. paasta_tools-1.21.3.dist-info/top_level.txt +2 -0
@@ -0,0 +1,164 @@
1
+ #!python
2
+ # Copyright 2015-2019 Yelp Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """
16
+ Usage: ./kubernetes_remove_evicted_pods.py [options]
17
+
18
+ Removes Evicted pods and notifies service owners
19
+ """
20
+ import argparse
21
+ import logging
22
+ from collections import defaultdict
23
+ from collections import namedtuple
24
+ from typing import Dict
25
+ from typing import List
26
+ from typing import Mapping
27
+ from typing import Sequence
28
+
29
+ from kubernetes.client import V1DeleteOptions
30
+ from pysensu_yelp import Status
31
+
32
+ from paasta_tools.kubernetes_tools import get_all_pods
33
+ from paasta_tools.kubernetes_tools import KubeClient
34
+ from paasta_tools.kubernetes_tools import V1Pod
35
+ from paasta_tools.monitoring_tools import send_event
36
+ from paasta_tools.utils import DEFAULT_SOA_DIR
37
+
38
+
39
+ log = logging.getLogger(__name__)
40
+ EvictedPod = namedtuple("EvictedPod", ["podname", "namespace", "eviction_msg"])
41
+
42
+
43
+ def parse_args() -> argparse.Namespace:
44
+ parser = argparse.ArgumentParser(
45
+ description="Removes evicted pods and notifies service owners"
46
+ )
47
+ parser.add_argument(
48
+ "-d",
49
+ "--soa-dir",
50
+ dest="soa_dir",
51
+ default=DEFAULT_SOA_DIR,
52
+ help="define a different soa config directory",
53
+ )
54
+ parser.add_argument(
55
+ "-v", "--verbose", action="store_true", dest="verbose", default=False
56
+ )
57
+ parser.add_argument(
58
+ "-n", "--dry-run", action="store_true", dest="dry_run", default=False
59
+ )
60
+ args = parser.parse_args()
61
+ return args
62
+
63
+
64
+ def get_evicted_pods(pods: Sequence[V1Pod]) -> Sequence[V1Pod]:
65
+ return [
66
+ pod
67
+ for pod in pods
68
+ if pod.status.phase == "Failed" and pod.status.reason == "Evicted"
69
+ ]
70
+
71
+
72
+ def get_pod_service(pod: V1Pod) -> str:
73
+ if pod.metadata.labels is not None:
74
+ return pod.metadata.labels.get("paasta.yelp.com/service")
75
+ else:
76
+ return None
77
+
78
+
79
+ def notify_service_owners(
80
+ services: Mapping[str, Sequence[EvictedPod]],
81
+ soa_dir: str,
82
+ dry_run: bool,
83
+ ) -> None:
84
+ check_overrides = {
85
+ "page": False,
86
+ "alert_after": "0m",
87
+ "realert_every": 1,
88
+ "tip": "Pods can be Evicted if they go over the allowed quota for a given resource. Check the Eviction message to figure out which resource quota was breached",
89
+ }
90
+ for service in services.keys():
91
+ check_name = f"pod-eviction.{service}"
92
+ check_output = "The following pods have been evicted and will be removed from the cluster:\n"
93
+ for pod in services[service]:
94
+ check_output += f"- {pod.podname}: {pod.eviction_msg}\n"
95
+ if dry_run:
96
+ log.info(f"Would have notified owners for service {service}")
97
+ else:
98
+ log.info(f"Notifying owners for service {service}")
99
+ send_event(
100
+ service,
101
+ check_name,
102
+ check_overrides,
103
+ Status.CRITICAL,
104
+ check_output,
105
+ soa_dir,
106
+ )
107
+
108
+
109
+ def remove_pods(
110
+ client: KubeClient,
111
+ services: Mapping[str, Sequence[EvictedPod]],
112
+ dry_run: bool,
113
+ ) -> None:
114
+ delete_options = V1DeleteOptions()
115
+ for service in services:
116
+ # Do not remove more than 2 pods per run
117
+ for pod in services[service][0:2]:
118
+ if dry_run:
119
+ log.info(f"Would have removed pod {pod.podname}")
120
+ else:
121
+ client.core.delete_namespaced_pod(
122
+ pod.podname,
123
+ pod.namespace,
124
+ body=delete_options,
125
+ grace_period_seconds=0,
126
+ propagation_policy="Background",
127
+ )
128
+ log.info(f"Removing pod {pod.podname}")
129
+
130
+
131
+ def evicted_pods_per_service(
132
+ client: KubeClient,
133
+ ) -> Mapping[str, Sequence[EvictedPod]]:
134
+ all_pods = get_all_pods(kube_client=client, namespace="")
135
+ evicted_pods = get_evicted_pods(all_pods)
136
+ log.info(f"Pods in evicted state: {[pod.metadata.name for pod in evicted_pods]}")
137
+ evicted_pods_aggregated: Dict[str, List[EvictedPod]] = defaultdict(list)
138
+ for pod in evicted_pods:
139
+ service = get_pod_service(pod)
140
+ if service:
141
+ evicted_pods_aggregated[service].append(
142
+ EvictedPod(
143
+ pod.metadata.name, pod.metadata.namespace, pod.status.message
144
+ )
145
+ )
146
+ else:
147
+ log.info(f"Could not get service name for pod {pod.metadata.name}")
148
+ return evicted_pods_aggregated
149
+
150
+
151
+ def main() -> None:
152
+ args = parse_args()
153
+ if args.verbose:
154
+ logging.basicConfig(level=logging.DEBUG)
155
+ else:
156
+ logging.basicConfig(level=logging.INFO)
157
+ kube_client = KubeClient()
158
+
159
+ evicted_pods = evicted_pods_per_service(kube_client)
160
+ remove_pods(kube_client, evicted_pods, args.dry_run)
161
+
162
+
163
+ if __name__ == "__main__":
164
+ main()
@@ -0,0 +1,44 @@
1
+ #!/bin/bash
2
+ # This script was created to help migrate from branches to tags for deployments.
3
+ # While it is probably useless as-is now, it can hopefully serve as a reference for making
4
+ # future bulk changes to services.
5
+ set -e
6
+
7
+ WORK_DIR=$(mktemp -d --tmpdir=/nail/tmp)
8
+ pushd ${WORK_DIR}
9
+
10
+ function cleanup {
11
+ popd
12
+ rm -rf "${WORK_DIR}"
13
+ }
14
+ trap cleanup EXIT
15
+
16
+ services=$(paasta list)
17
+ #services="example_service"
18
+
19
+
20
+ for service in ${services} ; do
21
+ echo "Processing ${service}"
22
+ jq_output=$(jq -r '.v1 | to_entries | .[] | .key + " " + .value.docker_image' /nail/etc/services/${service}/deployments.json)
23
+ if [ -z "$jq_output" ] ; then
24
+ echo "${service} has no deployments. Skipping."
25
+ continue
26
+ fi
27
+ # git_repo=$(paasta info -s ${service} | grep -oP 'Git Repo: \K.*$')
28
+ git_repo=$(script -qc "paasta info -s ${service}" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | grep 'Git Repo: ' | cut -d' ' -f3)
29
+ default_git_repo=git@github.yelpcorp.com:services/${service}.git
30
+ echo git clone ${git_repo-${default_git_repo}} ${service}
31
+ git clone ${git_repo} ${service}
32
+ unset git_repo
33
+ cd ${service}
34
+ while read -r deploy_group sha; do
35
+ deploy_group=$(echo ${deploy_group} | sed 's/^.*paasta-//')
36
+ sha=$(echo ${sha} | sed 's/^.*paasta-//')
37
+ echo "Mapping ${deploy_group} => ${sha}"
38
+ # echo paasta mark-for-deployment --git-url ${git_repo} --commit ${sha} --deploy-group ${deploy_group} --service ${service}
39
+ timestamp='00000000T000000'
40
+ git tag paasta-${deploy_group}-${timestamp}-deploy ${sha} || true
41
+ done <<< "$jq_output"
42
+ git push --tags origin master
43
+ cd -
44
+ done
@@ -0,0 +1,86 @@
1
+ #!python
2
+ import ast
3
+ import sys
4
+
5
+
6
+ class MockChecker(ast.NodeVisitor):
7
+ def __init__(self):
8
+ self.errors = 0
9
+ self.init_module_imports()
10
+
11
+ def init_module_imports(self):
12
+ self.imported_patch = False
13
+ self.imported_mock = False
14
+
15
+ def check_files(self, files):
16
+ for file in files:
17
+ self.check_file(file)
18
+
19
+ def check_file(self, filename):
20
+ self.current_filename = filename
21
+ try:
22
+ with open(filename, "r") as fd:
23
+ try:
24
+ file_ast = ast.parse(fd.read())
25
+ except SyntaxError as error:
26
+ print("SyntaxError on file %s:%d" % (filename, error.lineno))
27
+ return
28
+ except IOError:
29
+ print("Error opening filename: %s" % filename)
30
+ return
31
+ self.init_module_imports()
32
+ self.visit(file_ast)
33
+
34
+ def _call_uses_patch(self, node):
35
+ try:
36
+ return node.func.id == "patch"
37
+ except AttributeError:
38
+ return False
39
+
40
+ def _call_uses_mock_patch(self, node):
41
+ try:
42
+ return node.func.value.id == "mock" and node.func.attr == "patch"
43
+ except AttributeError:
44
+ return False
45
+
46
+ def visit_Import(self, node):
47
+ if [name for name in node.names if "mock" == name.name]:
48
+ self.imported_mock = True
49
+
50
+ def visit_ImportFrom(self, node):
51
+ if node.module == "mock" and (
52
+ name for name in node.names if "patch" == name.name
53
+ ):
54
+ self.imported_patch = True
55
+
56
+ def visit_Call(self, node):
57
+ try:
58
+ if (self.imported_patch and self._call_uses_patch(node)) or (
59
+ self.imported_mock and self._call_uses_mock_patch(node)
60
+ ):
61
+ if not any(
62
+ [keyword for keyword in node.keywords if keyword.arg == "autospec"]
63
+ ):
64
+ print(
65
+ "%s:%d: Found a mock without an autospec!"
66
+ % (self.current_filename, node.lineno)
67
+ )
68
+ self.errors += 1
69
+ except AttributeError:
70
+ pass
71
+ self.generic_visit(node)
72
+
73
+
74
+ def main(filenames):
75
+ checker = MockChecker()
76
+ checker.check_files(filenames)
77
+ if checker.errors == 0:
78
+ sys.exit(0)
79
+ else:
80
+ print("You probably meant to specify 'autospec=True' in these tests.")
81
+ print("If you really don't want to, specify 'autospec=None'")
82
+ sys.exit(1)
83
+
84
+
85
+ if __name__ == "__main__":
86
+ main(sys.argv[1:])
@@ -0,0 +1,135 @@
1
+ #!python
2
+ # Copyright 2015-2019 Yelp Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import argparse
16
+ import logging
17
+ from datetime import datetime
18
+ from datetime import timedelta
19
+ from datetime import timezone
20
+ from typing import Any
21
+ from typing import Callable
22
+ from typing import Sequence
23
+ from typing import Tuple
24
+
25
+ from paasta_tools.kubernetes.remote_run import get_max_job_duration_limit
26
+ from paasta_tools.kubernetes.remote_run import get_remote_run_jobs
27
+ from paasta_tools.kubernetes.remote_run import get_remote_run_role_bindings
28
+ from paasta_tools.kubernetes.remote_run import get_remote_run_roles
29
+ from paasta_tools.kubernetes.remote_run import get_remote_run_service_accounts
30
+ from paasta_tools.kubernetes_tools import get_all_managed_namespaces
31
+ from paasta_tools.kubernetes_tools import KubeClient
32
+
33
+
34
+ ListingFuncType = Callable[[KubeClient, str], Sequence[Any]]
35
+ DeletionFuncType = Callable[[str, str], Any]
36
+ log = logging.getLogger(__name__)
37
+
38
+
39
+ def clean_namespace(
40
+ kube_client: KubeClient,
41
+ namespace: str,
42
+ auth_age_limit: datetime,
43
+ job_age_limit: datetime,
44
+ dry_run: bool = False,
45
+ ):
46
+ """Clean ephemeral remote-run resource in a namespace
47
+
48
+ :param KubeClient kube_client: kubernetes client
49
+ :param str namepsace: kubernetes namespace
50
+ :param datetime auth_age_limit: expiration time for authentication resources
51
+ :param datetime job_age_limit: expiration time for job resources
52
+ :param bool dry_run: delete resources for real or not
53
+ """
54
+ dry_run_msg = " (dry_run)" if dry_run else ""
55
+ cleanup_actions: Sequence[Tuple[DeletionFuncType, ListingFuncType, datetime]] = (
56
+ (
57
+ kube_client.core.delete_namespaced_service_account,
58
+ get_remote_run_service_accounts,
59
+ auth_age_limit,
60
+ ),
61
+ (
62
+ kube_client.rbac.delete_namespaced_role,
63
+ get_remote_run_roles,
64
+ auth_age_limit,
65
+ ),
66
+ (
67
+ kube_client.rbac.delete_namespaced_role_binding,
68
+ get_remote_run_role_bindings,
69
+ auth_age_limit,
70
+ ),
71
+ (
72
+ kube_client.batches.delete_namespaced_job,
73
+ get_remote_run_jobs,
74
+ job_age_limit,
75
+ ),
76
+ )
77
+ for delete_func, list_func, age_limit in cleanup_actions:
78
+ for entity in list_func(kube_client, namespace):
79
+ if (
80
+ not entity.metadata.name.startswith("remote-run-")
81
+ or entity.metadata.creation_timestamp > age_limit
82
+ ):
83
+ continue
84
+ log.info(f"Deleting {entity.metadata.name} in {namespace}{dry_run_msg}")
85
+ if not dry_run:
86
+ delete_func(entity.metadata.name, namespace)
87
+
88
+
89
+ def parse_args() -> argparse.Namespace:
90
+ parser = argparse.ArgumentParser(
91
+ description="Clean ephemeral Kubernetes resources created by remote-run invocations",
92
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
93
+ )
94
+ parser.add_argument(
95
+ "--max-age",
96
+ type=int,
97
+ default=600,
98
+ help="Maximum age, in seconds, resources are allowed to have",
99
+ )
100
+ parser.add_argument(
101
+ "-n",
102
+ "--dry-run",
103
+ action="store_true",
104
+ default=False,
105
+ help="Do not actually delete resources",
106
+ )
107
+ parser.add_argument(
108
+ "-v",
109
+ "--verbose",
110
+ action="store_true",
111
+ default=False,
112
+ help="More verbose logging",
113
+ )
114
+ return parser.parse_args()
115
+
116
+
117
+ def main():
118
+ args = parse_args()
119
+ logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
120
+ kube_client = KubeClient()
121
+ now = datetime.now(tz=timezone.utc)
122
+ age_limit = now - timedelta(seconds=args.max_age)
123
+ job_age_limit = now - timedelta(seconds=get_max_job_duration_limit())
124
+ for namespace in get_all_managed_namespaces(kube_client):
125
+ clean_namespace(
126
+ kube_client,
127
+ namespace,
128
+ auth_age_limit=age_limit,
129
+ job_age_limit=job_age_limit,
130
+ dry_run=args.dry_run,
131
+ )
132
+
133
+
134
+ if __name__ == "__main__":
135
+ main()
@@ -0,0 +1,181 @@
1
+ #!python
2
+ # Copyright 2015-2019 Yelp Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """
16
+ Usage: ./paasta_cleanup_stale_nodes.py [options]
17
+
18
+ Removes terminated Kubernetes nodes from the Kubernetes API.
19
+
20
+ Command line options:
21
+
22
+ - -v, --verbose: Verbose output
23
+ - -n, --dry-run: Only report what would have been deleted
24
+ """
25
+ import argparse
26
+ import logging
27
+ import sys
28
+ from typing import List
29
+ from typing import Sequence
30
+ from typing import Tuple
31
+
32
+ import boto3
33
+ from boto3_type_annotations.ec2 import Client
34
+ from botocore.exceptions import ClientError
35
+ from kubernetes.client import V1DeleteOptions
36
+ from kubernetes.client import V1Node
37
+ from kubernetes.client.rest import ApiException
38
+
39
+ from paasta_tools.kubernetes_tools import get_all_nodes
40
+ from paasta_tools.kubernetes_tools import KubeClient
41
+
42
+ log = logging.getLogger(__name__)
43
+
44
+
45
+ def parse_args() -> argparse.Namespace:
46
+ parser = argparse.ArgumentParser(description="Remove terminated Kubernetes nodes")
47
+ parser.add_argument(
48
+ "-v", "--verbose", action="store_true", dest="verbose", default=False
49
+ )
50
+ parser.add_argument(
51
+ "-n", "--dry-run", action="store_true", dest="dry_run", default=False
52
+ )
53
+ args = parser.parse_args()
54
+ return args
55
+
56
+
57
+ def nodes_for_cleanup(ec2_client: Client, nodes: Sequence[V1Node]) -> List[V1Node]:
58
+ not_ready = [
59
+ node
60
+ for node in nodes
61
+ if not is_node_ready(node)
62
+ and "node-role.kubernetes.io/control-plane" not in node.metadata.labels
63
+ ]
64
+ terminated = terminated_nodes(ec2_client, not_ready)
65
+ return terminated
66
+
67
+
68
+ def terminated_nodes(ec2_client: Client, nodes: Sequence[V1Node]) -> List[V1Node]:
69
+ instance_ids = [node.spec.provider_id.split("/")[-1] for node in nodes]
70
+ # if there are any instances that don't exist in the query to describe_instance_status
71
+ # then amazon won't return the results for any, so we have to query the instances
72
+ # one by one
73
+ statuses = [
74
+ does_instance_exist(ec2_client, instance_id) for instance_id in instance_ids
75
+ ]
76
+ for node, status in zip(nodes, statuses):
77
+ log.debug(f"{node.metadata.name} exists: {status}")
78
+
79
+ return [node for node, status in zip(nodes, statuses) if not status]
80
+
81
+
82
+ def does_instance_exist(ec2_client: Client, instance_id: str):
83
+ try:
84
+ instance = ec2_client.describe_instance_status(InstanceIds=[instance_id])
85
+ if instance["InstanceStatuses"]:
86
+ status = instance["InstanceStatuses"][0]["InstanceState"]["Name"]
87
+ # see possible values at https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instance_status
88
+ # 'pending'|'running'|'shutting-down'|'terminated'|'stopping'|'stopped'
89
+ # it's unlikely that we'll ever be in this situation with a pending node - the common case is that
90
+ # the node is either running and been marked as not ready, or it's being shutdown
91
+ if status not in ("running", "pending"):
92
+ return False
93
+ return True
94
+
95
+ log.debug(
96
+ f"no instance status in response for {instance_id}; assuming to have been terminated"
97
+ )
98
+ return False
99
+ except ClientError as e:
100
+ if e.response["Error"]["Code"] == "InvalidInstanceID.NotFound":
101
+ log.debug(
102
+ f"instance {instance_id} not found; assuming to have been terminated"
103
+ )
104
+ return False
105
+ else:
106
+ log.error(f"error fetching instance status for {instance_id}")
107
+ raise e
108
+ return True
109
+
110
+
111
+ def terminate_nodes(
112
+ client: KubeClient, nodes: List[str]
113
+ ) -> Tuple[List[str], List[Tuple[str, Exception]]]:
114
+ success = []
115
+ errors = []
116
+ for node in nodes:
117
+ try:
118
+ body = V1DeleteOptions()
119
+ client.core.delete_node(node, body=body, propagation_policy="foreground")
120
+ except ApiException as e:
121
+ errors.append((node, e))
122
+ continue
123
+ success.append(node)
124
+ return (success, errors)
125
+
126
+
127
+ def is_node_ready(node: V1Node) -> bool:
128
+ for condition in node.status.conditions:
129
+ if condition.type == "Ready":
130
+ return condition.status == "True"
131
+ log.error(
132
+ f"no KubeletReady condition found for node {node.metadata.name}. Conditions {node.status.conditions}"
133
+ )
134
+ return True
135
+
136
+
137
+ def main() -> None:
138
+ args = parse_args()
139
+ if args.verbose:
140
+ logging.basicConfig(level=logging.DEBUG)
141
+ else:
142
+ logging.basicConfig(level=logging.INFO)
143
+
144
+ dry_run = args.dry_run
145
+
146
+ kube_client = KubeClient()
147
+ all_nodes = get_all_nodes(kube_client)
148
+ log.debug(f"found nodes in cluster {[node.metadata.name for node in all_nodes]}")
149
+
150
+ # we depend on iam credentials existing on the host for this to run.
151
+ # anywhere else, and you'll need to set credentials using environment variables
152
+ # we also make the assumption that all nodes are in the same region here
153
+ region = all_nodes[0].metadata.labels["failure-domain.beta.kubernetes.io/region"]
154
+ ec2_client = boto3.client("ec2", region)
155
+
156
+ filtered_nodes = nodes_for_cleanup(ec2_client, all_nodes)
157
+ if logging.DEBUG >= logging.root.level:
158
+ log.debug(
159
+ f"nodes to be deleted: {[node.metadata.name for node in filtered_nodes]}"
160
+ )
161
+
162
+ if not dry_run:
163
+ success, errors = terminate_nodes(
164
+ kube_client, [node.metadata.name for node in filtered_nodes]
165
+ )
166
+ else:
167
+ success, errors = [], []
168
+ log.info("dry run mode detected: not deleting nodes")
169
+
170
+ for node_name in success:
171
+ log.info(f"successfully deleted node {node_name}")
172
+
173
+ for node_name, exception in errors:
174
+ log.error(f"error deleting node: {node_name}: {exception}")
175
+
176
+ if errors:
177
+ sys.exit(1)
178
+
179
+
180
+ if __name__ == "__main__":
181
+ main()
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ set -eo pipefail
3
+ paasta_list_tron_namespaces | xargs -n 1 -r -P 1 paasta_setup_tron_namespace