Skip to content

Commit

Permalink
feat: graceful shutdown; logging fix; small image-90MB
Browse files Browse the repository at this point in the history
  • Loading branch information
kentbull committed Dec 21, 2024
1 parent 2d54cce commit 2ead9ad
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 57 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ push-all:

.PHONY: build-vlei
build-vlei:
@docker buildx build --platform=linux/amd64 --no-cache -f container/Dockerfile --tag gleif/vlei:latest --tag gleif/vlei:0.1.0 .
@docker buildx build --load --platform=linux/amd64 -f container/Dockerfile --tag gleif/vlei:latest --tag gleif/vlei:0.2.1 .
52 changes: 45 additions & 7 deletions container/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,53 @@
FROM python:3.10.4-buster
FROM python:3.12.6-slim AS builder

RUN apt-get update
RUN apt-get install -y ca-certificates
# Install compilation dependencies for Ubuntu including ca-certificates, libffi, and libsodium
RUN apt-get update && apt-get install -y \
build-essential \
libffi-dev \
libsodium-dev \
libssl-dev \
python3-dev \
python3-venv \
python3-pip \
curl

SHELL ["/bin/bash", "-c"]

# Setup Rust for blake3 dependency build
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y

WORKDIR /vLEI

RUN python -m venv venv
ENV PATH=/vLEI/venv/bin:${PATH}
RUN pip install --upgrade pip

COPY requirements.txt setup.py /vLEI/
RUN mkdir /vLEI/src

# Build vLEI-server
RUN . "$HOME/.cargo/env" && \
pip install -r requirements.txt

# Create smaller runner image by copying over built binary
FROM python:3.12.6-slim AS runner

RUN apt-get update
RUN apt-get install -y libsodium23

# Prevents Python from buffering stdout and stderr, logs to stdout immediately
ENV PYTHONUNBUFFERED=1
# Set default encoding to UTF-8
ENV PYTHONIOENCODING=UTF-8

WORKDIR /usr/local/var/
RUN git clone https://github.com/WebOfTrust/vLEI
WORKDIR /vLEI

COPY --from=builder /vLEI /vLEI
COPY src/ src/
COPY ./schema/acdc /vLEI/schema
COPY ./samples/acdc /vLEI/credentials
COPY ./samples/oobis /vLEI/oobis

ENV PATH=/vLEI/venv/bin:${PATH}

