Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
ce642c1
Füge experimentelle Änderungen für Registry und Discovery hinzu
Ornella33 Mar 25, 2025
7204ae2
Remove test.py from repository and add it to .gitignore
Ornella33 Mar 31, 2025
25cf282
correct discovery server implementation
Ornella33 Apr 1, 2025
b68efaa
remove unused code
Ornella33 Apr 2, 2025
b590e1c
add in-memory storage and adapt README
Ornella33 Apr 14, 2025
1b676e7
change main.py and disccovery.py
Ornella33 Apr 14, 2025
7cff8cf
Extract server-related components into server app
zrgt Apr 15, 2025
a6577be
Refactor `_get_aas_class_parsers`
zrgt Apr 15, 2025
11c59bc
fix aas_descriptor construct method
Ornella33 Apr 15, 2025
6d4aab1
Refactor `read_aas_json_file_into`
zrgt Apr 15, 2025
a34230f
Refactor `default()`
zrgt Apr 15, 2025
9079d82
fix method update_from
Ornella33 Apr 15, 2025
bd2a9c7
Merge remote-tracking branch 'rwth-iat/Experimental/server_app' into …
zrgt Apr 15, 2025
a366538
Refactor `_create_dict()`
zrgt Apr 15, 2025
72297f4
Remove `jsonization._create_dict` as not used
zrgt Apr 15, 2025
bd48dec
Split `http.py` into `repository` and `http_api_helpers`
zrgt Apr 15, 2025
6fd1612
Refactor server_model and move create interfaces folder
zrgt Apr 16, 2025
eba1d89
Refactor `result_to_xml` and `message_to_xml`
zrgt Apr 16, 2025
4acab0d
Move all response related to `response.py`
zrgt Apr 16, 2025
567b5f1
Create base classes for WSGI apps
zrgt Apr 16, 2025
3d15b51
Refactor `http_api_helpers.py` and `response.py`
zrgt Apr 16, 2025
cb107ed
Reformat code with PyCharm
zrgt Apr 16, 2025
4e1c647
Small fixes
zrgt Apr 17, 2025
95b2d5a
Refactor
zrgt Apr 17, 2025
b65c420
Refactor
zrgt Apr 17, 2025
b0f79d6
Refactor some methods in registry.py and fix some typos
Ornella33 Apr 17, 2025
7c8fbe2
remove xmlization for Registry and Discovery classes
Ornella33 Apr 17, 2025
eb44e8a
change according to xmlization removal for registry and discovery cla…
Ornella33 Apr 17, 2025
d608409
fix error with ServerAASToJSONEncoder
Ornella33 Apr 22, 2025
dde2499
Refactor `response.py`
zrgt Apr 23, 2025
df38540
Refactor utils
zrgt Apr 23, 2025
1da157f
Rename `server_model` to `model`
zrgt Apr 23, 2025
a96da47
correct typos from renaming server_model to model
Ornella33 Apr 24, 2025
115db62
Remove discovery/registry related code
zrgt May 22, 2025
65d1918
Merge remote-tracking branch 'rwth-iat/develop' into refactor/server
zrgt May 22, 2025
0c36396
Add missing code from PR #362
zrgt May 22, 2025
6b3c646
Revert changes in .gitignore
zrgt May 22, 2025
0a8546e
Fix copyright
zrgt May 22, 2025
bfd1411
Refactor `test_http.py` to `test_repository.py`
zrgt May 22, 2025
1fd76de
fix copyright
Frosty2500 May 29, 2025
a783066
fix MyPy errors, some tests
Frosty2500 May 29, 2025
66f3320
fix bugs, reintroduce Identifiable check
Frosty2500 Jun 3, 2025
3226718
Revert "Remove discovery/registry related code"
zrgt Jun 17, 2025
1268f6a
correct json serialisation for AASDescriptor
Ornella33 Apr 24, 2025
74b64d2
adapt filter options for get_all_aas_descritors and remove filter for…
Ornella33 Apr 25, 2025
b64d589
add service description
Ornella33 Apr 25, 2025
e494d3c
Merge remote-tracking branch 'rwth-iat/refactor/server' into refactor…
zrgt Jun 17, 2025
1de92b3
clean code
Ornella33 Jun 23, 2025
59748cf
add README and docker deployment for registry
Ornella33 Jul 8, 2025
a7efefc
remove files from another branch
Ornella33 Jul 8, 2025
d3d4dbb
Stop tracking unnecessary files
Ornella33 Jul 8, 2025
673f18d
Update README
Ornella33 Jul 15, 2025
a581603
add docker deployment for discovery service
Ornella33 Jul 15, 2025
42dd189
Update repository
Ornella33 Jul 15, 2025
d37bc01
Ignore test.py
Ornella33 Jul 15, 2025
d907b01
Merge remote-tracking branch 'origin/develop' into experimental/regis…
Ornella33 Jul 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ compliance_tool/aas_compliance_tool/version.py

