aetherscale

[unmaintained] code for a cloud provider tutorial
Log | Files | Refs | README | LICENSE

commit 918e8b645addc6d7acf69c34cfa565ebe811750b
parent 8736a5ea5d048752c5c46dc24004e1d4310fb586
Author: Stefan Koch <programming@stefan-koch.name>
Date:   Sat, 28 Nov 2020 17:03:33 +0100

use VDE for networking

Diffstat:
Maetherscale/computing.py | 61+++++++++++++++++++++++++++++++++++++++++++++++++++----------
Maetherscale/execution.py | 34++++++++++++++++++++++++++++++++++
Adata/systemd/aetherscale-vde.service | 8++++++++
3 files changed, 93 insertions(+), 10 deletions(-)

diff --git a/aetherscale/computing.py b/aetherscale/computing.py @@ -1,3 +1,4 @@ +import logging import json import os from pathlib import Path @@ -7,10 +8,19 @@ import random import string import subprocess import sys +import time from typing import List, Optional from . import interfaces +from . import execution +# TODO: Since this is not a command line interface file anymore, switch to +# logging from print + +# Non-VDE networking is deprecated and should not be used anymore +NETWORKING_MODE = 'vde' +VDE_FOLDER = '/tmp/vde.ctl' +VDE_TAP_INTERFACE = 'tap-vde' QUEUE_NAME = 'vm-queue' BASE_IMAGE_FOLDER = Path('base_images') @@ -110,20 +120,28 @@ def callback(ch, method, properties, body): print(str(e), file=sys.stderr) return - tap_device = f'vm-{vm_id}' - if not interfaces.create_tap_device( - tap_device, 'br0', run_qemu_username): - print(f'Could not create tap device for VM "{vm_id}"', - file=sys.stderr) - return + if NETWORKING_MODE != 'vde': + tap_device = f'vm-{vm_id}' + if not interfaces.create_tap_device( + tap_device, 'br0', run_qemu_username): + print(f'Could not create tap device for VM "{vm_id}"', + file=sys.stderr) + return mac_addr = interfaces.create_mac_address() print(f'Assigning MAC address "{mac_addr}" to VM "{vm_id}"') + if NETWORKING_MODE == 'vde': + netdev = \ + f'vde,id=pubnet,sock={VDE_FOLDER}' + else: + netdev = \ + f'tap,id=pubnet,ifname={tap_device},script=no,downscript=no' + p = subprocess.Popen([ 'qemu-system-x86_64', '-m', '4096', '-hda', str(user_image), '-device', f'virtio-net-pci,netdev=pubnet,mac={mac_addr}', - '-netdev', f'tap,id=pubnet,ifname={tap_device},script=no,downscript=no', + '-netdev', netdev, '-name', f'qemu-vm-{vm_id},process=vm-{vm_id}', ]) print(f'Started VM "{vm_id}" as process ID {p.pid}') @@ -143,8 +161,31 @@ def callback(ch, method, properties, body): def run(): channel.basic_consume(queue=QUEUE_NAME, on_message_callback=callback) - if not interfaces.check_device_existence('br0'): - interfaces.init_bridge( - 'br0', 'enp0s25', '192.168.2.10/24', '192.168.2.1') + # if we're on VDE networking, a TAP interface must already have been + # created + if NETWORKING_MODE == 'vde': + if not interfaces.check_device_existence(VDE_TAP_INTERFACE): + print( + f'Interface {VDE_TAP_INTERFACE} does not exist. ' + 'Please create it manually and then start this service again', + file=sys.stderr) + sys.exit(1) + + logging.info('Bringing up VDE networking') + execution.copy_systemd_unit( + Path('data/systemd/aetherscale-vde.service'), + 'aetherscale-vde.service') + execution.start_systemd_unit('aetherscale-vde.service') + # Give systemd a bit time to start VDE + time.sleep(0.5) + if not execution.systemctl_is_running('aetherscale-vde.service'): + logging.error('Failed to start VDE networking.') + sys.exit(1) + else: + if not interfaces.check_device_existence('br0'): + # TODO: Should remove hardcoded IP addresses, but this + # networking method will be deleted anyway + interfaces.init_bridge( + 'br0', 'enp0s25', '192.168.2.10/24', '192.168.2.1') channel.start_consuming() diff --git a/aetherscale/execution.py b/aetherscale/execution.py @@ -1,4 +1,6 @@ import logging +from pathlib import Path +import shutil import subprocess from typing import List @@ -12,3 +14,35 @@ def run_command_chain(commands: List[List[str]]) -> bool: return False return True + + +def copy_systemd_unit(unit_file: Path, unit_name: str): + if '.' not in unit_name: + raise ValueError('Unit name must contain the suffix, e.g. .service') + + systemd_unit_dir = Path().home() / '.config/systemd/user' + systemd_unit_dir.mkdir(parents=True, exist_ok=True) + target_unit_file = systemd_unit_dir / unit_name + + shutil.copyfile(unit_file, target_unit_file) + + # Reload system + subprocess.run(['systemctl', '--user', 'daemon-reload']) + + +def start_systemd_unit(unit_name: str) -> bool: + return run_command_chain([ + ['systemctl', '--user', 'start', unit_name], + ]) + + +def enable_systemd_unit(unit_name: str) -> bool: + return run_command_chain([ + ['systemctl', '--user', 'enable', unit_name], + ]) + + +def systemctl_is_running(unit_name: str) -> bool: + result = subprocess.run([ + 'systemctl', '--user', 'is-active', '--quiet', unit_name]) + return result.returncode == 0 diff --git a/data/systemd/aetherscale-vde.service b/data/systemd/aetherscale-vde.service @@ -0,0 +1,8 @@ +[Unit] +Description=aetherscale VDE networking + +[Service] +ExecStart=/usr/bin/vde_switch -tap tap-vde -s /tmp/vde.ctl + +[Install] +WantedBy=default.target