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 .method import Method
class Container:
__slots__ = ('image', 'methods', )
__slots__ = ('image', 'runtime', )
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.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:
__slots__ = ('hash', )
from typing import Optional
class Image:
__slots__ = ('path', 'hash', )
path: Optional[str]
hash: str
def __init__(self, hash: str) -> None:
def __init__(self, path: Optional[str], hash: str) -> None:
self.path = path
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 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.router import MethodCallRouterInterface
from phasmplatform.common.service import Service, ServiceDiscoveryInterface
from phasmplatform.common.value import NoneValue
from phasmplatform.common.state import from_toml as state_from_toml
from .runners.base import RunnerInterface
from .runners.wasmtime import WasmTimeRunner
@ -23,7 +24,6 @@ def runner_thread(runner: RunnerInterface, queue: Queue[MethodCall]) -> None:
except Empty:
break
print('rt call', runner, queue, call)
runner.do_call(call)
@ -82,10 +82,14 @@ class LocalhostMethodCallRouter(MethodCallRouterInterface):
def main() -> int:
with open('config.toml', 'rb') as fil:
config = from_toml(fil)
config = config_from_toml(fil)
del config
with open('./examples/echoserver.toml', 'rb') as fil:
state = state_from_toml(fil)
print(state)
localhost_queue: Queue[MethodCall] = Queue()
echo_client_queue: Queue[MethodCall] = Queue()
echo_server_queue: Queue[MethodCall] = Queue()
@ -96,7 +100,7 @@ def main() -> int:
localhost = LocalhostRunner()
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())
service_discovery.register_service(Service('echoserver', [
Method('echo', [
@ -104,7 +108,7 @@ def main() -> int:
], valuetype.bytes)
]), 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())
# service_discovery.register_service(echo_client, echo_client_queue)

View File

@ -67,9 +67,6 @@ class BaseRunner(RunnerInterface):
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:
line_width = 16

View File

@ -32,12 +32,6 @@ class WasmTimeRunner(BaseRunner):
self.store = wasmtime.Store()
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] = []
for imprt in self.module.imports:
service = service_discovery.find_service(imprt.module)
@ -125,13 +119,11 @@ class WasmTimeRunner(BaseRunner):
queue: Queue[Value] = Queue(maxsize=1)
def on_success(val: Value) -> None:
print('hi mom')
queue.put(val)
def on_error(err: MethodCallError) -> None:
print('Error while calling', service, method, args)
print('on_success', on_success)
call = MethodCall(method, call_args, on_success, on_error)
print(