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,316 @@
1
+ import json
2
+ import os
3
+ from typing import Any
4
+ from typing import Dict
5
+
6
+
7
+ def merge_vscode_settings(file: str, setting_dict: Dict[str, Any]) -> None:
8
+ os.makedirs("./.vscode", exist_ok=True)
9
+
10
+ json_path = os.path.join("./.vscode", file)
11
+ # first checks if the file exists
12
+ # if it does then load the file content as json into settings
13
+ # if it doesn't exist then set settings to empty
14
+ if os.path.exists(json_path):
15
+ with open(json_path, mode="r") as settings_file:
16
+ settings = json.load(settings_file)
17
+ else:
18
+ settings = {}
19
+
20
+ # update settings with the default configurations we want each file to have
21
+ merge_dicts(setting_dict, settings)
22
+
23
+ with open(json_path, mode="w") as settings_file:
24
+ json.dump(settings, settings_file, indent=2)
25
+
26
+
27
+ def merge_dicts(merge_from: Dict[str, Any], merge_to: Dict[str, Any]) -> None:
28
+ for key, value in merge_from.items():
29
+ if key in merge_to:
30
+ if value not in merge_to[key]:
31
+ for dict_entry in merge_from[key]:
32
+ if dict_entry not in merge_to[key]:
33
+ if isinstance(merge_to[key], list):
34
+ merge_to[key].append(dict_entry)
35
+ else:
36
+ temp_list = [merge_to[key]]
37
+ temp_list.append(dict_entry)
38
+ merge_to[key] = temp_list
39
+ else:
40
+ merge_to[key] = value
41
+
42
+
43
+ def install_vscode_support() -> None:
44
+ paasta_schema_settings = {
45
+ "version": "0.2.0",
46
+ "configurations": [
47
+ {
48
+ "name": "tox test",
49
+ "type": "python",
50
+ "request": "launch",
51
+ "cwd": "${workspaceFolder}",
52
+ "console": "integratedTerminal",
53
+ "python": "${workspaceFolder}/.paasta/bin/python",
54
+ "program": "${workspaceFolder}/.paasta/bin/tox",
55
+ "subProcess": True,
56
+ "args": ["-e", "py38-linux,docs,mypy,tests"],
57
+ },
58
+ {
59
+ "name": "paasta cli",
60
+ "cwd": "${workspaceFolder}",
61
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
62
+ "type": "python",
63
+ "request": "launch",
64
+ "module": "paasta_tools.cli.cli",
65
+ },
66
+ {
67
+ "name": "paasta rollback",
68
+ "cwd": "${workspaceFolder}",
69
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
70
+ "type": "python",
71
+ "request": "launch",
72
+ "module": "paasta_tools.cli.cli",
73
+ "args": [
74
+ "rollback",
75
+ "--service",
76
+ "katamari_test_service",
77
+ "--deploy-group",
78
+ "dev.canary",
79
+ "--commit",
80
+ "fa7f2023c84736bd05201ef96ebd3c3fed6ab903", # pragma: whitelist secret
81
+ ],
82
+ },
83
+ {
84
+ "name": "paasta mark-for-deployment",
85
+ "cwd": "${workspaceFolder}",
86
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
87
+ "type": "python",
88
+ "request": "launch",
89
+ "module": "paasta_tools.cli.cli",
90
+ "args": [
91
+ "mark-for-deployment",
92
+ "--service",
93
+ "katamari_test_service",
94
+ "--deploy-group",
95
+ "dev.canary",
96
+ "--commit",
97
+ "224173aca322207994e655c4316ddb16f00eaab7", # pragma: whitelist secret
98
+ "--wait-for-deployment",
99
+ ],
100
+ },
101
+ {
102
+ "name": "paasta status",
103
+ "cwd": "${workspaceFolder}",
104
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
105
+ "type": "python",
106
+ "request": "launch",
107
+ "module": "paasta_tools.cli.cli",
108
+ "args": [
109
+ "status",
110
+ "--service",
111
+ "katamari_test_service",
112
+ "--clusters",
113
+ "norcal-devc",
114
+ "--instance",
115
+ "canary",
116
+ ],
117
+ },
118
+ {
119
+ "name": "paasta playground",
120
+ "cwd": "${workspaceFolder}",
121
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
122
+ "type": "python",
123
+ "request": "launch",
124
+ "module": "paasta_tools.cli.cli",
125
+ "justMyCode": False,
126
+ "env": {"PAASTA_SYSTEM_CONFIG_DIR": "./etc_paasta_playground/"},
127
+ "args": [
128
+ "status",
129
+ "--service",
130
+ "compute-infra-test-service",
131
+ "--clusters",
132
+ "kind-${env:USER}-k8s-test",
133
+ "-d",
134
+ "./soa_config_playground/",
135
+ ],
136
+ "preLaunchTask": "Run API Playground",
137
+ },
138
+ {
139
+ "name": "paasta status playground",
140
+ "cwd": "${workspaceFolder}",
141
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
142
+ "type": "python",
143
+ "request": "launch",
144
+ "module": "paasta_tools.cli.cli",
145
+ "justMyCode": False,
146
+ "env": {"PAASTA_SYSTEM_CONFIG_DIR": "./etc_paasta_playground/"},
147
+ "args": [
148
+ "status",
149
+ "--service",
150
+ "compute-infra-test-service",
151
+ "--clusters",
152
+ "kind-${env:USER}-k8s-test",
153
+ "-d",
154
+ "./soa_config_playground/",
155
+ ],
156
+ },
157
+ {
158
+ "name": "paasta logs",
159
+ "cwd": "${workspaceFolder}",
160
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
161
+ "type": "python",
162
+ "request": "launch",
163
+ "module": "paasta_tools.cli.cli",
164
+ "args": [
165
+ "logs",
166
+ "--service",
167
+ "katamari_test_service",
168
+ "--cluster",
169
+ "norcal-devc",
170
+ "--instance",
171
+ "canary",
172
+ ],
173
+ },
174
+ {
175
+ "name": "paasta validate",
176
+ # This command has to be ran from inside the service repo in yelpsoa-configs
177
+ "cwd": "${userHome}/pg/yelpsoa-configs/",
178
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
179
+ "type": "python",
180
+ "request": "launch",
181
+ "module": "paasta_tools.cli.cli",
182
+ "args": ["validate", "--service", "katamari_test_service"],
183
+ },
184
+ {
185
+ # 1) Follow step 1 in "Running the PaaSTA HTTP API Locally" wiki
186
+ # 2) Run this "paasta API" test to debug paasta API
187
+ # 3) Run client command, e.g. PAASTA_SYSTEM_CONFIG_DIR=./etc_paasta_for_development/ .tox/py38-linux/bin/python paasta_tools/cli/cli.py status --clusters norcal-devc --service katamari_test_service
188
+ "name": "paasta API",
189
+ "cwd": "${workspaceFolder}",
190
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
191
+ "type": "python",
192
+ "request": "launch",
193
+ "module": "paasta_tools.run-paasta-api-in-dev-mode",
194
+ "env": {
195
+ "KUBECONFIG": "./etc_paasta_for_development/admin.conf",
196
+ "PAASTA_SYSTEM_CONFIG_DIR": "./etc_paasta_for_development/",
197
+ "PAASTA_TEST_CLUSTER": "norcal-devc",
198
+ "PYDEVD_USE_CYTHON": "NO",
199
+ "PYTHONUNBUFFERED": "1",
200
+ "PAASTA_API_SINGLE_PROCESS": "true",
201
+ },
202
+ },
203
+ {
204
+ "name": "paasta API playground",
205
+ "cwd": "${workspaceFolder}",
206
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
207
+ "type": "python",
208
+ "request": "launch",
209
+ "module": "paasta_tools.run-paasta-api-playground",
210
+ "justMyCode": False,
211
+ "env": {
212
+ "KUBECONFIG": "./k8s_itests/kubeconfig",
213
+ "PAASTA_SYSTEM_CONFIG_DIR": "./etc_paasta_playground/",
214
+ "PAASTA_TEST_CLUSTER": "kind-${env:USER}-k8s-test",
215
+ "PYDEVD_USE_CYTHON": "NO",
216
+ "PYTHONUNBUFFERED": "1",
217
+ "PAASTA_API_SINGLE_PROCESS": "true",
218
+ "PAASTA_API_SOA_DIR": "./soa_config_playground/",
219
+ },
220
+ },
221
+ {
222
+ "name": "Run setup k8s job in playground",
223
+ "cwd": "${workspaceFolder}",
224
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
225
+ "type": "python",
226
+ "request": "launch",
227
+ "module": "paasta_tools.setup_kubernetes_job",
228
+ "justMyCode": False,
229
+ "args": [
230
+ "-d",
231
+ "./soa_config_playground",
232
+ "-c",
233
+ "kind-${env:USER}-k8s-test",
234
+ "compute-infra-test-service.autoscaling",
235
+ ],
236
+ "env": {
237
+ "KUBECONFIG": "./k8s_itests/kubeconfig",
238
+ "PAASTA_SYSTEM_CONFIG_DIR": "./etc_paasta_playground/",
239
+ "PAASTA_TEST_CLUSTER": "kind-${env:USER}-k8s-test",
240
+ "PYDEVD_USE_CYTHON": "NO",
241
+ "PYTHONUNBUFFERED": "1",
242
+ },
243
+ },
244
+ {
245
+ "name": "Generate deployments.json in playground",
246
+ "cwd": "${workspaceFolder}",
247
+ "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
248
+ "type": "python",
249
+ "request": "launch",
250
+ "module": "paasta_tools.generate_deployments_for_service",
251
+ "justMyCode": False,
252
+ "args": [
253
+ "-d",
254
+ "./soa_config_playground",
255
+ "-s",
256
+ "compute-infra-test-service",
257
+ "-v",
258
+ ],
259
+ "env": {
260
+ "PAASTA_SYSTEM_CONFIG_DIR": "./etc_paasta_playground/",
261
+ "PYDEVD_USE_CYTHON": "NO",
262
+ "PYTHONUNBUFFERED": "1",
263
+ },
264
+ },
265
+ ],
266
+ }
267
+ merge_vscode_settings("launch.json", paasta_schema_settings)
268
+
269
+ recommended_extensions = {
270
+ "recommendations": [
271
+ "redhat.vscode-yaml",
272
+ "ms-python.python",
273
+ "ms-python.vscode-pylance",
274
+ "ms-vscode.makefile-tools",
275
+ ]
276
+ }
277
+ merge_vscode_settings("extensions.json", recommended_extensions)
278
+
279
+ playground_task = {
280
+ "version": "2.0.0",
281
+ "tasks": [
282
+ {
283
+ "label": "Run API Playground",
284
+ "type": "shell",
285
+ "isBackground": True,
286
+ "command": "make playground-api",
287
+ "presentation": {
288
+ "reveal": "always",
289
+ "panel": "new",
290
+ },
291
+ "problemMatcher": [
292
+ {
293
+ "pattern": [
294
+ {
295
+ "regexp": ".",
296
+ "file": 1,
297
+ "location": 2,
298
+ "message": 3,
299
+ }
300
+ ],
301
+ "background": {
302
+ "activeOnStart": True,
303
+ "beginsPattern": ".",
304
+ "endsPattern": "^(.*?)\\[INFO\\]",
305
+ },
306
+ }
307
+ ],
308
+ }
309
+ ],
310
+ }
311
+ merge_vscode_settings("tasks.json", playground_task)
312
+ print("VS Code IDE Helpers installed")
313
+
314
+
315
+ if __name__ == "__main__":
316
+ install_vscode_support()
@@ -0,0 +1,139 @@
1
+ #!python
2
+ # Copyright 2015-2018 Yelp Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import argparse
16
+ import os
17
+ import sys
18
+
19
+ from paasta_tools.envoy_tools import are_namespaces_up_in_eds
20
+ from paasta_tools.envoy_tools import are_services_up_in_pod as is_envoy_ready
21
+ from paasta_tools.smartstack_tools import (
22
+ are_services_up_on_ip_port as is_smartstack_ready,
23
+ )
24
+ from paasta_tools.utils import load_system_paasta_config
25
+
26
+
27
+ system_paasta_config = load_system_paasta_config()
28
+
29
+ synapse_port = system_paasta_config.get_synapse_port()
30
+ synapse_host = "169.254.255.254"
31
+ synapse_haproxy_url_format = system_paasta_config.get_synapse_haproxy_url_format()
32
+
33
+ envoy_host = os.environ["PAASTA_HOST"]
34
+ envoy_admin_port = system_paasta_config.get_envoy_admin_port()
35
+ envoy_admin_endpoint_format = system_paasta_config.get_envoy_admin_endpoint_format()
36
+ envoy_eds_path = "/nail/etc/envoy/endpoints"
37
+ pod_ip = os.environ["PAASTA_POD_IP"]
38
+
39
+ ###############################################################
40
+ #
41
+ # This file is used in the hacheck sidecar, make sure to update `check_proxy_up.sh`
42
+ # when changing this file
43
+ #
44
+ ###############################################################
45
+
46
+
47
+ def get_parser() -> argparse.ArgumentParser:
48
+ parser = argparse.ArgumentParser()
49
+
50
+ parser.add_argument(
51
+ "--enable-smartstack",
52
+ dest="smartstack_readiness_check_enabled",
53
+ action="store_true",
54
+ help="Check smartstack readiness",
55
+ )
56
+
57
+ parser.add_argument(
58
+ "--enable-envoy",
59
+ action="store_true",
60
+ dest="envoy_readiness_check_enabled",
61
+ help="Check envoy readiness",
62
+ )
63
+
64
+ parser.add_argument(
65
+ "--envoy-check-mode",
66
+ choices=["admin-port", "eds-dir"],
67
+ default="admin-port",
68
+ help="Query Envoy backends through the admin interface (default) or the EDS directory",
69
+ )
70
+
71
+ parser.add_argument(
72
+ "pod_port",
73
+ help="Pod Port",
74
+ type=int,
75
+ )
76
+
77
+ parser.add_argument(
78
+ "services",
79
+ nargs="+",
80
+ help="List of service.instance names",
81
+ )
82
+
83
+ return parser
84
+
85
+
86
+ def main() -> None:
87
+ args = get_parser().parse_args()
88
+
89
+ if args.smartstack_readiness_check_enabled:
90
+ smartstack_ready = is_smartstack_ready(
91
+ synapse_host=synapse_host,
92
+ synapse_port=synapse_port,
93
+ synapse_haproxy_url_format=synapse_haproxy_url_format,
94
+ services=args.services,
95
+ host_ip=pod_ip,
96
+ host_port=args.pod_port,
97
+ )
98
+ else:
99
+ smartstack_ready = True
100
+
101
+ if args.envoy_readiness_check_enabled:
102
+ if args.envoy_check_mode == "admin-port":
103
+ envoy_ready = is_envoy_ready(
104
+ envoy_host=envoy_host,
105
+ envoy_admin_port=envoy_admin_port,
106
+ envoy_admin_endpoint_format=envoy_admin_endpoint_format,
107
+ registrations=args.services,
108
+ pod_ip=pod_ip,
109
+ pod_port=args.pod_port,
110
+ )
111
+ elif args.envoy_check_mode == "eds-dir":
112
+ envoy_ready = are_namespaces_up_in_eds(
113
+ envoy_eds_path=envoy_eds_path,
114
+ namespaces=args.services,
115
+ pod_ip=pod_ip,
116
+ pod_port=args.pod_port,
117
+ )
118
+
119
+ else:
120
+ envoy_ready = True
121
+
122
+ if smartstack_ready and envoy_ready:
123
+ sys.exit(0)
124
+ else:
125
+ if not smartstack_ready:
126
+ print(
127
+ f"Could not find backend {pod_ip}:{args.pod_port} for service {args.services} "
128
+ f"on Haproxy at {synapse_host}:{synapse_port}"
129
+ )
130
+ if not envoy_ready:
131
+ print(
132
+ f"Could not find backend {pod_ip}:{args.pod_port} for service {args.services} "
133
+ f"on Envoy at {envoy_host}"
134
+ )
135
+ sys.exit(1)
136
+
137
+
138
+ if __name__ == "__main__":
139
+ main()
@@ -0,0 +1,50 @@
1
+ #!python
2
+ # Copyright 2015-2018 Yelp Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ import os
16
+ import sys
17
+
18
+ from paasta_tools.smartstack_tools import are_services_up_on_ip_port
19
+ from paasta_tools.utils import load_system_paasta_config
20
+
21
+ system_paasta_config = load_system_paasta_config()
22
+ synapse_port = system_paasta_config.get_synapse_port()
23
+ synapse_host = "169.254.255.254"
24
+ synapse_haproxy_url_format = system_paasta_config.get_synapse_haproxy_url_format()
25
+ host_ip = os.environ["PAASTA_POD_IP"]
26
+ port = sys.argv[1]
27
+ services = sys.argv[2:]
28
+
29
+ ###############################################################
30
+ #
31
+ # This file is used in the hacheck sidecar, make sure to update `check_smartstack_up.sh`
32
+ # when changing this file
33
+ #
34
+ ###############################################################
35
+
36
+ if are_services_up_on_ip_port(
37
+ synapse_host=synapse_host,
38
+ synapse_port=synapse_port,
39
+ synapse_haproxy_url_format=synapse_haproxy_url_format,
40
+ services=services,
41
+ host_ip=host_ip,
42
+ host_port=int(port),
43
+ ):
44
+ sys.exit(0)
45
+ else:
46
+ print(
47
+ f"Could not find backend {host_ip}:{port} for service {services} "
48
+ f"on Synapse at {synapse_host}:{synapse_port}"
49
+ )
50
+ sys.exit(1)
@@ -0,0 +1,109 @@
1
+ #!python
2
+ import sys
3
+
4
+ try:
5
+ import iptc
6
+ except TypeError:
7
+ print(
8
+ "Failed to import iptc. This happens sometimes during a python upgrade or during bootstrapping"
9
+ )
10
+ sys.exit(0)
11
+
12
+ from paasta_tools import iptables
13
+ from paasta_tools.utils import get_docker_client
14
+
15
+
16
+ def get_container_from_dport(dport, docker_client):
17
+ for container in docker_client.containers():
18
+ try:
19
+ ports = container["Ports"]
20
+ for port in ports:
21
+ if "PublicPort" in port:
22
+ if port["PublicPort"] == int(dport):
23
+ return container
24
+ except KeyError:
25
+ print(ports)
26
+ pass
27
+
28
+
29
+ def target_rule_to_dport(rule):
30
+ try:
31
+ # (('tcp', (('dport', ('31493',)),)),)
32
+ return rule.matches[0][1][0][1][0]
33
+ except IndexError:
34
+ return None
35
+
36
+
37
+ def kill_containers_with_duplicate_iptables_rules(docker_client):
38
+ chain_name = "DOCKER"
39
+ table = iptc.Table(iptc.Table.NAT)
40
+ chain = iptc.Chain(table, chain_name)
41
+
42
+ targets_seen = {}
43
+ raw_rules_seen = {}
44
+
45
+ for iptables_rule in chain.rules:
46
+ rule = iptables.Rule.from_iptc(iptables_rule)
47
+ target = rule.target_parameters
48
+ if target not in targets_seen:
49
+ targets_seen[target] = rule
50
+ raw_rules_seen[target] = iptables_rule
51
+ else:
52
+ dport = target_rule_to_dport(rule)
53
+ if dport is None:
54
+ continue
55
+ print(
56
+ "This is the second time we've seen a rule with the same target_parameters!"
57
+ )
58
+ print(rule)
59
+ container1 = get_container_from_dport(dport, docker_client)
60
+ print("The other rule with that target is:")
61
+ print(targets_seen[target])
62
+ dport2 = target_rule_to_dport(targets_seen[target])
63
+ container2 = get_container_from_dport(dport2, docker_client)
64
+ if container1 is None:
65
+ print(
66
+ "We have a duplicate iptables rule going to a container1, but no container1!"
67
+ )
68
+ print(rule)
69
+ print("Deleting this rule")
70
+ chain.delete_rule(iptables_rule)
71
+ elif container2 is None:
72
+ print(
73
+ "We have a iptables rule going to a container2, but no container2!"
74
+ )
75
+ print(targets_seen[target])
76
+ print("Deleting this rule")
77
+ chain.delete_rule(raw_rules_seen[target])
78
+ elif container1["Id"] == container2["Id"]:
79
+ print("The same container is getting traffic for both ports!")
80
+ print(container1)
81
+ print("Killing the container")
82
+ docker_client.kill(container1["Id"])
83
+ print("Deleting both iptables rules")
84
+ chain.delete_rule(iptables_rule)
85
+ chain.delete_rule(raw_rules_seen[target])
86
+ elif container1["Id"] != container2["Id"]:
87
+ print(
88
+ "These are two different containers, which means we have duplicate ips:"
89
+ )
90
+ print(container1)
91
+ print(container2)
92
+ print("Not sure which to kill, killing both")
93
+ docker_client.kill(container1["Id"])
94
+ docker_client.kill(container2["Id"])
95
+ print("Deleting the both iptables rules for good measure")
96
+ chain.delete_rule(iptables_rule)
97
+ chain.delete_rule(raw_rules_seen[target])
98
+ else:
99
+ print("Something unexpected went wrong. Exiting 1")
100
+ sys.exit(1)
101
+
102
+
103
+ def main():
104
+ docker_client = get_docker_client()
105
+ kill_containers_with_duplicate_iptables_rules(docker_client)
106
+
107
+
108
+ if __name__ == "__main__":
109
+ sys.exit(main())