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,1118 @@
1
+ # Copyright 2015-2016 Yelp Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ import argparse
15
+ import difflib
16
+ import fnmatch
17
+ import getpass
18
+ import hashlib
19
+ import logging
20
+ import os
21
+ import pty
22
+ import random
23
+ import re
24
+ import shutil
25
+ import socket
26
+ import subprocess
27
+ from collections import defaultdict
28
+ from shlex import quote
29
+ from typing import Callable
30
+ from typing import Collection
31
+ from typing import Generator
32
+ from typing import Iterable
33
+ from typing import List
34
+ from typing import Mapping
35
+ from typing import NamedTuple
36
+ from typing import Optional
37
+ from typing import Sequence
38
+ from typing import Set
39
+ from typing import Tuple
40
+
41
+ import ephemeral_port_reserve
42
+ from mypy_extensions import NamedArg
43
+
44
+ from paasta_tools import remote_git
45
+ from paasta_tools.adhoc_tools import load_adhoc_job_config
46
+ from paasta_tools.api.client import get_paasta_oapi_client
47
+ from paasta_tools.api.client import PaastaOApiClient
48
+ from paasta_tools.cassandracluster_tools import load_cassandracluster_instance_config
49
+ from paasta_tools.cli.authentication import get_sso_auth_token
50
+ from paasta_tools.eks_tools import EksDeploymentConfig
51
+ from paasta_tools.eks_tools import load_eks_service_config
52
+ from paasta_tools.flink_tools import load_flink_instance_config
53
+ from paasta_tools.flinkeks_tools import load_flinkeks_instance_config
54
+ from paasta_tools.kafkacluster_tools import load_kafkacluster_instance_config
55
+ from paasta_tools.kubernetes_tools import KubernetesDeploymentConfig
56
+ from paasta_tools.kubernetes_tools import load_kubernetes_service_config
57
+ from paasta_tools.long_running_service_tools import LongRunningServiceConfig
58
+ from paasta_tools.monkrelaycluster_tools import load_monkrelaycluster_instance_config
59
+ from paasta_tools.nrtsearchservice_tools import load_nrtsearchservice_instance_config
60
+ from paasta_tools.nrtsearchserviceeks_tools import (
61
+ load_nrtsearchserviceeks_instance_config,
62
+ )
63
+ from paasta_tools.paasta_service_config_loader import PaastaServiceConfigLoader
64
+ from paasta_tools.tron_tools import load_tron_instance_config
65
+ from paasta_tools.utils import _log
66
+ from paasta_tools.utils import _run
67
+ from paasta_tools.utils import compose_job_id
68
+ from paasta_tools.utils import DEFAULT_SOA_CONFIGS_GIT_URL
69
+ from paasta_tools.utils import DEFAULT_SOA_DIR
70
+ from paasta_tools.utils import get_service_instance_list
71
+ from paasta_tools.utils import INSTANCE_TYPE_TO_K8S_NAMESPACE
72
+ from paasta_tools.utils import INSTANCE_TYPES
73
+ from paasta_tools.utils import InstanceConfig
74
+ from paasta_tools.utils import list_all_instances_for_service
75
+ from paasta_tools.utils import list_clusters
76
+ from paasta_tools.utils import list_services
77
+ from paasta_tools.utils import load_system_paasta_config
78
+ from paasta_tools.utils import PAASTA_K8S_INSTANCE_TYPES
79
+ from paasta_tools.utils import PaastaColors
80
+ from paasta_tools.utils import SystemPaastaConfig
81
+ from paasta_tools.utils import validate_service_instance
82
+
83
+
84
+ log = logging.getLogger(__name__)
85
+
86
+
87
+ def is_file_in_dir(file_name, path):
88
+ """Recursively search path for file_name.
89
+
90
+ :param file_name: a string of a file name to find
91
+ :param path: a string path
92
+ :param file_ext: a string of a file extension
93
+ :return: a boolean
94
+ """
95
+ for root, dirnames, filenames in os.walk(path):
96
+ for filename in filenames:
97
+ if fnmatch.fnmatch(filename, file_name):
98
+ return os.path.join(root, filename)
99
+ return False
100
+
101
+
102
+ def get_file_contents(path):
103
+ """Open a file for reading
104
+
105
+ :param path: path of file to read
106
+ """
107
+ with open(path) as p:
108
+ return p.read()
109
+
110
+
111
+ def check_mark():
112
+ """
113
+ :return: string that can print a checkmark
114
+ """
115
+ return PaastaColors.green("\u2713")
116
+
117
+
118
+ def x_mark():
119
+ """
120
+ :return: string that can print an x-mark
121
+ """
122
+ return PaastaColors.red("\u2717")
123
+
124
+
125
+ def info_mark() -> str:
126
+ """
127
+ :return: string that can print an info symbol
128
+ """
129
+ return PaastaColors.blue("\u2139")
130
+
131
+
132
+ def success(msg):
133
+ """Format a paasta check success message.
134
+
135
+ :param msg: a string
136
+ :return: a beautiful string
137
+ """
138
+ return "{} {}".format(check_mark(), msg)
139
+
140
+
141
+ def failure(msg, link):
142
+ """Format a paasta check failure message.
143
+
144
+ :param msg: a string
145
+ :return: a beautiful string
146
+ """
147
+ return "{} {} {}".format(x_mark(), msg, PaastaColors.blue(link))
148
+
149
+
150
+ def info_message(msg: str) -> str:
151
+ return f"{info_mark()} {msg}"
152
+
153
+
154
+ class PaastaCheckMessages:
155
+
156
+ """Collection of message printed out by 'paasta check'.
157
+ Helpful as it avoids cumbersome maintenance of the unit tests.
158
+ """
159
+
160
+ DEPLOY_YAML_FOUND = success("deploy.yaml exists for a Jenkins pipeline")
161
+
162
+ DEPLOY_YAML_MISSING = failure(
163
+ "No deploy.yaml exists, so your service cannot be deployed.\n "
164
+ "Please push a deploy.yaml.\n "
165
+ "More info:",
166
+ "http://y/yelpsoa-configs",
167
+ )
168
+
169
+ DEPLOY_SECURITY_FOUND = success(
170
+ "Found a security-check entry in your deploy pipeline"
171
+ )
172
+ DEPLOY_SECURITY_MISSING = failure(
173
+ "No 'security-check' entry was found in your deploy.yaml.\n"
174
+ "Please add a security-check entry *AFTER* the itest entry in deploy.yaml\n"
175
+ "so your docker image can be checked against known security vulnerabilities.\n"
176
+ "More info:",
177
+ "http://paasta.readthedocs.io/en/latest/generated/paasta_tools.cli.cmds.security_check.html",
178
+ )
179
+
180
+ DOCKERFILE_FOUND = success("Found Dockerfile")
181
+
182
+ DOCKERFILE_MISSING = failure(
183
+ "Dockerfile not found. Create a Dockerfile and try again.\n " "More info:",
184
+ "http://y/paasta-runbook-dockerfile",
185
+ )
186
+
187
+ DOCKERFILE_YELPCORP = success(
188
+ "Your Dockerfile pulls from the standard Yelp images."
189
+ )
190
+
191
+ DOCKERFILE_NOT_YELPCORP = failure(
192
+ "Your Dockerfile does not use the standard Yelp images.\n "
193
+ "This is bad because your `docker pulls` will be slow and you won't be "
194
+ "using the local mirrors.\n"
195
+ "More info:",
196
+ "http://y/base-docker-images",
197
+ )
198
+
199
+ GIT_REPO_FOUND = success("Git repo found in the expected location.")
200
+
201
+ ADHOC_YAML_FOUND = success("Found adhoc.yaml file.")
202
+
203
+ MAKEFILE_FOUND = success("A Makefile is present")
204
+ MAKEFILE_MISSING = failure(
205
+ "No Makefile available. Please make a Makefile that responds\n"
206
+ "to the proper targets. More info:",
207
+ "http://paasta.readthedocs.io/en/latest/about/contract.html",
208
+ )
209
+ MAKEFILE_RESPONDS_BUILD_IMAGE = success(
210
+ "The Makefile responds to `make cook-image`"
211
+ )
212
+ MAKEFILE_RESPONDS_BUILD_IMAGE_FAIL = failure(
213
+ "The Makefile does not have a `make cook-image` target. local-run needs\n"
214
+ "this and expects it to build your docker image. More info:",
215
+ "http://paasta.readthedocs.io/en/latest/about/contract.html",
216
+ )
217
+ MAKEFILE_RESPONDS_ITEST = success("The Makefile responds to `make itest`")
218
+ MAKEFILE_RESPONDS_ITEST_FAIL = failure(
219
+ "The Makefile does not have a `make itest` target. Jenkins needs\n"
220
+ "this and expects it to build and itest your docker image. More info:",
221
+ "http://paasta.readthedocs.io/en/latest/about/contract.html",
222
+ )
223
+ MAKEFILE_RESPONDS_TEST = success("The Makefile responds to `make test`")
224
+ MAKEFILE_RESPONDS_TEST_FAIL = failure(
225
+ "The Makefile does not have a `make test` target. Jenkins needs\n"
226
+ "this and expects it to run unit tests. More info:",
227
+ "http://paasta.readthedocs.io/en/latest/about/contract.html",
228
+ )
229
+ MAKEFILE_HAS_A_TAB = success("The Makefile contains a tab character")
230
+ MAKEFILE_HAS_NO_TABS = failure(
231
+ "The Makefile contains no tab characters. Make sure you\n"
232
+ "didn't accidentally paste spaces (which `make` does not respect)\n"
233
+ "instead of a tab.",
234
+ "http://paasta.readthedocs.io/en/latest/about/contract.html",
235
+ )
236
+ MAKEFILE_HAS_DOCKER_TAG = success("The Makefile contains a docker tag")
237
+ MAKEFILE_HAS_NO_DOCKER_TAG = failure(
238
+ "The Makefile contains no reference to DOCKER_TAG. Make sure you\n"
239
+ "specify a DOCKER_TAG and that your itest tags your docker image with $DOCKER_TAG.",
240
+ "http://paasta.readthedocs.io/en/latest/about/contract.html",
241
+ )
242
+
243
+ SENSU_MONITORING_FOUND = success("monitoring.yaml found for Sensu monitoring")
244
+
245
+ SENSU_MONITORING_MISSING = failure(
246
+ "Your service is not using Sensu (monitoring.yaml).\n "
247
+ "Please setup a monitoring.yaml so we know where to send alerts.\n "
248
+ "More info:",
249
+ "http://y/monitoring-yaml",
250
+ )
251
+
252
+ SENSU_TEAM_MISSING = failure(
253
+ "Cannot get team name. Ensure 'team' field is set in monitoring.yaml.\n"
254
+ " More info:",
255
+ "http://y/monitoring-yaml",
256
+ )
257
+
258
+ SMARTSTACK_YAML_FOUND = success("Found smartstack.yaml file")
259
+
260
+ SMARTSTACK_PORT_MISSING = failure(
261
+ "Could not determine port. "
262
+ "Ensure 'proxy_port' is set in smartstack.yaml.\n "
263
+ "More info:",
264
+ "http://y/smartstack-cep323",
265
+ )
266
+
267
+ @staticmethod
268
+ def git_repo_missing(git_url):
269
+ git_url = PaastaColors.cyan(git_url)
270
+ return failure(
271
+ "Could not find Git repo %s. "
272
+ "Your service must be there.\n"
273
+ " More info:" % git_url,
274
+ "http://y/yelpsoa-configs",
275
+ )
276
+
277
+ @staticmethod
278
+ def sensu_team_found(team_name):
279
+ return success(
280
+ "Your service uses Sensu and team '%s' will get alerts." % team_name
281
+ )
282
+
283
+ @staticmethod
284
+ def smartstack_port_found(instance, port):
285
+ return success(
286
+ "Instance '%s' of your service is using smartstack port %d "
287
+ "and will be automatically load balanced" % (instance, port)
288
+ )
289
+
290
+ @staticmethod
291
+ def service_dir_found(service, soa_dir):
292
+ message = "yelpsoa-config directory for {} found in {}".format(
293
+ PaastaColors.cyan(service), soa_dir
294
+ )
295
+ return success(message)
296
+
297
+ @staticmethod
298
+ def service_dir_missing(service, soa_dir):
299
+ message = (
300
+ "Failed to locate yelpsoa-config directory for %s in %s.\n"
301
+ " Please follow the guide linked below to get boilerplate."
302
+ % (service, soa_dir)
303
+ )
304
+ return failure(message, "http://y/paasta-deploy")
305
+
306
+
307
+ class NoSuchService(Exception):
308
+
309
+ """Exception to be raised in the event that the service
310
+ name can not be guessed.
311
+ """
312
+
313
+ GUESS_ERROR_MSG = (
314
+ "Could not determine service name.\n"
315
+ "Please run this from the root of a copy "
316
+ "(git clone) of your service.\n"
317
+ "Alternatively, supply the %s name you wish to "
318
+ "inspect with the %s option."
319
+ % (PaastaColors.cyan("SERVICE"), PaastaColors.cyan("-s"))
320
+ )
321
+
322
+ CHECK_ERROR_MSG = (
323
+ "not found. Please provide a valid service name.\n"
324
+ "Ensure that a directory of the same name exists in %s."
325
+ % PaastaColors.green("/nail/etc/services")
326
+ )
327
+
328
+ def __init__(self, service):
329
+ self.service = service
330
+
331
+ def __str__(self):
332
+ if self.service:
333
+ return "SERVICE: {} {}".format(
334
+ PaastaColors.cyan(self.service), self.CHECK_ERROR_MSG
335
+ )
336
+ else:
337
+ return self.GUESS_ERROR_MSG
338
+
339
+
340
+ def guess_service_name():
341
+ """Deduce the service name from the pwd
342
+ :return : A string representing the service name
343
+ """
344
+ return os.path.basename(os.getcwd())
345
+
346
+
347
+ def validate_service_name(service, soa_dir=DEFAULT_SOA_DIR):
348
+ """Determine whether directory named service exists in the provided soa_dir
349
+ :param service: a string of the name of the service you wish to check exists
350
+ :param soa_dir: directory to look for service names
351
+ :return : boolean True
352
+ :raises: NoSuchService exception
353
+ """
354
+ if not service or not os.path.isdir(os.path.join(soa_dir, service)):
355
+ raise NoSuchService(service)
356
+ return True
357
+
358
+
359
+ def list_paasta_services(soa_dir: str = DEFAULT_SOA_DIR):
360
+ """Returns a sorted list of services that happen to have at
361
+ least one service.instance, which indicates it is on PaaSTA
362
+ """
363
+ the_list = []
364
+ for service in list_services(soa_dir):
365
+ if list_all_instances_for_service(service, soa_dir=soa_dir):
366
+ the_list.append(service)
367
+ return the_list
368
+
369
+
370
+ def list_service_instances(soa_dir: str = DEFAULT_SOA_DIR):
371
+ """Returns a sorted list of service<SPACER>instance names"""
372
+ the_list = []
373
+ for service in list_services(soa_dir):
374
+ for instance in list_all_instances_for_service(
375
+ service=service, soa_dir=soa_dir
376
+ ):
377
+ the_list.append(compose_job_id(service, instance))
378
+ return the_list
379
+
380
+
381
+ def list_instances(**kwargs):
382
+ """Returns a sorted list of all possible instance names
383
+ for tab completion. We try to guess what service you might be
384
+ operating on, otherwise we just provide *all* of them
385
+ """
386
+ all_instances: Set[str] = set()
387
+ service = guess_service_name()
388
+ try:
389
+ validate_service_name(service)
390
+ all_instances = set(list_all_instances_for_service(service))
391
+ except NoSuchService:
392
+ for service in list_services():
393
+ for instance in list_all_instances_for_service(service):
394
+ all_instances.add(instance)
395
+ return sorted(all_instances)
396
+
397
+
398
+ def calculate_remote_masters(
399
+ cluster: str, system_paasta_config: SystemPaastaConfig
400
+ ) -> Tuple[List[str], str]:
401
+ """Given a cluster, do a DNS lookup of that cluster (which
402
+ happens to point, eventually, to the Mesos masters in that cluster).
403
+ Return IPs of those Mesos masters.
404
+ """
405
+
406
+ cluster_fqdn = system_paasta_config.get_cluster_fqdn_format().format(
407
+ cluster=cluster
408
+ )
409
+ try:
410
+ _, _, ips = socket.gethostbyname_ex(cluster_fqdn)
411
+ output = None
412
+ except socket.gaierror as e:
413
+ output = f"ERROR while doing DNS lookup of {cluster_fqdn}:\n{e.strerror}\n "
414
+ ips = []
415
+ return (ips, output)
416
+
417
+
418
+ def find_connectable_master(
419
+ masters: Sequence[str],
420
+ ) -> Tuple[Optional[str], Optional[str]]:
421
+ """For each host in the iterable 'masters', try various connectivity
422
+ checks. For each master that fails, emit an error message about which check
423
+ failed and move on to the next master.
424
+
425
+ If a master passes all checks, return a tuple of the connectable master and
426
+ None. If no masters pass all checks, return a tuple of None and the output
427
+ from the DNS lookup.
428
+ """
429
+ timeout = 6.0 # seconds
430
+
431
+ connectable_master = None
432
+ for master in masters:
433
+ rc, output = check_ssh_on_master(master, timeout=timeout)
434
+ if rc is True:
435
+ connectable_master = master
436
+ output = None
437
+ break
438
+ return (connectable_master, output)
439
+
440
+
441
+ class NoMasterError(Exception):
442
+ pass
443
+
444
+
445
+ def connectable_master(cluster: str, system_paasta_config: SystemPaastaConfig) -> str:
446
+ masters, output = calculate_remote_masters(cluster, system_paasta_config)
447
+ if masters == []:
448
+ raise NoMasterError("ERROR: %s" % output)
449
+
450
+ random.shuffle(masters)
451
+
452
+ master, output = find_connectable_master(masters)
453
+ if not master:
454
+ raise NoMasterError(
455
+ f"ERROR: could not find connectable master in cluster {cluster}\nOutput: {output}"
456
+ )
457
+
458
+ return master
459
+
460
+
461
+ def check_ssh_on_master(master, timeout=10):
462
+ """Given a master, attempt to ssh to the master and run a simple command
463
+ with sudo to verify that ssh and sudo work properly. Return a tuple of the
464
+ success status (True or False) and any output from attempting the check.
465
+ """
466
+ check_command = "ssh -A -n -o StrictHostKeyChecking=no %s /bin/true" % master
467
+ rc, output = _run(check_command, timeout=timeout)
468
+ if rc == 0:
469
+ return (True, None)
470
+ if rc == 255: # ssh error
471
+ reason = "Return code was %d which probably means an ssh failure." % rc
472
+ hint = "HINT: Are you allowed to ssh to this machine %s?" % master
473
+ if rc == 1: # sudo error
474
+ reason = "Return code was %d which probably means a sudo failure." % rc
475
+ hint = "HINT: Is your ssh agent forwarded? (ssh-add -l)"
476
+ if rc == -9: # timeout error
477
+ reason = (
478
+ "Return code was %d which probably means ssh took too long and timed out."
479
+ % rc
480
+ )
481
+ hint = "HINT: Is there network latency? Try running somewhere closer to the cluster."
482
+ else: # unknown error
483
+ reason = "Return code was %d which is an unknown failure." % rc
484
+ hint = "HINT: Talk to #paasta and pastebin this output"
485
+ output = (
486
+ "ERROR cannot run check command %(check_command)s\n"
487
+ "%(reason)s\n"
488
+ "%(hint)s\n"
489
+ "Output from check command: %(output)s"
490
+ % {
491
+ "check_command": check_command,
492
+ "reason": reason,
493
+ "hint": hint,
494
+ "output": output,
495
+ }
496
+ )
497
+ return (False, output)
498
+
499
+
500
+ def run_on_master(
501
+ cluster,
502
+ system_paasta_config,
503
+ cmd_parts,
504
+ timeout=None,
505
+ err_code=-1,
506
+ graceful_exit=False,
507
+ stdin=None,
508
+ ):
509
+ """Find connectable master for :cluster: and :system_paasta_config: args and
510
+ invoke command from :cmd_parts:, wrapping it in ssh call.
511
+
512
+ :returns (exit code, output)
513
+
514
+ :param cluster: cluster to find master in
515
+ :param system_paasta_config: system configuration to lookup master data
516
+ :param cmd_parts: passed into paasta_tools.utils._run as command along with
517
+ ssh bits
518
+ :param timeout: see paasta_tools.utils._run documentation (default: None)
519
+ :param err_code: code to return along with error message when something goes
520
+ wrong (default: -1)
521
+ :param graceful_exit: wrap command in a bash script that waits for input and
522
+ kills the original command; trap SIGINT and send newline into stdin
523
+ """
524
+ try:
525
+ master = connectable_master(cluster, system_paasta_config)
526
+ except NoMasterError as e:
527
+ return (err_code, str(e))
528
+
529
+ if graceful_exit:
530
+ # Signals don't travel over ssh, kill process when anything lands on stdin instead
531
+ # The procedure here is:
532
+ # 1. send process to background and capture it's pid
533
+ # 2. wait for stdin with timeout in a loop, exit when original process finished
534
+ # 3. kill original process if loop finished (something on stdin)
535
+ cmd_parts.append(
536
+ "& p=$!; "
537
+ + "while ! read -t1; do ! kill -0 $p 2>/dev/null && kill $$; done; "
538
+ + "kill $p; wait"
539
+ )
540
+ stdin = subprocess.PIPE
541
+ stdin_interrupt = True
542
+ popen_kwargs = {"preexec_fn": os.setsid}
543
+ else:
544
+ stdin_interrupt = False
545
+ popen_kwargs = {}
546
+
547
+ cmd_parts = [
548
+ "ssh",
549
+ "-q",
550
+ "-t",
551
+ "-t",
552
+ "-A",
553
+ master,
554
+ "sudo /bin/bash -c %s" % quote(" ".join(cmd_parts)),
555
+ ]
556
+
557
+ log.debug("Running %s" % " ".join(cmd_parts))
558
+
559
+ return _run(
560
+ cmd_parts,
561
+ timeout=timeout,
562
+ stream=True,
563
+ stdin=stdin,
564
+ stdin_interrupt=stdin_interrupt,
565
+ popen_kwargs=popen_kwargs,
566
+ )
567
+
568
+
569
+ def lazy_choices_completer(list_func):
570
+ def inner(prefix, **kwargs):
571
+ options = list_func(**kwargs)
572
+ return [o for o in options if o.startswith(prefix)]
573
+
574
+ return inner
575
+
576
+
577
+ def figure_out_service_name(args, soa_dir=DEFAULT_SOA_DIR):
578
+ """Figures out and validates the input service name"""
579
+ service = args.service or guess_service_name()
580
+ try:
581
+ validate_service_name(service, soa_dir=soa_dir)
582
+ except NoSuchService as service_not_found:
583
+ print(service_not_found)
584
+ exit(1)
585
+ return service
586
+
587
+
588
+ def get_jenkins_build_output_url():
589
+ """Returns the URL for Jenkins job's output.
590
+ Returns None if it's not available.
591
+ """
592
+ build_output = os.environ.get("BUILD_URL")
593
+ if build_output:
594
+ build_output = build_output + "console"
595
+ return build_output
596
+
597
+
598
+ InstanceListerSig = Callable[
599
+ [
600
+ NamedArg(str, "service"),
601
+ NamedArg(Optional[str], "cluster"),
602
+ NamedArg(str, "instance_type"),
603
+ NamedArg(str, "soa_dir"),
604
+ ],
605
+ List[Tuple[str, str]],
606
+ ]
607
+
608
+ InstanceLoaderSig = Callable[
609
+ [
610
+ NamedArg(str, "service"),
611
+ NamedArg(str, "instance"),
612
+ NamedArg(str, "cluster"),
613
+ NamedArg(bool, "load_deployments"),
614
+ NamedArg(str, "soa_dir"),
615
+ ],
616
+ InstanceConfig,
617
+ ]
618
+
619
+ LongRunningServiceListerSig = Callable[
620
+ [
621
+ NamedArg(str, "service"),
622
+ NamedArg(Optional[str], "cluster"),
623
+ NamedArg(str, "instance_type"),
624
+ NamedArg(str, "soa_dir"),
625
+ ],
626
+ List[Tuple[str, str]],
627
+ ]
628
+
629
+ LongRunningServiceLoaderSig = Callable[
630
+ [
631
+ NamedArg(str, "service"),
632
+ NamedArg(str, "instance"),
633
+ NamedArg(str, "cluster"),
634
+ NamedArg(bool, "load_deployments"),
635
+ NamedArg(str, "soa_dir"),
636
+ ],
637
+ LongRunningServiceConfig,
638
+ ]
639
+
640
+
641
+ class InstanceTypeHandler(NamedTuple):
642
+ lister: InstanceListerSig
643
+ loader: InstanceLoaderSig
644
+
645
+
646
+ class LongRunningInstanceTypeHandler(NamedTuple):
647
+ lister: LongRunningServiceListerSig
648
+ loader: LongRunningServiceLoaderSig
649
+
650
+
651
+ INSTANCE_TYPE_HANDLERS: Mapping[str, InstanceTypeHandler] = defaultdict(
652
+ lambda: InstanceTypeHandler(None, None),
653
+ adhoc=InstanceTypeHandler(get_service_instance_list, load_adhoc_job_config),
654
+ kubernetes=InstanceTypeHandler(
655
+ get_service_instance_list, load_kubernetes_service_config
656
+ ),
657
+ eks=InstanceTypeHandler(get_service_instance_list, load_eks_service_config),
658
+ tron=InstanceTypeHandler(get_service_instance_list, load_tron_instance_config),
659
+ flink=InstanceTypeHandler(get_service_instance_list, load_flink_instance_config),
660
+ flinkeks=InstanceTypeHandler(
661
+ get_service_instance_list, load_flinkeks_instance_config
662
+ ),
663
+ cassandracluster=InstanceTypeHandler(
664
+ get_service_instance_list, load_cassandracluster_instance_config
665
+ ),
666
+ kafkacluster=InstanceTypeHandler(
667
+ get_service_instance_list, load_kafkacluster_instance_config
668
+ ),
669
+ nrtsearchservice=InstanceTypeHandler(
670
+ get_service_instance_list, load_nrtsearchservice_instance_config
671
+ ),
672
+ nrtsearchserviceeks=InstanceTypeHandler(
673
+ get_service_instance_list, load_nrtsearchserviceeks_instance_config
674
+ ),
675
+ monkrelays=InstanceTypeHandler(
676
+ get_service_instance_list, load_monkrelaycluster_instance_config
677
+ ),
678
+ )
679
+
680
+ LONG_RUNNING_INSTANCE_TYPE_HANDLERS: Mapping[
681
+ str, LongRunningInstanceTypeHandler
682
+ ] = defaultdict(
683
+ lambda: LongRunningInstanceTypeHandler(None, None),
684
+ kubernetes=LongRunningInstanceTypeHandler(
685
+ get_service_instance_list, load_kubernetes_service_config
686
+ ),
687
+ flink=LongRunningInstanceTypeHandler(
688
+ get_service_instance_list, load_flink_instance_config
689
+ ),
690
+ flinkeks=LongRunningInstanceTypeHandler(
691
+ get_service_instance_list, load_flinkeks_instance_config
692
+ ),
693
+ cassandracluster=LongRunningInstanceTypeHandler(
694
+ get_service_instance_list, load_cassandracluster_instance_config
695
+ ),
696
+ kafkacluster=LongRunningInstanceTypeHandler(
697
+ get_service_instance_list, load_kafkacluster_instance_config
698
+ ),
699
+ nrtsearchservice=LongRunningInstanceTypeHandler(
700
+ get_service_instance_list, load_nrtsearchservice_instance_config
701
+ ),
702
+ nrtsearchserviceeks=LongRunningInstanceTypeHandler(
703
+ get_service_instance_list, load_nrtsearchserviceeks_instance_config
704
+ ),
705
+ monkrelays=LongRunningInstanceTypeHandler(
706
+ get_service_instance_list, load_monkrelaycluster_instance_config
707
+ ),
708
+ eks=LongRunningInstanceTypeHandler(
709
+ get_service_instance_list, load_eks_service_config
710
+ ),
711
+ )
712
+
713
+
714
+ def get_instance_config(
715
+ service: str,
716
+ instance: str,
717
+ cluster: str,
718
+ soa_dir: str = DEFAULT_SOA_DIR,
719
+ load_deployments: bool = False,
720
+ instance_type: Optional[str] = None,
721
+ ) -> InstanceConfig:
722
+ """Returns the InstanceConfig object for whatever type of instance
723
+ it is. (kubernetes)"""
724
+ if instance_type is None:
725
+ instance_type = validate_service_instance(
726
+ service=service, instance=instance, cluster=cluster, soa_dir=soa_dir
727
+ )
728
+
729
+ instance_config_loader = INSTANCE_TYPE_HANDLERS[instance_type].loader
730
+ if instance_config_loader is None:
731
+ raise NotImplementedError(
732
+ "instance is %s of type %s which is not supported by paasta"
733
+ % (instance, instance_type)
734
+ )
735
+
736
+ return instance_config_loader(
737
+ service=service,
738
+ instance=instance,
739
+ cluster=cluster,
740
+ load_deployments=load_deployments,
741
+ soa_dir=soa_dir,
742
+ )
743
+
744
+
745
+ def get_namespaces_for_secret(
746
+ service: str, cluster: str, secret_name: str, soa_dir: str = DEFAULT_SOA_DIR
747
+ ) -> Set[str]:
748
+ secret_to_k8s_namespace = set()
749
+
750
+ k8s_instance_type_classes = {
751
+ "kubernetes": KubernetesDeploymentConfig,
752
+ "eks": EksDeploymentConfig,
753
+ }
754
+ for instance_type in INSTANCE_TYPES:
755
+ if instance_type in PAASTA_K8S_INSTANCE_TYPES:
756
+ config_loader = PaastaServiceConfigLoader(service, soa_dir)
757
+ for service_instance_config in config_loader.instance_configs(
758
+ cluster=cluster,
759
+ instance_type_class=k8s_instance_type_classes[instance_type],
760
+ ):
761
+ secret_to_k8s_namespace.add(service_instance_config.get_namespace())
762
+ else:
763
+ instances = get_service_instance_list(
764
+ service=service,
765
+ instance_type=instance_type,
766
+ cluster=cluster,
767
+ soa_dir=soa_dir,
768
+ )
769
+
770
+ for serv, instance in instances:
771
+ config = get_instance_config(serv, instance, cluster, soa_dir)
772
+ if secret_name in config.get_env():
773
+ secret_to_k8s_namespace.add(
774
+ INSTANCE_TYPE_TO_K8S_NAMESPACE[instance_type]
775
+ )
776
+
777
+ return secret_to_k8s_namespace
778
+
779
+
780
+ def select_k8s_secret_namespace(namespaces: Set[str]) -> Optional[str]:
781
+ namespaces_count = len(namespaces)
782
+
783
+ if not namespaces_count:
784
+ return None
785
+
786
+ if namespaces_count == 1:
787
+ return namespaces.pop()
788
+
789
+ # prioritise paasta, tron namespaces when found
790
+ for namespace in namespaces:
791
+ if namespace.startswith("paasta"):
792
+ return namespace
793
+ if namespace == "tron":
794
+ return namespace
795
+
796
+ # only experimental k8s namespaces
797
+ return namespaces.pop()
798
+
799
+
800
+ def extract_tags(paasta_tag: str) -> Mapping[str, str]:
801
+ """Returns a dictionary containing information from a git tag"""
802
+ regex = r"^refs/tags/(?:paasta-){1,2}(?P<deploy_group>[a-zA-Z0-9._-]+)(?:\+(?P<image_version>.*)){0,1}-(?P<tstamp>\d{8}T\d{6})-(?P<tag>.*?)$"
803
+ regex_match = re.match(regex, paasta_tag)
804
+ return regex_match.groupdict() if regex_match else {}
805
+
806
+
807
+ def list_deploy_groups(
808
+ service: Optional[str], soa_dir: str = DEFAULT_SOA_DIR, parsed_args=None, **kwargs
809
+ ) -> Set:
810
+ return set(
811
+ filter(
812
+ None,
813
+ {
814
+ config.get_deploy_group()
815
+ for config in get_instance_configs_for_service(
816
+ service=service
817
+ if service is not None
818
+ else parsed_args.service or guess_service_name(),
819
+ soa_dir=soa_dir,
820
+ )
821
+ },
822
+ )
823
+ )
824
+
825
+
826
+ def validate_given_deploy_groups(
827
+ all_deploy_groups: Collection[str], args_deploy_groups: Collection[str]
828
+ ) -> Tuple[Set[str], Set[str]]:
829
+ """Given two lists of deploy groups, return the intersection and difference between them.
830
+
831
+ :param all_deploy_groups: instances actually belonging to a service
832
+ :param args_deploy_groups: the desired instances
833
+ :returns: a tuple with (common, difference) indicating deploy groups common in both
834
+ lists and those only in args_deploy_groups
835
+ """
836
+ invalid_deploy_groups: Set[str]
837
+ valid_deploy_groups = set(args_deploy_groups).intersection(all_deploy_groups)
838
+ invalid_deploy_groups = set(args_deploy_groups).difference(all_deploy_groups)
839
+
840
+ return valid_deploy_groups, invalid_deploy_groups
841
+
842
+
843
+ def short_to_full_git_sha(short, refs):
844
+ """Converts a short git sha to a full SHA
845
+
846
+ :param short: A short Git SHA represented as a string
847
+ :param refs: A list of refs in the Git repository
848
+ :return: The full Git SHA or None if one can't be found
849
+ """
850
+ return [sha for sha in set(refs.values()) if sha.startswith(short)]
851
+
852
+
853
+ def validate_short_git_sha(value):
854
+ pattern = re.compile("[a-f0-9]{4,40}")
855
+ if not pattern.match(value):
856
+ raise argparse.ArgumentTypeError("%s is not a valid Git SHA" % value)
857
+ return value
858
+
859
+
860
+ def validate_full_git_sha(value: str) -> str:
861
+ pattern = re.compile("[a-f0-9]{40}")
862
+ if not pattern.match(value):
863
+ raise argparse.ArgumentTypeError(
864
+ "%s is not a full Git SHA, and PaaSTA needs the full SHA" % value
865
+ )
866
+ return value
867
+
868
+
869
+ def validate_git_sha(sha, git_url):
870
+ try:
871
+ validate_full_git_sha(sha)
872
+ return sha
873
+ except argparse.ArgumentTypeError:
874
+ refs = remote_git.list_remote_refs(git_url)
875
+ commits = short_to_full_git_sha(short=sha, refs=refs)
876
+ if len(commits) != 1:
877
+ raise ValueError(
878
+ "%s matched %d Git SHAs (with refs pointing at them). Must match exactly 1."
879
+ % (sha, len(commits))
880
+ )
881
+ return commits[0]
882
+
883
+
884
+ def get_subparser(subparsers, function, command, help_text, description):
885
+ new_parser = subparsers.add_parser(
886
+ command,
887
+ help=help_text,
888
+ description=(description),
889
+ epilog=(
890
+ "Note: This command requires SSH and sudo privileges on the remote PaaSTA "
891
+ "nodes."
892
+ ),
893
+ )
894
+ new_parser.add_argument(
895
+ "-s",
896
+ "--service",
897
+ help="The name of the service you wish to inspect",
898
+ required=True,
899
+ ).completer = lazy_choices_completer(list_services)
900
+ new_parser.add_argument(
901
+ "-c",
902
+ "--cluster",
903
+ help="Cluster on which the service is running"
904
+ "For example: --cluster pnw-prod",
905
+ required=True,
906
+ ).completer = lazy_choices_completer(list_clusters)
907
+ new_parser.add_argument(
908
+ "-i",
909
+ "--instance",
910
+ help="The instance that you wish to inspect" "For example: --instance main",
911
+ required=True,
912
+ default="main",
913
+ ) # No completer because we need to know service first and we can't until some other stuff has happened
914
+ new_parser.add_argument(
915
+ "-H",
916
+ "--host",
917
+ dest="host",
918
+ default=None,
919
+ help="Specify a specific host on which to run. Defaults to"
920
+ " one that is running the service chosen at random",
921
+ )
922
+ new_parser.add_argument(
923
+ "-m",
924
+ "--mesos-id",
925
+ dest="mesos_id",
926
+ default=None,
927
+ help="A specific mesos task ID, must match a task "
928
+ "running on the specified host. If not specified we "
929
+ "will pick a task at random",
930
+ )
931
+ new_parser.set_defaults(command=function)
932
+ return new_parser
933
+
934
+
935
+ def get_instance_configs_for_service(
936
+ service: str,
937
+ soa_dir: str,
938
+ type_filter: Optional[Iterable[str]] = None,
939
+ clusters: Optional[Sequence[str]] = None,
940
+ instances: Optional[Sequence[str]] = None,
941
+ ) -> Generator[InstanceConfig, None, None]:
942
+ if not clusters:
943
+ clusters = list_clusters(service=service, soa_dir=soa_dir)
944
+
945
+ if type_filter is None:
946
+ type_filter = INSTANCE_TYPE_HANDLERS.keys()
947
+
948
+ for cluster in clusters:
949
+ for instance_type, instance_handlers in INSTANCE_TYPE_HANDLERS.items():
950
+ if instance_type not in type_filter:
951
+ continue
952
+
953
+ instance_lister, instance_loader = instance_handlers
954
+
955
+ for _, instance in instance_lister(
956
+ service=service,
957
+ cluster=cluster,
958
+ soa_dir=soa_dir,
959
+ instance_type=instance_type,
960
+ ):
961
+ if instances and instance not in instances:
962
+ continue
963
+
964
+ yield instance_loader(
965
+ service=service,
966
+ instance=instance,
967
+ cluster=cluster,
968
+ soa_dir=soa_dir,
969
+ load_deployments=False,
970
+ )
971
+
972
+
973
+ def get_container_name(task):
974
+ container_name = "mesos-{}".format(task.executor["container"])
975
+ return container_name
976
+
977
+
978
+ def pick_random_port(service_name):
979
+ """Return a random port.
980
+
981
+ Tries to return the same port for the same service each time, when
982
+ possible.
983
+ """
984
+ hash_key = f"{service_name},{getpass.getuser()}".encode("utf8")
985
+ hash_number = int(hashlib.sha1(hash_key).hexdigest(), 16)
986
+ preferred_port = 33000 + (hash_number % 25000)
987
+ return ephemeral_port_reserve.reserve("0.0.0.0", preferred_port)
988
+
989
+
990
+ def trigger_deploys(
991
+ service: str,
992
+ system_config: Optional["SystemPaastaConfig"] = None,
993
+ ) -> None:
994
+ """Connects to the deploymentsd watcher on sysgit, which is an extremely simple
995
+ service that listens for a service string and then generates a service deployment"""
996
+ logline = f"Notifying soa-configs primary to generate a deployment for {service}"
997
+ _log(service=service, line=logline, component="deploy", level="event")
998
+ if not system_config:
999
+ system_config = load_system_paasta_config()
1000
+ server = system_config.get_git_repo_config("yelpsoa-configs").get(
1001
+ "deploy_server",
1002
+ DEFAULT_SOA_CONFIGS_GIT_URL,
1003
+ )
1004
+
1005
+ client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1006
+ try:
1007
+ client.connect((server, 5049))
1008
+ client.send(f"{service}\n".encode("utf-8"))
1009
+ finally:
1010
+ client.close()
1011
+
1012
+
1013
+ def verify_instances(
1014
+ args_instances: str,
1015
+ service: str,
1016
+ clusters: Sequence[str],
1017
+ soa_dir: str = DEFAULT_SOA_DIR,
1018
+ ) -> Sequence[str]:
1019
+ """Verify that a list of instances specified by user is correct for this service.
1020
+
1021
+ :param args_instances: a list of instances.
1022
+ :param service: the service name
1023
+ :param cluster: a list of clusters
1024
+ :returns: a list of instances specified in args_instances without any exclusions.
1025
+ """
1026
+ unverified_instances = args_instances.split(",")
1027
+ service_instances: Set[str] = list_all_instances_for_service(
1028
+ service, clusters=clusters, soa_dir=soa_dir
1029
+ )
1030
+
1031
+ misspelled_instances: Sequence[str] = [
1032
+ i for i in unverified_instances if i not in service_instances
1033
+ ]
1034
+
1035
+ if len(misspelled_instances) == 0:
1036
+ return misspelled_instances
1037
+
1038
+ # Check for instances with suffixes other than Tron instances (i.e. Flink instances)
1039
+ instances_without_suffixes = [x.split(".")[0] for x in unverified_instances]
1040
+
1041
+ misspelled_instances = [
1042
+ i for i in instances_without_suffixes if i not in service_instances
1043
+ ]
1044
+
1045
+ if misspelled_instances:
1046
+ suggestions: List[str] = []
1047
+ for instance in misspelled_instances:
1048
+ matches = difflib.get_close_matches(
1049
+ instance, service_instances, n=5, cutoff=0.5
1050
+ )
1051
+ suggestions.extend(matches) # type: ignore
1052
+ suggestions = list(set(suggestions))
1053
+
1054
+ if clusters:
1055
+ message = "{} doesn't have any instances matching {} on {}.".format(
1056
+ service,
1057
+ ", ".join(sorted(misspelled_instances)),
1058
+ ", ".join(sorted(clusters)),
1059
+ )
1060
+ else:
1061
+ message = "{} doesn't have any instances matching {}.".format(
1062
+ service, ", ".join(sorted(misspelled_instances))
1063
+ )
1064
+
1065
+ print(PaastaColors.red(message))
1066
+
1067
+ if suggestions:
1068
+ print("Did you mean any of these?")
1069
+ for instance in sorted(suggestions):
1070
+ print(" %s" % instance)
1071
+
1072
+ return misspelled_instances
1073
+
1074
+
1075
+ def get_paasta_oapi_api_clustername(cluster: str, is_eks: bool) -> str:
1076
+ """
1077
+ We'll be doing a tiny bit of lying while we have both EKS and non-EKS
1078
+ clusters: these will generally share the same PaaSTA name (i.e., the
1079
+ soaconfigs suffix will stay the same) - but we'll need a way to route API
1080
+ requests to the correct place. To do so, we'll add "fake" entries to our
1081
+ api_endpoints SystemPaastaConfig that are the PaaSTA clustername with an
1082
+ "eks-" prefix
1083
+ """
1084
+ return f"eks-{cluster}" if is_eks else cluster
1085
+
1086
+
1087
+ def get_paasta_oapi_client_with_auth(
1088
+ cluster: str = None,
1089
+ system_paasta_config: SystemPaastaConfig = None,
1090
+ http_res: bool = False,
1091
+ ) -> Optional[PaastaOApiClient]:
1092
+ return get_paasta_oapi_client(
1093
+ cluster=cluster,
1094
+ system_paasta_config=system_paasta_config,
1095
+ http_res=http_res,
1096
+ auth_token=get_sso_auth_token(paasta_apis=True),
1097
+ )
1098
+
1099
+
1100
+ def run_interactive_cli(
1101
+ cmd: str, shell: str = "/bin/bash", term: str = "xterm-256color"
1102
+ ):
1103
+ """Runs interactive command in a pseudo terminal, handling terminal size management
1104
+
1105
+ :param str cmd: shell command
1106
+ :param str shell: shell utility to use as wrapper
1107
+ :param str term: terminal type
1108
+ """
1109
+ cols, rows = shutil.get_terminal_size()
1110
+ if not os.path.isabs(shell):
1111
+ shell = shutil.which(shell)
1112
+ wrapped_cmd = (
1113
+ f"export SHELL={shell};"
1114
+ f"export TERM={term};"
1115
+ f"stty columns {cols} rows {rows};"
1116
+ f"exec {cmd}"
1117
+ )
1118
+ pty.spawn([shell, "-c", wrapped_cmd])