Skip to content

Commit fe63438

Browse files
refactor(compute): move libvirt VM pool driver into gcl_sdk
The libvirt-based machine pool driver and its universal-agent bridge (compute/agents/universal/drivers/pool.py) now live natively in gcl_sdk as a MetaCoordinatorAgentDriver (gcl_sdk.agents.universal.drivers.pool / .libvirt), so remove the exordos_core-side copies: - exordos_core/compute/pool/drivers/{base,exceptions,libvirt}.py - exordos_core/compute/agents/universal/drivers/pool.py (and the now-empty compute/agents/ tree) - the gcn_machine_pool_driver entry points and the PoolAgentDriver/ LocalPoolAgentDriver entries under gcl_sdk_universal_agent - the libvirt-python dependency (now pulled in transitively via the gcl_sdk[libvirt] extra) compute/dm/models.py and compute/constants.py now re-export the moved spec/storage-pool models and status enums from gcl_sdk instead of defining them locally, so existing call sites (models.LibvirtPoolDriverSpec, nc.MachineStatus, etc.) keep working unchanged. Also drop the dead MachinePool.load_driver() method, which had no remaining callers. compute/pool/dm/models.py (the control-plane Pool/Machine/MachineVolume ORM models used by the scheduler/builder) is untouched. Requires a gcl_sdk release containing gcl_sdk.agents.universal.drivers.pool/ .libvirt before `uv lock` can be re-run here; the gcl_sdk[libvirt] dependency bump in pyproject.toml is in place but uv.lock is left as-is until then.
1 parent 20dbb95 commit fe63438

12 files changed

Lines changed: 15 additions & 2947 deletions

File tree

exordos_core/compute/agents/__init__.py

Whitespace-only changes.

exordos_core/compute/agents/universal/__init__.py

Whitespace-only changes.

exordos_core/compute/agents/universal/drivers/pool.py

Lines changed: 0 additions & 830 deletions
This file was deleted.

exordos_core/compute/constants.py

Lines changed: 8 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,24 @@
1515
# under the License.
1616

1717
import enum
18-
import typing as tp
1918
import uuid as sys_uuid
2019

20+
from gcl_sdk.agents.universal.drivers.pool import BootAlternative # noqa: F401
21+
from gcl_sdk.agents.universal.drivers.pool import BootType # noqa: F401
22+
from gcl_sdk.agents.universal.drivers.pool import MachinePoolStatus # noqa: F401
23+
from gcl_sdk.agents.universal.drivers.pool import MachineStatus # noqa: F401
24+
from gcl_sdk.agents.universal.drivers.pool import NodeType # noqa: F401
25+
from gcl_sdk.agents.universal.drivers.pool import PortStatus # noqa: F401
26+
from gcl_sdk.agents.universal.drivers.pool import VolumeStatus # noqa: F401
27+
2128
DEF_SQL_LIMIT = 300
22-
EP_MACHINE_POOL_DRIVERS = "gcn_machine_pool_driver"
2329
EP_NETWORK_DRIVERS = "gcn_network_driver"
2430
DEF_ROOT_DISK_SIZE = 10
2531
POLICY_SERVICE_NAME = "compute"
2632

2733
NODE_SET_PROJECT = sys_uuid.UUID("11111113-bc70-4760-9fbf-9fcfe40da329")
2834

2935

30-
BootType = tp.Literal["hd", "network", "cdrom"]
31-
32-
3336
class NodeStatus(str, enum.Enum):
3437
NEW = "NEW"
3538
SCHEDULED = "SCHEDULED"
@@ -39,30 +42,6 @@ class NodeStatus(str, enum.Enum):
3942
ERROR = "ERROR"
4043

4144

42-
class MachineStatus(str, enum.Enum):
43-
NEW = "NEW"
44-
SCHEDULED = "SCHEDULED"
45-
IN_PROGRESS = "IN_PROGRESS"
46-
STARTED = "STARTED"
47-
ACTIVE = "ACTIVE"
48-
IDLE = "IDLE"
49-
ERROR = "ERROR"
50-
FLASHED = "FLASHED"
51-
NEED_RESCHEDULE = "NEED_RESCHEDULE"
52-
53-
54-
class VolumeStatus(str, enum.Enum):
55-
NEW = "NEW"
56-
IN_PROGRESS = "IN_PROGRESS"
57-
ACTIVE = "ACTIVE"
58-
ERROR = "ERROR"
59-
60-
61-
class NodeType(str, enum.Enum):
62-
VM = "VM"
63-
HW = "HW"
64-
65-
6645
class VolumeType(str, enum.Enum):
6746
QCOW2 = "QCOW2"
6847

