State loading from toml

This commit is contained in:
Johan B.W. de Vries 2023-04-11 12:27:36 +02:00
parent 45cafdf327
commit 628fb775e8
8 changed files with 193 additions and 26 deletions

13
examples/echoclient.toml Normal file
View File

@ -0,0 +1,13 @@
[echoclient-image]
apiVersion = "v0"
kind = "Image"
path = "examples/echoclient.wasm"
hash = "sha256@84cb22d12dfdd6b05cb906f6db83d59f473c9df85a33822f696344af2b92b502"
[echoclient-container]
apiVersion = "v0"
kind = "Container"
image = "echoclient-image"
runtime = "wasmtime"

34
examples/echoserver.toml Normal file
View File

@ -0,0 +1,34 @@
[echoserver-image]
apiVersion = "v0"
kind = "Image"
path = "examples/echoserver.wasm"
hash = "sha256@dfe03b4f7ce5e921931f8715384e35a6776fdc28837e42ffa04305bbadffcfc9"
[echoserver-container-0]
apiVersion = "v0"
kind = "Container"
image = "echoserver-image"
runtime = "wasmtime"
[echoserver-container-1]
apiVersion = "v0"
kind = "Container"
image = "echoserver-image"
runtime = "wasmtime"
[echoserver-service]
apiVersion = "v0"
kind = "Service"
name = "echoserver"
[echoserver-service.container]
byName = "echoserver-container-*"
[[echoserver-service.methods]]
name = "echo"
returns = "none"
args = [ {name = "msg", type = "bytes"} ]

View File

@ -1,15 +1,15 @@
from typing import List
from .image import Image from .image import Image
from .method import Method
class Container: class Container:
__slots__ = ('image', 'methods', ) __slots__ = ('image', 'runtime', )
image: Image image: Image
methods: List[Method] runtime: str
def __init__(self, image: Image, methods: List[Method]) -> None: def __init__(self, image: Image, runtime: str) -> None:
self.image = image self.image = image
self.methods = methods self.runtime = runtime
def __repr__(self) -> str:
return f'Container({repr(self.image)}, {repr(self.runtime)})'

View File

@ -1,7 +1,31 @@
class Image: from typing import Optional
__slots__ = ('hash', )
class Image:
__slots__ = ('path', 'hash', )
path: Optional[str]
hash: str hash: str
def __init__(self, hash: str) -> None: def __init__(self, path: Optional[str], hash: str) -> None:
self.path = path
self.hash = hash self.hash = hash
def __repr__(self) -> str:
return f'Image({repr(self.path)}, {repr(self.hash)})'
class ImageReference(Image):
__slots__ = ('name', )
name: str
def __init__(self, name: str) -> None:
# Intentionally do not call super()
# This will cause AttributeError exceptions when someone
# tries to access an image that's only a reference
self.name = name
def __repr__(self) -> str:
return f'ImageReference({repr(self.name)})'

View File

@ -0,0 +1,103 @@
from typing import TYPE_CHECKING, Any, BinaryIO, Dict, List
from .container import Container
from .image import Image, ImageReference
from .method import Method
from .service import Service
if TYPE_CHECKING:
import tomli as tomllib
else:
try:
import tomllib
except ImportError:
import tomli as tomllib
class State:
__slots__ = ('images', 'containers', 'services', )
images: List[Image]
containers: List[Container]
services: List[Service]
def __init__(
self,
images: List[Image],
containers: List[Container],
services: List[Service],
) -> None:
self.images = images
self.containers = containers
self.services = services
def __repr__(self) -> str:
return f'State({repr(self.images)}, {repr(self.containers)}, {repr(self.services)})'
def image_from_toml(spec: Dict[str, Any]) -> Image:
"""
Loads an Image spec from toml
"""
return Image(str(spec['path']), str(spec['hash']))
def container_from_toml(spec: Dict[str, Any]) -> Container:
"""
Loads a Container spec from toml
"""
return Container(ImageReference(str(spec['image'])), str(spec['runtime']))
def service_from_toml(spec: Dict[str, Any]) -> Service:
"""
Loads a Service spec from toml
"""
methods: List[Method] = []
return Service(str(spec['name']), methods)
def from_toml(toml: BinaryIO) -> State:
"""
Loads the given toml and builds a state instance out of it
"""
toml_dict = tomllib.load(toml)
images: List[Image] = []
images_by_name: Dict[str, Image] = {}
containers: List[Container] = []
services: List[Service] = []
for name, spec in toml_dict.items():
if spec['apiVersion'] != 'v0':
raise NotImplementedError('apiVersion', spec['apiVersion'])
if spec['kind'] == 'Image':
image = image_from_toml(spec)
images.append(image)
assert name not in images_by_name, f'Duplicate image name: {name}'
images_by_name[name] = image
continue
if spec['kind'] == 'Container':
containers.append(container_from_toml(spec))
continue
if spec['kind'] == 'Service':
services.append(service_from_toml(spec))
continue
raise NotImplementedError(spec)
for container in containers:
if not isinstance(container.image, ImageReference):
continue
image_opt = images_by_name.get(container.image.name, None)
assert image_opt is not None, f'Image reference not resolved: {container.image.name}'
container.image = image_opt
return State(images, containers, services)

