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

@ -163,3 +163,21 @@ def get_etcd_counter(etcd_client, key):
if kv:
return int(kv.value)
return None
def mac2ipv6(mac, prefix):
# only accept MACs separated by a colon
parts = mac.split(":")
# modify parts to match IPv6 value
parts.insert(3, "ff")
parts.insert(4, "fe")
parts[0] = "%x" % (int(parts[0], 16) ^ 2)
# format output
ipv6Parts = [str(0)]*4
for i in range(0, len(parts), 2):
ipv6Parts.append("".join(parts[i:i+2]))
lower_part = ipaddress.IPv6Address(":".join(ipv6Parts))
prefix = ipaddress.IPv6Address(prefix)
return str(prefix + int(lower_part))

View file

@ -1,6 +1,8 @@
import json
import subprocess
import os
import pynetbox
import decouple
import schemas
@ -12,7 +14,8 @@ from flask_restful import Resource, Api
from ucloud_common.vm import VMStatus
from ucloud_common.request import RequestEntry, RequestType
from helper import generate_mac, get_ip_addr, get_etcd_counter, increment_etcd_counter
from helper import (generate_mac, get_ip_addr, get_etcd_counter,
increment_etcd_counter, mac2ipv6)
from config import (
etcd_client,
@ -46,7 +49,7 @@ class CreateVM(Resource):
'os-ssd': validator.specs['os-ssd'],
'hdd': validator.specs['hdd']
}
macs = [generate_mac() for i in range(len(data["network"]))]
vm_entry = {
"name": data["vm_name"],
"owner": data["name"],
@ -57,7 +60,7 @@ class CreateVM(Resource):
"image_uuid": validator.image_uuid,
"log": [],
"vnc_socket": "",
"network": data["network"],
"network": list(zip(data["network"], macs)),
"metadata": {
"ssh-keys": []
},
@ -80,7 +83,13 @@ class VmStatus(Resource):
if validator.is_valid():
vm = VM_POOL.get(os.path.join(VM_PREFIX, data["uuid"]))
vm_value = vm.value.copy()
# vm_value["ip"] = list(map(str, get_ip_addr(vm.mac, "br0")))
vm_value["ip"] = []
for network_and_mac in vm.network:
network_name, mac = network_and_mac
network = etcd_client.get(os.path.join(NETWORK_PREFIX, data["name"], network_name),
value_in_json=True)
ipv6_addr = network.value.get("ipv6").split("::")[0] + "::"
vm_value["ip"].append(mac2ipv6(mac, ipv6_addr))
vm.value = vm_value
return vm.value
else:
@ -296,7 +305,8 @@ class GetSSHKeys(Resource):
if not validator.key_name.value:
# {user_prefix}/{realm}/{name}/key/
etcd_key = os.path.join(USER_PREFIX, data["realm"], data["name"], "key")
etcd_key = os.path.join(decouple.config("USER_PREFIX"), data["realm"],
data["name"], "key")
etcd_entry = etcd_client.get_prefix(etcd_key, value_in_json=True)
keys = {key.key.split("/")[-1]: key.value for key in etcd_entry}
@ -304,8 +314,8 @@ class GetSSHKeys(Resource):
else:
# {user_prefix}/{realm}/{name}/key/{key_name}
etcd_key = os.path.join(USER_PREFIX, data["realm"], data["name"],
"key", data["key_name"])
etcd_key = os.path.join(decouple.config("USER_PREFIX"), data["realm"],
data["name"], "key", data["key_name"])
etcd_entry = etcd_client.get(etcd_key, value_in_json=True)
if etcd_entry:
@ -367,8 +377,25 @@ class CreateNetwork(Resource):
network_entry = {
"id": increment_etcd_counter(etcd_client, "/v1/counter/vxlan"),
"type": data["type"]
"type": data["type"],
}
if validator.user.value:
nb = pynetbox.api(url=decouple.config("NETBOX_URL"),
token=decouple.config("NETBOX_TOKEN"))
nb_prefix = nb.ipam.prefixes.get(prefix=decouple.config("PREFIX"))
prefix = nb_prefix.available_prefixes.create(data=
{
"prefix_length": decouple.config("PREFIX_LENGTH", cast=int),
"description": "{}'s network \"{}\"".format(data["name"],
data["network_name"]),
"is_pool": True
}
)
network_entry["ipv6"] = prefix["prefix"]
else:
network_entry["ipv6"] = "fd00::/64"
network_key = os.path.join(NETWORK_PREFIX, data["name"], data["network_name"])
etcd_client.put(network_key, network_entry, value_in_json=True)
return {"message": "Network successfully added."}

View file

@ -438,11 +438,12 @@ class CreateNetwork(OTPSchema):
def __init__(self, data):
self.network_name = Field("network_name", str, data.get("network_name", KeyError))
self.type = Field("type", str, data.get("type", KeyError))
self.user = Field("user", bool, bool(data.get("user", False)))
self.network_name.validation = self.network_name_validation
self.type.validation = self.network_type_validation
fields = [self.network_name, self.type]
fields = [self.network_name, self.type, self.user]
super().__init__(data, fields=fields)
def network_name_validation(self):