# ignore the content of the server storage
server/storage/
test.py
/storage/
50 changes: 50 additions & 0 deletions discovery_server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
FROM python:3.11-alpine

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PYTHONPATH="${PYTHONPATH}:/app"

# If we have more dependencies for the server it would make sense
# to refactor uswgi to the pyproject.toml
RUN apk update && \
apk add --no-cache nginx supervisor gcc musl-dev linux-headers python3-dev git bash && \
pip install uwsgi && \
apk del git bash


COPY discovery_server/uwsgi.ini /etc/uwsgi/
COPY discovery_server/supervisord.ini /etc/supervisor/conf.d/supervisord.ini
COPY discovery_server/stop-supervisor.sh /etc/supervisor/stop-supervisor.sh
RUN chmod +x /etc/supervisor/stop-supervisor.sh

# Makes it possible to use a different configuration
ENV UWSGI_INI=/etc/uwsgi/uwsgi.ini
# object stores aren't thread-safe yet
# https://github.com/eclipse-basyx/basyx-python-sdk/issues/205
ENV UWSGI_CHEAPER=0
ENV UWSGI_PROCESSES=1
ENV NGINX_MAX_UPLOAD=1M
ENV NGINX_WORKER_PROCESSES=1
ENV LISTEN_PORT=80
ENV CLIENT_BODY_BUFFER_SIZE=1M

# Copy the entrypoint that will generate Nginx additional configs
COPY discovery_server/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

ENV SETUPTOOLS_SCM_PRETEND_VERSION=1.0.0


COPY ./discovery_server/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY ./sdk /sdk
COPY ./server /app/server
COPY ./discovery_server/app /app

WORKDIR /app
RUN pip install ../sdk

CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.ini"]
48 changes: 48 additions & 0 deletions discovery_server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Eclipse BaSyx Python SDK - Discovery Service

