-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Michael Engel <[email protected]>
- Loading branch information
Showing
18 changed files
with
568 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Workshop - October 2024 | ||
|
||
Complementary slides for this demo can be found [here](./slides.pdf). | ||
|
||
## Preparations | ||
|
||
### Setup AutoSD VM | ||
|
||
1. Download AutoSD image `auto-osbuild-qemu-autosd9-developer-regular` from | ||
|
||
``` | ||
https://autosd.sig.centos.org/AutoSD-9/nightly/sample-images/ | ||
``` | ||
|
||
2. Run image with | ||
|
||
```bash | ||
# get image name | ||
$ AUTOSD_IMAGE_NAME="$(curl https://autosd.sig.centos.org/AutoSD-9/nightly/sample-images/ | grep -oE 'auto-osbuild-qemu-autosd9-developer-regular-x86_64-[0-9]+\.[A-Za-z0-9]+\.qcow2\.xz' | head -n 1)" | ||
|
||
# download and decompress the image | ||
$ wget \ | ||
-O auto-osbuild-qemu-autosd9-developer-regular-x86_64.qcow2.xz \ | ||
https://autosd.sig.centos.org/AutoSD-9/nightly/sample-images/$AUTOSD_IMAGE_NAME | ||
$ xz -d auto-osbuild-qemu-autosd9-developer-regular-x86_64.qcow2.xz | ||
|
||
# run the image | ||
$ /usr/bin/qemu-system-x86_64 \ | ||
-drive file=/usr/share/OVMF/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \ | ||
-drive file=/usr/share/OVMF/OVMF_VARS.fd,if=pflash,format=raw,unit=1,snapshot=on,readonly=off \ | ||
-smp 20 \ | ||
-enable-kvm \ | ||
-m 2G \ | ||
-machine q35 \ | ||
-cpu host \ | ||
-device virtio-net-pci,netdev=n0 \ | ||
-netdev user,id=n0,net=10.0.2.0/24,hostfwd=tcp::2222-:22,hostfwd=tcp::8420-:8420 \ | ||
-drive file=auto-osbuild-qemu-autosd9-developer-regular-x86_64.qcow2,index=0,media=disk,format=qcow2,if=virtio,snapshot=off | ||
``` | ||
|
||
3. Login and enable ssh access for root: | ||
|
||
```bash | ||
$ vim /etc/ssh/sshd_config | ||
... | ||
PasswordAuthentication yes | ||
PermitRootLogin yes | ||
... | ||
``` | ||
|
||
### Setup everything | ||
|
||
Copy the [demo directory](./demo/) to the VM: | ||
|
||
```bash | ||
$ scp -r -P 2222 demo/ [email protected]:/root/ | ||
``` | ||
|
||
SSH to the VM and run the [setup.sh](./demo/setup.sh) (might need a reboot and another run due to the `kernel-automotive-modules-extra` package for vcan): | ||
|
||
```bash | ||
$ ssh -P 2222 [email protected] | ||
[email protected]'s password: | ||
**** | ||
[root@localhost ~]# chmod +x ./demo/setup.sh | ||
[root@localhost ~]# ./demo/setup.sh | ||
``` | ||
### Run the demo | ||
After running the [setup script](#setup-everything), run the demo inside the VM: | ||
```bash | ||
$ ./demo/run.sh | ||
... | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import can | ||
import signal | ||
import threading | ||
import logging | ||
import sys | ||
from flask_cors import CORS | ||
from flask import Flask, Response | ||
from werkzeug.serving import make_server, BaseWSGIServer | ||
|
||
logger = logging.getLogger(__name__) | ||
logger.setLevel(logging.INFO) | ||
logger.addHandler(logging.StreamHandler(stream=sys.stdout)) | ||
|
||
|
||
class Server(): | ||
|
||
def __init__(self) -> None: | ||
self.app = Flask(__name__) | ||
self.app.config.from_object(__name__) | ||
self.app.config.from_envvar('SKELETON_SETTINGS', silent=True) | ||
CORS(self.app) | ||
self.app.wsgi_app = ProxyFixupHelper(self.app.wsgi_app) | ||
|
||
@self.app.route("/tire/pressure", methods=["GET"]) | ||
def handle_tire_pressure(): | ||
print("Handling GET /tire/pressure...") | ||
|
||
return Response(f"{self.tire_pressure}", status=200, mimetype="text/plain") | ||
|
||
self.server: BaseWSGIServer = make_server("127.0.0.1", 5000, self.app) | ||
|
||
self.tire_pressure = 0 | ||
self.canbus = can.Bus(interface='socketcan', | ||
channel='vcan0', | ||
receive_own_messages=False) | ||
|
||
self.tire_pressure_worker: threading.Thread = None | ||
self.flask_worker: threading.Thread = None | ||
|
||
def update_tire_pressure(self): | ||
try: | ||
for msg in self.canbus: | ||
pressure = int.from_bytes( | ||
msg.data, byteorder='big', signed=False) | ||
logger.info( | ||
f"Update tire pressure from '{self.tire_pressure}' to '{pressure}'") | ||
self.tire_pressure = pressure | ||
except can.exceptions.CanError as ex: | ||
if not self.canbus._is_shutdown: | ||
logger.error(f"CANError: {ex}") | ||
|
||
def run(self) -> None: | ||
self.tire_pressure_worker = threading.Thread( | ||
target=self.update_tire_pressure, args=()) | ||
self.tire_pressure_worker.start() | ||
|
||
self.flask_worker = threading.Thread( | ||
target=self.server.serve_forever, args=()) | ||
self.flask_worker.start() | ||
|
||
self.tire_pressure_worker.join() | ||
self.flask_worker.join() | ||
|
||
def shutdown(self) -> None: | ||
self.canbus.shutdown() | ||
self.server.shutdown() | ||
|
||
|
||
class ProxyFixupHelper(object): | ||
def __init__(self, app): | ||
self.app = app | ||
|
||
def __call__(self, environ, start_response): | ||
# Only perform this fixup if the current remote host is localhost. | ||
if environ['REMOTE_ADDR'] == '127.0.0.1': | ||
host = environ.get('HTTP_X_REAL_IP', False) | ||
if host: | ||
environ['REMOTE_ADDR'] = host | ||
return self.app(environ, start_response) | ||
|
||
|
||
class ShutdownHandler: | ||
def __init__(self, server: Server) -> None: | ||
self.server = server | ||
|
||
def handle_kill(self, signum, frame): | ||
self.server.shutdown() | ||
|
||
def __enter__(self): | ||
signal.signal(signal.SIGINT, self.handle_kill) | ||
|
||
def __exit__(self, type, value, traceback): | ||
pass | ||
|
||
|
||
if __name__ == "__main__": | ||
server = Server() | ||
with ShutdownHandler(server): | ||
server.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import time | ||
import signal | ||
import requests | ||
import logging | ||
import sys | ||
|
||
logger = logging.getLogger(__name__) | ||
logger.setLevel(logging.INFO) | ||
logger.addHandler(logging.StreamHandler(stream=sys.stdout)) | ||
|
||
|
||
class Monitor(): | ||
|
||
def __init__(self) -> None: | ||
self.is_running = True | ||
|
||
def run(self) -> None: | ||
while self.is_running: | ||
try: | ||
resp = requests.get("http://127.0.0.1:5000/tire/pressure") | ||
if resp.status_code != 200: | ||
logger.error(f"Failed to fetch tire pressure") | ||
continue | ||
|
||
pressure = int(resp.content) | ||
if pressure < 50: | ||
logger.error(f"Tire pressue '{pressure}' below threshold!") | ||
else: | ||
logger.info(f"Tire pressure '{pressure}' is fine") | ||
except Exception as ex: | ||
logger.error(f"Failed fetching tire pressure: {ex}") | ||
|
||
time.sleep(5) | ||
|
||
def shutdown(self) -> None: | ||
self.is_running = False | ||
|
||
|
||
class ShutdownHandler: | ||
def __init__(self, monitor: Monitor) -> None: | ||
self.monitor = monitor | ||
|
||
def handle_kill(self, signum, frame): | ||
self.monitor.shutdown() | ||
|
||
def __enter__(self): | ||
signal.signal(signal.SIGINT, self.handle_kill) | ||
|
||
def __exit__(self, type, value, traceback): | ||
pass | ||
|
||
|
||
if __name__ == "__main__": | ||
monitor = Monitor() | ||
with ShutdownHandler(monitor): | ||
monitor.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import sys | ||
from bluechi.api import Node, Variant | ||
|
||
|
||
def set_cpu_weight(node_name: str, unit_name: str, cpu_weight: int): | ||
node = Node(node_name) | ||
if node.status != "online": | ||
print("Node {node_name} not online, aborting...") | ||
return | ||
|
||
node.set_unit_properties( | ||
unit_name, True, [("CPUWeight", Variant("t", cpu_weight))]) | ||
|
||
|
||
if __name__ == "__main__": | ||
if len(sys.argv) != 4: | ||
print(f"Usage: python3 {sys.argv[0]} node_name unit_name cpu_weight") | ||
sys.exit(1) | ||
|
||
node_name = sys.argv[1] | ||
unit_name = sys.argv[2] | ||
value = int(sys.argv[3]) | ||
|
||
set_cpu_weight(node_name, unit_name, value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import can | ||
import signal | ||
import time | ||
import random | ||
import logging | ||
import sys | ||
|
||
logger = logging.getLogger(__name__) | ||
logger.setLevel(logging.INFO) | ||
logger.addHandler(logging.StreamHandler(stream=sys.stdout)) | ||
|
||
|
||
class TirePressureService(): | ||
|
||
def __init__(self) -> None: | ||
self.canbus = can.Bus(interface='socketcan', | ||
channel='vcan0', | ||
receive_own_messages=False) | ||
self.is_running = True | ||
|
||
def run(self): | ||
try: | ||
while self.is_running: | ||
pressure = random.randrange(0, 100) | ||
logger.info( | ||
f"Sending CAN message with tire pressure: {pressure}") | ||
msg = can.Message(data=[pressure]) | ||
self.canbus.send(msg) | ||
|
||
time.sleep(2) | ||
except can.exceptions.CanError as ex: | ||
if not self.canbus._is_shutdown: | ||
logger.error(f"CANError: {ex}") | ||
|
||
def shutdown(self): | ||
self.is_running = False | ||
self.canbus.shutdown() | ||
|
||
|
||
class ShutdownHandler: | ||
def __init__(self, service: TirePressureService) -> None: | ||
self.service = service | ||
|
||
def handle_kill(self, signum, frame): | ||
service.shutdown() | ||
|
||
def __enter__(self): | ||
signal.signal(signal.SIGINT, self.handle_kill) | ||
|
||
def __exit__(self, type, value, traceback): | ||
pass | ||
|
||
|
||
if __name__ == "__main__": | ||
service = TirePressureService() | ||
with ShutdownHandler(service): | ||
service.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[bluechi-agent] | ||
NodeName=vm | ||
ControllerHost=127.0.0.1 | ||
ControllerPort=8420 | ||
#ManagerAddress= | ||
LogLevel=DEBUG | ||
LogTarget=journald |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[bluechi-agent] | ||
NodeName=worker | ||
ControllerHost=127.0.0.1 | ||
ControllerPort=8420 | ||
#ManagerAddress= | ||
LogLevel=DEBUG | ||
LogTarget=journald |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[bluechi-controller] | ||
ControllerPort=8420 | ||
AllowedNodeNames=vm,worker,laptop | ||
LogLevel=DEBUG | ||
LogTarget=journald | ||
LogIsQuiet=false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
FROM quay.io/centos/centos:stream9 | ||
|
||
RUN dnf upgrade --refresh --nodocs -y && \ | ||
dnf install python3-pip -y && \ | ||
dnf -y clean all | ||
RUN pip3 install requests | ||
|
||
RUN mkdir -p /var/demo | ||
COPY ./applications/monitor.py /var/demo/monitor.py | ||
|
||
CMD ["/usr/bin/python3", "/var/demo/monitor.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
FROM quay.io/centos/centos:stream9 | ||
|
||
RUN dnf upgrade --refresh --nodocs -y && \ | ||
dnf install --nodocs epel-release -y && \ | ||
dnf copr enable @centos-automotive-sig/bluechi-snapshot -y && \ | ||
dnf install bluechi-agent \ | ||
bluechi-selinux \ | ||
systemd \ | ||
kmod \ | ||
can-utils \ | ||
python3-pip \ | ||
-y && \ | ||
dnf -y clean all | ||
RUN pip3 install requests | ||
|
||
COPY ./bluechi-config/agent-worker.conf /etc/bluechi/agent.conf.d/agent.conf | ||
|
||
RUN mkdir -p /var/demo | ||
COPY ./applications/monitor.py /var/demo/monitor.py | ||
COPY ./services/demo-monitor.service /etc/systemd/system/demo-monitor.service | ||
|
||
CMD ["/sbin/init"] |
Oops, something went wrong.