diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index caab87d0b..dedb827a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -292,7 +292,7 @@ jobs: defaults: run: - working-directory: ./server/app + working-directory: ./server steps: - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} @@ -302,26 +302,26 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - python -m pip install ../../sdk + python -m pip install ../sdk python -m pip install .[dev] - name: Check typing with MyPy run: | - python -m mypy . + python -m mypy app test - name: Check code style with PyCodestyle run: | - python -m pycodestyle --count --max-line-length 120 . + python -m pycodestyle --count --max-line-length 120 app test - server-package: + server-repository-docker: # This job checks if we can build our server package runs-on: ubuntu-latest defaults: run: - working-directory: ./server + working-directory: ./server/docker/repository steps: - uses: actions/checkout@v4 - name: Build the Docker image run: | - docker build -t basyx-python-server -f Dockerfile .. + docker build -t basyx-python-server -f Dockerfile ../../.. - name: Run container run: | docker run -d --name basyx-python-server basyx-python-server diff --git a/server/README.md b/server/README.md index d368d4ae5..0d5203f9b 100644 --- a/server/README.md +++ b/server/README.md @@ -19,7 +19,7 @@ The container image can be built via: $ docker build -t basyx-python-server -f Dockerfile .. ``` -Note that when cloning this repository on Windows, Git may convert the line separators to CRLF. This breaks [`entrypoint.sh`](entrypoint.sh) and [`stop-supervisor.sh`](stop-supervisor.sh). Ensure both files use LF line separators (`\n`) before building. +Note that when cloning this repository on Windows, Git may convert the line separators to CRLF. This breaks [`entrypoint.sh`](docker/repository/entrypoint.sh) and [`stop-supervisor.sh`](docker/common/stop-supervisor.sh). Ensure both files use LF line separators (`\n`) before building. ## Running @@ -60,51 +60,13 @@ This implies the following start-up behaviour: - Any AAS/Submodel *already present* is skipped, unless `STORAGE_OVERWRITE = True`, in which case it is replaced. - Supplementary files (e.g., `File` SubmodelElements) are never persisted by the LocalFileBackend. -### Running Examples - -Putting it all together, the container can be started via the following command: -``` -$ docker run -p 8080:80 -v ./input:/input -v ./storage:/storage basyx-python-server -``` - -Since Windows uses backslashes instead of forward slashes in paths, you'll have to adjust the path to the storage directory there: -``` -> docker run -p 8080:80 -v .\input:/input -v .\storage:/storage basyx-python-server -``` - -By default, the server will use the standard settings described [above](#options). Those settings can be adapted in the following way: -``` -$ docker run -p 8080:80 -v ./input:/input2 -v ./storage:/storage2 -e API_BASE_PATH=/api/v3.1/ -e INPUT=/input2 -e STORAGE=/storage2 -e STORAGE_PERSISTENCY=True -e STORAGE_OVERWRITE=True basyx-python-server -``` - ## Building and Running the Image with Docker Compose -The container image can also be built and run via: -``` -$ docker compose up -``` - -An exemplary [`compose.yml`](compose.yml) file for the server is given [here](compose.yml): -```yaml -name: basyx-python-server -services: - app: - build: - context: .. - dockerfile: server/Dockerfile - ports: - - "8080:80" - volumes: - - ./input:/input - - ./storage:/storage - environment: - STORAGE_PERSISTENCY: True -``` +Example configurations can be found in the `./example_configurations` directory. -Input files are read from `./input` and stored persistently under `./storage` on your host system. The server can be accessed at http://localhost:8080/api/v3.0/ from your host system. -To get a different setup, the [`compose.yml`](compose.yml) file can be adapted using the options described [above](#options), similar to the third [running example](#running-examples). +Currently, we offer: -Note that the `Dockerfile` has to be specified explicitly via `dockerfile: server/Dockerfile`, as the build context must be set to the parent directory of `/server` to allow access to the local `/sdk`. +- [repository_standalone](example_configurations/repository_standalone/README.md): Standalone repository server ## Running without Docker (Debugging Only) diff --git a/server/app/__init__.py b/server/app/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/server/app/interfaces/base.py b/server/app/interfaces/base.py index 360ba8514..8234eddc2 100644 --- a/server/app/interfaces/base.py +++ b/server/app/interfaces/base.py @@ -25,7 +25,7 @@ from basyx.aas.adapter.json import StrictStrippedAASFromJsonDecoder, StrictAASFromJsonDecoder, AASToJsonEncoder from basyx.aas.adapter.xml import xml_serialization, XMLConstructables, read_aas_xml_element from basyx.aas.model import AbstractObjectStore -from util.converters import base64url_decode +from app.util.converters import base64url_decode T = TypeVar("T") diff --git a/server/app/interfaces/repository.py b/server/app/interfaces/repository.py index 18976c81b..c1ee513e5 100644 --- a/server/app/interfaces/repository.py +++ b/server/app/interfaces/repository.py @@ -22,7 +22,7 @@ from basyx.aas import model from basyx.aas.adapter import aasx -from util.converters import IdentifierToBase64URLConverter, IdShortPathConverter, base64url_decode +from app.util.converters import IdentifierToBase64URLConverter, IdShortPathConverter, base64url_decode from .base import ObjectStoreWSGIApp, APIResponse, is_stripped_request, HTTPApiDecoder, T diff --git a/server/app/services/__init__.py b/server/app/services/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/server/app/main.py b/server/app/services/run_repository.py similarity index 99% rename from server/app/main.py rename to server/app/services/run_repository.py index 3b37edab2..478e4d215 100644 --- a/server/app/main.py +++ b/server/app/services/run_repository.py @@ -14,7 +14,7 @@ from basyx.aas.adapter.aasx import DictSupplementaryFileContainer from basyx.aas.backend.local_file import LocalFileIdentifiableStore from basyx.aas.model.provider import DictIdentifiableStore -from interfaces.repository import WSGIApp +from app.interfaces.repository import WSGIApp from typing import Tuple, Union diff --git a/server/stop-supervisor.sh b/server/docker/common/stop-supervisor.sh similarity index 100% rename from server/stop-supervisor.sh rename to server/docker/common/stop-supervisor.sh diff --git a/server/supervisord.ini b/server/docker/common/supervisord.ini similarity index 100% rename from server/supervisord.ini rename to server/docker/common/supervisord.ini diff --git a/server/Dockerfile b/server/docker/repository/Dockerfile similarity index 72% rename from server/Dockerfile rename to server/docker/repository/Dockerfile index 7ad70bc66..eed1c1abe 100644 --- a/server/Dockerfile +++ b/server/docker/repository/Dockerfile @@ -15,10 +15,14 @@ RUN apk update && \ pip install uwsgi && \ apk del git bash - -COPY server/uwsgi.ini /etc/uwsgi/ -COPY server/supervisord.ini /etc/supervisor/conf.d/supervisord.ini -COPY server/stop-supervisor.sh /etc/supervisor/stop-supervisor.sh +# Copy only the files we need to run the container +# The argumentation for this is to keep the containers as slim as possible. +COPY ./sdk /sdk +COPY ./server/app /server/app +COPY ./server/pyproject.toml /server/pyproject.toml +COPY ./server/docker/repository/uwsgi.ini /etc/uwsgi/ +COPY ./server/docker/common/supervisord.ini /etc/supervisor/conf.d/supervisord.ini +COPY ./server/docker/common/stop-supervisor.sh /etc/supervisor/stop-supervisor.sh RUN chmod +x /etc/supervisor/stop-supervisor.sh # Makes it possible to use a different configuration @@ -41,17 +45,15 @@ ENV STORAGE_OVERWRITE=False VOLUME ["/input", "/storage"] # Copy the entrypoint that will generate Nginx additional configs -COPY server/entrypoint.sh /entrypoint.sh +COPY server/docker/repository/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] ENV SETUPTOOLS_SCM_PRETEND_VERSION=1.0.0 -COPY ./sdk /sdk -COPY ./server/app /app -WORKDIR /app -RUN pip install ../sdk -RUN pip install . +WORKDIR /server/app +RUN pip install ../../sdk +RUN pip install .. CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.ini"] diff --git a/server/entrypoint.sh b/server/docker/repository/entrypoint.sh similarity index 100% rename from server/entrypoint.sh rename to server/docker/repository/entrypoint.sh diff --git a/server/uwsgi.ini b/server/docker/repository/uwsgi.ini similarity index 79% rename from server/uwsgi.ini rename to server/docker/repository/uwsgi.ini index 9c54ae1cc..ac4294aca 100644 --- a/server/uwsgi.ini +++ b/server/docker/repository/uwsgi.ini @@ -1,5 +1,5 @@ [uwsgi] -wsgi-file = /app/main.py +wsgi-file = /server/app/services/run_repository.py socket = /tmp/uwsgi.sock chown-socket = nginx:nginx chmod-socket = 664 diff --git a/server/example_configurations/repository_standalone/README.md b/server/example_configurations/repository_standalone/README.md new file mode 100644 index 000000000..ce84c5f67 --- /dev/null +++ b/server/example_configurations/repository_standalone/README.md @@ -0,0 +1,15 @@ +# Repository Standalone + +This example Docker compose configuration starts a repository server. + +The container image can also be built and run via: +``` +$ docker compose up +``` + +Input files are read from `./input` and stored persistently under `./storage` on your host system. +The server can be accessed at http://localhost:8080/api/v3.0/ from your host system. +To get a different setup, the `compose.yaml` file can be adapted using the options described in the main server [README.md](../../README.md#options). + +Note that the `Dockerfile` has to be specified explicitly via `dockerfile: server/docker/repository/Dockerfile`, as the build context must be set to the repository root to allow access to the local `/sdk`. + diff --git a/server/compose.yml b/server/example_configurations/repository_standalone/compose.yaml similarity index 71% rename from server/compose.yml rename to server/example_configurations/repository_standalone/compose.yaml index f7e014c37..10e8b17f1 100644 --- a/server/compose.yml +++ b/server/example_configurations/repository_standalone/compose.yaml @@ -2,8 +2,8 @@ name: basyx-python-server services: app: build: - context: .. - dockerfile: server/Dockerfile + context: ../../.. + dockerfile: server/docker/repository/Dockerfile ports: - "8080:80" volumes: diff --git a/server/app/pyproject.toml b/server/pyproject.toml similarity index 90% rename from server/app/pyproject.toml rename to server/pyproject.toml index 030be7397..8c40deff9 100644 --- a/server/app/pyproject.toml +++ b/server/pyproject.toml @@ -16,8 +16,8 @@ build-backend = "setuptools.build_meta" # from app.version import version # print(f"Project version: {version}") # ``` -root = "../.." # Defines the path to the root of the repository -version_file = "version.py" +root = ".." # Defines the path to the root of the repository +version_file = "app/version.py" [project] name = "basyx-python-server" @@ -55,7 +55,7 @@ dev = [ "Homepage" = "https://github.com/eclipse-basyx/basyx-python-sdk" [tool.setuptools] -packages = { find = { exclude = ["test*"] } } +packages = { find = { include = ["app*"], exclude = ["test*"] } } [tool.setuptools.package-data] app = ["py.typed"] diff --git a/server/test/interfaces/test_repository.py b/server/test/interfaces/test_repository.py index 0c7f4c1a8..5cf421a51 100644 --- a/server/test/interfaces/test_repository.py +++ b/server/test/interfaces/test_repository.py @@ -34,7 +34,7 @@ from basyx.aas import model from basyx.aas.adapter.aasx import DictSupplementaryFileContainer -from server.app.interfaces.repository import WSGIApp +from app.interfaces.repository import WSGIApp from basyx.aas.examples.data.example_aas import create_full_example from typing import Set