This is a Python-based implementation of the **BaSyx Asset Administration Shell (AAS) Discovery Service**.
It provides basic discovery functionality for AAS IDs and their corresponding assets, as specified in the official [Discovery Service Specification v3.1.0_SSP-001](https://app.swaggerhub.com/apis/Plattform_i40/DiscoveryServiceSpecification/V3.1.0_SSP-001).

## Overview

The Discovery Service stores and retrieves relations between AAS identifiers and asset identifiers. It acts as a lookup service for resolving asset-related queries to corresponding AAS.

## Features

| Function | Description | Example URL |
|------------------------------------------|----------------------------------------------------------|-----------------------------------------------------------------------|
| **search_all_aas_ids_by_asset_link** | Find AAS identifiers by providing asset link values | `POST http://localhost:8084/api/v3.0/lookup/shellsByAssetLink` |
| **get_all_specific_asset_ids_by_aas_id** | Return specific asset ids associated with an AAS ID | `GET http://localhost:8084/api/v3.0/lookup/shells/{aasIdentifier}` |
| **post_all_asset_links_by_id** | Register specific asset ids linked to an AAS | `POST http://localhost:8084/api/v3.0/lookup/shells/{aasIdentifier}` |
| **delete_all_asset_links_by_id** | Delete all asset links associated with a specific AAS ID | `DELETE http://localhost:8084/api/v3.0/lookup/shells/{aasIdentifier}` |
|

## Configuration

The service can be configured to use either:

- **In-memory storage** (default): Temporary data storage that resets on service restart.
- **MongoDB storage**: Persistent backend storage using MongoDB.

### Configuration via Environment Variables

| Variable | Description | Default |
|------------------|--------------------------------------------|-----------------------------|
| `STORAGE_TYPE` | `inmemory` or `mongodb` | `inmemory` |
| `MONGODB_URI` | MongoDB connection URI | `mongodb://localhost:27017` |
| `MONGODB_DBNAME` | Name of the MongoDB database | `basyx_registry` |

## Deployment via Docker

A `Dockerfile` and `docker-compose.yml` are provided for simple deployment.
The container image can be built and run via:
```bash
docker compose up --build
```
## Test

Examples of asset links and specific asset IDs for testing purposes are provided as JSON files in the [storage](./storage) folder.

## Acknowledgments

This Dockerfile is inspired by the [tiangolo/uwsgi-nginx-docker](https://github.com/tiangolo/uwsgi-nginx-docker) repository.
25 changes: 25 additions & 0 deletions discovery_server/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os
import sys
from server.app.interfaces.discovery import DiscoveryAPI, MongoDiscoveryStore,InMemoryDiscoveryStore

storage_type = os.getenv("STORAGE_TYPE", "inmemory")
base_path = os.getenv("API_BASE_PATH")

wsgi_optparams = {}

if base_path is not None:
wsgi_optparams["base_path"] = base_path

if storage_type == "inmemory":
application = DiscoveryAPI(InMemoryDiscoveryStore(), **wsgi_optparams)

elif storage_type == "mongodb":
uri = os.getenv("MONGODB_URI", "mongodb://localhost:27017")
dbname = os.getenv("MONGODB_DBNAME", "basyx_registry")

application = DiscoveryAPI(MongoDiscoveryStore(uri,dbname), **wsgi_optparams)

else:
print(f"STORAGE_TYPE must be either inmemory or mongodb! Current value: {storage_type}",
file=sys.stderr)

9 changes: 9 additions & 0 deletions discovery_server/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
app:
build:
context: ..
dockerfile: discovery_server/Dockerfile
ports:
- "8084:80"
environment:
- STORAGE_TYPE=inmemory
71 changes: 71 additions & 0 deletions discovery_server/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env sh
set -e

# Get the maximum upload file size for Nginx, default to 0: unlimited
USE_NGINX_MAX_UPLOAD=${NGINX_MAX_UPLOAD:-0}

# Get the number of workers for Nginx, default to 1
USE_NGINX_WORKER_PROCESSES=${NGINX_WORKER_PROCESSES:-1}

# Set the max number of connections per worker for Nginx, if requested
# Cannot exceed worker_rlimit_nofile, see NGINX_WORKER_OPEN_FILES below
NGINX_WORKER_CONNECTIONS=${NGINX_WORKER_CONNECTIONS:-1024}

# Get the listen port for Nginx, default to 80
USE_LISTEN_PORT=${LISTEN_PORT:-80}

# Get the client_body_buffer_size for Nginx, default to 1M
USE_CLIENT_BODY_BUFFER_SIZE=${CLIENT_BODY_BUFFER_SIZE:-1M}

# Create the conf.d directory if it doesn't exist
if [ ! -d /etc/nginx/conf.d ]; then
mkdir -p /etc/nginx/conf.d
fi

if [ -f /app/nginx.conf ]; then
cp /app/nginx.conf /etc/nginx/nginx.conf
else
content='user nginx;\n'
# Set the number of worker processes in Nginx
content=$content"worker_processes ${USE_NGINX_WORKER_PROCESSES};\n"
content=$content'error_log /var/log/nginx/error.log warn;\n'
content=$content'pid /var/run/nginx.pid;\n'
content=$content'events {\n'
content=$content" worker_connections ${NGINX_WORKER_CONNECTIONS};\n"
content=$content'}\n'
content=$content'http {\n'
content=$content' include /etc/nginx/mime.types;\n'
content=$content' default_type application/octet-stream;\n'
content=$content' log_format main '"'\$remote_addr - \$remote_user [\$time_local] \"\$request\" '\n"
content=$content' '"'\$status \$body_bytes_sent \"\$http_referer\" '\n"
content=$content' '"'\"\$http_user_agent\" \"\$http_x_forwarded_for\"';\n"
content=$content' access_log /var/log/nginx/access.log main;\n'
content=$content' sendfile on;\n'
content=$content' keepalive_timeout 65;\n'
content=$content' include /etc/nginx/conf.d/*.conf;\n'
content=$content'}\n'
content=$content'daemon off;\n'
# Set the max number of open file descriptors for Nginx workers, if requested
if [ -n "${NGINX_WORKER_OPEN_FILES}" ] ; then
content=$content"worker_rlimit_nofile ${NGINX_WORKER_OPEN_FILES};\n"
fi
# Save generated /etc/nginx/nginx.conf
printf "$content" > /etc/nginx/nginx.conf

content_server='server {\n'
content_server=$content_server" listen ${USE_LISTEN_PORT};\n"
content_server=$content_server' location / {\n'
content_server=$content_server' include uwsgi_params;\n'
content_server=$content_server' uwsgi_pass unix:///tmp/uwsgi.sock;\n'
content_server=$content_server' }\n'
content_server=$content_server'}\n'
# Save generated server /etc/nginx/conf.d/nginx.conf
printf "$content_server" > /etc/nginx/conf.d/nginx.conf

# # Generate additional configuration
printf "client_max_body_size $USE_NGINX_MAX_UPLOAD;\n" > /etc/nginx/conf.d/upload.conf
printf "client_body_buffer_size $USE_CLIENT_BODY_BUFFER_SIZE;\n" > /etc/nginx/conf.d/body-buffer-size.conf
printf "add_header Access-Control-Allow-Origin *;\n" > /etc/nginx/conf.d/cors-header.conf
fi

exec "$@"
2 changes: 2 additions & 0 deletions discovery_server/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Werkzeug
pymongo
8 changes: 8 additions & 0 deletions discovery_server/stop-supervisor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env sh

printf "READY\n"

while read line; do
echo "Processing Event: $line" >&2
kill $PPID
done < /dev/stdin
62 changes: 62 additions & 0 deletions discovery_server/storage/AssetIdsFullExample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[
{
"semanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "ud800;udbff3udbffUud800Bud800qudbffhudbffTd6^dnTudbff5?Aoudbff36Xud800>udbffUudbff<ud800Wkpud800;udbff5nC;ud800:I7udbff?ud800gudbffLPJudbff\\YemTudbffhudbffV/budbff?6udbff09O=*ud800UWQ14369ud800<,ud800pgud800V[.USud800FqsjTudbffO7>\"Hjeud800Fudbff;udbffC?5q]udbff8aIudbffkp[?sud800kXljub;Gudbffqud8003ud8005udbff[>Z6d_udbffO=hxs R9<_pudbffo"
}
],
"referredSemanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "ooOud800pqudbfffud800b:4udbffiudbff<P5ud800Pudbff?#udbff[Mudbff?Pet_ud800Wudbff4udbff\\ud800Gudbff@fKN;'ud800E*qud800:ud8003pdudbffpud800aNud800H@nHud800Xudbff^udbffuudbffnl:udbffKudbffr"
}
]
}
},
"supplementalSemanticIds": [
{
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "Ft2ud800lud800Yud800?Mpud800judbffNudbffl"
}
],
"referredSemanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "NYA=ud800U3EDFud800kud800ixTqud800MudbffMZ?ud800iAnuHGTud800EudbffPud800=ud800?udbff3AKoxkudbffX-ud800Zudbff2MNud800mudbffI2ud800dfV*udbffNnud800\\ud800Gsdud800Pud8004=seud800nudbff>udbffd_ud800sJudbffOudbffiB:udbff@pEudbffM;8ud800mS;udbff3ud800q8udbff^udbffmDhFttgudbffrudbffhudbffrEud800e"
}
]
}
}
],
"name": "ud800Vud800?ud800tudbff1Ah_ud8003udbffZud800d5WAud800ScMIud800e>",
"value": "udbffBudbffSud800<D3mudbff4ud800Rudbffhudbff@HudbffRud8008udbffD%udbffGudbffH/:mS,Q?`ud800YudbffLdehNuCudbffW<_Zqud800MI5@udbff9[:>udbffn%ud800kudbffa:Tcfudbff?udbff?ud8005udbffZudbff_ud800iud800qq.@Zud800jml<ud800m>udbffFB<:Wfud800=audbffludbffailudbff?ud800uLudbff7ud800GJqG'ud800kudbffrudbff>>RudbffQudbff=udbffQS]UudbffOZS",
"externalSubjectId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "^7<\\agVu_%ud800:pD<-ud800j9udbffkiKCudbffVudbffjudbffDudbffiudbffZsud800WhLG:tQfLP"
}
],
"referredSemanticId": {
"type": "ExternalReference",
"keys": [
{
"type": "GlobalReference",
"value": "]Pud800DudbffY[0Y<gudbffJudbffcud800nud8007oudbffMudbff3f[rud800@9ud800Kudbff?6]$qud800D:1KGfudbffUud800Aud800?udbffsj<hWud800`udbff2ud800oud800Zud800EArudbffjud800Fudbff:rSudbffJud800[udbffZudbffeudbffnRR`ud8003udbffGud800R"
}
]
}
}
}
]
6 changes: 6 additions & 0 deletions discovery_server/storage/ListOfAssetIds.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"name": "ud800Vud800?ud800tudbff1Ah_ud8003udbffZud800d5WAud800ScMIud800e>",
"value": "udbffBudbffSud800<D3mudbff4ud800Rudbffhudbff@HudbffRud8008udbffD%udbffGudbffH/:mS,Q?`ud800YudbffLdehNuCudbffW<_Zqud800MI5@udbff9[:>udbffn%ud800kudbffa:Tcfudbff?udbff?ud8005udbffZudbff_ud800iud800qq.@Zud800jml<ud800m>udbffFB<:Wfud800=audbffludbffailudbff?ud800uLudbff7ud800GJqG'ud800kudbffrudbff>>RudbffQudbff=udbffQS]UudbffOZS"
}
]
27 changes: 27 additions & 0 deletions discovery_server/supervisord.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[supervisord]
nodaemon=true

