|
| 1 | +from typing import Any, Dict, Optional |
| 2 | + |
| 3 | +from dstack._internal.core.models.configurations import ServiceConfiguration |
| 4 | +from dstack._internal.core.models.runs import ApplyRunPlanInput, JobSubmission, RunSpec |
| 5 | +from dstack._internal.server.schemas.runs import GetRunPlanRequest |
| 6 | + |
| 7 | + |
| 8 | +def get_apply_plan_excludes(plan: ApplyRunPlanInput) -> Optional[Dict]: |
| 9 | + """ |
| 10 | + Returns `plan` exclude mapping to exclude certain fields from the request. |
| 11 | + Use this method to exclude new fields when they are not set to keep |
| 12 | + clients backward-compatibility with older servers. |
| 13 | + """ |
| 14 | + apply_plan_excludes = {} |
| 15 | + run_spec_excludes = get_run_spec_excludes(plan.run_spec) |
| 16 | + if run_spec_excludes is not None: |
| 17 | + apply_plan_excludes["run_spec"] = run_spec_excludes |
| 18 | + current_resource = plan.current_resource |
| 19 | + if current_resource is not None: |
| 20 | + current_resource_excludes = {} |
| 21 | + current_resource_excludes["status_message"] = True |
| 22 | + apply_plan_excludes["current_resource"] = current_resource_excludes |
| 23 | + current_resource_excludes["run_spec"] = get_run_spec_excludes(current_resource.run_spec) |
| 24 | + job_submissions_excludes = {} |
| 25 | + current_resource_excludes["jobs"] = { |
| 26 | + "__all__": {"job_submissions": {"__all__": job_submissions_excludes}} |
| 27 | + } |
| 28 | + job_submissions = [js for j in current_resource.jobs for js in j.job_submissions] |
| 29 | + if all(map(_should_exclude_job_submission_jpd_cpu_arch, job_submissions)): |
| 30 | + job_submissions_excludes["job_provisioning_data"] = { |
| 31 | + "instance_type": {"resources": {"cpu_arch"}} |
| 32 | + } |
| 33 | + if all(map(_should_exclude_job_submission_jrd_cpu_arch, job_submissions)): |
| 34 | + job_submissions_excludes["job_runtime_data"] = { |
| 35 | + "offer": {"instance": {"resources": {"cpu_arch"}}} |
| 36 | + } |
| 37 | + if all(js.exit_status is None for js in job_submissions): |
| 38 | + job_submissions_excludes["exit_status"] = True |
| 39 | + latest_job_submission = current_resource.latest_job_submission |
| 40 | + if latest_job_submission is not None: |
| 41 | + latest_job_submission_excludes = {} |
| 42 | + current_resource_excludes["latest_job_submission"] = latest_job_submission_excludes |
| 43 | + if _should_exclude_job_submission_jpd_cpu_arch(latest_job_submission): |
| 44 | + latest_job_submission_excludes["job_provisioning_data"] = { |
| 45 | + "instance_type": {"resources": {"cpu_arch"}} |
| 46 | + } |
| 47 | + if _should_exclude_job_submission_jrd_cpu_arch(latest_job_submission): |
| 48 | + latest_job_submission_excludes["job_runtime_data"] = { |
| 49 | + "offer": {"instance": {"resources": {"cpu_arch"}}} |
| 50 | + } |
| 51 | + if latest_job_submission.exit_status is None: |
| 52 | + latest_job_submission_excludes["exit_status"] = True |
| 53 | + return {"plan": apply_plan_excludes} |
| 54 | + |
| 55 | + |
| 56 | +def get_get_plan_excludes(request: GetRunPlanRequest) -> Optional[Dict]: |
| 57 | + """ |
| 58 | + Excludes new fields when they are not set to keep |
| 59 | + clients backward-compatibility with older servers. |
| 60 | + """ |
| 61 | + get_plan_excludes = {} |
| 62 | + run_spec_excludes = get_run_spec_excludes(request.run_spec) |
| 63 | + if run_spec_excludes is not None: |
| 64 | + get_plan_excludes["run_spec"] = run_spec_excludes |
| 65 | + if request.max_offers is None: |
| 66 | + get_plan_excludes["max_offers"] = True |
| 67 | + return get_plan_excludes |
| 68 | + |
| 69 | + |
| 70 | +def get_run_spec_excludes(run_spec: RunSpec) -> Optional[Dict]: |
| 71 | + """ |
| 72 | + Returns `run_spec` exclude mapping to exclude certain fields from the request. |
| 73 | + Use this method to exclude new fields when they are not set to keep |
| 74 | + clients backward-compatibility with older servers. |
| 75 | + """ |
| 76 | + spec_excludes: dict[str, Any] = {} |
| 77 | + configuration_excludes: dict[str, Any] = {} |
| 78 | + profile_excludes: set[str] = set() |
| 79 | + configuration = run_spec.configuration |
| 80 | + profile = run_spec.profile |
| 81 | + |
| 82 | + if configuration.fleets is None: |
| 83 | + configuration_excludes["fleets"] = True |
| 84 | + if profile is not None and profile.fleets is None: |
| 85 | + profile_excludes.add("fleets") |
| 86 | + if configuration.tags is None: |
| 87 | + configuration_excludes["tags"] = True |
| 88 | + if profile is not None and profile.tags is None: |
| 89 | + profile_excludes.add("tags") |
| 90 | + if isinstance(configuration, ServiceConfiguration) and not configuration.rate_limits: |
| 91 | + configuration_excludes["rate_limits"] = True |
| 92 | + if configuration.shell is None: |
| 93 | + configuration_excludes["shell"] = True |
| 94 | + if configuration.priority is None: |
| 95 | + configuration_excludes["priority"] = True |
| 96 | + if configuration.startup_order is None: |
| 97 | + configuration_excludes["startup_order"] = True |
| 98 | + if profile is not None and profile.startup_order is None: |
| 99 | + profile_excludes.add("startup_order") |
| 100 | + if configuration.stop_criteria is None: |
| 101 | + configuration_excludes["stop_criteria"] = True |
| 102 | + if profile is not None and profile.stop_criteria is None: |
| 103 | + profile_excludes.add("stop_criteria") |
| 104 | + |
| 105 | + if configuration_excludes: |
| 106 | + spec_excludes["configuration"] = configuration_excludes |
| 107 | + if profile_excludes: |
| 108 | + spec_excludes["profile"] = profile_excludes |
| 109 | + if spec_excludes: |
| 110 | + return spec_excludes |
| 111 | + return None |
| 112 | + |
| 113 | + |
| 114 | +def _should_exclude_job_submission_jpd_cpu_arch(job_submission: JobSubmission) -> bool: |
| 115 | + try: |
| 116 | + return job_submission.job_provisioning_data.instance_type.resources.cpu_arch is None |
| 117 | + except AttributeError: |
| 118 | + return True |
| 119 | + |
| 120 | + |
| 121 | +def _should_exclude_job_submission_jrd_cpu_arch(job_submission: JobSubmission) -> bool: |
| 122 | + try: |
| 123 | + return job_submission.job_runtime_data.offer.instance.resources.cpu_arch is None |
| 124 | + except AttributeError: |
| 125 | + return True |
0 commit comments