Skip to content

Commit

Permalink
Added october 2024 workshop
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Engel <[email protected]>
  • Loading branch information
engelmi committed Oct 9, 2024
1 parent 44eed1f commit f30bee8
Show file tree
Hide file tree
Showing 18 changed files with 568 additions and 0 deletions.
77 changes: 77 additions & 0 deletions workshop-october-2024/README.md
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
...
```
99 changes: 99 additions & 0 deletions workshop-october-2024/demo/applications/manager.py
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()
56 changes: 56 additions & 0 deletions workshop-october-2024/demo/applications/monitor.py
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()
24 changes: 24 additions & 0 deletions workshop-october-2024/demo/applications/set-cpu-weight.py
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)
57 changes: 57 additions & 0 deletions workshop-october-2024/demo/applications/tire-sensor.py
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()
7 changes: 7 additions & 0 deletions workshop-october-2024/demo/bluechi-config/agent-vm.conf
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
7 changes: 7 additions & 0 deletions workshop-october-2024/demo/bluechi-config/agent-worker.conf
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
6 changes: 6 additions & 0 deletions workshop-october-2024/demo/bluechi-config/controller.conf
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
11 changes: 11 additions & 0 deletions workshop-october-2024/demo/container/monitor
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"]
22 changes: 22 additions & 0 deletions workshop-october-2024/demo/container/worker
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"]
Loading

0 comments on commit f30bee8

Please sign in to comment.