Skip to content

Commit b3e9ac2

Browse files
committed
Merge origin/develop into aas-demonstrator
2 parents 366993e + 65802ea commit b3e9ac2

24 files changed

Lines changed: 433 additions & 3244 deletions

.github/workflows/release.yml

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ on:
44
release:
55
types: [published]
66

7+
env:
8+
TARGET_PLATFORM: "linux/amd64,linux/arm/v7,linux/arm64"
9+
710
jobs:
811
sdk-publish:
912
# This job publishes the package to PyPI
@@ -59,7 +62,54 @@ jobs:
5962
with:
6063
password: ${{ secrets.PYPI_ORG_TOKEN }}
6164

62-
server-publish:
65+
server-repository-publish:
66+
# This job publishes the server docker image to DockerHub
67+
runs-on: ubuntu-latest
68+
defaults:
69+
run:
70+
working-directory: ./server
71+
steps:
72+
- name: Checkout Repository
73+
uses: actions/checkout@v4
74+
75+
- name: Extract Docker image metadata
76+
id: meta
77+
uses: docker/metadata-action@v5
78+
with:
79+
images: eclipsebasyx/basyx-python-repository
80+
# This fetches the latest git tag and adds an additional "latest" to it, so e.g. `2.1.0,latest`
81+
tags: |
82+
type=semver,pattern={{version}}
83+
type=raw,value=latest
84+
labels: |
85+
org.opencontainers.image.title=BaSyx Python Repository Service
86+
org.opencontainers.image.description=Eclipse BaSyx Python SDK - Repository HTTP Server
87+
org.opencontainers.image.source=https://github.com/eclipse-basyx/basyx-python-sdk/tree/main/server
88+
org.opencontainers.image.licenses=MIT
89+
90+
- name: Log in to Docker Hub
91+
uses: docker/login-action@v4
92+
with:
93+
username: ${{ secrets.DOCKER_HUB_USER }}
94+
password: ${{ secrets.DOCKER_HUB_TOKEN }}
95+
96+
- name: Setup QEMU
97+
uses: docker/setup-qemu-action@v4
98+
99+
- name: Set up Docker Buildx
100+
uses: docker/setup-buildx-action@v4
101+
102+
- name: Build and Push Repository Docker Image
103+
uses: docker/build-push-action@v6
104+
with:
105+
context: .
106+
file: ./server/docker/repository/Dockerfile
107+
platforms: ${{ env.TARGET_PLATFORM }}
108+
push: true
109+
tags: ${{ steps.meta.outputs.tags }}
110+
labels: ${{ steps.meta.outputs.labels }}
111+
112+
server-discovery-publish:
63113
# This job publishes the server docker image to DockerHub
64114
runs-on: ubuntu-latest
65115
defaults:
@@ -73,14 +123,14 @@ jobs:
73123
id: meta
74124
uses: docker/metadata-action@v5
75125
with:
76-
images: eclipsebasyx/basyx-python-server
126+
images: eclipsebasyx/basyx-python-discovery
77127
# This fetches the latest git tag and adds an additional "latest" to it, so e.g. `2.1.0,latest`
78128
tags: |
79129
type=semver,pattern={{version}}
80130
type=raw,value=latest
81131
labels: |
82-
org.opencontainers.image.title=BaSyx Python Server
83-
org.opencontainers.image.description=Eclipse BaSyx Python SDK - HTTP Server
132+
org.opencontainers.image.title=BaSyx Python Discovery Service
133+
org.opencontainers.image.description=Eclipse BaSyx Python SDK - Discovery HTTP Server
84134
org.opencontainers.image.source=https://github.com/eclipse-basyx/basyx-python-sdk/tree/main/server
85135
org.opencontainers.image.licenses=MIT
86136
@@ -90,11 +140,65 @@ jobs:
90140
username: ${{ secrets.DOCKER_HUB_USER }}
91141
password: ${{ secrets.DOCKER_HUB_TOKEN }}
92142