View File

@ -6,11 +6,12 @@ import time
from queue import Empty, Queue from queue import Empty, Queue
from phasmplatform.common import valuetype from phasmplatform.common import valuetype
from phasmplatform.common.config import from_toml from phasmplatform.common.config import from_toml as config_from_toml
from phasmplatform.common.method import Method, MethodArgument, MethodCall from phasmplatform.common.method import Method, MethodArgument, MethodCall
from phasmplatform.common.router import MethodCallRouterInterface from phasmplatform.common.router import MethodCallRouterInterface
from phasmplatform.common.service import Service, ServiceDiscoveryInterface from phasmplatform.common.service import Service, ServiceDiscoveryInterface
from phasmplatform.common.value import NoneValue from phasmplatform.common.value import NoneValue
from phasmplatform.common.state import from_toml as state_from_toml
from .runners.base import RunnerInterface from .runners.base import RunnerInterface
from .runners.wasmtime import WasmTimeRunner from .runners.wasmtime import WasmTimeRunner
@ -23,7 +24,6 @@ def runner_thread(runner: RunnerInterface, queue: Queue[MethodCall]) -> None:
except Empty: except Empty:
break break
print('rt call', runner, queue, call)
runner.do_call(call) runner.do_call(call)
@ -82,10 +82,14 @@ class LocalhostMethodCallRouter(MethodCallRouterInterface):
def main() -> int: def main() -> int:
with open('config.toml', 'rb') as fil: with open('config.toml', 'rb') as fil:
config = from_toml(fil) config = config_from_toml(fil)
del config del config
with open('./examples/echoserver.toml', 'rb') as fil:
state = state_from_toml(fil)
print(state)
localhost_queue: Queue[MethodCall] = Queue() localhost_queue: Queue[MethodCall] = Queue()
echo_client_queue: Queue[MethodCall] = Queue() echo_client_queue: Queue[MethodCall] = Queue()
echo_server_queue: Queue[MethodCall] = Queue() echo_server_queue: Queue[MethodCall] = Queue()
@ -96,7 +100,7 @@ def main() -> int:
localhost = LocalhostRunner() localhost = LocalhostRunner()
service_discovery.register_service(make_prelude(), localhost_queue) service_discovery.register_service(make_prelude(), localhost_queue)
with open('/home/johan/projects/idea/phasm/examples/echoserver.wasm', 'rb') as fil: with open('./examples/echoserver.wasm', 'rb') as fil:
echo_server = WasmTimeRunner(service_discovery, method_call_router, fil.read()) echo_server = WasmTimeRunner(service_discovery, method_call_router, fil.read())
service_discovery.register_service(Service('echoserver', [ service_discovery.register_service(Service('echoserver', [
Method('echo', [ Method('echo', [
@ -104,7 +108,7 @@ def main() -> int:
], valuetype.bytes) ], valuetype.bytes)
]), echo_server_queue) ]), echo_server_queue)
with open('/home/johan/projects/idea/phasm/examples/echoclient.wasm', 'rb') as fil: with open('./examples/echoclient.wasm', 'rb') as fil:
echo_client = WasmTimeRunner(service_discovery, method_call_router, fil.read()) echo_client = WasmTimeRunner(service_discovery, method_call_router, fil.read())
# service_discovery.register_service(echo_client, echo_client_queue) # service_discovery.register_service(echo_client, echo_client_queue)

View File

@ -67,9 +67,6 @@ class BaseRunner(RunnerInterface):
raise NotImplementedError(value_type, val) raise NotImplementedError(value_type, val)
def log_bytes(self, msg_ptr: int) -> None:
print('LOG: ' + self.read_bytes(msg_ptr).decode())
def dump_memory(textio: TextIO, mem: bytes) -> None: def dump_memory(textio: TextIO, mem: bytes) -> None:
line_width = 16 line_width = 16

View File

@ -32,12 +32,6 @@ class WasmTimeRunner(BaseRunner):
self.store = wasmtime.Store() self.store = wasmtime.Store()
self.module = wasmtime.Module(self.store.engine, wasm_bin) self.module = wasmtime.Module(self.store.engine, wasm_bin)
from typing import Any
def dump_args(*args: Any, **kwargs: Any) -> None:
print('args', args)
print('kwargs', kwargs)
imports: List[wasmtime.Func] = [] imports: List[wasmtime.Func] = []
for imprt in self.module.imports: for imprt in self.module.imports:
service = service_discovery.find_service(imprt.module) service = service_discovery.find_service(imprt.module)
@ -125,13 +119,11 @@ class WasmTimeRunner(BaseRunner):
queue: Queue[Value] = Queue(maxsize=1) queue: Queue[Value] = Queue(maxsize=1)
def on_success(val: Value) -> None: def on_success(val: Value) -> None:
print('hi mom')
queue.put(val) queue.put(val)
def on_error(err: MethodCallError) -> None: def on_error(err: MethodCallError) -> None:
print('Error while calling', service, method, args) print('Error while calling', service, method, args)
print('on_success', on_success)
call = MethodCall(method, call_args, on_success, on_error) call = MethodCall(method, call_args, on_success, on_error)
print( print(