"vscode:/vscode.git/clone" did not exist on "8525a021205965cc4ee76173561c6cb671f704ce"
Unverified Commit 3bbc0c04 authored by Jakob Görgen's avatar Jakob Görgen
Browse files

added json deserialization to system module

parent 7fac851b
......@@ -44,6 +44,8 @@ class Channel(utils_base.IdObj):
def toJSON(self):
json_obj = super().toJSON()
json_obj["type"] = self.__class__.__name__
json_obj["module"] = self.__class__.__module__
json_obj["synchronized"] = self._synchronized
json_obj["sync_period"] = self.sync_period
json_obj["sys_channel"] = self.sys_channel.id()
......
......@@ -35,11 +35,36 @@ class System(util_base.IdObj):
def __init__(self) -> None:
super().__init__()
self.all_component: list[Component] = []
self._all_components: dict[int, Component] = {}
self._all_interfaces: dict[int, Interface] = {}
self._all_channels: dict[int, Channel] = {}
def add_component(self, c: Component) -> None:
def _add_component(self, c: Component) -> None:
assert c.system == self
self.all_component.append(c)
assert c.id() not in self._all_components
self._all_components[c.id()] = c
def get_comp(self, ident: int) -> Component:
assert ident in self._all_components
return self._all_components[ident]
def _add_interface(self, i: Interface) -> None:
assert i.component.id() in self._all_components
assert i.id() not in self._all_interfaces
self._all_interfaces[i.id()] = i
def get_inf(self, ident: int) -> Interface:
assert ident in self._all_interfaces
return self._all_interfaces[ident]
def _add_channel(self, c: Channel) -> None:
assert c.a.id() in self._all_interfaces and c.b.id() in self._all_interfaces
assert c.id() not in self._all_channels
self._all_channels[c.id()] = c
def get_chan(self, ident: int) -> Channel:
assert ident in self._all_channels
return self._all_channels[ident]
def toJSON(self) -> dict:
json_obj = super().toJSON()
......@@ -47,19 +72,15 @@ class System(util_base.IdObj):
json_obj["module"] = self.__class__.__module__
components_json = []
channels: set[Channel] = set()
for comp in self.all_component:
for _, comp in self._all_components.items():
util_base.has_attribute(comp, "toJSON")
comp_json = comp.toJSON()
components_json.append(comp_json)
for inf in comp.interfaces():
channels.add(inf.channel)
json_obj["all_component"] = components_json
json_obj["all_components"] = components_json
channels_json = []
for chan in channels:
for _, chan in self._all_channels.items():
util_base.has_attribute(chan, "toJSON")
channels_json.append(chan.toJSON())
......@@ -67,10 +88,26 @@ class System(util_base.IdObj):
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, json_obj: dict) -> System:
instance = super().fromJSON(json_obj)
instance._all_components = {}
instance._all_interfaces = {}
instance._all_channels = {}
components_json = util_base.get_json_attr_top(json_obj, "all_components")
for comp_json in components_json:
comp_class = util_base.get_cls_by_json(comp_json)
util_base.has_attribute(comp_class, "fromJSON")
comp = comp_class.fromJSON(instance, comp_json)
channels_json = util_base.get_json_attr_top(json_obj, "channels")
for chan_json in channels_json:
chan_class = util_base.get_cls_by_json(chan_json)
util_base.has_attribute(chan_class, "fromJSON")
chan = chan_class.fromJSON(instance, chan_json)
return instance
class Component(util_base.IdObj):
......@@ -78,17 +115,17 @@ class Component(util_base.IdObj):
def __init__(self, s: System) -> None:
super().__init__()
self.system = s
self.ifs: list[Interface] = []
s.parameters = {}
s.add_component(self)
self.name: str = ""
s._add_component(self)
self.name: str | None = None
@abc.abstractmethod
def interfaces(self) -> list[Interface]:
return []
return self.ifs
@abc.abstractmethod
def add_if(self, interface: tp.Any) -> None:
raise Exception("must be overwritten by subclass")
# NOTE: overwrite and call in subclasses
def add_if(self, interface: Interface) -> None:
self.ifs.append(interface)
def channels(self) -> list[Channel]:
return [i.channel for i in self.interfaces() if i.is_connected()]
......@@ -111,16 +148,29 @@ class Component(util_base.IdObj):
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: System, json_obj: dict) -> Component:
instance = super().fromJSON(json_obj)
instance.name = util_base.get_json_attr_top_or_none(json_obj, "name")
instance.system = system
system._add_component(instance)
instance.ifs = []
interfaces_json = util_base.get_json_attr_top(json_obj, "interfaces")
for inf_json in interfaces_json:
inf_class = util_base.get_cls_by_json(inf_json)
util_base.has_attribute(inf_class, "fromJSON")
# NOTE: this will add the interface to the system map for retrieval in sub-classes
inf = inf_class.fromJSON(system, inf_json)
return instance
class Interface(util_base.IdObj):
def __init__(self, c: Component) -> None:
super().__init__()
self.component = c
c.system._add_interface(self)
self.channel: Channel | None = None
def is_connected(self) -> bool:
......@@ -130,7 +180,10 @@ class Interface(util_base.IdObj):
self.channel = None
def connect(self, c: Channel) -> None:
assert self.channel is None
if self.channel is not None:
raise Exception(
f"cannot connect interface {self.id()} to channel {c.id()}. interface is already connected to channel {self.channel.id()}"
)
self.channel = c
def find_peer(self) -> Interface:
......@@ -164,10 +217,16 @@ class Interface(util_base.IdObj):
json_obj["channel"] = self.channel.id()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: System, json_obj: dict) -> Interface:
instance = super().fromJSON(json_obj)
comp_id = util_base.get_json_attr_top(json_obj, "component")
comp = system.get_comp(comp_id)
instance.component = comp
comp.add_if(instance)
system._add_interface(instance)
instance.channel = None
return instance
class Channel(util_base.IdObj):
......@@ -178,6 +237,7 @@ class Channel(util_base.IdObj):
self.a.connect(self)
self.b: Interface = b
self.b.connect(self)
a.component.system._add_channel(self)
def interfaces(self) -> list[Interface]:
return [self.a, self.b]
......@@ -206,7 +266,20 @@ class Channel(util_base.IdObj):
json_obj["interface_b"] = self.b.id()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: System, json_obj: dict) -> Channel:
instance = super().fromJSON(json_obj)
instance.latency = int(util_base.get_json_attr_top(json_obj, "latency"))
inf_id_a = int(util_base.get_json_attr_top(json_obj, "interface_a"))
inf_id_b = int(util_base.get_json_attr_top(json_obj, "interface_b"))
inf_a = system.get_inf(ident=inf_id_a)
inf_b = system.get_inf(ident=inf_id_b)
instance.a = inf_a
instance.a.connect(instance)
instance.b = inf_b
instance.b.connect(instance)
system._add_channel(instance)
return instance
......@@ -20,6 +20,8 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations
from simbricks.orchestration.system import base
from simbricks.orchestration.utils import base as utils_base
......@@ -44,46 +46,50 @@ class EthSimpleNIC(base.Component):
super().__init__(s)
self._ip: str | None = None
self._eth_if: EthInterface = EthInterface(self)
super().add_if(self._eth_if)
def add_ipv4(self, ip: str) -> None:
assert self._ip is None
self._ip = ip
def add_if(self, interface: EthInterface) -> None:
raise Exception("EthSimpleNIC already has ethernet interface")
utils_base.has_expected_type(interface, EthInterface)
if hasattr(self, "_eth_if") and self._eth_if:
raise Exception(
f"you overwrite EthSimpleNIC._eth_if ({self._eth_if.id()} -> {interface.id()}) "
)
self._eth_if = interface
super().add_if(self._eth_if)
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["ip"] = self._ip
json_obj["eth_if"] = self._eth_if.id()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> EthSimpleNIC:
instance = super().fromJSON(system, json_obj)
instance._ip = utils_base.get_json_attr_top(json_obj, "ip")
eth_inf_id = int(utils_base.get_json_attr_top(json_obj, "eth_if"))
instance._eth_if = system.get_inf(eth_inf_id)
return instance
class BaseEthNetComponent(base.Component):
def __init__(self, s: base.System) -> None:
super().__init__(s)
self.eth_ifs: list[EthInterface] = []
def add_if(self, i: EthInterface) -> None:
self.eth_ifs.append(i)
utils_base.has_expected_type(i, EthInterface)
super().add_if(i)
def interfaces(self) -> list[EthInterface]:
return self.eth_ifs
def toJSON(self) -> dict:
json_obj = super().toJSON()
eth_interfaces = [inf.id() for inf in self.eth_ifs]
json_obj["eth_if"] = eth_interfaces
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
return super().toJSON()
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> BaseEthNetComponent:
return super().fromJSON(system, json_obj)
class EthWire(BaseEthNetComponent):
......@@ -91,9 +97,9 @@ class EthWire(BaseEthNetComponent):
super().__init__(s)
def add_if(self, i: EthInterface) -> None:
if len(self.eth_ifs) > 2:
if len(self.ifs) > 2:
raise Exception("one can only add 2 interfaces to a EthWire")
self.eth_ifs.append(i)
super().add_if(i)
class EthSwitch(BaseEthNetComponent):
......
......@@ -27,6 +27,7 @@ import abc
import io
from simbricks.orchestration.instantiation import base as inst_base
from simbricks.orchestration.utils import base as utils_base
from simbricks.orchestration.system import base as sys_base
if tp.TYPE_CHECKING:
from simbricks.orchestration.system import host as sys_host
......@@ -35,19 +36,21 @@ if tp.TYPE_CHECKING:
class Application(utils_base.IdObj):
def __init__(self, h: sys_host.Host) -> None:
super().__init__()
self.host = h
self.host: sys_host.Host = h
def toJSON(self) -> dict:
json_obj = {}
json_obj = super().toJSON()
json_obj["type"] = self.__class__.__name__
json_obj["module"] = self.__class__.__module__
json_obj["host"] = self.host.id()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict):
instance = super().fromJSON(json_obj)
host_id = utils_base.get_json_attr_top(json_obj, "host")
instance.host = system.get_comp(host_id)
return instance
# Note AK: Maybe we can factor most of the duplicate calls with the host out
......@@ -57,7 +60,7 @@ class BaseLinuxApplication(Application):
super().__init__(h)
self.start_delay: float | None = None
self.end_delay: float | None = None
self.wait = False
self.wait: bool = False
@abc.abstractmethod
def run_cmds(self, inst: inst_base.Instantiation) -> list[str]:
......@@ -101,60 +104,70 @@ class BaseLinuxApplication(Application):
simulated node.
"""
return io.BytesIO(bytes(s, encoding="UTF-8"))
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["start_delay"] = self.start_delay
json_obj["end_delay"] = self.end_delay
json_obj["wait"] = self.wait
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict):
instance = super().fromJSON(system, json_obj)
instance.start_delay = utils_base.get_json_attr_top_or_none(
json_obj, "start_delay"
)
instance.end_delay = utils_base.get_json_attr_top_or_none(json_obj, "end_delay")
instance.wait = utils_base.get_json_attr_top(json_obj, "wait")
return instance
class PingClient(BaseLinuxApplication):
def __init__(self, h: sys_host.LinuxHost, server_ip: str = "192.168.64.1") -> None:
super().__init__(h)
self.server_ip = server_ip
self.server_ip: str = server_ip
def run_cmds(self, inst: inst_base.Instantiation) -> tp.List[str]:
return [f"ping {self.server_ip} -c 10"]
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["server_ip"] = self.server_ip
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict):
instance = super().fromJSON(system, json_obj)
instance.server_ip = utils_base.get_json_attr_top(json_obj, "server_ip")
return instance
class Sleep(BaseLinuxApplication):
def __init__(self, h: sys_host.LinuxHost, delay: float = 10, infinite: bool = False) -> None:
def __init__(
self, h: sys_host.LinuxHost, delay: float = 10, infinite: bool = False
) -> None:
super().__init__(h)
self.infinite: bool = infinite
self.delay = delay
self.delay: float = delay
def run_cmds(self, inst: inst_base.Instantiation) -> list[str]:
if self.infinite:
return [f"sleep infinity"]
return [f"sleep {self.delay}"]
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["infinite"] = self.infinite
json_obj["delay"] = self.delay
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> Sleep:
instance = super().fromJSON(system, json_obj)
instance.infinite = bool(utils_base.get_json_attr_top(json_obj, "infinite"))
instance.delay = float(utils_base.get_json_attr_top(json_obj, "delay"))
return instance
class NetperfServer(BaseLinuxApplication):
......@@ -164,6 +177,10 @@ class NetperfServer(BaseLinuxApplication):
def run_cmds(self, inst: inst_base.Instantiation) -> list[str]:
return ["netserver", "sleep infinity"]
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> NetperfServer:
return super().fromJSON(system, json_obj)
class NetperfClient(BaseLinuxApplication):
def __init__(self, h: sys_host.LinuxHost, server_ip: str = "192.168.64.1") -> None:
......@@ -182,15 +199,22 @@ class NetperfClient(BaseLinuxApplication):
" -- -o mean_latency,p50_latency,p90_latency,p99_latency"
),
]
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["server_ip"] = self.server_ip
json_obj["duration_tp"] = self.duration_tp
json_obj["duration_lat"] = self.duration_lat
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> NetperfClient:
instance = super().fromJSON(system, json_obj)
instance.server_ip = utils_base.get_json_attr_top(json_obj, "server_ip")
instance.duration_tp = int(
utils_base.get_json_attr_top(json_obj, "duration_tp")
)
instance.duration_lat = int(
utils_base.get_json_attr_top(json_obj, "duration_lat")
)
return instance
......@@ -39,15 +39,8 @@ if tp.TYPE_CHECKING:
class Host(base.Component):
def __init__(self, s: base.System):
super().__init__(s)
self.ifs: list[base.Interface] = []
self.applications: list[app.Application] = []
def interfaces(self) -> list[base.Interface]:
return self.ifs
def add_if(self, interface: base.Interface) -> None:
self.ifs.append(interface)
def add_app(self, a: app.Application) -> None:
self.applications.append(a)
......@@ -56,24 +49,33 @@ class Host(base.Component):
applications_json = []
for app in self.applications:
utils_base.has_attribute(app, 'toJSON')
utils_base.has_attribute(app, "toJSON")
applications_json.append(app.toJSON())
json_obj["applications"] = applications_json
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> Host:
instance = super().fromJSON(system=system, json_obj=json_obj)
instance.applications = []
applications_json = utils_base.get_json_attr_top(json_obj, "applications")
for app_json in applications_json:
app_class = utils_base.get_cls_by_json(app_json)
utils_base.has_attribute(app_class, "fromJSON")
app = app_class.fromJSON(system, app_json)
instance.add_app(app)
return instance
class FullSystemHost(Host):
def __init__(self, s: base.System) -> None:
super().__init__(s)
self.memory = 512
self.cores = 1
self.cpu_freq = "3GHz"
self.memory: int = 512
self.cores: int = 1
self.cpu_freq: str = "3GHz"
self.disks: list[disk_images.DiskImage] = []
def add_disk(self, disk: disk_images.DiskImage) -> None:
......@@ -91,16 +93,28 @@ class FullSystemHost(Host):
disks_json = []
for disk in self.disks:
utils_base.has_attribute(disk, 'toJSON')
utils_base.has_attribute(disk, "toJSON")
disks_json.append(disk.toJSON())
json_obj["disks"] = disks_json
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> FullSystemHost:
instance = super().fromJSON(system, json_obj)
instance.memory = int(utils_base.get_json_attr_top(json_obj, "memory"))
instance.cores = int(utils_base.get_json_attr_top(json_obj, "cores"))
instance.cpu_freq = utils_base.get_json_attr_top(json_obj, "cpu_freq")
instance.disks = []
disks_json = utils_base.get_json_attr_top(json_obj, "disks")
for disk_js in disks_json:
disk_class = utils_base.get_cls_by_json(disk_js)
utils_base.has_attribute(disk_class, "fromJSON")
disk = disk_class.fromJSON(system, disk_js)
instance.add_disk(disk)
return instance
class BaseLinuxHost(FullSystemHost):
......@@ -200,17 +214,19 @@ class BaseLinuxHost(FullSystemHost):
simulated node.
"""
return io.BytesIO(bytes(s, encoding="UTF-8"))
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["load_modules"] = self.load_modules
json_obj["kcmd_append"] = self.kcmd_append
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> BaseLinuxHost:
instance = super().fromJSON(system, json_obj)
instance.load_modules = utils_base.get_json_attr_top(json_obj, "load_modules")
instance.kcmd_append = utils_base.get_json_attr_top(json_obj, "kcmd_append")
return instance
class LinuxHost(BaseLinuxHost):
......@@ -275,17 +291,19 @@ class LinuxHost(BaseLinuxHost):
cmds.append(f"ip addr add {com._ip}/24 dev {ifn}")
return cmds
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["drivers"] = self.drivers
json_obj["hostname"] = self.hostname
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> LinuxHost:
instance = super().fromJSON(system, json_obj)
instance.drivers = utils_base.get_json_attr_top(json_obj, "drivers")
instance.hostname = utils_base.get_json_attr_top(json_obj, "hostname")
return instance
class I40ELinuxHost(LinuxHost):
......
......@@ -29,6 +29,7 @@ import tarfile
import typing as tp
from simbricks.orchestration.utils import base as utils_base
from simbricks.orchestration.instantiation import base as inst_base
from simbricks.orchestration.system import base as sys_base
if tp.TYPE_CHECKING:
from simbricks.orchestration.system import host as sys_host
......@@ -85,17 +86,22 @@ class DiskImage(utils_base.IdObj):
await self._prepare_format(inst, format)
def toJSON(self) -> dict:
json_obj = {}
json_obj = super().toJSON()
json_obj["type"] = self.__class__.__name__
json_obj["module"] = self.__class__.__module__
json_obj["host"] = self.host.id()
json_obj["qemu_img_exec"] = self._qemu_img_exec
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> DiskImage:
instance = super().fromJSON(json_obj)
host_id = int(utils_base.get_json_attr_top(json_obj, "host"))
instance.host = system.get_comp(host_id)
instance._qemu_img_exec = utils_base.get_json_attr_top(
json_obj, "qemu_img_exec"
)
return instance
# Disk image where user just provides a path
......@@ -111,17 +117,19 @@ class ExternalDiskImage(DiskImage):
def path(self, inst: inst_base.Instantiation, format: str) -> str:
DiskImage.assert_is_file(self._path)
return self._path
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["path"] = self._path
json_obj["formats"] = self.formats
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> DiskImage:
instance = super().fromJSON(system, json_obj)
instance._path = utils_base.get_json_attr_top(json_obj, "path")
instance.formats = utils_base.get_json_attr_top(json_obj, "formats")
return instance
# Disk images shipped with simbricks
......@@ -144,17 +152,19 @@ class DistroDiskImage(DiskImage):
raise RuntimeError("Unsupported disk format")
DiskImage.assert_is_file(path)
return path
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["name"] = self.name
json_obj["formats"] = self.formats
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> DiskImage:
instance = super().fromJSON(system, json_obj)
instance.name = utils_base.get_json_attr_top(json_obj, "name")
instance.formats = utils_base.get_json_attr_top(json_obj, "formats")
return instance
# Abstract base class for dynamically generated images
......@@ -169,6 +179,10 @@ class DynamicDiskImage(DiskImage):
async def _prepare_format(self, inst: inst_base.Instantiation, format: str) -> None:
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> DynamicDiskImage:
return super().fromJSON(system, json_obj)
# Builds the Tar with the commands to run etc.
class LinuxConfigDiskImage(DynamicDiskImage):
......@@ -206,6 +220,10 @@ class LinuxConfigDiskImage(DynamicDiskImage):
tar.addfile(tarinfo=f_i, fileobj=f)
f.close()
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> LinuxConfigDiskImage:
return super().fromJSON(system, json_obj)
# This is an additional example: building disk images directly from python
# Could of course also have a version that generates the packer config from
......@@ -226,8 +244,9 @@ class PackerDiskImage(DynamicDiskImage):
json_obj = super().toJSON()
json_obj["config_path"] = self.config_path
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, system: sys_base.System, json_obj: dict) -> PackerDiskImage:
instance = super().fromJSON(system, json_obj)
instance.config_path = utils_base.get_json_attr_top(json_obj, "config_path")
return instance
......@@ -20,6 +20,8 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations
from simbricks.orchestration.system import base
from simbricks.orchestration.utils import base as utils_base
......@@ -38,7 +40,7 @@ class MemDeviceInterface(base.Interface):
def connect(self, c: base.Channel) -> None:
# Note AK: a bit ugly, but I think we can't get around a rt check here
if not c is isinstance(c, MemChannel):
raise TypeError('MemDeviceInterface only connects to MemChannel')
raise TypeError("MemDeviceInterface only connects to MemChannel")
super().connect(c)
......@@ -48,7 +50,7 @@ class MemChannel(base.Channel):
def host_if(self) -> MemHostInterface:
return self.a
def dev_if(self) -> MemDeviceInterface:
return self.b
......@@ -57,17 +59,19 @@ class MemSimpleDevice(base.Component):
def __init__(self, s: base.System):
super().__init__(s)
self._mem_if: MemDeviceInterface = MemDeviceInterface(c=self)
self._addr = 0xe000000000000000
super().add_if(self._mem_if)
self._addr = 0xE000000000000000
self._size = 1024 * 1024 * 1024 # 1GB
self._as_id = 0
def interfaces(self) -> list[base.Interface]:
return [self._mem_if]
def add_if(self, interface: MemDeviceInterface) -> None:
utils_base.has_expected_type(obj=interface, expected_type=MemDeviceInterface)
assert self._mem_if is None
utils_base.has_expected_type(interface, MemDeviceInterface)
if self._mem_if:
raise Exception(
f"you overwrite MemDeviceInterface._mem_if ({self._mem_if.id()} -> {interface.id()}) "
)
self._mem_if = interface
super().add_if(self._mem_if)
def toJSON(self) -> dict:
json_obj = super().toJSON()
......@@ -76,8 +80,16 @@ class MemSimpleDevice(base.Component):
json_obj["size"] = self._size
json_obj["as_id"] = self._as_id
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
\ No newline at end of file
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> MemSimpleDevice:
instance = super().fromJSON(system, json_obj)
mem_if_id = int(utils_base.get_json_attr_top(json_obj, "mem_if"))
addr = utils_base.get_json_attr_top(json_obj, "addr")
size = utils_base.get_json_attr_top(json_obj, "size")
as_id = utils_base.get_json_attr_top(json_obj, "as_id")
instance.mem_if = system.get_inf(mem_if_id)
instance.addr = addr
instance.size = size
instance.as_id = as_id
return instance
......@@ -20,28 +20,65 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations
from simbricks.orchestration.system import base
from simbricks.orchestration.system import pcie
from simbricks.orchestration.system import eth
from simbricks.orchestration.utils import base as utils_base
class SimplePCIeNIC(pcie.PCIeSimpleDevice, eth.EthSimpleNIC):
class SimplePCIeNIC(base.Component):
def __init__(self, s: base.System) -> None:
super().__init__(s)
def interfaces(self) -> list[base.Interface]:
return [self._pci_if, self._eth_if]
self._ip: str | None = None
self._eth_if: eth.EthInterface = eth.EthInterface(self)
super().add_if(self._eth_if)
self._pci_if: pcie.PCIeDeviceInterface = pcie.PCIeDeviceInterface(self)
super().add_if(self._pci_if)
def add_if(self, interface: eth.EthInterface | pcie.PCIeDeviceInterface) -> None:
match interface:
case eth.EthInterface():
eth.EthSimpleNIC.add_if(self, interface=interface)
if hasattr(self, "_eth_if") and self._eth_if:
print(interface)
print(self._eth_if)
raise Exception(
f"you overwrite SimplePCIeNIC._eth_if ({self._eth_if.id()} -> {interface.id()}) "
)
self._eth_if = interface
case pcie.PCIeDeviceInterface():
pcie.PCIeSimpleDevice.add_if(self, interface=interface)
if hasattr(self, "_pci_if") and self._pci_if:
raise Exception(
f"you overwrite SimplePCIeNIC._pci_if. ({self._pci_if.id()} -> {interface.id()})"
)
self._pci_if = interface
case _:
raise Exception(
f"interface must have type EthInterface or PCIeDeviceInterface but has type {type(interface)}"
)
super().add_if(interface)
def add_ipv4(self, ip: str) -> None:
assert self._ip is None
self._ip = ip
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["ip"] = self._ip
json_obj["eth_if"] = self._eth_if.id()
json_obj["pci_if"] = self._pci_if.id()
return json_obj
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> SimplePCIeNIC:
instance = super().fromJSON(system, json_obj)
instance._ip = utils_base.get_json_attr_top(json_obj, "ip")
eth_inf_id = int(utils_base.get_json_attr_top(json_obj, "eth_if"))
instance._eth_if = system.get_inf(eth_inf_id)
inf_id = int(utils_base.get_json_attr_top(json_obj, "pci_if"))
instance._pci_if = system.get_inf(inf_id)
return instance
class IntelI40eNIC(SimplePCIeNIC):
......
......@@ -20,6 +20,8 @@
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import annotations
from simbricks.orchestration.system import base
from simbricks.orchestration.utils import base as utils_base
......@@ -57,19 +59,25 @@ class PCIeSimpleDevice(base.Component):
def __init__(self, s: base.System):
super().__init__(s)
self._pci_if: PCIeDeviceInterface = PCIeDeviceInterface(self)
def interfaces(self) -> list[base.Interface]:
return [self._pci_if]
super().add_if(self._pci_if)
def add_if(self, interface: PCIeDeviceInterface) -> None:
raise Exception("PCIeSimpleDevice already has PCI device interface")
utils_base.has_expected_type(interface, PCIeDeviceInterface)
if self._pci_if:
raise Exception(
f"you overwrite PCIeSimpleDevice._pci_if. ({self._pci_if.id()} -> {interface.id()})"
)
self._pci_if = interface
super().add_if(interface)
def toJSON(self) -> dict:
json_obj = super().toJSON()
json_obj["pci_if"] = self._pci_if.id()
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
\ No newline at end of file
@classmethod
def fromJSON(cls, system: base.System, json_obj: dict) -> PCIeSimpleDevice:
instance = super().fromJSON(system=system, json_obj=json_obj)
inf_id = int(utils_base.get_json_attr_top(json_obj, "pci_if"))
instance._pci_if = system.get_inf(inf_id)
return instance
......@@ -22,6 +22,7 @@
import abc
import itertools
import importlib
class IdObj(abc.ABC):
......@@ -37,11 +38,13 @@ class IdObj(abc.ABC):
json_obj = {}
json_obj["id"] = self._id
return json_obj
@staticmethod
def fromJSON(json_obj):
# TODO
pass
@classmethod
def fromJSON(cls, json_obj):
instance = cls.__new__(cls)
instance._id = get_json_attr_top(json_obj, "id")
return instance
def check_type(obj, expected_type) -> bool:
"""
......@@ -57,9 +60,41 @@ def has_expected_type(obj, expected_type) -> None:
raise Exception(
f"obj of type {type(obj)} has not the type or is not a subtype of {expected_type}"
)
def has_attribute(obj, attr: str) -> None:
if not hasattr(obj, attr):
raise Exception(
f"obj of type {type(obj)} no attribute called {attr}"
)
raise Exception(f"obj of type {type(obj)} no attribute called {attr}")
def get_json_attr_top_or_none(json_obj: dict, attr: str) -> dict | None:
if attr in json_obj:
return json_obj[attr]
return None
def has_json_attr_top(json_obj: dict, attr: str) -> None:
if not attr in json_obj:
raise Exception(f"{json_obj} does not contain key {attr}")
def get_json_attr_top(json_obj: dict, attr: str) -> dict:
has_json_attr_top(json_obj, attr)
return json_obj[attr]
def get_cls_from_type_module(type_name: str, module_name: str):
# Import the module
module = importlib.import_module(module_name)
# Get the class from the module
cls = getattr(module, type_name)
return cls
def get_cls_by_json(json_obj: dict):
type_name = get_json_attr_top(json_obj, "type")
module_name = get_json_attr_top(json_obj, "module")
return get_cls_from_type_module(type_name, module_name)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment