More Networking Implementation

This commit is contained in:
ahmadbilalkhalid 2019-11-15 21:11:45 +05:00
commit fefbe2e1c7
17 changed files with 243 additions and 119 deletions

View file

@ -10,23 +10,26 @@ import subprocess as sp
import tempfile
import time
import random
import ipaddress
from functools import wraps
from os.path import join
from typing import Union
from decouple import config
from string import Template
import bitmath
import sshtunnel
import qmp
from config import (WITHOUT_CEPH, VM_PREFIX, VM_DIR, IMAGE_DIR,
NETWORK_PREFIX, etcd_client, logging,
request_pool, running_vms, vm_pool)
from decouple import config
from ucloud_common.helpers import get_ipv4_address
from ucloud_common.request import RequestEntry, RequestType
from ucloud_common.vm import VMEntry, VMStatus
from config import (WITHOUT_CEPH, VM_PREFIX, VM_DIR, IMAGE_DIR,
NETWORK_PREFIX, etcd_client, logging,
request_pool, running_vms, vm_pool)
class VM:
def __init__(self, key, handle, vnc_socket_file):
@ -38,10 +41,12 @@ class VM:
return "VM({})".format(self.key)
def create_dev(script, _id, dev):
assert isinstance(_id, str) and isinstance(dev, str), "_id and dev both must be string"
def create_dev(script, _id, dev, ip=None):
command = [script, _id, dev]
if ip:
command.append(ip)
try:
output = sp.check_output([script, _id, dev], stderr=sp.PIPE)
output = sp.check_output(command, stderr=sp.PIPE)
except Exception as e:
print(e.stderr)
return None
@ -49,13 +54,13 @@ def create_dev(script, _id, dev):
return output.decode("utf-8").strip()
def create_vxlan_br_tap(_id, _dev):
def create_vxlan_br_tap(_id, _dev, ip=None):
network_script_base = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'network')
vxlan = create_dev(script=os.path.join(network_script_base, 'create-vxlan.sh'),
_id=_id, dev=_dev)
if vxlan:
bridge = create_dev(script=os.path.join(network_script_base, 'create-bridge.sh'),
_id=_id, dev=vxlan)
_id=_id, dev=vxlan, ip=ip)
if bridge:
tap = create_dev(script=os.path.join(network_script_base, 'create-tap.sh'),
_id=str(random.randint(1, 100000)), dev=bridge)
@ -85,6 +90,28 @@ def generate_mac(uaa=False, multicast=False, oui=None, separator=':', byte_fmt='
return separator.join(byte_fmt % b for b in mac)
def update_radvd_conf(etcd_client):
network_script_base = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'network')
networks = {
net.value['ipv6']:net.value['id']
for net in etcd_client.get_prefix('/v1/network/', value_in_json=True)
if net.value.get('ipv6')
}
radvd_template = open(os.path.join(network_script_base,
'radvd-template.conf'), 'r').read()
radvd_template = Template(radvd_template)
content = [radvd_template.safe_substitute(bridge='br{}'.format(networks[net]),
prefix=net)
for net in networks if networks.get(net)]
with open('/etc/radvd.conf', 'w') as radvd_conf:
radvd_conf.writelines(content)
sp.check_output(['systemctl', 'restart', 'radvd'])
def get_start_command_args(
vm_entry, vnc_sock_filename: str, migration=False, migration_port=4444,
):
@ -94,7 +121,6 @@ def get_start_command_args(
vm_uuid = vm_entry.uuid
vm_networks = vm_entry.network
if WITHOUT_CEPH:
command = "-drive file={},format=raw,if=virtio,cache=none".format(
os.path.join(VM_DIR, vm_uuid)
@ -114,18 +140,22 @@ def get_start_command_args(
command += " -incoming tcp:0:{}".format(migration_port)
tap = None
for network_name in vm_networks:
for network_and_mac in vm_networks:
network_name, mac = network_and_mac
_key = os.path.join(NETWORK_PREFIX, vm_entry.owner, network_name)
network = etcd_client.get(_key, value_in_json=True)
network_type = network.value["type"]
network_id = str(network.value["id"])
network_ipv6 = network.value["ipv6"]
if network_type == "vxlan":
tap = create_vxlan_br_tap(network_id, config("VXLAN_PHY_DEV"))
tap = create_vxlan_br_tap(network_id, config("VXLAN_PHY_DEV"), network_ipv6)
update_radvd_conf(etcd_client)
command += " -netdev tap,id=vmnet{net_id},ifname={tap},script=no,downscript=no"\
" -device virtio-net-pci,netdev=vmnet{net_id},mac={mac}"\
.format(tap=tap, net_id=network_id, mac=generate_mac())
.format(tap=tap, net_id=network_id, mac=mac)
return command.split(" ")