State loading from toml
This commit is contained in:
parent
45cafdf327
commit
628fb775e8
13
examples/echoclient.toml
Normal file
13
examples/echoclient.toml
Normal 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
34
examples/echoserver.toml
Normal 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"} ]
|
||||||
@ -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)})'
|
||||||
|
|||||||
@ -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)})'
|
||||||
|
|||||||
103
phasmplatform/common/state.py
Normal file
103
phasmplatform/common/state.py
Normal 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)
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user