paasta-tools 1.27.0__py3-none-any.whl → 1.35.8__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.

Potentially problematic release.


This version of paasta-tools might be problematic. Click here for more details.

Files changed (192) hide show
  1. paasta_tools/__init__.py +1 -1
  2. paasta_tools/api/api_docs/swagger.json +9 -1
  3. paasta_tools/api/tweens/auth.py +2 -1
  4. paasta_tools/api/views/instance.py +9 -2
  5. paasta_tools/api/views/remote_run.py +2 -0
  6. paasta_tools/async_utils.py +4 -1
  7. paasta_tools/bounce_lib.py +8 -5
  8. paasta_tools/check_services_replication_tools.py +10 -4
  9. paasta_tools/check_spark_jobs.py +1 -1
  10. paasta_tools/cli/cli.py +4 -4
  11. paasta_tools/cli/cmds/autoscale.py +2 -0
  12. paasta_tools/cli/cmds/check.py +2 -0
  13. paasta_tools/cli/cmds/cook_image.py +2 -0
  14. paasta_tools/cli/cmds/get_docker_image.py +2 -0
  15. paasta_tools/cli/cmds/get_image_version.py +2 -0
  16. paasta_tools/cli/cmds/get_latest_deployment.py +2 -0
  17. paasta_tools/cli/cmds/info.py +10 -3
  18. paasta_tools/cli/cmds/itest.py +2 -0
  19. paasta_tools/cli/cmds/list_namespaces.py +2 -0
  20. paasta_tools/cli/cmds/local_run.py +122 -27
  21. paasta_tools/cli/cmds/logs.py +31 -7
  22. paasta_tools/cli/cmds/mark_for_deployment.py +14 -4
  23. paasta_tools/cli/cmds/mesh_status.py +3 -2
  24. paasta_tools/cli/cmds/push_to_registry.py +2 -0
  25. paasta_tools/cli/cmds/remote_run.py +156 -12
  26. paasta_tools/cli/cmds/rollback.py +6 -2
  27. paasta_tools/cli/cmds/secret.py +4 -2
  28. paasta_tools/cli/cmds/security_check.py +2 -0
  29. paasta_tools/cli/cmds/spark_run.py +7 -3
  30. paasta_tools/cli/cmds/status.py +59 -29
  31. paasta_tools/cli/cmds/validate.py +325 -40
  32. paasta_tools/cli/cmds/wait_for_deployment.py +2 -0
  33. paasta_tools/cli/schemas/adhoc_schema.json +3 -0
  34. paasta_tools/cli/schemas/autoscaling_schema.json +3 -2
  35. paasta_tools/cli/schemas/eks_schema.json +24 -1
  36. paasta_tools/cli/schemas/kubernetes_schema.json +1 -0
  37. paasta_tools/cli/schemas/smartstack_schema.json +14 -0
  38. paasta_tools/cli/utils.py +34 -20
  39. paasta_tools/contrib/bounce_log_latency_parser.py +1 -1
  40. paasta_tools/contrib/check_orphans.py +1 -1
  41. paasta_tools/contrib/get_running_task_allocation.py +1 -1
  42. paasta_tools/contrib/ide_helper.py +14 -14
  43. paasta_tools/contrib/mock_patch_checker.py +1 -1
  44. paasta_tools/contrib/paasta_update_soa_memcpu.py +10 -14
  45. paasta_tools/contrib/render_template.py +1 -1
  46. paasta_tools/contrib/shared_ip_check.py +1 -1
  47. paasta_tools/generate_deployments_for_service.py +2 -0
  48. paasta_tools/instance/hpa_metrics_parser.py +3 -5
  49. paasta_tools/instance/kubernetes.py +70 -36
  50. paasta_tools/kubernetes/application/controller_wrappers.py +23 -2
  51. paasta_tools/kubernetes/remote_run.py +52 -25
  52. paasta_tools/kubernetes_tools.py +60 -69
  53. paasta_tools/long_running_service_tools.py +15 -5
  54. paasta_tools/mesos/master.py +1 -1
  55. paasta_tools/metrics/metastatus_lib.py +1 -25
  56. paasta_tools/metrics/metrics_lib.py +12 -3
  57. paasta_tools/paastaapi/__init__.py +1 -1
  58. paasta_tools/paastaapi/api/autoscaler_api.py +1 -1
  59. paasta_tools/paastaapi/api/default_api.py +1 -1
  60. paasta_tools/paastaapi/api/remote_run_api.py +1 -1
  61. paasta_tools/paastaapi/api/resources_api.py +1 -1
  62. paasta_tools/paastaapi/api/service_api.py +1 -1
  63. paasta_tools/paastaapi/api_client.py +1 -1
  64. paasta_tools/paastaapi/configuration.py +2 -2
  65. paasta_tools/paastaapi/exceptions.py +1 -1
  66. paasta_tools/paastaapi/model/adhoc_launch_history.py +1 -1
  67. paasta_tools/paastaapi/model/autoscaler_count_msg.py +1 -1
  68. paasta_tools/paastaapi/model/autoscaling_override.py +1 -1
  69. paasta_tools/paastaapi/model/deploy_queue.py +1 -1
  70. paasta_tools/paastaapi/model/deploy_queue_service_instance.py +1 -1
  71. paasta_tools/paastaapi/model/envoy_backend.py +1 -1
  72. paasta_tools/paastaapi/model/envoy_location.py +1 -1
  73. paasta_tools/paastaapi/model/envoy_status.py +1 -1
  74. paasta_tools/paastaapi/model/flink_cluster_overview.py +1 -1
  75. paasta_tools/paastaapi/model/flink_config.py +1 -1
  76. paasta_tools/paastaapi/model/flink_job.py +1 -1
  77. paasta_tools/paastaapi/model/flink_job_details.py +1 -1
  78. paasta_tools/paastaapi/model/flink_jobs.py +1 -1
  79. paasta_tools/paastaapi/model/float_and_error.py +1 -1
  80. paasta_tools/paastaapi/model/hpa_metric.py +1 -1
  81. paasta_tools/paastaapi/model/inline_object.py +1 -1
  82. paasta_tools/paastaapi/model/inline_response200.py +1 -1
  83. paasta_tools/paastaapi/model/inline_response2001.py +1 -1
  84. paasta_tools/paastaapi/model/inline_response202.py +1 -1
  85. paasta_tools/paastaapi/model/inline_response403.py +1 -1
  86. paasta_tools/paastaapi/model/instance_bounce_status.py +1 -1
  87. paasta_tools/paastaapi/model/instance_mesh_status.py +1 -1
  88. paasta_tools/paastaapi/model/instance_status.py +1 -1
  89. paasta_tools/paastaapi/model/instance_status_adhoc.py +1 -1
  90. paasta_tools/paastaapi/model/instance_status_cassandracluster.py +1 -1
  91. paasta_tools/paastaapi/model/instance_status_flink.py +1 -1
  92. paasta_tools/paastaapi/model/instance_status_kafkacluster.py +1 -1
  93. paasta_tools/paastaapi/model/instance_status_kubernetes.py +1 -1
  94. paasta_tools/paastaapi/model/instance_status_kubernetes_autoscaling_status.py +1 -1
  95. paasta_tools/paastaapi/model/instance_status_kubernetes_v2.py +1 -1
  96. paasta_tools/paastaapi/model/instance_status_tron.py +1 -1
  97. paasta_tools/paastaapi/model/instance_tasks.py +1 -1
  98. paasta_tools/paastaapi/model/integer_and_error.py +1 -1
  99. paasta_tools/paastaapi/model/kubernetes_container.py +1 -1
  100. paasta_tools/paastaapi/model/kubernetes_container_v2.py +1 -1
  101. paasta_tools/paastaapi/model/kubernetes_healthcheck.py +1 -1
  102. paasta_tools/paastaapi/model/kubernetes_pod.py +1 -1
  103. paasta_tools/paastaapi/model/kubernetes_pod_event.py +1 -1
  104. paasta_tools/paastaapi/model/kubernetes_pod_v2.py +1 -1
  105. paasta_tools/paastaapi/model/kubernetes_replica_set.py +1 -1
  106. paasta_tools/paastaapi/model/kubernetes_version.py +4 -1
  107. paasta_tools/paastaapi/model/remote_run_outcome.py +1 -1
  108. paasta_tools/paastaapi/model/remote_run_start.py +4 -1
  109. paasta_tools/paastaapi/model/remote_run_stop.py +1 -1
  110. paasta_tools/paastaapi/model/remote_run_token.py +1 -1
  111. paasta_tools/paastaapi/model/resource.py +1 -1
  112. paasta_tools/paastaapi/model/resource_item.py +1 -1
  113. paasta_tools/paastaapi/model/resource_value.py +1 -1
  114. paasta_tools/paastaapi/model/smartstack_backend.py +1 -1
  115. paasta_tools/paastaapi/model/smartstack_location.py +1 -1
  116. paasta_tools/paastaapi/model/smartstack_status.py +1 -1
  117. paasta_tools/paastaapi/model/task_tail_lines.py +1 -1
  118. paasta_tools/paastaapi/model_utils.py +1 -1
  119. paasta_tools/paastaapi/rest.py +1 -1
  120. paasta_tools/remote_git.py +2 -2
  121. paasta_tools/run-paasta-api-in-dev-mode.py +2 -2
  122. paasta_tools/run-paasta-api-playground.py +2 -2
  123. paasta_tools/setup_kubernetes_job.py +43 -1
  124. paasta_tools/setup_prometheus_adapter_config.py +82 -0
  125. paasta_tools/setup_tron_namespace.py +2 -2
  126. paasta_tools/tron_tools.py +4 -1
  127. paasta_tools/utils.py +29 -11
  128. paasta_tools/yaml_tools.py +1 -1
  129. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_orphans.py +1 -1
  130. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_spark_jobs.py +1 -1
  131. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/generate_deployments_for_service.py +2 -0
  132. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/get_running_task_allocation.py +1 -1
  133. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/ide_helper.py +14 -14
  134. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/paasta_update_soa_memcpu.py +10 -14
  135. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/setup_kubernetes_job.py +43 -1
  136. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/setup_prometheus_adapter_config.py +82 -0
  137. paasta_tools-1.35.8.dist-info/METADATA +79 -0
  138. {paasta_tools-1.27.0.dist-info → paasta_tools-1.35.8.dist-info}/RECORD +186 -191
  139. {paasta_tools-1.27.0.dist-info → paasta_tools-1.35.8.dist-info}/WHEEL +1 -1
  140. paasta_tools/frameworks/adhoc_scheduler.py +0 -71
  141. paasta_tools/frameworks/native_scheduler.py +0 -652
  142. paasta_tools/frameworks/task_store.py +0 -245
  143. paasta_tools/mesos_maintenance.py +0 -848
  144. paasta_tools/paasta_native_serviceinit.py +0 -21
  145. paasta_tools-1.27.0.dist-info/METADATA +0 -75
  146. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/apply_external_resources.py +0 -0
  147. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/bounce_log_latency_parser.py +0 -0
  148. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_autoscaler_max_instances.py +0 -0
  149. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_cassandracluster_services_replication.py +0 -0
  150. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_flink_services_health.py +0 -0
  151. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_kubernetes_api.py +0 -0
  152. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_kubernetes_services_replication.py +0 -0
  153. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_manual_oapi_changes.sh +0 -0
  154. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/check_oom_events.py +0 -0
  155. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/cleanup_kubernetes_cr.py +0 -0
  156. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/cleanup_kubernetes_crd.py +0 -0
  157. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/cleanup_kubernetes_jobs.py +0 -0
  158. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/create_dynamodb_table.py +0 -0
  159. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/create_paasta_playground.py +0 -0
  160. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/delete_kubernetes_deployments.py +0 -0
  161. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/emit_allocated_cpu_metrics.py +0 -0
  162. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/generate_all_deployments +0 -0
  163. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/generate_authenticating_services.py +0 -0
  164. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/generate_services_file.py +0 -0
  165. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/generate_services_yaml.py +0 -0
  166. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/habitat_fixer.py +0 -0
  167. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/is_pod_healthy_in_proxy.py +0 -0
  168. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/is_pod_healthy_in_smartstack.py +0 -0
  169. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/kill_bad_containers.py +0 -0
  170. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/kubernetes_remove_evicted_pods.py +0 -0
  171. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/mass-deploy-tag.sh +0 -0
  172. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/mock_patch_checker.py +0 -0
  173. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/paasta_cleanup_remote_run_resources.py +0 -0
  174. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/paasta_cleanup_stale_nodes.py +0 -0
  175. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/paasta_deploy_tron_jobs +0 -0
  176. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/paasta_execute_docker_command.py +0 -0
  177. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/paasta_secrets_sync.py +0 -0
  178. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/paasta_tabcomplete.sh +0 -0
  179. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/render_template.py +0 -0
  180. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/rightsizer_soaconfigs_update.py +0 -0
  181. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/service_shard_remove.py +0 -0
  182. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/service_shard_update.py +0 -0
  183. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/setup_istio_mesh.py +0 -0
  184. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/setup_kubernetes_cr.py +0 -0
  185. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/setup_kubernetes_crd.py +0 -0
  186. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/setup_kubernetes_internal_crd.py +0 -0
  187. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/shared_ip_check.py +0 -0
  188. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/synapse_srv_namespaces_fact.py +0 -0
  189. {paasta_tools-1.27.0.data → paasta_tools-1.35.8.data}/scripts/timeouts_metrics_prom.py +0 -0
  190. {paasta_tools-1.27.0.dist-info → paasta_tools-1.35.8.dist-info}/entry_points.txt +0 -0
  191. {paasta_tools-1.27.0.dist-info → paasta_tools-1.35.8.dist-info/licenses}/LICENSE +0 -0
  192. {paasta_tools-1.27.0.dist-info → paasta_tools-1.35.8.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,7 @@
5
5
 
6
6
  No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501
7
7
 
8
- The version of the OpenAPI document: 1.2.0
8
+ The version of the OpenAPI document: 1.3.0
9
9
  Generated by: https://openapi-generator.tech
10
10
  """
11
11
 
@@ -5,7 +5,7 @@
5
5
 
6
6
  No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501
7
7
 
8
- The version of the OpenAPI document: 1.2.0
8
+ The version of the OpenAPI document: 1.3.0
9
9
  Generated by: https://openapi-generator.tech
10
10
  """
11
11
 
@@ -5,7 +5,7 @@
5
5
 
6
6
  No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501
7
7
 
8
- The version of the OpenAPI document: 1.2.0
8
+ The version of the OpenAPI document: 1.3.0
9
9
  Generated by: https://openapi-generator.tech
10
10
  """
11
11
 
@@ -5,7 +5,7 @@
5
5
 
6
6
  No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501
7
7
 
8
- The version of the OpenAPI document: 1.2.0
8
+ The version of the OpenAPI document: 1.3.0
9
9
  Generated by: https://openapi-generator.tech
10
10
  """
11
11
 
@@ -5,7 +5,7 @@
5
5
 
6
6
  No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501
7
7
 
8
- The version of the OpenAPI document: 1.2.0
8
+ The version of the OpenAPI document: 1.3.0
9
9
  Generated by: https://openapi-generator.tech
10
10
  """
11
11
 
@@ -72,8 +72,8 @@ def create_remote_refs(git_url, ref_mutator, force=False):
72
72
  determine_wants = ref_mutator
73
73
  # We know we don't need to push any objects.
74
74
 
75
- def generate_pack_contents(have, want):
76
- return []
75
+ def generate_pack_contents(have, want, ofs_delta=None):
76
+ return 0, []
77
77
 
78
78
  return client.send_pack(path, determine_wants, generate_pack_contents)
79
79
 
@@ -45,8 +45,8 @@ def main():
45
45
  api.main("dev-mode")
46
46
  else:
47
47
  os.execl(
48
- ".tox/py38-linux/bin/python",
49
- ".tox/py38-linux/bin/python",
48
+ ".tox/py310-linux/bin/python",
49
+ ".tox/py310-linux/bin/python",
50
50
  "-m",
51
51
  "paasta_tools.api.api",
52
52
  *["-D", "-c", cluster, str(port)],
@@ -39,8 +39,8 @@ def main():
39
39
  api.main("dev-mode")
40
40
  else:
41
41
  os.execl(
42
- ".tox/py38-linux/bin/python",
43
- ".tox/py38-linux/bin/python",
42
+ ".tox/py310-linux/bin/python",
43
+ ".tox/py310-linux/bin/python",
44
44
  "-m",
45
45
  "paasta_tools.api.api",
46
46
  *["-D", "-c", cluster, str(port)],
@@ -52,6 +52,7 @@ from paasta_tools.kubernetes_tools import load_kubernetes_service_config_no_cach
52
52
  from paasta_tools.metrics import metrics_lib
53
53
  from paasta_tools.utils import decompose_job_id
54
54
  from paasta_tools.utils import DEFAULT_SOA_DIR
55
+ from paasta_tools.utils import DeploymentVersion
55
56
  from paasta_tools.utils import InvalidJobNameError
56
57
  from paasta_tools.utils import load_system_paasta_config
57
58
  from paasta_tools.utils import NoConfigurationForServiceError
@@ -241,7 +242,7 @@ def get_kubernetes_deployment_config(
241
242
  service_instance_configs_list.append((True, None))
242
243
  except NoConfigurationForServiceError:
243
244
  error_msg = (
244
- f"Could not read kubernetes configuration file for %s.%s in cluster %s"
245
+ "Could not read kubernetes configuration file for %s.%s in cluster %s"
245
246
  % (service_instance[0], service_instance[1], cluster)
246
247
  )
247
248
  log.error(error_msg)
@@ -363,6 +364,14 @@ def setup_kube_deployments(
363
364
  for deployment in existing_kube_deployments
364
365
  }
365
366
 
367
+ existing_deployment_versions: Dict[
368
+ Tuple[str, str, str], List[DeploymentVersion]
369
+ ] = {}
370
+ for deployment in existing_kube_deployments:
371
+ existing_deployment_versions.setdefault(
372
+ (deployment.service, deployment.instance, deployment.namespace), []
373
+ ).append(deployment.deployment_version)
374
+
366
375
  hpa_overrides = hpa_overrides or {}
367
376
 
368
377
  applications = [
@@ -379,6 +388,39 @@ def setup_kube_deployments(
379
388
  else (_, None)
380
389
  for _, service_instance in service_instance_configs_list
381
390
  ]
391
+
392
+ def sort_key(ok_app: Tuple[bool, Optional[Application]]) -> int:
393
+ """This will return 1 if the desired deployment_version matches an existing deployment_version, 2 if the deployment is unhealthy and 0
394
+ otherwise. This will cause applications that need a new deployment_version to be handled first.
395
+ This prioritizes "real" bounces (developers pushing new service versions) over things that are likely to be big
396
+ bounces (config-only changes).
397
+ Most of the time, this won't matter much, as we should get through our backlog quickly, but when there is a
398
+ backlog, we want to avoid blocking developers.
399
+ """
400
+ _, app = ok_app
401
+ if app:
402
+ if (
403
+ app.kube_deployment.deployment_version
404
+ in existing_deployment_versions.get(
405
+ (
406
+ app.kube_deployment.service,
407
+ app.kube_deployment.instance,
408
+ app.kube_deployment.namespace,
409
+ ),
410
+ [],
411
+ )
412
+ ):
413
+ # Desired version exists, so this is just a configuration update; handle this second.
414
+ return 1
415
+ else:
416
+ # Desired version doesn't exist, handle this first.
417
+ return 0
418
+ else:
419
+ # Handle broken app last.
420
+ return 2
421
+
422
+ applications.sort(key=sort_key)
423
+
382
424
  api_updates = 0
383
425
  for _, app in applications:
384
426
  if app:
@@ -53,6 +53,9 @@ from paasta_tools.long_running_service_tools import (
53
53
  from paasta_tools.long_running_service_tools import (
54
54
  DEFAULT_UWSGI_AUTOSCALING_MOVING_AVERAGE_WINDOW,
55
55
  )
56
+ from paasta_tools.long_running_service_tools import (
57
+ DEFAULT_WORKER_LOAD_AUTOSCALING_MOVING_AVERAGE_WINDOW,
58
+ )
56
59
  from paasta_tools.long_running_service_tools import METRICS_PROVIDER_ACTIVE_REQUESTS
57
60
  from paasta_tools.long_running_service_tools import METRICS_PROVIDER_CPU
58
61
  from paasta_tools.long_running_service_tools import METRICS_PROVIDER_GUNICORN
@@ -60,6 +63,7 @@ from paasta_tools.long_running_service_tools import METRICS_PROVIDER_PISCINA
60
63
  from paasta_tools.long_running_service_tools import METRICS_PROVIDER_PROMQL
61
64
  from paasta_tools.long_running_service_tools import METRICS_PROVIDER_UWSGI
62
65
  from paasta_tools.long_running_service_tools import METRICS_PROVIDER_UWSGI_V2
66
+ from paasta_tools.long_running_service_tools import METRICS_PROVIDER_WORKER_LOAD
63
67
  from paasta_tools.paasta_service_config_loader import PaastaServiceConfigLoader
64
68
  from paasta_tools.utils import DEFAULT_SOA_DIR
65
69
  from paasta_tools.utils import get_services_for_cluster
@@ -214,6 +218,10 @@ def create_instance_scaling_rule(
214
218
  return create_instance_uwsgi_v2_scaling_rule(
215
219
  service, instance_config, metrics_provider_config, paasta_cluster
216
220
  )
221
+ if metrics_provider_config["type"] == METRICS_PROVIDER_WORKER_LOAD:
222
+ return create_instance_worker_load_scaling_rule(
223
+ service, instance_config, metrics_provider_config, paasta_cluster
224
+ )
217
225
  if metrics_provider_config["type"] == METRICS_PROVIDER_PISCINA:
218
226
  return create_instance_piscina_scaling_rule(
219
227
  service, instance_config, metrics_provider_config, paasta_cluster
@@ -523,6 +531,80 @@ def create_instance_uwsgi_v2_scaling_rule(
523
531
  }
524
532
 
525
533
 
534
+ def create_instance_worker_load_scaling_rule(
535
+ service: str,
536
+ instance_config: KubernetesDeploymentConfig,
537
+ metrics_provider_config: MetricsProviderDict,
538
+ paasta_cluster: str,
539
+ ) -> PrometheusAdapterRule:
540
+ """
541
+ Creates a Prometheus adapter rule config for a given service instance using generic worker_busy metric.
542
+ """
543
+ instance = instance_config.instance
544
+ moving_average_window = metrics_provider_config.get(
545
+ "moving_average_window_seconds",
546
+ DEFAULT_WORKER_LOAD_AUTOSCALING_MOVING_AVERAGE_WINDOW,
547
+ )
548
+ deployment_name = get_kubernetes_app_name(service=service, instance=instance)
549
+
550
+ # In order for autoscaling to work safely while a service migrates from one namespace to another, the HPA needs to
551
+ # make sure that the deployment in the new namespace is scaled up enough to handle _all_ the load.
552
+ # This is because once the new deployment is 100% healthy, cleanup_kubernetes_job will delete the deployment out of
553
+ # the old namespace all at once, suddenly putting all the load onto the deployment in the new namespace.
554
+ # To ensure this, we must NOT filter on namespace in worker_filter_terms (which is used when calculating total_load.
555
+ # This makes sure that desired_instances includes load from all namespaces.
556
+ worker_filter_terms = f"paasta_cluster='{paasta_cluster}',paasta_service='{service}',paasta_instance='{instance}'"
557
+
558
+ # k8s:deployment:pods_status_ready is a metric created by summing kube_pod_status_ready
559
+ # over paasta service/instance/cluster. it counts the number of ready pods in a paasta
560
+ # deployment.
561
+ ready_pods = f"""
562
+ (sum(
563
+ k8s:deployment:pods_status_ready{{{worker_filter_terms}}} >= 0
564
+ or
565
+ max_over_time(
566
+ k8s:deployment:pods_status_ready{{{worker_filter_terms}}}[{DEFAULT_EXTRAPOLATION_TIME}s]
567
+ )
568
+ ) by (kube_deployment))
569
+ """
570
+ load_per_instance = f"""
571
+ avg(
572
+ worker_busy{{{worker_filter_terms}}}
573
+ ) by (kube_pod, kube_deployment)
574
+ """
575
+ missing_instances = f"""
576
+ clamp_min(
577
+ {ready_pods} - count({load_per_instance}) by (kube_deployment),
578
+ 0
579
+ )
580
+ """
581
+ total_load = f"""
582
+ (
583
+ sum(
584
+ {load_per_instance}
585
+ ) by (kube_deployment)
586
+ +
587
+ {missing_instances}
588
+ )
589
+ """
590
+ total_load_smoothed = f"""
591
+ avg_over_time(
592
+ (
593
+ {total_load}
594
+ )[{moving_average_window}s:]
595
+ )
596
+ """
597
+
598
+ metric_name = f"{deployment_name}-worker-load-prom"
599
+
600
+ return {
601
+ "name": {"as": metric_name},
602
+ "seriesQuery": f"worker_busy{{{worker_filter_terms}}}",
603
+ "resources": {"template": "kube_<<.Resource>>"},
604
+ "metricsQuery": _minify_promql(total_load_smoothed),
605
+ }
606
+
607
+
526
608
  def create_instance_piscina_scaling_rule(
527
609
  service: str,
528
610
  instance_config: KubernetesDeploymentConfig,
@@ -114,7 +114,7 @@ def ensure_service_accounts(job_configs: List[TronJobConfig]) -> None:
114
114
  )
115
115
 
116
116
 
117
- def main():
117
+ def main() -> None:
118
118
  args = parse_args()
119
119
  log_level = logging.DEBUG if args.verbose else logging.INFO
120
120
  logging.basicConfig(level=log_level)
@@ -232,7 +232,7 @@ def main():
232
232
  log.debug(f"Updated {updated}")
233
233
 
234
234
  if updated_namespaces != new_configs.keys():
235
- skipped = set(new_configs.keys()) - set(updated_namespaces.keys())
235
+ skipped = list(set(new_configs.keys()) - set(updated_namespaces.keys()))
236
236
  log.debug(f"Skipped {skipped}")
237
237
 
238
238
  skipped_report = skipped if args.verbose else len(skipped)
@@ -506,6 +506,9 @@ class TronActionConfig(InstanceConfig):
506
506
  # XXX: update PAASTA_RESOURCE_* env vars to use the correct value from spark_args and set
507
507
  # these to the correct values for the executors as part of the driver commandline
508
508
 
509
+ # our internal Spark configuration service needs this to determine if any special behavior is required
510
+ env["SPARK_DRIVER_TYPE"] = "tron"
511
+
509
512
  return env
510
513
 
511
514
  def get_iam_role(self) -> str:
@@ -1289,7 +1292,7 @@ def load_tron_service_config_no_cache(
1289
1292
  def create_complete_master_config(cluster, soa_dir=DEFAULT_SOA_DIR):
1290
1293
  system_paasta_config = load_system_paasta_config()
1291
1294
  tronfig_folder = get_tronfig_folder(soa_dir=soa_dir, cluster=cluster)
1292
- config = read_yaml_file(os.path.join(tronfig_folder, f"MASTER.yaml"))
1295
+ config = read_yaml_file(os.path.join(tronfig_folder, "MASTER.yaml"))
1293
1296
  master_config = format_master_config(
1294
1297
  config,
1295
1298
  system_paasta_config.get_volumes(),
paasta_tools/utils.py CHANGED
@@ -53,6 +53,7 @@ from typing import Collection
53
53
  from typing import ContextManager
54
54
  from typing import Dict
55
55
  from typing import FrozenSet
56
+ from typing import Generic
56
57
  from typing import IO
57
58
  from typing import Iterable
58
59
  from typing import Iterator
@@ -181,6 +182,7 @@ CAPS_DROP = [
181
182
  "SYS_CHROOT",
182
183
  "SETFCAP",
183
184
  ]
185
+ DEFAULT_READONLY_DOCKER_REGISTRY_AUTH_FILE = "/nail/etc/docker-registry-ro"
184
186
 
185
187
 
186
188
  class RollbackTypes(Enum):
@@ -1948,6 +1950,7 @@ class TopologySpreadConstraintDict(TypedDict, total=False):
1948
1950
  topology_key: str
1949
1951
  when_unsatisfiable: Literal["ScheduleAnyway", "DoNotSchedule"]
1950
1952
  max_skew: int
1953
+ match_label_keys: List[str]
1951
1954
 
1952
1955
 
1953
1956
  class SystemPaastaConfigDict(TypedDict, total=False):
@@ -2035,7 +2038,6 @@ class SystemPaastaConfigDict(TypedDict, total=False):
2035
2038
  synapse_port: int
2036
2039
  taskproc: Dict
2037
2040
  tron: Dict
2038
- gunicorn_exporter_sidecar_image_url: str
2039
2041
  vault_cluster_map: Dict
2040
2042
  vault_environment: str
2041
2043
  volumes: List[DockerVolume]
@@ -2066,6 +2068,9 @@ class SystemPaastaConfigDict(TypedDict, total=False):
2066
2068
  enable_tron_tsc: bool
2067
2069
  default_spark_iam_user: str
2068
2070
  default_spark_driver_pool_override: str
2071
+ readonly_docker_registry_auth_file: str
2072
+ private_docker_registries: List[str]
2073
+ unhealthy_pod_eviction_policy: str
2069
2074
 
2070
2075
 
2071
2076
  def load_system_paasta_config(
@@ -2166,7 +2171,7 @@ class SystemPaastaConfig:
2166
2171
 
2167
2172
  def get_default_spark_iam_user(self) -> str:
2168
2173
  return self.config_dict.get(
2169
- "default_spark_iam_user", "/etc/boto_cfg/mrjob.yaml"
2174
+ "default_spark_iam_user", "/etc/boto_cfg/spark_driver.yaml"
2170
2175
  )
2171
2176
 
2172
2177
  def get_default_spark_driver_pool_override(self) -> str:
@@ -2668,13 +2673,6 @@ class SystemPaastaConfig:
2668
2673
  def default_should_use_uwsgi_exporter(self) -> bool:
2669
2674
  return self.config_dict.get("default_should_use_uwsgi_exporter", False)
2670
2675
 
2671
- def get_gunicorn_exporter_sidecar_image_url(self) -> str:
2672
- """Get the docker image URL for the gunicorn_exporter sidecar container"""
2673
- return self.config_dict.get(
2674
- "gunicorn_exporter_sidecar_image_url",
2675
- "docker-paasta.yelpcorp.com:443/gunicorn_exporter-k8s-sidecar:v0.24.0-yelp0",
2676
- )
2677
-
2678
2676
  def get_mark_for_deployment_max_polling_threads(self) -> int:
2679
2677
  return self.config_dict.get("mark_for_deployment_max_polling_threads", 4)
2680
2678
 
@@ -2847,6 +2845,26 @@ class SystemPaastaConfig:
2847
2845
  # NOTE: this should never happen unless we've gotten bad data
2848
2846
  return None
2849
2847
 
2848
+ def get_readonly_docker_registry_auth_file(self) -> str:
2849
+ """Get the location of the readonly docker registry auth file as an absolute path."""
2850
+ return self.config_dict.get(
2851
+ "readonly_docker_registry_auth_file",
2852
+ DEFAULT_READONLY_DOCKER_REGISTRY_AUTH_FILE,
2853
+ )
2854
+
2855
+ def get_private_docker_registries(self) -> Set[str]:
2856
+ """Get all the internal Docker registries without generally-available RO creds."""
2857
+ return set(self.config_dict.get("private_docker_registries", []))
2858
+
2859
+ def get_unhealthy_pod_eviction_policy(self) -> str:
2860
+ """
2861
+ Get the unhealthy pod eviction policy for the cluster. Posible values:
2862
+ * IfHealthyBudget: unhealthy pods will only be evicted wrt to PodDisruptionBudget
2863
+ * AlwaysAllow: evict unhealthy pods regardless of the PodDisruptionBudget status.
2864
+ Defaults to IfHealthyBudget
2865
+ """
2866
+ return self.config_dict.get("unhealthy_pod_eviction_policy", "IfHealthyBudget")
2867
+
2850
2868
 
2851
2869
  def _run(
2852
2870
  command: Union[str, List[str]],
@@ -3460,7 +3478,7 @@ def get_docker_host() -> str:
3460
3478
 
3461
3479
 
3462
3480
  def get_docker_client() -> APIClient:
3463
- client_opts = kwargs_from_env(assert_hostname=False)
3481
+ client_opts = kwargs_from_env()
3464
3482
  if "base_url" in client_opts:
3465
3483
  return APIClient(**client_opts)
3466
3484
  else:
@@ -4139,7 +4157,7 @@ def timeout(
4139
4157
  return decorate
4140
4158
 
4141
4159
 
4142
- class _Timeout:
4160
+ class _Timeout(Generic[_TimeoutFuncRetType]):
4143
4161
  def __init__(
4144
4162
  self,
4145
4163
  function: Callable[..., _TimeoutFuncRetType],
@@ -2,7 +2,7 @@ import sys
2
2
 
3
3
  import yaml
4
4
 
5
- # try and catch both /opt/venvs/paasta-tools and ~/pg/paasta/.tox/py38-linux as if we're being run as an application,
5
+ # try and catch both /opt/venvs/paasta-tools and ~/pg/paasta/.tox/py310-linux as if we're being run as an application,
6
6
  # we likely want to fail on a potential slowdown rather than experience a performance regression
7
7
  if "paasta" in sys.prefix:
8
8
  from yaml import CSafeLoader as Loader
@@ -56,7 +56,7 @@ def get_zk_data(ignored_services: Set[str]) -> SmartstackData:
56
56
  zk = KazooClient(hosts=zk_hosts)
57
57
  zk.start()
58
58
 
59
- logger.debug(f"pulling smartstack data from zookeeper")
59
+ logger.debug("pulling smartstack data from zookeeper")
60
60
  zk_data = {}
61
61
  services = zk.get_children(PREFIX)
62
62
  for service in services:
@@ -124,7 +124,7 @@ def format_framework(info):
124
124
  def format_message_for_service(service, frameworks):
125
125
  output = f"Found the following long-running Spark frameworks associated with service {service}.\n"
126
126
  output += (
127
- f"Please check why they are still running and terminate if appropriate.\n\n"
127
+ "Please check why they are still running and terminate if appropriate.\n\n"
128
128
  )
129
129
  output += "\n".join(format_framework(f) for f in frameworks)
130
130
  return output
@@ -101,6 +101,8 @@ def parse_args() -> argparse.Namespace:
101
101
  "--service",
102
102
  required=True,
103
103
  help="Service name to make the deployments.json for",
104
+ # strip any potential trailing / for folks tab-completing directories
105
+ type=lambda x: x.rstrip("/"),
104
106
  )
105
107
  args = parser.parse_args()
106
108
  return args
@@ -1,5 +1,6 @@
1
1
  #!python
2
2
  import argparse
3
+ import json
3
4
  import time
4
5
  from typing import Any
5
6
  from typing import Dict
@@ -12,7 +13,6 @@ from typing import Optional
12
13
  from typing import Tuple
13
14
 
14
15
  import a_sync
15
- import simplejson as json
16
16
  from kubernetes.client import V1Pod
17
17
  from kubernetes.client import V1ResourceRequirements
18
18
 
@@ -53,12 +53,12 @@ def install_vscode_support() -> None:
53
53
  "python": "${workspaceFolder}/.paasta/bin/python",
54
54
  "program": "${workspaceFolder}/.paasta/bin/tox",
55
55
  "subProcess": True,
56
- "args": ["-e", "py38-linux,docs,mypy,tests"],
56
+ "args": ["-e", "py310-linux,docs,mypy,tests"],
57
57
  },
58
58
  {
59
59
  "name": "paasta cli",
60
60
  "cwd": "${workspaceFolder}",
61
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
61
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
62
62
  "type": "python",
63
63
  "request": "launch",
64
64
  "module": "paasta_tools.cli.cli",
@@ -66,7 +66,7 @@ def install_vscode_support() -> None:
66
66
  {
67
67
  "name": "paasta rollback",
68
68
  "cwd": "${workspaceFolder}",
69
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
69
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
70
70
  "type": "python",
71
71
  "request": "launch",
72
72
  "module": "paasta_tools.cli.cli",
@@ -83,7 +83,7 @@ def install_vscode_support() -> None:
83
83
  {
84
84
  "name": "paasta mark-for-deployment",
85
85
  "cwd": "${workspaceFolder}",
86
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
86
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
87
87
  "type": "python",
88
88
  "request": "launch",
89
89
  "module": "paasta_tools.cli.cli",
@@ -101,7 +101,7 @@ def install_vscode_support() -> None:
101
101
  {
102
102
  "name": "paasta status",
103
103
  "cwd": "${workspaceFolder}",
104
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
104
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
105
105
  "type": "python",
106
106
  "request": "launch",
107
107
  "module": "paasta_tools.cli.cli",
@@ -118,7 +118,7 @@ def install_vscode_support() -> None:
118
118
  {
119
119
  "name": "paasta playground",
120
120
  "cwd": "${workspaceFolder}",
121
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
121
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
122
122
  "type": "python",
123
123
  "request": "launch",
124
124
  "module": "paasta_tools.cli.cli",
@@ -138,7 +138,7 @@ def install_vscode_support() -> None:
138
138
  {
139
139
  "name": "paasta status playground",
140
140
  "cwd": "${workspaceFolder}",
141
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
141
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
142
142
  "type": "python",
143
143
  "request": "launch",
144
144
  "module": "paasta_tools.cli.cli",
@@ -157,7 +157,7 @@ def install_vscode_support() -> None:
157
157
  {
158
158
  "name": "paasta logs",
159
159
  "cwd": "${workspaceFolder}",
160
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
160
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
161
161
  "type": "python",
162
162
  "request": "launch",
163
163
  "module": "paasta_tools.cli.cli",
@@ -175,7 +175,7 @@ def install_vscode_support() -> None:
175
175
  "name": "paasta validate",
176
176
  # This command has to be ran from inside the service repo in yelpsoa-configs
177
177
  "cwd": "${userHome}/pg/yelpsoa-configs/",
178
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
178
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
179
179
  "type": "python",
180
180
  "request": "launch",
181
181
  "module": "paasta_tools.cli.cli",
@@ -184,10 +184,10 @@ def install_vscode_support() -> None:
184
184
  {
185
185
  # 1) Follow step 1 in "Running the PaaSTA HTTP API Locally" wiki
186
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
187
+ # 3) Run client command, e.g. PAASTA_SYSTEM_CONFIG_DIR=./etc_paasta_for_development/ .tox/py310-linux/bin/python paasta_tools/cli/cli.py status --clusters norcal-devc --service katamari_test_service
188
188
  "name": "paasta API",
189
189
  "cwd": "${workspaceFolder}",
190
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
190
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
191
191
  "type": "python",
192
192
  "request": "launch",
193
193
  "module": "paasta_tools.run-paasta-api-in-dev-mode",
@@ -203,7 +203,7 @@ def install_vscode_support() -> None:
203
203
  {
204
204
  "name": "paasta API playground",
205
205
  "cwd": "${workspaceFolder}",
206
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
206
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
207
207
  "type": "python",
208
208
  "request": "launch",
209
209
  "module": "paasta_tools.run-paasta-api-playground",
@@ -221,7 +221,7 @@ def install_vscode_support() -> None:
221
221
  {
222
222
  "name": "Run setup k8s job in playground",
223
223
  "cwd": "${workspaceFolder}",
224
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
224
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
225
225
  "type": "python",
226
226
  "request": "launch",
227
227
  "module": "paasta_tools.setup_kubernetes_job",
@@ -244,7 +244,7 @@ def install_vscode_support() -> None:
244
244
  {
245
245
  "name": "Generate deployments.json in playground",
246
246
  "cwd": "${workspaceFolder}",
247
- "python": "${workspaceFolder}/.tox/py38-linux/bin/python",
247
+ "python": "${workspaceFolder}/.tox/py310-linux/bin/python",
248
248
  "type": "python",
249
249
  "request": "launch",
250
250
  "module": "paasta_tools.generate_deployments_for_service",
@@ -181,6 +181,9 @@ def get_report_from_splunk(creds, app, filename, criteria_filter):
181
181
  "date": d["result"]["_time"].split(" ")[0],
182
182
  "instance": criteria.split(" ")[2],
183
183
  "money": d["result"].get("estimated_monthly_savings", 0),
184
+ "old_cpus": d["result"].get("current_cpus"),
185
+ "old_disk": d["result"].get("current_disk"),
186
+ "old_mem": d["result"].get("current_mem"),
184
187
  "owner": d["result"].get("service_owner", "Unavailable"),
185
188
  "project": d["result"].get("project", "Unavailable"),
186
189
  "service": criteria.split(" ")[0],
@@ -192,24 +195,17 @@ def get_report_from_splunk(creds, app, filename, criteria_filter):
192
195
  "max_instances": d["result"].get("suggested_max_instances"),
193
196
  "mem": d["result"].get("suggested_mem"),
194
197
  "min_instances": d["result"].get("suggested_min_instances"),
195
- "old_cpus": d["result"].get("current_cpus"),
196
- "old_disk": d["result"].get("current_disk"),
197
- "old_mem": d["result"].get("current_mem"),
198
198
  }
199
199
 
200
200
  # the report we get is all strings, so we need to convert them to the right types
201
201
  field_conversions = {
202
- "current_cpus": float,
203
- "suggested_cpu_burst_add": float,
204
- "suggested_cpus": float,
205
- "suggested_disk": int,
206
- "suggested_hacheck_cpus": float,
207
- "suggested_max_instances": int,
208
- "suggested_mem": int,
209
- "suggested_min_instances": int,
210
- # not quite sure why these are floats...they're ints in soaconfigs
211
- "current_disk": _force_str_to_int,
212
- "current_mem": _force_str_to_int,
202
+ "cpus": float,
203
+ "cpu_burst_add": float,
204
+ "disk": int,
205
+ "hacheck_cpus": float,
206
+ "max_instances": int,
207
+ "mem": int,
208
+ "min_instances": int,
213
209
  }
214
210
 
215
211
  # merge results if we've already seen rows for this service