WORKDIR /usr/local/var/vLEI
RUN pip install -r requirements.txt
CMD ["vLEI-server", "-s", "/vLEI/schema", "-c", "/vLEI/credentials", "-o", "/vLEI/oobis"]
48 changes: 24 additions & 24 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from setuptools import find_packages, setup
setup(
name='vlei',
version='0.0.1', # also change in src/vlei/__init__.py
version='0.2.1', # 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",
Expand All @@ -51,7 +51,7 @@
'Operating System :: Unix',
'Operating System :: POSIX',
'Operating System :: Microsoft :: Windows',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: Implementation :: CPython',
'Topic :: Utilities',
],
Expand All @@ -61,34 +61,34 @@
'Issue Tracker': 'https://github.com/WebOfTrust/keripy/issues',
},
keywords=[
# eg: 'keyword1', 'keyword2', 'keyword3',
'keri','acdc','vlei'
],
python_requires='>=3.10.4',
python_requires='>=3.12.2',
install_requires=[
'lmdb>=1.2.1',
'pysodium>=0.7.9',
'blake3>=0.2.0',
'msgpack>=1.0.2',
'cbor2>=5.4.1',
'multidict>=5.1.0',
'ordered-set>=4.1.0',
'hio>=0.5.8',
'multicommand>=0.1.1',
'jsonschema>=3.2.0',
'falcon>=3.0.1',
'daemonocle>=1.2.3',
'hjson>=3.0.2',
'PyYaml>=6.0',
'apispec>=5.1.1',
'mnemonic>=0.20',
'keri>=1.0.0',
'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',
],
extras_require={
},
tests_require=[
'coverage>=5.5',
'pytest>=6.2.5',
],
'coverage>=7.4.4',
'pytest>=8.1.1',
],
setup_requires=[
],
entry_points={
Expand Down
2 changes: 1 addition & 1 deletion src/vlei/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-

__version__ = '0.1.1' # also change in setup.py
__version__ = '0.2.1' # also change in setup.py

6 changes: 4 additions & 2 deletions src/vlei/app/caching.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import os

from keri.core import scheming
from keri import help

logger = help.ogler.getLogger()

def cacheSchema(path, d):
for root, dirs, files in os.walk(path):
Expand All @@ -16,7 +18,7 @@ def cacheSchema(path, d):
with open(os.path.join(root, file), 'r') as f:
ked = json.load(f)
schemer = scheming.Schemer(sed=ked)
print(f"caching schema {schemer.said}")
logger.info(f"caching schema {schemer.said}")
d[schemer.said] = schemer.raw

return d
Expand All @@ -28,7 +30,7 @@ def cacheCredential(path, d):
if file.endswith('-acdc.cesr'):
with open(os.path.join(root, file), 'r') as f:
said = file.removesuffix('-acdc.cesr')
print(f"caching credential {said}")
logger.info(f"caching credential {said}")
d[said] = f.read()

return d
Expand Down
2 changes: 1 addition & 1 deletion src/vlei/app/generating.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from keri.core import coring


def populateSAIDS(d: dict, idage: str = coring.Ids.dollar, code: str = coring.MtrDex.Blake3_256):
def populateSAIDS(d: dict, idage: str = coring.Saids.dollar, code: str = coring.MtrDex.Blake3_256):
if 'properties' in d:
props = d['properties']

Expand Down
5 changes: 5 additions & 0 deletions src/vlei/app/serving.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@


class SchemaEnd:
"""Returns ACDC credential schemas on HTTP GET"""

def __init__(self, schemaDir, credDir):
self.schemaCache = caching.cacheSchema(schemaDir, dict())
self.credentialCache = caching.cacheCredential(credDir, dict())

def on_get(self, _, rep, said):
"""
Returns either ACDC JSON Schema or ACDC Credential if the key (SAID) is in the cache.
The cache is loaded on startup with the -s (schema) and -c (credentials) arguments.
"""
if said in self.schemaCache:
data = self.schemaCache[said]

Expand Down
19 changes: 10 additions & 9 deletions src/vlei/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import os
from pathlib import Path

from keri.core import scheming, coring
from keri.core import coring, scheming

from vlei.app import generating


Expand All @@ -23,43 +24,43 @@ def main():
# legal entity -> qvi edge
p = f'{path}/../../schema/acdc/legal-entity-vLEI-credential.json'
le = __load(p)
le['properties']['e']['oneOf'][1]['properties']['qvi']["properties"]['s']['const'] = qvi[coring.Ids.dollar]
le['properties']['e']['oneOf'][1]['properties']['qvi']["properties"]['s']['const'] = qvi[coring.Saids.dollar]
le = generating.populateSAIDS(le)
__save(p, le)

# oor auth -> le edge
p = f'{path}/../../schema/acdc/oor-authorization-vlei-credential.json'
oorAuth = __load(p)
oorAuth['properties']['e']['oneOf'][1]['properties']['le']["properties"]['s']['const'] = le[coring.Ids.dollar]
oorAuth['properties']['e']['oneOf'][1]['properties']['le']["properties"]['s']['const'] = le[coring.Saids.dollar]
oorAuth = generating.populateSAIDS(oorAuth)
__save(p, oorAuth)

# oor -> oor auth edge
p = f'{path}/../../schema/acdc/legal-entity-official-organizational-role-vLEI-credential.json'
oor = __load(p)
oor['properties']['e']['oneOf'][1]['properties']['auth']["properties"]['s']['const'] = oorAuth[coring.Ids.dollar]
oor['properties']['e']['oneOf'][1]['properties']['auth']["properties"]['s']['const'] = oorAuth[coring.Saids.dollar]
oor = generating.populateSAIDS(oor)
__save(p, oor)

# ecr auth -> le edge
p = f'{path}/../../schema/acdc/ecr-authorization-vlei-credential.json'
ecrAuth = __load(p)
ecrAuth['properties']['e']['oneOf'][1]['properties']['le']["properties"]['s']['const'] = le[coring.Ids.dollar]
ecrAuth['properties']['e']['oneOf'][1]['properties']['le']["properties"]['s']['const'] = le[coring.Saids.dollar]
ecrAuth = generating.populateSAIDS(ecrAuth)
__save(p, ecrAuth)

# ecr -> ecr auth edge and le edge
p = f'{path}/../../schema/acdc/legal-entity-engagement-context-role-vLEI-credential.json'
ecr = __load(p)
ecr['properties']['e']['oneOf'][1]['properties']['auth']["properties"]['s']['const'] = ecrAuth[coring.Ids.dollar]
ecr['properties']['e']['oneOf'][2]['properties']['le']["properties"]['s']['const'] = le[coring.Ids.dollar]
ecr['properties']['e']['oneOf'][1]['properties']['auth']["properties"]['s']['const'] = ecrAuth[coring.Saids.dollar]
ecr['properties']['e']['oneOf'][2]['properties']['le']["properties"]['s']['const'] = le[coring.Saids.dollar]
ecr = generating.populateSAIDS(ecr)
__save(p, ecr)

p = f'{path}/../../schema/acdc/verifiable-ixbrl-report-attestation.json'
vira = __load(p)
vira['properties']['e']['oneOf'][0]['properties']['oor']["properties"]['s']['const'] = oor[coring.Ids.dollar]
vira['properties']['e']['oneOf'][1]['properties']['ecr']["properties"]['s']['const'] = ecr[coring.Ids.dollar]
vira['properties']['e']['oneOf'][0]['properties']['oor']["properties"]['s']['const'] = oor[coring.Saids.dollar]
vira['properties']['e']['oneOf'][1]['properties']['ecr']["properties"]['s']['const'] = ecr[coring.Saids.dollar]
vira = generating.populateSAIDS(vira)
__save(p, vira)

Expand Down
20 changes: 17 additions & 3 deletions src/vlei/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
"""
import argparse
import logging
import signal

import falcon
from hio.base import doing
from hio.core import http, tcp

from keri import help

from vlei.app import serving

parser = argparse.ArgumentParser(description="Runs vLEI schema server")
Expand All @@ -35,6 +39,8 @@
parser.add_argument("--cafilepath", action="store", required=False, default=None,
help="TLS server CA certificate chain")

logger = help.ogler.getLogger()


def createHttpServer(port, app, keypath=None, certpath=None, cafilepath=None):
"""
Expand Down Expand Up @@ -62,15 +68,16 @@ def createHttpServer(port, app, keypath=None, certpath=None, cafilepath=None):


def launch(args):
logger.setLevel(logging.INFO)
app = falcon.App()
port = int(args.http)
keypath = args.keypath
certpath = args.certpath
cafilepath = args.cafilepath
if keypath is not None and certpath is not None and cafilepath is not None:
print(f"Starting on port {port} with TLS enabled")
logger.info(f"vLEI-server starting on port {port} with TLS enabled")
else:
print(f"Starting on port {port} with TLS disabled")
logger.info(f"vLEI-server starting on port {port} with TLS disabled")
server = createHttpServer(port=int(args.http), app=app,
keypath=args.keypath, certpath=args.certpath,
cafilepath=args.cafilepath)
Expand All @@ -82,10 +89,17 @@ def launch(args):

doers = [httpServerDoer]

# Shutdown hook
def shutdownHandler(sig, frame):
logger.info("Received signal %s", signal.strsignal(sig))
doist.exit()
signal.signal(signal.SIGTERM, shutdownHandler)

tock = 0.03125
doist = doing.Doist(limit=0.0, tock=tock, real=True)
doist.do(doers=doers)
doist.do(doers=doers) # Enters the doist loop until shutdown

logger.info("vLEI-server stopped")

def main():
args = parser.parse_args()
Expand Down
16 changes: 7 additions & 9 deletions tests/test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from pathlib import Path

import pytest
from keri.core import scheming, coring
from keri.core import coring, scheming
from keri.kering import ValidationError


Expand Down Expand Up @@ -59,21 +59,21 @@ def test_legal_entity_chain():
qvi = json.load(open(f'{__path()}/../schema/acdc/qualified-vLEI-issuer-vLEI-credential.json', 'r'))
le = json.load(open(f'{__path()}/../schema/acdc/legal-entity-vLEI-credential.json', 'r'))

assert le['properties']['e']['oneOf'][1]['properties']['qvi']["properties"]['s']['const'] == qvi[coring.Ids.dollar]
assert le['properties']['e']['oneOf'][1]['properties']['qvi']["properties"]['s']['const'] == qvi[coring.Saids.dollar]


def test_ecr_auth_chain():
auth = json.load(open(f'{__path()}/../schema/acdc/ecr-authorization-vlei-credential.json', 'r'))

assert auth['properties']['e']['oneOf'][1]['properties']['le']["properties"]['s']['const'] == __le()[
coring.Ids.dollar]
coring.Saids.dollar]