93-
- name: Build and Push Docker Image
143+
- name: Setup QEMU
144+
uses: docker/setup-qemu-action@v4
145+
146+
- name: Set up Docker Buildx
147+
uses: docker/setup-buildx-action@v4
148+
149+
- name: Build and Push Repository Docker Image
150+
uses: docker/build-push-action@v6
151+
with:
152+
context: .
153+
file: ./server/docker/discovery/Dockerfile
154+
platforms: ${{ env.TARGET_PLATFORM }}
155+
push: true
156+
tags: ${{ steps.meta.outputs.tags }}
157+
labels: ${{ steps.meta.outputs.labels }}
158+
159+
server-registry-publish:
160+
# This job publishes the server docker image to DockerHub
161+
runs-on: ubuntu-latest
162+
defaults:
163+
run:
164+
working-directory: ./server
165+
steps:
166+
- name: Checkout Repository
167+
uses: actions/checkout@v4
168+
169+
- name: Extract Docker image metadata
170+
id: meta
171+
uses: docker/metadata-action@v5
172+
with:
173+
images: eclipsebasyx/basyx-python-registry
174+
# This fetches the latest git tag and adds an additional "latest" to it, so e.g. `2.1.0,latest`
175+
tags: |
176+
type=semver,pattern={{version}}
177+
type=raw,value=latest
178+
labels: |
179+
org.opencontainers.image.title=BaSyx Python Registry Service
180+
org.opencontainers.image.description=Eclipse BaSyx Python SDK - Registry HTTP Server
181+
org.opencontainers.image.source=https://github.com/eclipse-basyx/basyx-python-sdk/tree/main/server
182+
org.opencontainers.image.licenses=MIT
183+
184+
- name: Log in to Docker Hub
185+
uses: docker/login-action@v4
186+
with:
187+
username: ${{ secrets.DOCKER_HUB_USER }}
188+
password: ${{ secrets.DOCKER_HUB_TOKEN }}
189+
190+
- name: Setup QEMU
191+
uses: docker/setup-qemu-action@v4
192+
193+
- name: Set up Docker Buildx
194+
uses: docker/setup-buildx-action@v4
195+
196+
- name: Build and Push Repository Docker Image
94197
uses: docker/build-push-action@v6
95198
with:
96199
context: .
97-
file: ./server/Dockerfile # Todo: Update paths
200+
file: ./server/docker/registry/Dockerfile
201+
platforms: ${{ env.TARGET_PLATFORM }}
98202
push: true
99203
tags: ${{ steps.meta.outputs.tags }}
100204
labels: ${{ steps.meta.outputs.labels }}

compliance_tool/aas_compliance_tool/compliance_check_aasx.py

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -88,69 +88,6 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana
8888
return identifiable_store, files, new_cp
8989

9090