@@ -77,51 +56,5 @@ class MachineBuildStatus(str, enum.Enum):
7756
READY = "READY"
7857

7958

80-
class MachinePoolStatus(str, enum.Enum):
81-
ACTIVE = "ACTIVE"
82-
DISABLED = "DISABLED"
83-
MAINTENANCE = "MAINTENANCE"
84-
IN_PROGRESS = "IN_PROGRESS"
85-
86-
87-
class BootAlternative(str, enum.Enum):
88-
hd0 = "hd0"
89-
hd1 = "hd1"
90-
hd2 = "hd2"
91-
hd3 = "hd3"
92-
hd4 = "hd4"
93-
hd5 = "hd5"
94-
hd6 = "hd6"
95-
hd7 = "hd7"
96-
cdrom = "cdrom"
97-
network = "network"
98-
99-
@property
100-
def hd_prefix(self) -> str:
101-
return "hd"
102-
103-
@property
104-
def boot_from_hd(self) -> bool:
105-
return self.value.startswith(self.hd_prefix)
106-
107-
@property
108-
def boot_type(self) -> BootType:
109-
if self.boot_from_hd:
110-
return self.hd_prefix
111-
elif self.value == "cdrom":
112-
return "cdrom"
113-
elif self.value == "network":
114-
return "network"
115-
116-
raise ValueError(f"Invalid boot alternative: {self.value}")
117-
118-
119-
class PortStatus(str, enum.Enum):
120-
NEW = "NEW"
121-
IN_PROGRESS = "IN_PROGRESS"
122-
ACTIVE = "ACTIVE"
123-
ERROR = "ERROR"
124-
125-
12659
class PlacementPolicyKind(str, enum.Enum):
12760
SOFT_ANTI_AFFINITY = "soft-anti-affinity"

exordos_core/compute/dm/models.py

Lines changed: 6 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020

2121
from gcl_sdk.agents.universal.api import crypto as ua_crypto
2222
from gcl_sdk.agents.universal.dm import models as ua_models
23+
from gcl_sdk.agents.universal.drivers.pool import AbstractPoolDriverSpec # noqa: F401
24+
from gcl_sdk.agents.universal.drivers.pool import AbstractStoragePool # noqa: F401
25+
from gcl_sdk.agents.universal.drivers.pool import DummyPoolDriverSpec
26+
from gcl_sdk.agents.universal.drivers.pool import ExordosLocalHyperDriverSpec
27+
from gcl_sdk.agents.universal.drivers.pool import LibvirtPoolDriverSpec
28+
from gcl_sdk.agents.universal.drivers.pool import ThinStoragePool
2329
from gcl_sdk.infra.dm import models as infra_models
2430
import netaddr
2531
from restalchemy.dm import filters as dm_filters
@@ -38,7 +44,6 @@
3844
from exordos_core.compute import constants as nc
3945

4046
if tp.TYPE_CHECKING:
41-
from exordos_core.compute.pool.drivers.base import AbstractPoolDriver
4247
from exordos_core.network.driver.base import AbstractNetworkDriver
4348

4449

@@ -61,135 +66,6 @@ def from_unicode(self, value):
6166
return self.from_simple_type(value)
6267

6368

