paasta-tools 1.30.7__py3-none-any.whl → 1.30.9__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 (89) hide show
  1. paasta_tools/__init__.py +1 -1
  2. paasta_tools/api/views/instance.py +9 -2
  3. paasta_tools/async_utils.py +4 -1
  4. paasta_tools/bounce_lib.py +8 -5
  5. paasta_tools/check_services_replication_tools.py +10 -4
  6. paasta_tools/check_spark_jobs.py +1 -1
  7. paasta_tools/cli/cli.py +4 -4
  8. paasta_tools/cli/cmds/logs.py +29 -7
  9. paasta_tools/cli/cmds/mark_for_deployment.py +2 -2
  10. paasta_tools/cli/cmds/mesh_status.py +1 -1
  11. paasta_tools/cli/cmds/remote_run.py +1 -1
  12. paasta_tools/cli/cmds/rollback.py +1 -1
  13. paasta_tools/cli/cmds/spark_run.py +3 -3
  14. paasta_tools/cli/cmds/status.py +24 -21
  15. paasta_tools/cli/cmds/validate.py +3 -3
  16. paasta_tools/cli/utils.py +32 -19
  17. paasta_tools/contrib/check_orphans.py +1 -1
  18. paasta_tools/contrib/get_running_task_allocation.py +1 -1
  19. paasta_tools/instance/kubernetes.py +2 -1
  20. paasta_tools/kubernetes_tools.py +5 -1
  21. paasta_tools/metrics/metastatus_lib.py +0 -24
  22. paasta_tools/metrics/metrics_lib.py +12 -3
  23. paasta_tools/setup_kubernetes_job.py +43 -1
  24. paasta_tools/setup_tron_namespace.py +2 -2
  25. paasta_tools/tron_tools.py +1 -1
  26. paasta_tools/utils.py +2 -1
  27. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_orphans.py +1 -1
  28. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_spark_jobs.py +1 -1
  29. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/get_running_task_allocation.py +1 -1
  30. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/setup_kubernetes_job.py +43 -1
  31. {paasta_tools-1.30.7.dist-info → paasta_tools-1.30.9.dist-info}/METADATA +2 -2
  32. {paasta_tools-1.30.7.dist-info → paasta_tools-1.30.9.dist-info}/RECORD +84 -89
  33. paasta_tools/frameworks/adhoc_scheduler.py +0 -71
  34. paasta_tools/frameworks/native_scheduler.py +0 -652
  35. paasta_tools/frameworks/task_store.py +0 -245
  36. paasta_tools/mesos_maintenance.py +0 -848
  37. paasta_tools/paasta_native_serviceinit.py +0 -21
  38. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/apply_external_resources.py +0 -0
  39. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/bounce_log_latency_parser.py +0 -0
  40. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_autoscaler_max_instances.py +0 -0
  41. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_cassandracluster_services_replication.py +0 -0
  42. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_flink_services_health.py +0 -0
  43. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_kubernetes_api.py +0 -0
  44. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_kubernetes_services_replication.py +0 -0
  45. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_manual_oapi_changes.sh +0 -0
  46. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/check_oom_events.py +0 -0
  47. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/cleanup_kubernetes_cr.py +0 -0
  48. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/cleanup_kubernetes_crd.py +0 -0
  49. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/cleanup_kubernetes_jobs.py +0 -0
  50. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/create_dynamodb_table.py +0 -0
  51. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/create_paasta_playground.py +0 -0
  52. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/delete_kubernetes_deployments.py +0 -0
  53. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/emit_allocated_cpu_metrics.py +0 -0
  54. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/generate_all_deployments +0 -0
  55. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/generate_authenticating_services.py +0 -0
  56. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/generate_deployments_for_service.py +0 -0
  57. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/generate_services_file.py +0 -0
  58. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/generate_services_yaml.py +0 -0
  59. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/habitat_fixer.py +0 -0
  60. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/ide_helper.py +0 -0
  61. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/is_pod_healthy_in_proxy.py +0 -0
  62. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/is_pod_healthy_in_smartstack.py +0 -0
  63. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/kill_bad_containers.py +0 -0
  64. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/kubernetes_remove_evicted_pods.py +0 -0
  65. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/mass-deploy-tag.sh +0 -0
  66. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/mock_patch_checker.py +0 -0
  67. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/paasta_cleanup_remote_run_resources.py +0 -0
  68. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/paasta_cleanup_stale_nodes.py +0 -0
  69. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/paasta_deploy_tron_jobs +0 -0
  70. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/paasta_execute_docker_command.py +0 -0
  71. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/paasta_secrets_sync.py +0 -0
  72. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/paasta_tabcomplete.sh +0 -0
  73. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/paasta_update_soa_memcpu.py +0 -0
  74. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/render_template.py +0 -0
  75. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/rightsizer_soaconfigs_update.py +0 -0
  76. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/service_shard_remove.py +0 -0
  77. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/service_shard_update.py +0 -0
  78. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/setup_istio_mesh.py +0 -0
  79. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/setup_kubernetes_cr.py +0 -0
  80. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/setup_kubernetes_crd.py +0 -0
  81. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/setup_kubernetes_internal_crd.py +0 -0
  82. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/setup_prometheus_adapter_config.py +0 -0
  83. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/shared_ip_check.py +0 -0
  84. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/synapse_srv_namespaces_fact.py +0 -0
  85. {paasta_tools-1.30.7.data → paasta_tools-1.30.9.data}/scripts/timeouts_metrics_prom.py +0 -0
  86. {paasta_tools-1.30.7.dist-info → paasta_tools-1.30.9.dist-info}/WHEEL +0 -0
  87. {paasta_tools-1.30.7.dist-info → paasta_tools-1.30.9.dist-info}/entry_points.txt +0 -0
  88. {paasta_tools-1.30.7.dist-info → paasta_tools-1.30.9.dist-info}/licenses/LICENSE +0 -0
  89. {paasta_tools-1.30.7.dist-info → paasta_tools-1.30.9.dist-info}/top_level.txt +0 -0
