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,758 @@
1
+ #!/usr/bin/env 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 base64
17
+ import contextlib
18
+ import hashlib
19
+ import json
20
+ import logging
21
+ import os
22
+ import sys
23
+ import time
24
+ from collections import defaultdict
25
+ from functools import partial
26
+ from typing import Callable
27
+ from typing import Dict
28
+ from typing import Generator
29
+ from typing import List
30
+ from typing import Mapping
31
+ from typing import Optional
32
+ from typing import Set
33
+ from typing import Tuple
34
+
35
+ from kubernetes.client.rest import ApiException
36
+ from typing_extensions import Literal
37
+
38
+ from paasta_tools.eks_tools import EksDeploymentConfig
39
+ from paasta_tools.kubernetes_tools import create_secret
40
+ from paasta_tools.kubernetes_tools import create_secret_signature
41
+ from paasta_tools.kubernetes_tools import ensure_namespace
42
+ from paasta_tools.kubernetes_tools import get_paasta_secret_name
43
+ from paasta_tools.kubernetes_tools import get_paasta_secret_signature_name
44
+ from paasta_tools.kubernetes_tools import get_secret_signature
45
+ from paasta_tools.kubernetes_tools import get_vault_key_secret_name
46
+ from paasta_tools.kubernetes_tools import KubeClient
47
+ from paasta_tools.kubernetes_tools import KubernetesDeploymentConfig
48
+ from paasta_tools.kubernetes_tools import sanitise_kubernetes_name
49
+ from paasta_tools.kubernetes_tools import update_secret
50
+ from paasta_tools.kubernetes_tools import update_secret_signature
51
+ from paasta_tools.metrics import metrics_lib
52
+ from paasta_tools.paasta_service_config_loader import PaastaServiceConfigLoader
53
+ from paasta_tools.secret_tools import get_secret_name_from_ref
54
+ from paasta_tools.secret_tools import get_secret_provider
55
+ from paasta_tools.utils import DEFAULT_SOA_DIR
56
+ from paasta_tools.utils import DEFAULT_VAULT_TOKEN_FILE
57
+ from paasta_tools.utils import get_service_instance_list
58
+ from paasta_tools.utils import INSTANCE_TYPE_TO_K8S_NAMESPACE
59
+ from paasta_tools.utils import INSTANCE_TYPES
60
+ from paasta_tools.utils import load_system_paasta_config
61
+ from paasta_tools.utils import PAASTA_K8S_INSTANCE_TYPES
62
+ from paasta_tools.utils import SHARED_SECRETS_K8S_NAMESPACES
63
+
64
+ log = logging.getLogger(__name__)
65
+
66
+
67
+ K8S_INSTANCE_TYPE_CLASSES = (
68
+ KubernetesDeploymentConfig,
69
+ EksDeploymentConfig,
70
+ )
71
+
72
+
73
+ def parse_args() -> argparse.Namespace:
74
+ parser = argparse.ArgumentParser(description="Sync paasta secrets into k8s")
75
+ parser.add_argument(
76
+ "service_list",
77
+ nargs="+",
78
+ help="The list of services to sync secrets for",
79
+ metavar="SERVICE",
80
+ )
81
+ parser.add_argument(
82
+ "-c",
83
+ "--cluster",
84
+ dest="cluster",
85
+ metavar="CLUSTER",
86
+ default=None,
87
+ help="Kubernetes cluster name",
88
+ )
89
+ parser.add_argument(
90
+ "-d",
91
+ "--soa-dir",
92
+ dest="soa_dir",
93
+ metavar="SOA_DIR",
94
+ default=DEFAULT_SOA_DIR,
95
+ help="define a different soa config directory",
96
+ )
97
+ parser.add_argument(
98
+ "-n",
99
+ "--namespace",
100
+ dest="namespace",
101
+ help="Overwrite destination namespace for secrets",
102
+ )
103
+ parser.add_argument(
104
+ "-t",
105
+ "--vault-token-file",
106
+ dest="vault_token_file",
107
+ default=DEFAULT_VAULT_TOKEN_FILE,
108
+ help="Define a different vault token file location",
109
+ )
110
+ parser.add_argument(
111
+ "-v", "--verbose", action="store_true", dest="verbose", default=False
112
+ )
113
+ parser.add_argument(
114
+ "--secret-type",
115
+ choices=[
116
+ "all",
117
+ "paasta-secret",
118
+ "boto-key",
119
+ "crypto-key",
120
+ "datastore-credentials",
121
+ ],
122
+ default="all",
123
+ type=str,
124
+ help="Define which type of secret to add/update. Default is 'all' (which does not include datastore-credentials)",
125
+ )
126
+ args = parser.parse_args()
127
+ return args
128
+
129
+
130
+ @contextlib.contextmanager
131
+ def set_temporary_environment_variables(
132
+ environ: Mapping[str, str]
133
+ ) -> Generator[None, None, None]:
134
+ """
135
+ *Note the return value means "yields None, takes None, and when finished, returns None"*
136
+
137
+ Modifies the os.environ variable then yields this temporary state. Resets it when finished.
138
+
139
+ :param environ: Environment variables to set
140
+ """
141
+ old_environ = dict(os.environ) # ensure we're storing a copy
142
+ os.environ.update(environ)
143
+ try:
144
+ yield
145
+ finally:
146
+ os.environ.clear()
147
+ os.environ.update(old_environ)
148
+
149
+
150
+ def main() -> None:
151
+ args = parse_args()
152
+ if args.verbose:
153
+ logging.basicConfig(level=logging.DEBUG)
154
+ else:
155
+ logging.basicConfig(level=logging.WARNING)
156
+
157
+ system_paasta_config = load_system_paasta_config()
158
+ if args.cluster:
159
+ cluster = args.cluster
160
+ else:
161
+ cluster = system_paasta_config.get_cluster()
162
+
163
+ timer = metrics_lib.system_timer(
164
+ dimensions=dict(
165
+ cluster=cluster,
166
+ )
167
+ )
168
+
169
+ timer.start()
170
+ secret_provider_name = system_paasta_config.get_secret_provider_name()
171
+ vault_cluster_config = system_paasta_config.get_vault_cluster_config()
172
+ kube_client = KubeClient()
173
+ services_to_k8s_namespaces_to_allowlist = (
174
+ get_services_to_k8s_namespaces_to_allowlist(
175
+ service_list=args.service_list,
176
+ cluster=cluster,
177
+ soa_dir=args.soa_dir,
178
+ kube_client=kube_client,
179
+ )
180
+ )
181
+
182
+ result = sync_all_secrets(
183
+ kube_client=kube_client,
184
+ cluster=cluster,
185
+ services_to_k8s_namespaces_to_allowlist=services_to_k8s_namespaces_to_allowlist,
186
+ secret_provider_name=secret_provider_name,
187
+ vault_cluster_config=vault_cluster_config,
188
+ soa_dir=args.soa_dir,
189
+ vault_token_file=args.vault_token_file,
190
+ overwrite_namespace=args.namespace,
191
+ secret_type=args.secret_type,
192
+ )
193
+ exit_code = 0 if result else 1
194
+
195
+ timer.stop(tmp_dimensions={"result": exit_code})
196
+ logging.info(
197
+ f"Stopping timer for {cluster} with result {exit_code}: {timer()}ms elapsed"
198
+ )
199
+ sys.exit(exit_code)
200
+
201
+
202
+ def get_services_to_k8s_namespaces_to_allowlist(
203
+ service_list: List[str], cluster: str, soa_dir: str, kube_client: KubeClient
204
+ ) -> Dict[
205
+ str, # service
206
+ Dict[
207
+ str, # namespace
208
+ Optional[Set[str]], # allowlist of secret names, None means allow all.
209
+ ],
210
+ ]:
211
+ """
212
+ Generate a mapping of service -> namespace -> allowlist of secrets, e.g.
213
+
214
+ {
215
+ "yelp-main": {
216
+ "paasta": {"secret1", "secret2"},
217
+ "paastasvc-yelp-main": {"secret1", "secret3"},
218
+ "paasta-flinks": None,
219
+ },
220
+ "_shared": {
221
+ "paasta": {"sharedsecret1"},
222
+ "paastasvc-yelp-main": {"sharedsecret1", "sharedsecret2"},
223
+ "paasta-flinks": None,
224
+ }
225
+ }
226
+
227
+ This mapping is used by sync_all_secrets / sync_secrets:
228
+ sync_secrets will only sync secrets into a namespace if the allowlist is None or contains that secret's name.
229
+ """
230
+ services_to_k8s_namespaces_to_allowlist: Dict[
231
+ str, Dict[str, Optional[Set[str]]]
232
+ ] = defaultdict(dict)
233
+
234
+ for service in service_list:
235
+ if service == "_shared":
236
+ # _shared is handled specially for each service.
237
+ continue
238
+
239
+ config_loader = PaastaServiceConfigLoader(service, soa_dir)
240
+ for instance_type_class in K8S_INSTANCE_TYPE_CLASSES:
241
+ for service_instance_config in config_loader.instance_configs(
242
+ cluster=cluster, instance_type_class=instance_type_class
243
+ ):
244
+ secrets_used, shared_secrets_used = get_secrets_used_by_instance(
245
+ service_instance_config
246
+ )
247
+ allowlist = services_to_k8s_namespaces_to_allowlist[service].setdefault(
248
+ service_instance_config.get_namespace(),
249
+ set(),
250
+ )
251
+ if allowlist is not None:
252
+ allowlist.update(secrets_used)
253
+
254
+ if "_shared" in service_list:
255
+ shared_allowlist = services_to_k8s_namespaces_to_allowlist[
256
+ "_shared"
257
+ ].setdefault(
258
+ service_instance_config.get_namespace(),
259
+ set(),
260
+ )
261
+ if shared_allowlist is not None:
262
+ shared_allowlist.update(shared_secrets_used)
263
+
264
+ for instance_type in INSTANCE_TYPES:
265
+ if instance_type in PAASTA_K8S_INSTANCE_TYPES:
266
+ continue # handled above.
267
+
268
+ instances = get_service_instance_list(
269
+ service=service,
270
+ instance_type=instance_type,
271
+ cluster=cluster,
272
+ soa_dir=soa_dir,
273
+ )
274
+ if instances:
275
+ # Currently, all instance types besides kubernetes use one big namespace, defined in
276
+ # INSTANCE_TYPE_TO_K8S_NAMESPACE. Sync all shared secrets and all secrets belonging to any service
277
+ # which uses that instance type.
278
+
279
+ services_to_k8s_namespaces_to_allowlist[service][
280
+ INSTANCE_TYPE_TO_K8S_NAMESPACE[instance_type]
281
+ ] = None
282
+ if "_shared" in service_list:
283
+ services_to_k8s_namespaces_to_allowlist["_shared"][
284
+ INSTANCE_TYPE_TO_K8S_NAMESPACE[instance_type]
285
+ ] = None
286
+
287
+ return dict(services_to_k8s_namespaces_to_allowlist)
288
+
289
+
290
+ def get_secrets_used_by_instance(
291
+ service_instance_config: KubernetesDeploymentConfig,
292
+ ) -> Tuple[Set[str], Set[str]]:
293
+ (
294
+ secret_env_vars,
295
+ shared_secret_env_vars,
296
+ ) = service_instance_config.get_env_vars_that_use_secrets()
297
+
298
+ secrets_used = {get_secret_name_from_ref(v) for v in secret_env_vars.values()}
299
+ shared_secrets_used = {
300
+ get_secret_name_from_ref(v) for v in shared_secret_env_vars.values()
301
+ }
302
+
303
+ for secret_volume in service_instance_config.get_secret_volumes():
304
+ # currently, only per-service secrets are supported for secret_volumes.
305
+ secrets_used.add(secret_volume["secret_name"])
306
+
307
+ return secrets_used, shared_secrets_used
308
+
309
+
310
+ def sync_all_secrets(
311
+ kube_client: KubeClient,
312
+ cluster: str,
313
+ services_to_k8s_namespaces_to_allowlist: Dict[str, Dict[str, Set[str]]],
314
+ secret_provider_name: str,
315
+ vault_cluster_config: Dict[str, str],
316
+ soa_dir: str,
317
+ vault_token_file: str,
318
+ secret_type: Literal[
319
+ "all", "paasta-secret", "crypto-key", "boto-key", "datastore-credentials"
320
+ ] = "all",
321
+ overwrite_namespace: Optional[str] = None,
322
+ ) -> bool:
323
+ results = []
324
+
325
+ for (
326
+ service,
327
+ namespaces_to_allowlist,
328
+ ) in services_to_k8s_namespaces_to_allowlist.items():
329
+ sync_service_secrets: Dict[str, List[Callable]] = defaultdict(list)
330
+
331
+ if overwrite_namespace:
332
+ namespaces_to_allowlist = {
333
+ overwrite_namespace: None
334
+ if overwrite_namespace in SHARED_SECRETS_K8S_NAMESPACES
335
+ else namespaces_to_allowlist.get(overwrite_namespace, set()),
336
+ }
337
+ for namespace, secret_allowlist in namespaces_to_allowlist.items():
338
+ ensure_namespace(kube_client, namespace)
339
+ sync_service_secrets["paasta-secret"].append(
340
+ partial(
341
+ sync_secrets,
342
+ kube_client=kube_client,
343
+ cluster=cluster,
344
+ service=service,
345
+ secret_provider_name=secret_provider_name,
346
+ vault_cluster_config=vault_cluster_config,
347
+ soa_dir=soa_dir,
348
+ namespace=namespace,
349
+ vault_token_file=vault_token_file,
350
+ secret_allowlist=secret_allowlist,
351
+ )
352
+ )
353
+ sync_service_secrets["boto-key"].append(
354
+ partial(
355
+ sync_boto_secrets,
356
+ kube_client=kube_client,
357
+ cluster=cluster,
358
+ service=service,
359
+ soa_dir=soa_dir,
360
+ )
361
+ )
362
+ sync_service_secrets["crypto-key"].append(
363
+ partial(
364
+ sync_crypto_secrets,
365
+ kube_client=kube_client,
366
+ cluster=cluster,
367
+ service=service,
368
+ secret_provider_name=secret_provider_name,
369
+ vault_cluster_config=vault_cluster_config,
370
+ soa_dir=soa_dir,
371
+ vault_token_file=vault_token_file,
372
+ )
373
+ )
374
+
375
+ sync_service_secrets["datastore-credentials"].append(
376
+ partial(
377
+ sync_datastore_credentials,
378
+ kube_client=kube_client,
379
+ cluster=cluster,
380
+ service=service,
381
+ secret_provider_name=secret_provider_name,
382
+ vault_cluster_config=vault_cluster_config,
383
+ soa_dir=soa_dir,
384
+ vault_token_file=vault_token_file,
385
+ overwrite_namespace=overwrite_namespace,
386
+ )
387
+ )
388
+
389
+ if secret_type == "all":
390
+ results.append(
391
+ all(sync() for sync in sync_service_secrets["paasta-secret"])
392
+ )
393
+ results.append(all(sync() for sync in sync_service_secrets["boto-key"]))
394
+ results.append(all(sync() for sync in sync_service_secrets["crypto-key"]))
395
+ # note that since datastore-credentials are in a different vault, they're not synced as part of 'all'
396
+ else:
397
+ results.append(all(sync() for sync in sync_service_secrets[secret_type]))
398
+
399
+ return all(results)
400
+
401
+
402
+ def sync_secrets(
403
+ kube_client: KubeClient,
404
+ cluster: str,
405
+ service: str,
406
+ secret_provider_name: str,
407
+ vault_cluster_config: Dict[str, str],
408
+ soa_dir: str,
409
+ namespace: str,
410
+ vault_token_file: str,
411
+ secret_allowlist: Optional[Set[str]],
412
+ ) -> bool:
413
+ secret_dir = os.path.join(soa_dir, service, "secrets")
414
+ secret_provider_kwargs = {
415
+ "vault_cluster_config": vault_cluster_config,
416
+ # TODO: make vault-tools support k8s auth method so we don't have to
417
+ # mount a token in.
418
+ "vault_auth_method": "token",
419
+ "vault_token_file": vault_token_file,
420
+ }
421
+ secret_provider = get_secret_provider(
422
+ secret_provider_name=secret_provider_name,
423
+ soa_dir=soa_dir,
424
+ service_name=service,
425
+ cluster_names=[cluster],
426
+ secret_provider_kwargs=secret_provider_kwargs,
427
+ )
428
+ if not os.path.isdir(secret_dir):
429
+ log.debug(f"No secrets dir for {service}")
430
+ return True
431
+
432
+ with os.scandir(secret_dir) as secret_file_paths:
433
+ for secret_file_path in secret_file_paths:
434
+ if secret_file_path.path.endswith("json"):
435
+ secret = secret_file_path.name.replace(".json", "")
436
+ if secret_allowlist is not None:
437
+ if secret not in secret_allowlist:
438
+ log.debug(
439
+ f"Skipping {service}.{secret} in {namespace} because it's not in in secret_allowlist"
440
+ )
441
+ continue
442
+
443
+ with open(secret_file_path, "r") as secret_file:
444
+ secret_signature = secret_provider.get_secret_signature_from_data(
445
+ json.load(secret_file)
446
+ )
447
+
448
+ if secret_signature:
449
+ create_or_update_k8s_secret(
450
+ service=service,
451
+ signature_name=get_paasta_secret_signature_name(
452
+ namespace, service, sanitise_kubernetes_name(secret)
453
+ ),
454
+ secret_name=get_paasta_secret_name(
455
+ namespace, service, sanitise_kubernetes_name(secret)
456
+ ),
457
+ get_secret_data=(
458
+ lambda: {
459
+ secret: base64.b64encode(
460
+ # If signatures does not match, it'll sys.exit(1)
461
+ secret_provider.decrypt_secret_raw(secret)
462
+ ).decode("utf-8")
463
+ }
464
+ ),
465
+ secret_signature=secret_signature,
466
+ kube_client=kube_client,
467
+ namespace=namespace,
468
+ )
469
+
470
+ return True
471
+
472
+
473
+ def sync_datastore_credentials(
474
+ kube_client: KubeClient,
475
+ cluster: str,
476
+ service: str,
477
+ secret_provider_name: str,
478
+ vault_cluster_config: Dict[str, str],
479
+ soa_dir: str,
480
+ vault_token_file: str,
481
+ overwrite_namespace: Optional[str] = None,
482
+ ) -> bool:
483
+ """
484
+ Map all the passwords requested for this service-instance to a single Kubernetes Secret store.
485
+ Volume mounts will then map the associated secrets to their associated mount paths.
486
+ """
487
+ config_loader = PaastaServiceConfigLoader(service=service, soa_dir=soa_dir)
488
+ system_paasta_config = load_system_paasta_config()
489
+ datastore_credentials_vault_overrides = (
490
+ system_paasta_config.get_datastore_credentials_vault_overrides()
491
+ )
492
+
493
+ for instance_type_class in K8S_INSTANCE_TYPE_CLASSES:
494
+ for instance_config in config_loader.instance_configs(
495
+ cluster=cluster, instance_type_class=instance_type_class
496
+ ):
497
+ namespace = (
498
+ overwrite_namespace
499
+ if overwrite_namespace is not None
500
+ else instance_config.get_namespace()
501
+ )
502
+ datastore_credentials = instance_config.get_datastore_credentials()
503
+ with set_temporary_environment_variables(
504
+ datastore_credentials_vault_overrides
505
+ ):
506
+ # expects VAULT_ADDR_OVERRIDE, VAULT_CA_OVERRIDE, and VAULT_TOKEN_OVERRIDE to be set
507
+ # in order to use a custom vault shard. overriden temporarily in this context
508
+ provider = get_secret_provider(
509
+ secret_provider_name=secret_provider_name,
510
+ soa_dir=soa_dir,
511
+ service_name=service,
512
+ cluster_names=[cluster],
513
+ # overridden by env variables but still needed here for spec validation
514
+ secret_provider_kwargs={
515
+ "vault_cluster_config": vault_cluster_config,
516
+ "vault_auth_method": "token",
517
+ "vault_token_file": vault_token_file,
518
+ },
519
+ )
520
+
521
+ secret_data = {}
522
+ for datastore, credentials in datastore_credentials.items():
523
+ # mypy loses type hints on '.items' and throws false positives. unfortunately have to type: ignore
524
+ # https://github.com/python/mypy/issues/7178
525
+ for credential in credentials: # type: ignore
526
+ vault_path = f"secrets/datastore/{datastore}/{credential}"
527
+ secrets = provider.get_data_from_vault_path(vault_path)
528
+ if not secrets:
529
+ # no secrets found at this path. skip syncing
530
+ log.debug(
531
+ f"Warning: no secrets found at requested path {vault_path}."
532
+ )
533
+ continue
534
+
535
+ # decrypt and save in secret_data
536
+ vault_key_path = get_vault_key_secret_name(vault_path)
537
+
538
+ # kubernetes expects data to be base64 encoded binary in utf-8 when put into secret maps
539
+ # may look like:
540
+ # {'master': {'passwd': '****', 'user': 'v-approle-mysql-serv-nVcYexH95A2'}, 'reporting': {'passwd': '****', 'user': 'v-approle-mysql-serv-GgCpRIh9Ut7'}, 'slave': {'passwd': '****', 'user': 'v-approle-mysql-serv-PzjPwqNMbqu'}
541
+ secret_data[vault_key_path] = base64.b64encode(
542
+ json.dumps(secrets).encode("utf-8")
543
+ ).decode("utf-8")
544
+
545
+ create_or_update_k8s_secret(
546
+ service=service,
547
+ signature_name=instance_config.get_datastore_credentials_signature_name(),
548
+ secret_name=instance_config.get_datastore_credentials_secret_name(),
549
+ get_secret_data=(lambda: secret_data),
550
+ secret_signature=_get_dict_signature(secret_data),
551
+ kube_client=kube_client,
552
+ namespace=namespace,
553
+ )
554
+
555
+ return True
556
+
557
+
558
+ def sync_crypto_secrets(
559
+ kube_client: KubeClient,
560
+ cluster: str,
561
+ service: str,
562
+ secret_provider_name: str,
563
+ vault_cluster_config: Dict[str, str],
564
+ soa_dir: str,
565
+ vault_token_file: str,
566
+ ) -> bool:
567
+ """
568
+ For each key-name in `crypto_key`,
569
+ 1. Fetch all versions of the key-name from Vault superregion mapped from cluster, e.g. `kubestage` maps to `devc` Vault server.
570
+ 2. Create K8s secret from JSON blob containing all key versions.
571
+ 3. Create signatures as K8s configmap based on JSON blob hash.
572
+
573
+ So each replica of a service instance gets the same key, thereby reducing requests to Vault API as we only talk to vault during secret syncing
574
+ """
575
+ config_loader = PaastaServiceConfigLoader(service=service, soa_dir=soa_dir)
576
+ for instance_type_class in K8S_INSTANCE_TYPE_CLASSES:
577
+ for instance_config in config_loader.instance_configs(
578
+ cluster=cluster, instance_type_class=instance_type_class
579
+ ):
580
+ crypto_keys = instance_config.get_crypto_keys_from_config()
581
+ if not crypto_keys:
582
+ continue
583
+ secret_data = {}
584
+ provider = get_secret_provider(
585
+ secret_provider_name=secret_provider_name,
586
+ soa_dir=soa_dir,
587
+ service_name=service,
588
+ cluster_names=[cluster],
589
+ secret_provider_kwargs={
590
+ "vault_cluster_config": vault_cluster_config,
591
+ "vault_auth_method": "token",
592
+ "vault_token_file": vault_token_file,
593
+ },
594
+ )
595
+ for key in crypto_keys:
596
+ key_versions = provider.get_key_versions(key)
597
+ if not key_versions:
598
+ log.error(
599
+ f"No key versions found for {key} on {instance_config.get_sanitised_deployment_name()}"
600
+ )
601
+ continue
602
+
603
+ secret_data[get_vault_key_secret_name(key)] = base64.b64encode(
604
+ json.dumps(key_versions).encode("utf-8")
605
+ ).decode("utf-8")
606
+
607
+ if not secret_data:
608
+ continue
609
+
610
+ create_or_update_k8s_secret(
611
+ service=service,
612
+ signature_name=instance_config.get_crypto_secret_signature_name(),
613
+ # the secret name here must match the secret name given in the secret volume config,
614
+ # i.e. `kubernetes.client.V1SecretVolumeSource`'s `secret_name` must match below
615
+ secret_name=instance_config.get_crypto_secret_name(),
616
+ get_secret_data=(lambda: secret_data),
617
+ secret_signature=_get_dict_signature(secret_data),
618
+ kube_client=kube_client,
619
+ namespace=instance_config.get_namespace(),
620
+ )
621
+
622
+ return True
623
+
624
+
625
+ def sync_boto_secrets(
626
+ kube_client: KubeClient,
627
+ cluster: str,
628
+ service: str,
629
+ soa_dir: str,
630
+ ) -> bool:
631
+ config_loader = PaastaServiceConfigLoader(service=service, soa_dir=soa_dir)
632
+ for instance_type_class in K8S_INSTANCE_TYPE_CLASSES:
633
+ for instance_config in config_loader.instance_configs(
634
+ cluster=cluster, instance_type_class=instance_type_class
635
+ ):
636
+ boto_keys = instance_config.config_dict.get("boto_keys", [])
637
+ if not boto_keys:
638
+ continue
639
+ boto_keys.sort()
640
+ secret_data = {}
641
+ for key in boto_keys:
642
+ for filetype in ["sh", "yaml", "json", "cfg"]:
643
+ this_key = key + "." + filetype
644
+ sanitised_key = this_key.replace(".", "-").replace("_", "--")
645
+ try:
646
+ with open(f"/etc/boto_cfg_private/{this_key}") as f:
647
+ secret_data[sanitised_key] = base64.b64encode(
648
+ f.read().encode("utf-8")
649
+ ).decode("utf-8")
650
+ except IOError:
651
+ log.warning(
652
+ f"Boto key {this_key} required for {service} could not be found."
653
+ )
654
+ secret_data[sanitised_key] = base64.b64encode(
655
+ "This user no longer exists. Remove it from boto_keys.".encode(
656
+ "utf-8"
657
+ )
658
+ ).decode("utf-8")
659
+
660
+ if not secret_data:
661
+ continue
662
+
663
+ create_or_update_k8s_secret(
664
+ service=service,
665
+ signature_name=instance_config.get_boto_secret_signature_name(),
666
+ secret_name=instance_config.get_boto_secret_name(),
667
+ get_secret_data=(lambda: secret_data),
668
+ secret_signature=_get_dict_signature(secret_data),
669
+ kube_client=kube_client,
670
+ namespace=instance_config.get_namespace(),
671
+ )
672
+ return True
673
+
674
+
675
+ def _get_dict_signature(data: Dict[str, str]) -> str:
676
+ return hashlib.sha1(
677
+ "|".join(f"{key}:{value}" for key, value in data.items()).encode("utf-8")
678
+ ).hexdigest()
679
+
680
+
681
+ def create_or_update_k8s_secret(
682
+ service: str,
683
+ secret_name: str,
684
+ signature_name: str,
685
+ get_secret_data: Callable[[], Dict[str, str]],
686
+ secret_signature: str,
687
+ kube_client: KubeClient,
688
+ namespace: str,
689
+ ) -> None:
690
+ """
691
+ :param get_secret_data: is a function to postpone fetching data in order to reduce service load, e.g. Vault API
692
+ """
693
+ # In order to prevent slamming the k8s API, add some artificial delay here
694
+ delay = load_system_paasta_config().get_secret_sync_delay_seconds()
695
+ if delay:
696
+ time.sleep(delay)
697
+
698
+ kubernetes_signature = get_secret_signature(
699
+ kube_client=kube_client,
700
+ signature_name=signature_name,
701
+ namespace=namespace,
702
+ )
703
+
704
+ if not kubernetes_signature:
705
+ log.info(f"{secret_name} for {service} in {namespace} not found, creating")
706
+ try:
707
+ create_secret(
708
+ kube_client=kube_client,
709
+ service_name=service,
710
+ secret_name=secret_name,
711
+ secret_data=get_secret_data(),
712
+ namespace=namespace,
713
+ )
714
+ except ApiException as e:
715
+ if e.status == 409:
716
+ log.warning(
717
+ f"Secret {secret_name} for {service} already exists in {namespace} but no signature found. Updating secret and signature."
718
+ )
719
+ update_secret(
720
+ kube_client=kube_client,
721
+ secret_name=secret_name,
722
+ secret_data=get_secret_data(),
723
+ service_name=service,
724
+ namespace=namespace,
725
+ )
726
+ else:
727
+ raise
728
+ create_secret_signature(
729
+ kube_client=kube_client,
730
+ service_name=service,
731
+ signature_name=signature_name,
732
+ secret_signature=secret_signature,
733
+ namespace=namespace,
734
+ )
735
+ elif secret_signature != kubernetes_signature:
736
+ log.info(
737
+ f"{secret_name} for {service} in {namespace} needs updating as signature changed"
738
+ )
739
+ update_secret(
740
+ kube_client=kube_client,
741
+ secret_name=secret_name,
742
+ secret_data=get_secret_data(),
743
+ service_name=service,
744
+ namespace=namespace,
745
+ )
746
+ update_secret_signature(
747
+ kube_client=kube_client,
748
+ service_name=service,
749
+ signature_name=signature_name,
750
+ secret_signature=secret_signature,
751
+ namespace=namespace,
752
+ )
753
+ else:
754
+ log.info(f"{secret_name} for {service} in {namespace} up to date")
755
+
756
+
757
+ if __name__ == "__main__":
758
+ main()