[program:uwsgi]
command=/usr/local/bin/uwsgi --ini /etc/uwsgi/uwsgi.ini
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
startsecs = 0
autorestart=false
# may make sense to have autorestart enabled in production

[program:nginx]
command=/usr/sbin/nginx
stdout_logfile=/var/log/nginx.out.log
stdout_logfile_maxbytes=0
stderr_logfile=/var/log/nginx.err.log
stderr_logfile_maxbytes=0
stopsignal=QUIT
startsecs = 0
autorestart=false
# may make sense to have autorestart enabled in production

[eventlistener:quit_on_failure]
events=PROCESS_STATE_STOPPED,PROCESS_STATE_EXITED,PROCESS_STATE_FATAL
command=/etc/supervisor/stop-supervisor.sh
9 changes: 9 additions & 0 deletions discovery_server/uwsgi.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[uwsgi]
wsgi-file = /app/main.py
socket = /tmp/uwsgi.sock
chown-socket = nginx:nginx
chmod-socket = 664
hook-master-start = unix_signal:15 gracefully_kill_them_all
need-app = true
die-on-term = true
show-config = false
49 changes: 49 additions & 0 deletions registry_server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
FROM python:3.11-alpine

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# If we have more dependencies for the server it would make sense
# to refactor uswgi to the pyproject.toml
RUN apk update && \
apk add --no-cache nginx supervisor gcc musl-dev linux-headers python3-dev git bash && \
pip install uwsgi && \
apk del git bash


COPY registry_server/uwsgi.ini /etc/uwsgi/
COPY registry_server/supervisord.ini /etc/supervisor/conf.d/supervisord.ini
COPY registry_server/stop-supervisor.sh /etc/supervisor/stop-supervisor.sh
RUN chmod +x /etc/supervisor/stop-supervisor.sh

# Makes it possible to use a different configuration
ENV UWSGI_INI=/etc/uwsgi/uwsgi.ini
# object stores aren't thread-safe yet
# https://github.com/eclipse-basyx/basyx-python-sdk/issues/205
ENV UWSGI_CHEAPER=0
ENV UWSGI_PROCESSES=1
ENV NGINX_MAX_UPLOAD=1M
ENV NGINX_WORKER_PROCESSES=1
ENV LISTEN_PORT=80
ENV CLIENT_BODY_BUFFER_SIZE=1M

# Copy the entrypoint that will generate Nginx additional configs
COPY registry_server/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

ENV SETUPTOOLS_SCM_PRETEND_VERSION=1.0.0


COPY ./registry_server/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY ./sdk /sdk
COPY ./server /server
COPY ./registry_server/app /app

WORKDIR /app
RUN pip install ../sdk

CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.ini"]
Loading