More Networking Implementation
This commit is contained in:
parent
f6eb2ec01f
commit
fefbe2e1c7
17 changed files with 243 additions and 119 deletions
|
|
@ -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))
|
||||
|
|
|
|||
43
api/main.py
43
api/main.py
|
|
@ -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."}
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue