actinia-cloudevent-plugin 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- actinia_cloudevent_plugin/__init__.py +33 -0
- actinia_cloudevent_plugin/api/__init__.py +4 -0
- actinia_cloudevent_plugin/api/cloudevent.py +104 -0
- actinia_cloudevent_plugin/apidocs/__init__.py +4 -0
- actinia_cloudevent_plugin/apidocs/cloudevent.py +49 -0
- actinia_cloudevent_plugin/core/__init__.py +4 -0
- actinia_cloudevent_plugin/core/processing.py +106 -0
- actinia_cloudevent_plugin/endpoints.py +63 -0
- actinia_cloudevent_plugin/main.py +65 -0
- actinia_cloudevent_plugin/model/__init__.py +4 -0
- actinia_cloudevent_plugin/model/response_models.py +52 -0
- actinia_cloudevent_plugin/resources/__init__.py +4 -0
- actinia_cloudevent_plugin/resources/config.py +91 -0
- actinia_cloudevent_plugin/resources/logging.py +130 -0
- actinia_cloudevent_plugin-0.1.0.dist-info/METADATA +134 -0
- actinia_cloudevent_plugin-0.1.0.dist-info/RECORD +19 -0
- actinia_cloudevent_plugin-0.1.0.dist-info/WHEEL +5 -0
- actinia_cloudevent_plugin-0.1.0.dist-info/licenses/LICENSE.txt +621 -0
- actinia_cloudevent_plugin-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Copyright (c) 2018-2025 mundialis GmbH & Co. KG.
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
actinia plugin initalization
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__license__ = "GPLv3"
|
|
21
|
+
__author__ = "Carmen Tawalika, Anika Weinmann"
|
|
22
|
+
__copyright__ = "Copyright 2022 mundialis GmbH & Co. KG"
|
|
23
|
+
__maintainer__ = "mundialis GmbH & Co. KG"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
import importlib.metadata
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
# Change here if project is renamed and does not equal the package name
|
|
30
|
+
DIST_NAME = __name__
|
|
31
|
+
__version__ = importlib.metadata.version(DIST_NAME)
|
|
32
|
+
except Exception():
|
|
33
|
+
__version__ = "unknown"
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Copyright (c) 2025 mundialis GmbH & Co. KG.
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
Hello World class
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__license__ = "GPLv3"
|
|
21
|
+
__author__ = "Lina Krisztian"
|
|
22
|
+
__copyright__ = "Copyright 2025 mundialis GmbH & Co. KG"
|
|
23
|
+
__maintainer__ = "mundialis GmbH & Co. KG"
|
|
24
|
+
|
|
25
|
+
from flask import jsonify, make_response
|
|
26
|
+
from flask_restful_swagger_2 import Resource, swagger
|
|
27
|
+
from requests.exceptions import ConnectionError # noqa: A004
|
|
28
|
+
|
|
29
|
+
from actinia_cloudevent_plugin.apidocs import cloudevent
|
|
30
|
+
from actinia_cloudevent_plugin.core.processing import (
|
|
31
|
+
cloud_event_to_process_chain,
|
|
32
|
+
receive_cloud_event,
|
|
33
|
+
send_binary_cloud_event,
|
|
34
|
+
# send_structured_cloud_event,
|
|
35
|
+
)
|
|
36
|
+
from actinia_cloudevent_plugin.model.response_models import (
|
|
37
|
+
SimpleStatusCodeResponseModel,
|
|
38
|
+
)
|
|
39
|
+
from actinia_cloudevent_plugin.resources.config import EVENTRECEIVER
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Cloudevent(Resource):
|
|
43
|
+
"""Cloudevent handling."""
|
|
44
|
+
|
|
45
|
+
def __init__(self) -> None:
|
|
46
|
+
"""Cloudevent class initialisation."""
|
|
47
|
+
self.msg = (
|
|
48
|
+
"Received event <EVENT1> and returned event <EVENT2>"
|
|
49
|
+
" with actinia-job <ACTINIA_JOB>."
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def get(self):
|
|
53
|
+
"""Cloudevent get method: not allowed response."""
|
|
54
|
+
res = jsonify(
|
|
55
|
+
SimpleStatusCodeResponseModel(
|
|
56
|
+
status=405,
|
|
57
|
+
message="Method Not Allowed",
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
return make_response(res, 405)
|
|
61
|
+
|
|
62
|
+
@swagger.doc(cloudevent.describe_cloudevent_post_docs)
|
|
63
|
+
def post(self) -> SimpleStatusCodeResponseModel:
|
|
64
|
+
"""Cloudevent post method with cloudevent from postbody.
|
|
65
|
+
|
|
66
|
+
Receives cloudevent, transforms to process chain (pc),
|
|
67
|
+
sends pc to actinia + start process,
|
|
68
|
+
and returns cloudevent with queue name.
|
|
69
|
+
"""
|
|
70
|
+
# Transform postbody to cloudevent
|
|
71
|
+
event_received = receive_cloud_event()
|
|
72
|
+
# With received process chain start actinia process + return cloudevent
|
|
73
|
+
actinia_job = cloud_event_to_process_chain(event_received)
|
|
74
|
+
# URL to which the generated cloudevent is sent
|
|
75
|
+
url = EVENTRECEIVER.url
|
|
76
|
+
# TODO: binary or structured cloud event?
|
|
77
|
+
# From https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#message
|
|
78
|
+
# A "structured-mode message" is one where the entire event (attributes and data)
|
|
79
|
+
# are encoded in the message body, according to a specific event format.
|
|
80
|
+
# A "binary-mode message" is one where the event data is stored in the message body,
|
|
81
|
+
# and event attributes are stored as part of message metadata.
|
|
82
|
+
# Often, binary mode is used when the producer of the CloudEvent wishes to add the
|
|
83
|
+
# CloudEvent's metadata to an existing event without impacting the message's body.
|
|
84
|
+
# In most cases a CloudEvent encoded as a binary-mode message will not break an
|
|
85
|
+
# existing receiver's processing of the event because the message's metadata
|
|
86
|
+
# typically allows for extension attributes.
|
|
87
|
+
# In other words, a binary formatted CloudEvent would work for both
|
|
88
|
+
# a CloudEvents enabled receiver as well as one that is unaware of CloudEvents.
|
|
89
|
+
try:
|
|
90
|
+
event_returned = send_binary_cloud_event(
|
|
91
|
+
event_received,
|
|
92
|
+
actinia_job,
|
|
93
|
+
url,
|
|
94
|
+
)
|
|
95
|
+
return SimpleStatusCodeResponseModel(
|
|
96
|
+
status=204,
|
|
97
|
+
message=self.msg.replace("<EVENT1>", event_received["id"])
|
|
98
|
+
.replace("<EVENT2>", event_returned["id"])
|
|
99
|
+
.replace("<ACTINIA_JOB>", actinia_job),
|
|
100
|
+
)
|
|
101
|
+
except ConnectionError as e:
|
|
102
|
+
return f"Connection ERROR when returning cloudevent: {e}"
|
|
103
|
+
except Exception() as e:
|
|
104
|
+
return f"ERROR when returning cloudevent: {e}"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Copyright (c) 2025 mundialis GmbH & Co. KG.
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
Hello World class
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__license__ = "GPLv3"
|
|
21
|
+
__author__ = "Lina Krisztian"
|
|
22
|
+
__copyright__ = "Copyright 2025 mundialis GmbH & Co. KG"
|
|
23
|
+
__maintainer__ = "mundialis GmbH & Co. KG"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
from actinia_cloudevent_plugin.model.response_models import (
|
|
27
|
+
SimpleStatusCodeResponseModel,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
describe_cloudevent_post_docs = {
|
|
31
|
+
# "summary" is taken from the description of the get method
|
|
32
|
+
"tags": ["cloudevent"],
|
|
33
|
+
"description": (
|
|
34
|
+
"Receives cloudevent, transforms and starts pc and returns cloudevent."
|
|
35
|
+
),
|
|
36
|
+
"responses": {
|
|
37
|
+
"200": {
|
|
38
|
+
"description": (
|
|
39
|
+
"This response returns received, and returned events, "
|
|
40
|
+
"generated queue name and the status"
|
|
41
|
+
),
|
|
42
|
+
"schema": SimpleStatusCodeResponseModel,
|
|
43
|
+
},
|
|
44
|
+
"400": {
|
|
45
|
+
"description": "This response returns an error message",
|
|
46
|
+
"schema": SimpleStatusCodeResponseModel,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Copyright (c) 2025 mundialis GmbH & Co. KG.
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
Example core functionality
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__license__ = "GPLv3"
|
|
21
|
+
__author__ = "Lina Krisztian"
|
|
22
|
+
__copyright__ = "Copyright 2025 mundialis GmbH & Co. KG"
|
|
23
|
+
__maintainer__ = "mundialis GmbH & Co. KG"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
import requests
|
|
27
|
+
from cloudevents.conversion import to_binary, to_structured
|
|
28
|
+
from cloudevents.http import CloudEvent, from_http
|
|
29
|
+
from flask import request
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def receive_cloud_event():
|
|
33
|
+
"""Return cloudevent from postpody."""
|
|
34
|
+
# Parses CloudEvent 'data' and 'headers' into a CloudEvent.
|
|
35
|
+
event = from_http(request.headers, request.get_data())
|
|
36
|
+
|
|
37
|
+
# ? TODO
|
|
38
|
+
# eventually Filter the event (see example below)
|
|
39
|
+
event_type = event["type"]
|
|
40
|
+
if event_type == "com.example.object.created":
|
|
41
|
+
print("Object created event received!")
|
|
42
|
+
|
|
43
|
+
return event
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def cloud_event_to_process_chain(event) -> str:
|
|
47
|
+
"""Return queue name for process chain of event."""
|
|
48
|
+
# (Remove ruff-exception, when pc variable used)
|
|
49
|
+
pc = event.get_data()["list"][0] # noqa: F841
|
|
50
|
+
# !! TODO !!: pc to job
|
|
51
|
+
# NOTE: as standalone app -> consider for queue name creation
|
|
52
|
+
# HTTP POST pc to actinia-module plugin processing endpoint
|
|
53
|
+
# # # include an identifier for grouping cloudevents of same actinia process (?)
|
|
54
|
+
# # # (e.g. new metadata field "queue_name", or within data, or use existign id)
|
|
55
|
+
# -> actinia core returns resource-url, including resource_id (and queue name)
|
|
56
|
+
# (queuename = xx_<resource_id>; if configured accordingly within actinia -> each job own queue)
|
|
57
|
+
# via knative jobsink: start actinia worker (with queue name)
|
|
58
|
+
# (https://knative.dev/docs/eventing/sinks/job-sink/#usage)
|
|
59
|
+
# e.g. HTTP POST with queue name
|
|
60
|
+
# kubectl run curl --image=curlimages/curl --rm=true --restart=Never -ti -- -X POST -v \
|
|
61
|
+
# -H "content-type: application/json" \
|
|
62
|
+
# -H "ce-specversion: 1.0" \
|
|
63
|
+
# -H "ce-source: my/curl/command" \
|
|
64
|
+
# -H "ce-type: my.demo.event" \
|
|
65
|
+
# -H "ce-id: 123" \
|
|
66
|
+
# -d '{"details":"queuename"}' \
|
|
67
|
+
# http://job-sink.knative-eventing.svc.cluster.local/default/job-sink-logger
|
|
68
|
+
return "<queue_name>_<resource_id>" # queue name and resource id
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def send_binary_cloud_event(event, actinia_job, url):
|
|
72
|
+
"""Return posted binary event with actinia_job."""
|
|
73
|
+
attributes = {
|
|
74
|
+
"specversion": event["specversion"],
|
|
75
|
+
"source": "/actinia-cloudevent-plugin",
|
|
76
|
+
"type": "com.mundialis.actinia.process.started",
|
|
77
|
+
"subject": event["subject"],
|
|
78
|
+
"datacontenttype": "application/json",
|
|
79
|
+
}
|
|
80
|
+
data = {"actinia_job": actinia_job}
|
|
81
|
+
|
|
82
|
+
event = CloudEvent(attributes, data)
|
|
83
|
+
headers, body = to_binary(event)
|
|
84
|
+
# send event
|
|
85
|
+
requests.post(url, headers=headers, data=body)
|
|
86
|
+
|
|
87
|
+
return event
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def send_structured_cloud_event(event, actinia_job, url):
|
|
91
|
+
"""Return posted structured event with actinia_job."""
|
|
92
|
+
attributes = {
|
|
93
|
+
"specversion": event["specversion"],
|
|
94
|
+
"source": "/actinia-cloudevent-plugin",
|
|
95
|
+
"type": "com.mundialis.actinia.process.started",
|
|
96
|
+
"subject": event["subject"],
|
|
97
|
+
"datacontenttype": "application/json",
|
|
98
|
+
}
|
|
99
|
+
data = {"actinia_job": actinia_job}
|
|
100
|
+
|
|
101
|
+
event = CloudEvent(attributes, data)
|
|
102
|
+
headers, body = to_structured(event)
|
|
103
|
+
# send event
|
|
104
|
+
requests.post(url, headers=headers, data=body)
|
|
105
|
+
|
|
106
|
+
return event
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Copyright (c) 2018-2025 mundialis GmbH & Co. KG.
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
Add endpoints to flask app with endpoint definitions and routes
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__license__ = "GPLv3"
|
|
21
|
+
__author__ = "Carmen Tawalika, Anika Weinmann, Lina Krisztian"
|
|
22
|
+
__copyright__ = "Copyright 2022-2024 mundialis GmbH & Co. KG"
|
|
23
|
+
__maintainer__ = "mundialis GmbH & Co. KG"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
import sys
|
|
27
|
+
|
|
28
|
+
import werkzeug
|
|
29
|
+
from flask import current_app, send_from_directory
|
|
30
|
+
from flask_restful_swagger_2 import Api
|
|
31
|
+
|
|
32
|
+
from actinia_cloudevent_plugin.api.cloudevent import Cloudevent
|
|
33
|
+
from actinia_cloudevent_plugin.resources.logging import log
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# endpoints loaded if run as actinia-core plugin as well as standalone app
|
|
37
|
+
def create_endpoints(flask_api: Api) -> None:
|
|
38
|
+
"""Create plugin endpoints."""
|
|
39
|
+
app = flask_api.app
|
|
40
|
+
apidoc = flask_api
|
|
41
|
+
|
|
42
|
+
package = sys._getframe().f_back.f_globals["__package__"] # noqa: SLF001
|
|
43
|
+
if package != "actinia_core":
|
|
44
|
+
|
|
45
|
+
@app.route("/")
|
|
46
|
+
def index():
|
|
47
|
+
try:
|
|
48
|
+
return current_app.send_static_file("index.html")
|
|
49
|
+
except werkzeug.exceptions.NotFound:
|
|
50
|
+
log.debug("No index.html found. Serving backup.")
|
|
51
|
+
# when actinia-cloudevent-plugin is installed in single mode,
|
|
52
|
+
# the swagger endpoint would be "latest/api/swagger.json".
|
|
53
|
+
# As api docs exist in single mode,
|
|
54
|
+
# use this fallback for plugin mode.
|
|
55
|
+
return """<h1 style='color:red'>actinia-metadata-plugin</h1>
|
|
56
|
+
<a href="api/v1/swagger.json">API docs</a>"""
|
|
57
|
+
|
|
58
|
+
@app.route("/<path:filename>")
|
|
59
|
+
def static_content(filename):
|
|
60
|
+
# WARNING: all content from folder "static" will be accessible!
|
|
61
|
+
return send_from_directory(app.static_folder, filename)
|
|
62
|
+
|
|
63
|
+
apidoc.add_resource(Cloudevent, "/")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Copyright (c) 2025 mundialis GmbH & Co. KG.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
Application entrypoint. Creates Flask app and swagger docs, adds endpoints
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__author__ = "Carmen Tawalika, Lina Krisztian"
|
|
21
|
+
__copyright__ = "2025-present mundialis GmbH & Co. KG"
|
|
22
|
+
__license__ = "Apache-2.0"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from flask import Flask
|
|
26
|
+
from flask_cors import CORS
|
|
27
|
+
from flask_restful_swagger_2 import Api
|
|
28
|
+
|
|
29
|
+
from actinia_cloudevent_plugin.endpoints import create_endpoints
|
|
30
|
+
from actinia_cloudevent_plugin.resources.logging import log
|
|
31
|
+
|
|
32
|
+
flask_app = Flask(__name__)
|
|
33
|
+
# allows endpoints with and without trailing slashes
|
|
34
|
+
flask_app.url_map.strict_slashes = False
|
|
35
|
+
CORS(flask_app)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
API_VERSION = "v1"
|
|
39
|
+
|
|
40
|
+
URL_PREFIX = f"/api/{API_VERSION}"
|
|
41
|
+
|
|
42
|
+
apidoc = Api(
|
|
43
|
+
flask_app,
|
|
44
|
+
title="actinia-cloudevent-plugin",
|
|
45
|
+
prefix=URL_PREFIX,
|
|
46
|
+
api_version=API_VERSION,
|
|
47
|
+
api_spec_url=f"{URL_PREFIX}/swagger",
|
|
48
|
+
schemes=["https", "http"],
|
|
49
|
+
consumes=["application/json"],
|
|
50
|
+
description="""Receives cloudevent,
|
|
51
|
+
transforms it to an actinia process chain
|
|
52
|
+
and returns cloudevent back.
|
|
53
|
+
""",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
create_endpoints(apidoc)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if __name__ == "__main__":
|
|
60
|
+
# call this for development only with:
|
|
61
|
+
# `python3 -m actinia_cloudevent_plugin.main`
|
|
62
|
+
log.debug("starting app in development mode...")
|
|
63
|
+
# ruff: S201 :Use of `debug=True` in Flask app detected
|
|
64
|
+
flask_app.run(debug=True, use_reloader=False) # noqa: S201
|
|
65
|
+
# for production environent use application in wsgi.py
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Copyright (c) 2018-2024 mundialis GmbH & Co. KG.
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
Response models
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__license__ = "GPLv3"
|
|
21
|
+
__author__ = "Anika Weinmann"
|
|
22
|
+
__copyright__ = "Copyright 2022 mundialis GmbH & Co. KG"
|
|
23
|
+
__maintainer__ = "mundialis GmbH & Co. KG"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
from typing import ClassVar
|
|
27
|
+
|
|
28
|
+
from flask_restful_swagger_2 import Schema
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SimpleStatusCodeResponseModel(Schema):
|
|
32
|
+
"""Simple response schema to inform about status."""
|
|
33
|
+
|
|
34
|
+
type: str = "object"
|
|
35
|
+
properties: ClassVar[dict] = {
|
|
36
|
+
"status": {
|
|
37
|
+
"type": "number",
|
|
38
|
+
"description": "The status code of the request.",
|
|
39
|
+
},
|
|
40
|
+
"message": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "A short message to describes the status",
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
required: ClassVar[list[str]] = ["status", "message"]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
simple_response_example = SimpleStatusCodeResponseModel(
|
|
49
|
+
status=200,
|
|
50
|
+
message="success",
|
|
51
|
+
)
|
|
52
|
+
SimpleStatusCodeResponseModel.example = simple_response_example
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Copyright (c) 2018-2025 mundialis GmbH & Co. KG.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
Configuration file
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
__author__ = "Carmen Tawalika, Lina Krisztian"
|
|
21
|
+
__copyright__ = "2018-2025 mundialis GmbH & Co. KG"
|
|
22
|
+
__license__ = "Apache-2.0"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
import configparser
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
# config can be overwritten by mounting *.ini files into folders inside
|
|
29
|
+
# the config folder.
|
|
30
|
+
DEFAULT_CONFIG_PATH = "config"
|
|
31
|
+
CONFIG_FILES = [
|
|
32
|
+
str(f) for f in Path(DEFAULT_CONFIG_PATH).glob("**/*.ini") if f.is_file()
|
|
33
|
+
]
|
|
34
|
+
GENERATED_CONFIG = DEFAULT_CONFIG_PATH + "/actinia-cloudevent-plugin.cfg"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class EVENTRECEIVER:
|
|
38
|
+
"""Default config for cloudevent receiver."""
|
|
39
|
+
|
|
40
|
+
url = "http://localhost:3000/"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class LOGCONFIG:
|
|
44
|
+
"""Default config for logging."""
|
|
45
|
+
|
|
46
|
+
logfile = "actinia-cloudevent-plugin.log"
|
|
47
|
+
level = "INFO"
|
|
48
|
+
type = "stdout"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class Configfile:
|
|
52
|
+
"""Configuration file."""
|
|
53
|
+
|
|
54
|
+
def __init__(self) -> None:
|
|
55
|
+
"""Overwrite config classes.
|
|
56
|
+
|
|
57
|
+
Will overwrite the config classes above when config files
|
|
58
|
+
named DEFAULT_CONFIG_PATH/**/*.ini exist.
|
|
59
|
+
On first import of the module it is initialized.
|
|
60
|
+
"""
|
|
61
|
+
config = configparser.ConfigParser()
|
|
62
|
+
config.read(CONFIG_FILES)
|
|
63
|
+
if len(config) <= 1:
|
|
64
|
+
print("Could not find any config file, using default values.")
|
|
65
|
+
return
|
|
66
|
+
print("Loading config files: " + str(CONFIG_FILES) + " ...")
|
|
67
|
+
|
|
68
|
+
with open( # noqa: PTH123
|
|
69
|
+
GENERATED_CONFIG,
|
|
70
|
+
"w",
|
|
71
|
+
encoding="utf-8",
|
|
72
|
+
) as configfile:
|
|
73
|
+
config.write(configfile)
|
|
74
|
+
print("Configuration written to " + GENERATED_CONFIG)
|
|
75
|
+
|
|
76
|
+
# LOGGING
|
|
77
|
+
if config.has_section("LOGCONFIG"):
|
|
78
|
+
if config.has_option("LOGCONFIG", "logfile"):
|
|
79
|
+
LOGCONFIG.logfile = config.get("LOGCONFIG", "logfile")
|
|
80
|
+
if config.has_option("LOGCONFIG", "level"):
|
|
81
|
+
LOGCONFIG.level = config.get("LOGCONFIG", "level")
|
|
82
|
+
if config.has_option("LOGCONFIG", "type"):
|
|
83
|
+
LOGCONFIG.type = config.get("LOGCONFIG", "type")
|
|
84
|
+
|
|
85
|
+
# EVENTRECEIVER
|
|
86
|
+
if config.has_section("EVENTRECEIVER"):
|
|
87
|
+
if config.has_option("EVENTRECEIVER", "url"):
|
|
88
|
+
EVENTRECEIVER.url = config.get("EVENTRECEIVER", "url")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
init = Configfile()
|