diff --git a/Makefile b/Makefile index 9c8312d..f33a723 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: push-all VERSION=0.2.2 -IMAGE_NAME=kentbull/vlei +IMAGE_NAME=gleif/vlei push-all: @docker push $(IMAGE_NAME) --all-tags diff --git a/README.md b/README.md index faace6b..8b4324e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# vLEI +# vLEI Server + +Verifiable Legal Entity Identifier Schema Generator and Server | main | dev | |--------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------| diff --git a/setup.py b/setup.py index c07ace1..9cbd451 100644 --- a/setup.py +++ b/setup.py @@ -27,14 +27,23 @@ from glob import glob from os.path import basename from os.path import splitext +from pathlib import Path from setuptools import find_packages, setup + +this_directory = Path(__file__).parent +if (this_directory / "README.md").exists(): # If building inside a container, like in the `container/Dockerfile`, this file won't exist and fails the build + long_description = (this_directory / "README.md").read_text() +else: + long_description = "Verifiable Legal Entity Identifier Schema Generator and Server" + setup( name='vlei', - version='0.2.1', # also change in src/vlei/__init__.py + version='0.2.2', # also change in src/vlei/__init__.py license='Apache Software License 2.0', description='Verifiable Legal Entity Identifier', - long_description="Verifiable Legal Entity Identifier Schema Generator and Server", + long_description=long_description, + long_description_content_type='text/markdown', author='Samuel M. Smith', author_email='smith.samuel.m@gmail.com', url='https://github.com/WebOfTrust/vLEI', @@ -65,32 +74,20 @@ ], python_requires='>=3.12.2', install_requires=[ - 'lmdb>=1.4.1', - 'pysodium>=0.7.17', - 'blake3>=0.4.1', - 'msgpack>=1.0.8', - 'cbor2>=5.6.2', - 'multidict>=6.0.5', - 'ordered-set>=4.1.0', 'hio==0.6.14', - 'multicommand>=1.0.0', - 'jsonschema>=4.21.1', - 'falcon>=3.1.3', - 'daemonocle>=1.2.3', - 'hjson>=3.1.0', - 'PyYaml>=6.0.2', - 'apispec>=6.8.0', - 'mnemonic>=0.21', - 'keri>=1.2.1', + 'keri>=1.2.2', + 'falcon>=4.0.2', + 'multicommand>=1.0.0' ], extras_require={ }, tests_require=[ - 'coverage>=7.4.4', - 'pytest>=8.1.1', -'requests==2.32.3' + 'coverage>=7.6.10', + 'pytest>=8.3.4', + 'requests==2.32.3' ], setup_requires=[ + 'setuptools==75.8.0' ], entry_points={ 'console_scripts': [ diff --git a/src/vlei/__init__.py b/src/vlei/__init__.py index f4ee8d0..f8ff8c6 100644 --- a/src/vlei/__init__.py +++ b/src/vlei/__init__.py @@ -1,4 +1,4 @@ # -*- encoding: utf-8 -*- -__version__ = '0.2.1' # also change in setup.py +__version__ = '0.2.2' # also change in setup.py diff --git a/src/vlei/app/serving.py b/src/vlei/app/serving.py index 41f81f7..2361f19 100644 --- a/src/vlei/app/serving.py +++ b/src/vlei/app/serving.py @@ -9,6 +9,7 @@ import falcon from hio.core import http from keri import help +from keri.help import nowIso8601 from vlei.app import caching @@ -78,6 +79,12 @@ def on_get(self, req, rep, alias): url = p.open().read() raise falcon.HTTPMovedPermanently(location=url) +class HealthEnd: + """Health resource for determining that a container is live""" + + def on_get(self, req, resp): + resp.status = falcon.HTTP_OK + resp.media = {"message": f"Health is okay. Time is {nowIso8601()}"} def loadEnds(app, schemaDir, credDir, oobiDir): sink = http.serving.StaticSink(staticDirPath="./static") @@ -88,3 +95,6 @@ def loadEnds(app, schemaDir, credDir, oobiDir): wellknownEnd = WellKnownEnd(oobiDir) app.add_route("/.well-known/keri/oobi/{alias}", wellknownEnd) + + healthEnd = HealthEnd() + app.add_route("/health", healthEnd) diff --git a/src/vlei/app/shutdown.py b/src/vlei/app/shutdown.py index db269a8..ad3f90e 100644 --- a/src/vlei/app/shutdown.py +++ b/src/vlei/app/shutdown.py @@ -45,7 +45,6 @@ def enter(self): def recur(self, tock=0.0): """Generator coroutine checking once per tock for shutdown flag""" # Checks once per tock if the shutdown flag has been set and if so initiates the shutdown process - logger.info("Recurring graceful shutdown doer") while not self.shutdown_received: yield tock # will iterate forever in here until shutdown flag set diff --git a/src/vlei/server.py b/src/vlei/server.py index 61645ab..45847d6 100644 --- a/src/vlei/server.py +++ b/src/vlei/server.py @@ -50,11 +50,11 @@ class VLEIConfig: # HTTP port to listen on http: int = 7723 # ACDC schema directory - schemaDir: str = None + schemaDir: str = "./schema/acdc/" # ACDC material directory - credDir: str = None + credDir: str = "./samples/acdc/" # Well known OOBI directory - oobiDir: str = None + oobiDir: str = "./samples/oobis/" # TLS key material keypath: str = None certpath: str = None diff --git a/tests/test_server.py b/tests/test_server.py index e69de29..389d534 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -0,0 +1,46 @@ +import multiprocessing +import os +import signal +import time + +import requests + +from vlei import server + + +def wait_for_server(port, timeout=10): + """Poll server until it responds or until timeout""" + url=f"http://127.0.0.1:{port}/health" + start_time=time.time() + while time.time() - start_time < timeout: + try: + response = requests.get(url) + if response.status_code == 200: + return True # Server is up + except requests.ConnectionError: + pass # Server not ready yet + time.sleep(0.25) # Retry every 1/4 second + return False # Timeout + +def test_shutdown_signals(): + config = server.VLEIConfig(http=9999) + + # Test SIGTERM + vlei_process = multiprocessing.Process(target=server.launch, args=[config]) + vlei_process.start() + assert wait_for_server(config.http), "vLEI-server did not start as expected." + + os.kill(vlei_process.pid, signal.SIGTERM) # Send SigTerm to the process, signal 15 + vlei_process.join(timeout=10) + assert not vlei_process.is_alive(), "SIGTERM: vLEI-server process did not shut down as expected." + assert vlei_process.exitcode == 0, f"SIGTERM: vLEI-server exited with non-zero exit code {vlei_process.exitcode}" + + # Test SIGINT + vlei_process = multiprocessing.Process(target=server.launch, args=[config]) + vlei_process.start() + assert wait_for_server(config.http), "Agency did not start as expected." + + os.kill(vlei_process.pid, signal.SIGINT) # Sends SigInt to the process, signal 2 + vlei_process.join(timeout=10) + assert not vlei_process.is_alive(), "SIGINT: vLEI-server process did not shut down as expected." + assert vlei_process.exitcode == 0, f"SIGINT: vLEI-server exited with non-zero exit code {vlei_process.exitcode}"