@@ -43,7 +43,6 @@ from paasta_tools.kubernetes_tools import paasta_prefixed
43
43
  from paasta_tools.kubernetes_tools import PodStatus
44
44
  from paasta_tools.mesos.master import MesosMetrics
45
45
  from paasta_tools.mesos.master import MesosState
46
- from paasta_tools.mesos_maintenance import MAINTENANCE_ROLE
47
46
  from paasta_tools.mesos_tools import get_all_tasks_from_state
48
47
  from paasta_tools.mesos_tools import get_mesos_quorum
49
48
  from paasta_tools.mesos_tools import get_number_of_mesos_masters
@@ -97,9 +96,6 @@ def get_mesos_cpu_status(
97
96
  total = metrics["master/cpus_total"]
98
97
  used = metrics["master/cpus_used"]
99
98
 
100
- for slave in mesos_state["slaves"]:
101
- used += reserved_maintenence_resources(slave["reserved_resources"])["cpus"]
102
-
103
99
  available = total - used
104
100
  return total, used, available
105
101
 
@@ -135,9 +131,6 @@ def get_mesos_memory_status(
135
131
  total = metrics["master/mem_total"]
136
132
  used = metrics["master/mem_used"]
137
133
 
138
- for slave in mesos_state["slaves"]:
139
- used += reserved_maintenence_resources(slave["reserved_resources"])["mem"]
140
-
141
134
  available = total - used
142
135
 
143
136
  return total, used, available
@@ -176,9 +169,6 @@ def get_mesos_disk_status(
176
169
  total = metrics["master/disk_total"]
177
170
  used = metrics["master/disk_used"]
178
171
 
179
- for slave in mesos_state["slaves"]:
180
- used += reserved_maintenence_resources(slave["reserved_resources"])["disk"]
181
-
182
172
  available = total - used
183
173
  return total, used, available
184
174
 
@@ -216,9 +206,6 @@ def get_mesos_gpu_status(
216
206
  total = metrics["master/gpus_total"]
217
207
  used = metrics["master/gpus_used"]
218
208
 
219
- for slave in mesos_state["slaves"]:
220
- used += reserved_maintenence_resources(slave["reserved_resources"])["gpus"]
221
-
222
209
  available = total - used
223
210
  return total, used, available
224
211
 
@@ -647,11 +634,6 @@ def calculate_resource_utilization_for_slaves(
647
634
  for task in tasks:
648
635
  task_resources = task["resources"]
649
636
  resource_free_dict.subtract(Counter(filter_mesos_state_metrics(task_resources)))
650
- for slave in slaves:
651
- filtered_resources = filter_mesos_state_metrics(
652
- reserved_maintenence_resources(slave["reserved_resources"])
653
- )
654
- resource_free_dict.subtract(Counter(filtered_resources))
655
637
  return {
656
638
  "free": ResourceInfo(
657
639
  cpus=resource_free_dict["cpus"],
@@ -1102,9 +1084,3 @@ def get_table_rows_for_resource_info_dict(
1102
1084
  return attribute_values + format_row_for_resource_utilization_healthchecks(
1103
1085
  healthcheck_utilization_pairs
1104
1086
  )
1105
-
1106
-
1107
- def reserved_maintenence_resources(
1108
- resources: MesosResources,
1109
- ):
1110
- return resources.get(MAINTENANCE_ROLE, {"cpus": 0, "mem": 0, "disk": 0, "gpus": 0})
@@ -8,6 +8,7 @@ from inspect import currentframe
8
8
  from types import TracebackType
9
9
  from typing import Any
10
10
  from typing import Callable
11
+ from typing import cast
11
12
  from typing import Dict
12
13
  from typing import Optional
13
14
  from typing import Type
@@ -110,10 +111,18 @@ class MeteoriteMetrics(BaseMetrics):
110
111
  )
111
112
 
112
113
  def create_timer(self, name: str, **kwargs: Any) -> TimerProtocol:
113
- return yelp_meteorite.create_timer(self.base_name + "." + name, **kwargs)
114
+ # yelp_meteorite returns an EmptyMetric object if the timer is misconfigured
115
+ # ...but that doesn't have the same interface ;_;
116
+ return cast(
117
+ Timer, yelp_meteorite.create_timer(self.base_name + "." + name, **kwargs)
118
+ )
114
119
 
115
120
  def create_gauge(self, name: str, **kwargs: Any) -> GaugeProtocol:
116
- return yelp_meteorite.create_gauge(self.base_name + "." + name, **kwargs)
121
+ # yelp_meteorite returns an EmptyMetric object if the gauge is misconfigured
122
+ # ...but that doesn't have the same interface ;_;
123
+ return cast(
124
+ Gauge, yelp_meteorite.create_gauge(self.base_name + "." + name, **kwargs)
125
+ )
117
126
 
118
127
  def create_counter(self, name: str, **kwargs: Any) -> CounterProtocol:
119
128
  return yelp_meteorite.create_counter(self.base_name + "." + name, **kwargs)
@@ -163,7 +172,7 @@ class Gauge(GaugeProtocol):
163
172
  log.debug(f"gauge {self.name} set to {value}")
164
173
 
165
174
 
166
- class Counter(GaugeProtocol):
175
+ class Counter(CounterProtocol):
167
176
  def __init__(self, name: str) -> None:
168
177
  self.name = name
169
178
  self.counter = 0
@@ -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:
@@ -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)
@@ -1289,7 +1289,7 @@ def load_tron_service_config_no_cache(
1289
1289
  def create_complete_master_config(cluster, soa_dir=DEFAULT_SOA_DIR):
1290
1290
  system_paasta_config = load_system_paasta_config()
1291
1291
  tronfig_folder = get_tronfig_folder(soa_dir=soa_dir, cluster=cluster)
1292
- config = read_yaml_file(os.path.join(tronfig_folder, f"MASTER.yaml"))
1292
+ config = read_yaml_file(os.path.join(tronfig_folder, "MASTER.yaml"))
1293
1293
  master_config = format_master_config(
1294
1294
  config,
1295
1295
  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
@@ -4139,7 +4140,7 @@ def timeout(
4139
4140
  return decorate
4140
4141
 
4141
4142
 
4142
- class _Timeout:
4143
+ class _Timeout(Generic[_TimeoutFuncRetType]):
4143
4144
  def __init__(
4144
4145
  self,
4145
4146
  function: Callable[..., _TimeoutFuncRetType],
@@ -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
@@ -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
 
@@ -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:
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paasta-tools
3
- Version: 1.30.7
3
+ Version: 1.30.9
4
4
  Summary: Tools for Yelps SOA infrastructure
5
5
  Author: Compute Infrastructure @ Yelp
6
6
  Author-email: compute-infra@yelp.com
7
7
  Provides: paasta_tools
8
- Requires-Python: >=3.8.0
8
+ Requires-Python: >=3.9.0
9
9
  License-File: LICENSE
10
10
  Requires-Dist: a-sync>=0.5.0
11
11
  Requires-Dist: aiohttp>=3.5.4