64-
class AbstractStoragePool(
65-
models.SimpleViewMixin,
66-
types_dynamic.AbstractKindModel,
67-
):
68-
"""The abstract model for storage pool.
69-
70-
This model is used to represent the storage pool and determine
71-
the its interfaces.
72-
"""
73-
74-
uuid = properties.property(
75-
types.UUID(),
76-
read_only=True,
77-
id_property=True,
78-
default=lambda: sys_uuid.uuid4(),
79-
)
80-
pool_type = properties.property(types.String(), required=True)
81-
82-
@property
83-
def capacity(self) -> int:
84-
"""Storage pool capacity."""
85-
return 0
86-
87-
@property
88-
def available(self) -> int:
89-
"""Storage pool available space."""
90-
return 0
91-
92-
def allocate_capacity(self, size: int) -> None:
93-
"""Allocate capacity."""
94-
raise NotImplementedError()
95-
96-
def free_capacity(self, size: int) -> None:
97-
"""Free capacity."""
98-
raise NotImplementedError()
99-
100-
def has_capacity(self, size: int) -> bool:
101-
"""Check if the storage pool has enough capacity."""
102-
return self.available >= size
103-
104-
105-
class AbstractPoolDriverSpec(
106-
types_dynamic.AbstractKindModel,
107-
models.SimpleViewMixin,
108-
):
109-
"""Base class for all pool driver specs."""
110-
111-
112-
class LibvirtPoolDriverSpec(AbstractPoolDriverSpec):
113-
KIND = "libvirt"
114-
115-
connection_uri = properties.property(
116-
types.String(max_length=2048),
117-
required=True,
118-
)
119-
network = properties.property(
120-
types.AllowNone(types.String(max_length=255)),
121-
default=None,
122-
)
123-
storage_pool = properties.property(
124-
types.AllowNone(types.String(max_length=255)),
125-
default=None,
126-
)
127-
machine_prefix = properties.property(
128-
types.AllowNone(types.String(max_length=255)),
129-
default=None,
130-
)
131-
network_type = properties.property(
132-
types.Enum(["network", "bridge"]),
133-
default="network",
134-
)
135-
iface_rom_file = properties.property(
136-
types.AllowNone(types.String(max_length=255)),
137-
default=None,
138-
)
139-
iface_mtu = properties.property(
140-
types.Integer(min_value=0, max_value=65536),
141-
default=1500,
142-
)
143-
iface_source = properties.property(
144-
types.AllowNone(types.String(max_length=255)),
145-
default=None,
146-
)
147-
148-
149-
class ExordosLocalHyperDriverSpec(LibvirtPoolDriverSpec):
150-
KIND = "exordos_local_hyper"
151-
152-
node = properties.property(types.UUID(), required=True)
153-
154-
155-
class DummyPoolDriverSpec(AbstractPoolDriverSpec):
156-
KIND = "dummy"
157-
158-
159-
class ThinStoragePool(
160-
AbstractStoragePool,
161-
models.ModelWithNameDesc,
162-
):
163-
"""The model represents thin provisioned storage pool."""
164-
165-
KIND = "thin_storage_pool"
166-
167-
capacity_usable = properties.property(types.Integer(min_value=0), default=0)
168-
capacity_provisioned = properties.property(types.Integer(min_value=0), default=0)
169-
oversubscription_ratio = properties.property(
170-
types.Float(min_value=0.0), default=1.0
171-
)
172-
available_actual = properties.property(types.Integer(min_value=0), default=0)
173-
174-
@property
175-
def capacity(self) -> int:
176-
"""Storage pool capacity."""
177-
return int(self.capacity_usable * self.oversubscription_ratio)
178-
179-
@property
180-
def available(self) -> int:
181-
"""Storage pool available space."""
182-
return self.capacity - self.capacity_provisioned
183-
184-
def allocate_capacity(self, size: int) -> None:
185-
"""Allocate capacity."""
186-
self.capacity_provisioned += size
187-
188-
def free_capacity(self, size: int) -> None:
189-
"""Free capacity."""
190-
self.capacity_provisioned -= size
191-
192-
19369
class MachinePool(
19470
models.ModelWithUUID,
19571
models.ModelWithNameDesc,
@@ -198,7 +74,6 @@ class MachinePool(
19874
models.SimpleViewMixin,
19975
):
20076
__tablename__ = "machine_pools"
201-
__driver_map__ = {}
20277

20378
driver_spec = properties.property(
20479
types_dynamic.KindModelSelectorType(
@@ -235,38 +110,6 @@ class MachinePool(
235110
default=list,
236111
)
237112

238-
def load_driver(self) -> tp.Type["AbstractPoolDriver"]:
239-
"""
240-
Load the driver for the machine pool.
241-
242-
This method will try to load all drivers from the
243-
``exordos_core.machine_pool_drivers`` entry point group and try to
244-
instantiate them with the current machine pool. If a driver is
245-
successfully loaded, it is stored in a cache for faster access.
246-
247-
If no driver is found, a ValueError is raised.
248-
249-
:return: The loaded driver class
250-
:raises ValueError: If no driver is found
251-
"""
252-
driver_key = str(self.driver_spec)
253-
254-
if driver_key in self.__driver_map__:
255-
return self.__driver_map__[driver_key]
256-
257-
ep_group = utils.load_group_from_entry_point(nc.EP_MACHINE_POOL_DRIVERS)
258-
for e in ep_group:
259-
try:
260-
class_ = e.load()
261-
driver = class_(self)
262-
self.__driver_map__[driver_key] = driver
263-
return driver
264-
except Exception:
265-
# Just try another driver
266-
pass
267-
268-
raise ValueError(f"Driver for spec '{self.driver_spec}' not found")
269-
270113

271114
class Volume(
272115
infra_models.Volume,

exordos_core/compute/pool/drivers/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)