def test_oor_auth_chain():
auth = json.load(open(f'{__path()}/../schema/acdc/oor-authorization-vlei-credential.json', 'r'))

assert auth['properties']['e']['oneOf'][1]['properties']['le']["properties"]['s']['const'] == __le()[
coring.Ids.dollar]
coring.Saids.dollar]


def test_oor_chain():
Expand All @@ -83,18 +83,16 @@ def test_oor_chain():
auth = json.load(open(f'{Path(__file__).parent}/../schema/acdc/oor-authorization-vlei-credential.json', 'r'))

assert oor['properties']['e']['oneOf'][1]['properties']['auth']["properties"]['s']['const'] == auth[
coring.Ids.dollar]
coring.Saids.dollar]


def test_ecr_chain():
auth = json.load(open(f'{__path()}/../schema/acdc/ecr-authorization-vlei-credential.json', 'r'))
ecr = json.load(
open(f'{__path()}/../schema/acdc/legal-entity-engagement-context-role-vLEI-credential.json', 'r'))

assert ecr['properties']['e']['oneOf'][1]['properties']['auth']["properties"]['s']['const'] == auth[
coring.Ids.dollar]
assert ecr['properties']['e']['oneOf'][2]['properties']['le']["properties"]['s']['const'] == __le()[
coring.Ids.dollar]
assert ecr['properties']['e']['oneOf'][1]['properties']['auth']["properties"]['s']['const'] == auth[coring.Saids.dollar]
assert ecr['properties']['e']['oneOf'][2]['properties']['le']["properties"]['s']['const'] == __le()[coring.Saids.dollar]


def __le():
Expand Down

0 comments on commit 2ead9ad

Please sign in to comment.