Skip to content

Commit 7e68452

Browse files
author
Andrey Cheptsov
committed
Refactor fleet offer semantics for create-instance filtering
1 parent fe08e54 commit 7e68452

File tree

1 file changed

+61
-31
lines changed
  • src/dstack/_internal/server/services

1 file changed

+61
-31
lines changed

src/dstack/_internal/server/services/fleets.py

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -443,24 +443,20 @@ async def get_plan(
443443
offers = []
444444
if effective_spec.configuration.ssh_config is None:
445445
requirements = get_fleet_requirements(effective_spec)
446-
if _is_elastic_cloud_fleet_spec(effective_spec):
447-
offers_with_backends = await offers_services.get_offers_by_requirements(
448-
project=project,
449-
profile=effective_spec.merged_profile,
450-
requirements=requirements,
451-
multinode=(
452-
effective_spec.configuration.placement == InstanceGroupPlacement.CLUSTER
453-
),
454-
blocks=effective_spec.configuration.blocks,
455-
)
456-
else:
457-
offers_with_backends = await get_create_instance_offers(
458-
project=project,
459-
profile=effective_spec.merged_profile,
460-
requirements=requirements,
461-
fleet_spec=effective_spec,
462-
blocks=effective_spec.configuration.blocks,
463-
)
446+
nodes = effective_spec.configuration.nodes
447+
include_only_create_instance_supported_backends = True
448+
if nodes is not None:
449+
include_only_create_instance_supported_backends = nodes.target != 0
450+
offers_with_backends = await get_fleet_offers(
451+
project=project,
452+
profile=effective_spec.merged_profile,
453+
requirements=requirements,
454+
fleet_spec=effective_spec,
455+
blocks=effective_spec.configuration.blocks,
456+
include_only_create_instance_supported_backends=(
457+
include_only_create_instance_supported_backends
458+
),
459+
)
464460
offers = [offer for _, offer in offers_with_backends]
465461

466462
_remove_fleet_spec_sensitive_info(effective_spec)
@@ -480,17 +476,42 @@ async def get_plan(
480476
return plan
481477

482478

483-
def _is_elastic_cloud_fleet_spec(fleet_spec: FleetSpec) -> bool:
484-
nodes = fleet_spec.configuration.nodes
485-
return (
486-
fleet_spec.configuration.ssh_config is None
487-
and nodes is not None
488-
and nodes.min == 0
489-
and nodes.target == 0
479+
async def get_create_instance_offers(
480+
project: ProjectModel,
481+
profile: Profile,
482+
requirements: Requirements,
483+
placement_group: Optional[PlacementGroup] = None,
484+
fleet_spec: Optional[FleetSpec] = None,
485+
fleet_model: Optional[FleetModel] = None,
486+
blocks: Union[int, Literal["auto"]] = 1,
487+
exclude_not_available: bool = False,
488+
master_job_provisioning_data: Optional[JobProvisioningData] = None,
489+
infer_master_job_provisioning_data_from_fleet_instances: bool = True,
490+
) -> List[Tuple[Backend, InstanceOfferWithAvailability]]:
491+
"""
492+
Return fleet offers restricted to backends that support `create_instance`.
493+
494+
This method is for create-instance provisioning semantics
495+
(typically VM-based backends, not container-only backends).
496+
"""
497+
return await get_fleet_offers(
498+
project=project,
499+
profile=profile,
500+
requirements=requirements,
501+
placement_group=placement_group,
502+
fleet_spec=fleet_spec,
503+
fleet_model=fleet_model,
504+
blocks=blocks,
505+
exclude_not_available=exclude_not_available,
506+
master_job_provisioning_data=master_job_provisioning_data,
507+
infer_master_job_provisioning_data_from_fleet_instances=(
508+
infer_master_job_provisioning_data_from_fleet_instances
509+
),
510+
include_only_create_instance_supported_backends=True,
490511
)
491512

492513

493-
async def get_create_instance_offers(
514+
async def get_fleet_offers(
494515
project: ProjectModel,
495516
profile: Profile,
496517
requirements: Requirements,
@@ -501,7 +522,15 @@ async def get_create_instance_offers(
501522
exclude_not_available: bool = False,
502523
master_job_provisioning_data: Optional[JobProvisioningData] = None,
503524
infer_master_job_provisioning_data_from_fleet_instances: bool = True,
525+
include_only_create_instance_supported_backends: bool = True,
504526
) -> List[Tuple[Backend, InstanceOfferWithAvailability]]:
527+
"""
528+
Return offers for fleet planning and provisioning.
529+
530+
By default, restricts to backends that support `create_instance`.
531+
Set `include_only_create_instance_supported_backends=False` to include
532+
all matching backends.
533+
"""
505534
multinode = False
506535
if fleet_spec is not None:
507536
multinode = fleet_spec.configuration.placement == InstanceGroupPlacement.CLUSTER
@@ -530,11 +559,12 @@ async def get_create_instance_offers(
530559
placement_group=placement_group,
531560
blocks=blocks,
532561
)
533-
offers = [
534-
(backend, offer)
535-
for backend, offer in offers
536-
if offer.backend in BACKENDS_WITH_CREATE_INSTANCE_SUPPORT
537-
]
562+
if include_only_create_instance_supported_backends:
563+
offers = [
564+
(backend, offer)
565+
for backend, offer in offers
566+
if offer.backend in BACKENDS_WITH_CREATE_INSTANCE_SUPPORT
567+
]
538568
return offers
539569

540570

0 commit comments

Comments
 (0)