91-
def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> None:
92-
"""
93-
Checks a given file against the official json schema and reports any issues using the given
94-
:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager`
95-
96-
Opens the file and checks if the data inside is stored in XML or JSON. Then calls the respective compliance tool
97-
schema check
98-
"""
99-
logger = logging.getLogger('compliance_check')
100-
logger.addHandler(state_manager)
101-
logger.propagate = False
102-
logger.setLevel(logging.INFO)
103-
104-
# create handler to get logger info
105-
logger_deserialization = logging.getLogger(aasx.__name__)
106-
logger_deserialization.addHandler(state_manager)
107-
logger_deserialization.propagate = False
108-
logger_deserialization.setLevel(logging.INFO)
109-
110-
state_manager.add_step('Open file')
111-
try:
112-
# open given file
113-
reader = aasx.AASXReader(file_path)
114-
state_manager.set_step_status_from_log()
115-
except ValueError as error:
116-
logger.error(error)
117-
state_manager.set_step_status_from_log()
118-
state_manager.add_step('Read file')
119-
state_manager.set_step_status(Status.NOT_EXECUTED)
120-
return
121-
122-
try:
123-
# read given file (Find XML and JSON parts)
124-
state_manager.add_step('Read file')
125-
core_rels = reader.reader.get_related_parts_by_type()
126-
try:
127-
aasx_origin_part = core_rels[aasx.RELATIONSHIP_TYPE_AASX_ORIGIN][0]
128-
except IndexError as e:
129-
raise ValueError("Not a valid AASX file: aasx-origin Relationship is missing.") from e
130-
state_manager.set_step_status(Status.SUCCESS)
131-
for aas_part in reader.reader.get_related_parts_by_type(aasx_origin_part)[
132-
aasx.RELATIONSHIP_TYPE_AAS_SPEC]:
133-
content_type = reader.reader.get_content_type(aas_part)
134-
extension = aas_part.split("/")[-1].split(".")[-1]
135-
with reader.reader.open_part(aas_part) as p:
136-
if content_type.split(";")[0] in (
137-
"text/xml", "application/xml") or content_type == "" and extension == "xml":
138-
logger.debug("Parsing AAS objects from XML stream in OPC part {} ...".format(aas_part))
139-
compliance_check_xml._check_schema(p, state_manager)
140-
elif content_type.split(";")[0] == "application/json" \
141-
or content_type == "" and extension == "json":
142-
logger.debug("Parsing AAS objects from JSON stream in OPC part {} ...".format(aas_part))
143-
compliance_check_json._check_schema(io.TextIOWrapper(p, encoding='utf-8-sig'), state_manager)
144-
else:
145-
raise ValueError("Could not determine part format of AASX part {} (Content Type: {}, extension: {}"
146-
.format(aas_part, content_type, extension))
147-
except ValueError as error:
148-
logger.error(error)
149-
state_manager.set_step_status(Status.FAILED)
150-
finally:
151-
reader.close()
152-
153-
15491
def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager, **kwargs) -> None:
15592
"""
15693
Checks if a file contains all elements of the aas example and reports any issues using the given

compliance_tool/aas_compliance_tool/compliance_check_json.py

Lines changed: 0 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -23,84 +23,6 @@
2323
from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status
2424

2525

26-
JSON_SCHEMA_FILE = os.path.join(os.path.dirname(__file__), 'schemas/aasJSONSchema.json')
27-
28-
29-
def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> None:
30-
"""
31-
Checks a given file against the official json schema and reports any issues using the given
32-
:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager`
33-
34-
Add the steps: `Open file`, `Read file and check if it is conform to the json syntax` and `Validate file against
35-
official json schema`
36-
37-
:param file_path: Path to the file which should be checked
38-
:param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps
39-
"""
40-
logger = logging.getLogger('compliance_check')
41-
logger.addHandler(state_manager)
42-
logger.propagate = False
43-
logger.setLevel(logging.INFO)
44-
45-
state_manager.add_step('Open file')
46-
try:
47-
# open given file
48-
file_to_be_checked = open(file_path, 'r', encoding='utf-8-sig')
49-
except IOError as error:
50-
state_manager.set_step_status(Status.FAILED)
51-
logger.error(error)
52-
state_manager.add_step('Read file and check if it is conform to the json syntax')
53-
state_manager.set_step_status(Status.NOT_EXECUTED)
54-
state_manager.add_step('Validate file against official json schema')
55-
state_manager.set_step_status(Status.NOT_EXECUTED)
56-
return
57-
return _check_schema(file_to_be_checked, state_manager)
58-
59-
60-
def _check_schema(file_to_be_checked: IO[str], state_manager: ComplianceToolStateManager):
61-
logger = logging.getLogger('compliance_check')
62-
logger.addHandler(state_manager)
63-
logger.propagate = False
64-
logger.setLevel(logging.INFO)
65-
66-
try:
67-
with file_to_be_checked:
68-
state_manager.set_step_status(Status.SUCCESS)
69-
# read given file and check if it is conform to the json syntax
70-
state_manager.add_step('Read file and check if it is conform to the json syntax')
71-
json_to_be_checked = json.load(file_to_be_checked)
72-
state_manager.set_step_status(Status.SUCCESS)
73-
except json.decoder.JSONDecodeError as error:
74-
state_manager.set_step_status(Status.FAILED)
75-
logger.error(error)
76-
state_manager.add_step('Validate file against official json schema')
77-
state_manager.set_step_status(Status.NOT_EXECUTED)
78-
return
79-
80-
# load json schema
81-
with open(JSON_SCHEMA_FILE, 'r', encoding='utf-8-sig') as json_file:
82-
aas_json_schema = json.load(json_file)
83-
state_manager.add_step('Validate file against official json schema')
84-
85-
# validate given file against schema
86-
try:
87-
import jsonschema # type: ignore
88-
except ImportError as error:
89-
state_manager.set_step_status(Status.NOT_EXECUTED)
90-
logger.error("Python package 'jsonschema' is required for validating the JSON file.", error)
91-
return
92-
93-
try:
94-
jsonschema.validate(instance=json_to_be_checked, schema=aas_json_schema)
95-
except jsonschema.exceptions.ValidationError as error:
96-
state_manager.set_step_status(Status.FAILED)
97-
logger.error(error)
98-
return
99-
100-
state_manager.set_step_status(Status.SUCCESS)
101-
return
102-
103-
10426
def check_deserialization(file_path: str, state_manager: ComplianceToolStateManager,
10527
file_info: Optional[str] = None) -> model.DictIdentifiableStore:
10628
"""

compliance_tool/aas_compliance_tool/compliance_check_xml.py

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -23,83 +23,6 @@
2323
from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status
2424

2525

26-
XML_SCHEMA_FILE = os.path.join(os.path.dirname(__file__), 'schemas/aasXMLSchema.xsd')
27-
28-
29-
def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> None:
30-
"""
31-
Checks a given file against the official xml schema and reports any issues using the given
32-
:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager`
33-
34-
Add the steps: `Open file`, `Read file`, `Check if it is conform to the xml syntax` and `Validate file against
35-
official xml schema`
36-
37-
:param file_path: Path to the file which should be checked
38-
:param state_manager: :class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager` to log the steps
39-
"""
40-
logger = logging.getLogger('compliance_check')
41-
logger.addHandler(state_manager)
42-
logger.propagate = False
43-
logger.setLevel(logging.INFO)
44-
45-
state_manager.add_step('Open file')
46-
try:
47-
# open given file
48-
file_to_be_checked = open(file_path, 'rb')
49-
state_manager.set_step_status(Status.SUCCESS)
50-
except IOError as error:
51-
state_manager.set_step_status(Status.FAILED)
52-
logger.error(error)
53-
state_manager.add_step('Read file and check if it is conform to the xml syntax')
54-
state_manager.set_step_status(Status.NOT_EXECUTED)
55-
state_manager.add_step('Validate file against official xml schema')
56-
state_manager.set_step_status(Status.NOT_EXECUTED)
57-
return
58-
return _check_schema(file_to_be_checked, state_manager)
59-
60-
61-
def _check_schema(file_to_be_checked, state_manager):
62-
logger = logging.getLogger('compliance_check')
63-
logger.addHandler(state_manager)
64-
logger.propagate = False
65-
logger.setLevel(logging.INFO)
66-
67-
state_manager.add_step('Read file and check if it is conform to the xml syntax')
68-
try:
69-
# read given file and check if it is conform to the xml syntax
70-
parser = etree.XMLParser(remove_blank_text=True, remove_comments=True)
71-
etree.parse(file_to_be_checked, parser)
72-
state_manager.set_step_status(Status.SUCCESS)
73-
except etree.XMLSyntaxError as error:
74-
state_manager.set_step_status(Status.FAILED)
75-
logger.error(error)
76-
state_manager.add_step('Validate file against official xml schema')
77-
state_manager.set_step_status(Status.NOT_EXECUTED)
78-
file_to_be_checked.close()
79-
return
80-
except Exception:
81-
file_to_be_checked.close()
82-
raise
83-
84-
# load aas xml schema
85-
aas_xml_schema = etree.XMLSchema(file=XML_SCHEMA_FILE)
86-
parser = etree.XMLParser(schema=aas_xml_schema)
87-
88-
state_manager.add_step('Validate file against official xml schema')
89-
# validate given file against schema
90-
try:
91-
file_to_be_checked.seek(0) # Reset reading file offset (cursor) to the beginning of the file
92-
with file_to_be_checked:
93-
etree.parse(file_to_be_checked, parser=parser)
94-
except etree.ParseError as error:
95-
state_manager.set_step_status(Status.FAILED)
96-
logger.error(error)
97-
return
98-
99-
state_manager.set_step_status(Status.SUCCESS)
100-
return
101-
102-
10326
def check_deserialization(file_path: str, state_manager: ComplianceToolStateManager,
10427
file_info: Optional[str] = None) -> model.DictIdentifiableStore:
10528
"""

0 commit comments

Comments
 (0)