2018-09-20 03:25:58 -04:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
# network.py - PVC client function library, Network fuctions
|
2018-09-20 03:25:58 -04:00
|
|
|
# Part of the Parallel Virtual Cluster (PVC) system
|
|
|
|
#
|
2021-03-25 17:01:55 -04:00
|
|
|
# Copyright (C) 2018-2021 Joshua M. Boniface <joshua@boniface.me>
|
2018-09-20 03:25:58 -04:00
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
2021-03-25 16:57:17 -04:00
|
|
|
# the Free Software Foundation, version 3.
|
2018-09-20 03:25:58 -04:00
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
import re
|
2020-11-06 19:22:49 -05:00
|
|
|
|
2021-06-21 18:40:11 -04:00
|
|
|
import daemon_lib.common as common
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-09-20 03:25:58 -04:00
|
|
|
#
|
|
|
|
# Cluster search functions
|
|
|
|
#
|
2021-05-29 20:53:42 -04:00
|
|
|
def getClusterNetworkList(zkhandler):
|
2018-09-23 15:26:20 -04:00
|
|
|
# Get a list of VNIs by listing the children of /networks
|
2021-11-06 03:02:43 -04:00
|
|
|
vni_list = zkhandler.children("base.network")
|
2018-09-23 15:26:20 -04:00
|
|
|
description_list = []
|
|
|
|
# For each VNI, get the corresponding description from the data
|
|
|
|
for vni in vni_list:
|
2021-11-06 03:02:43 -04:00
|
|
|
description_list.append(zkhandler.read(("network", vni)))
|
2018-09-23 15:26:20 -04:00
|
|
|
return vni_list, description_list
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def searchClusterByVNI(zkhandler, vni):
|
2018-09-20 03:25:58 -04:00
|
|
|
try:
|
|
|
|
# Get the lists
|
2021-05-29 20:53:42 -04:00
|
|
|
vni_list, description_list = getClusterNetworkList(zkhandler)
|
2018-09-20 03:25:58 -04:00
|
|
|
# We're looking for UUID, so find that element ID
|
2018-09-23 15:26:20 -04:00
|
|
|
index = vni_list.index(vni)
|
2018-09-20 03:25:58 -04:00
|
|
|
# Get the name_list element at that index
|
2018-09-23 15:26:20 -04:00
|
|
|
description = description_list[index]
|
2018-09-20 03:25:58 -04:00
|
|
|
except ValueError:
|
|
|
|
# We didn't find anything
|
|
|
|
return None
|
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
return description
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def searchClusterByDescription(zkhandler, description):
|
2018-09-20 03:25:58 -04:00
|
|
|
try:
|
|
|
|
# Get the lists
|
2021-05-29 20:53:42 -04:00
|
|
|
vni_list, description_list = getClusterNetworkList(zkhandler)
|
2018-09-20 03:25:58 -04:00
|
|
|
# We're looking for name, so find that element ID
|
2018-09-23 15:26:20 -04:00
|
|
|
index = description_list.index(description)
|
2018-09-20 03:25:58 -04:00
|
|
|
# Get the uuid_list element at that index
|
2018-09-23 15:26:20 -04:00
|
|
|
vni = vni_list[index]
|
2018-09-20 03:25:58 -04:00
|
|
|
except ValueError:
|
|
|
|
# We didn't find anything
|
|
|
|
return None
|
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
return vni
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def getNetworkVNI(zkhandler, network):
|
2018-09-23 15:26:20 -04:00
|
|
|
# Validate and obtain alternate passed value
|
|
|
|
if network.isdigit():
|
2021-05-29 20:53:42 -04:00
|
|
|
net_description = searchClusterByVNI(zkhandler, network)
|
|
|
|
net_vni = searchClusterByDescription(zkhandler, net_description)
|
2018-09-23 15:26:20 -04:00
|
|
|
else:
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = searchClusterByDescription(zkhandler, network)
|
|
|
|
net_description = searchClusterByVNI(zkhandler, net_vni)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
return net_vni
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def getNetworkDescription(zkhandler, network):
|
2018-09-20 03:25:58 -04:00
|
|
|
# Validate and obtain alternate passed value
|
2018-09-23 15:26:20 -04:00
|
|
|
if network.isdigit():
|
2021-05-29 20:53:42 -04:00
|
|
|
net_description = searchClusterByVNI(zkhandler, network)
|
|
|
|
net_vni = searchClusterByDescription(zkhandler, net_description)
|
2018-09-20 03:25:58 -04:00
|
|
|
else:
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = searchClusterByDescription(zkhandler, network)
|
|
|
|
net_description = searchClusterByVNI(zkhandler, net_vni)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
return net_description
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def getNetworkDHCPLeases(zkhandler, vni):
|
2018-11-18 00:55:04 -05:00
|
|
|
# Get a list of DHCP leases by listing the children of /networks/<vni>/dhcp4_leases
|
2021-11-06 03:02:43 -04:00
|
|
|
leases = zkhandler.children(("network.lease", vni))
|
2021-06-12 18:40:25 -04:00
|
|
|
return sorted(leases)
|
2018-10-02 00:02:23 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def getNetworkDHCPReservations(zkhandler, vni):
|
2018-11-18 00:55:04 -05:00
|
|
|
# Get a list of DHCP reservations by listing the children of /networks/<vni>/dhcp4_reservations
|
2021-11-06 03:02:43 -04:00
|
|
|
reservations = zkhandler.children(("network.reservation", vni))
|
2021-06-12 18:40:25 -04:00
|
|
|
return sorted(reservations)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def getNetworkACLs(zkhandler, vni, _direction):
|
2018-10-17 00:23:27 -04:00
|
|
|
# Get the (sorted) list of active ACLs
|
2021-11-06 03:02:43 -04:00
|
|
|
if _direction == "both":
|
|
|
|
directions = ["in", "out"]
|
2018-10-17 20:05:22 -04:00
|
|
|
else:
|
|
|
|
directions = [_direction]
|
|
|
|
|
2018-10-17 00:23:27 -04:00
|
|
|
full_acl_list = []
|
2018-10-17 20:05:22 -04:00
|
|
|
for direction in directions:
|
2021-11-06 03:02:43 -04:00
|
|
|
unordered_acl_list = zkhandler.children((f"network.rule.{direction}", vni))
|
2021-06-13 20:55:15 -04:00
|
|
|
if len(unordered_acl_list) < 1:
|
|
|
|
continue
|
|
|
|
|
2018-11-02 00:42:44 -04:00
|
|
|
ordered_acls = dict()
|
2018-10-17 20:05:22 -04:00
|
|
|
for acl in unordered_acl_list:
|
2021-11-06 03:02:43 -04:00
|
|
|
order = zkhandler.read(
|
|
|
|
(f"network.rule.{direction}", vni, "rule.order", acl)
|
|
|
|
)
|
2021-06-13 20:55:15 -04:00
|
|
|
if order is None:
|
|
|
|
continue
|
2018-10-17 20:05:22 -04:00
|
|
|
ordered_acls[order] = acl
|
2018-10-17 00:23:27 -04:00
|
|
|
|
2018-10-17 20:05:22 -04:00
|
|
|
for order in sorted(ordered_acls.keys()):
|
2021-11-06 03:02:43 -04:00
|
|
|
rule = zkhandler.read((f"network.rule.{direction}", vni, "rule.rule", acl))
|
2021-06-13 20:55:15 -04:00
|
|
|
if rule is None:
|
|
|
|
continue
|
2021-11-06 03:02:43 -04:00
|
|
|
full_acl_list.append(
|
|
|
|
{
|
|
|
|
"direction": direction,
|
|
|
|
"order": int(order),
|
|
|
|
"description": ordered_acls[order],
|
|
|
|
"rule": rule,
|
|
|
|
}
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
|
|
|
return full_acl_list
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def getNetworkInformation(zkhandler, vni):
|
2021-11-06 03:02:43 -04:00
|
|
|
description = zkhandler.read(("network", vni))
|
|
|
|
nettype = zkhandler.read(("network.type", vni))
|
|
|
|
mtu = zkhandler.read(("network.mtu", vni))
|
|
|
|
domain = zkhandler.read(("network.domain", vni))
|
|
|
|
name_servers = zkhandler.read(("network.nameservers", vni))
|
|
|
|
ip6_network = zkhandler.read(("network.ip6.network", vni))
|
|
|
|
ip6_gateway = zkhandler.read(("network.ip6.gateway", vni))
|
|
|
|
dhcp6_flag = zkhandler.read(("network.ip6.dhcp", vni))
|
|
|
|
ip4_network = zkhandler.read(("network.ip4.network", vni))
|
|
|
|
ip4_gateway = zkhandler.read(("network.ip4.gateway", vni))
|
|
|
|
dhcp4_flag = zkhandler.read(("network.ip4.dhcp", vni))
|
|
|
|
dhcp4_start = zkhandler.read(("network.ip4.dhcp_start", vni))
|
|
|
|
dhcp4_end = zkhandler.read(("network.ip4.dhcp_end", vni))
|
2019-07-04 23:01:22 -04:00
|
|
|
|
|
|
|
# Construct a data structure to represent the data
|
|
|
|
network_information = {
|
2021-11-06 03:02:43 -04:00
|
|
|
"vni": int(vni),
|
|
|
|
"description": description,
|
|
|
|
"type": nettype,
|
|
|
|
"mtu": mtu,
|
|
|
|
"domain": domain,
|
|
|
|
"name_servers": name_servers.split(","),
|
|
|
|
"ip6": {
|
|
|
|
"network": ip6_network,
|
|
|
|
"gateway": ip6_gateway,
|
|
|
|
"dhcp_flag": dhcp6_flag,
|
|
|
|
},
|
|
|
|
"ip4": {
|
|
|
|
"network": ip4_network,
|
|
|
|
"gateway": ip4_gateway,
|
|
|
|
"dhcp_flag": dhcp4_flag,
|
|
|
|
"dhcp_start": dhcp4_start,
|
|
|
|
"dhcp_end": dhcp4_end,
|
2020-11-06 22:29:49 -05:00
|
|
|
},
|
2019-07-04 23:01:22 -04:00
|
|
|
}
|
|
|
|
return network_information
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def getDHCPLeaseInformation(zkhandler, vni, mac_address):
|
2020-05-09 10:20:06 -04:00
|
|
|
# Check whether this is a dynamic or static lease
|
2021-11-06 03:02:43 -04:00
|
|
|
if zkhandler.exists(("network.lease", vni, "lease", mac_address)):
|
|
|
|
type_key = "lease"
|
|
|
|
elif zkhandler.exists(("network.reservation", vni, "reservation", mac_address)):
|
|
|
|
type_key = "reservation"
|
2021-05-29 20:53:42 -04:00
|
|
|
else:
|
2021-06-13 21:10:42 -04:00
|
|
|
return None
|
2020-11-06 19:05:48 -05:00
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
hostname = zkhandler.read(
|
|
|
|
(f"network.{type_key}", vni, f"{type_key}.hostname", mac_address)
|
|
|
|
)
|
|
|
|
ip4_address = zkhandler.read(
|
|
|
|
(f"network.{type_key}", vni, f"{type_key}.ip", mac_address)
|
|
|
|
)
|
|
|
|
if type_key == "lease":
|
|
|
|
timestamp = zkhandler.read(
|
|
|
|
(f"network.{type_key}", vni, f"{type_key}.expiry", mac_address)
|
|
|
|
)
|
2020-05-09 10:20:06 -04:00
|
|
|
else:
|
2021-11-06 03:02:43 -04:00
|
|
|
timestamp = "static"
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2019-07-04 23:01:22 -04:00
|
|
|
# Construct a data structure to represent the data
|
|
|
|
lease_information = {
|
2021-11-06 03:02:43 -04:00
|
|
|
"hostname": hostname,
|
|
|
|
"ip4_address": ip4_address,
|
|
|
|
"mac_address": mac_address,
|
|
|
|
"timestamp": timestamp,
|
2019-07-04 23:01:22 -04:00
|
|
|
}
|
|
|
|
return lease_information
|
2018-10-03 23:16:31 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-06-12 18:40:25 -04:00
|
|
|
def getACLInformation(zkhandler, vni, direction, acl):
|
2021-11-06 03:02:43 -04:00
|
|
|
order = zkhandler.read((f"network.rule.{direction}", vni, "rule.order", acl))
|
|
|
|
rule = zkhandler.read((f"network.rule.{direction}", vni, "rule.rule", acl))
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2019-07-04 23:01:22 -04:00
|
|
|
# Construct a data structure to represent the data
|
|
|
|
acl_information = {
|
2021-11-06 03:02:43 -04:00
|
|
|
"order": order,
|
|
|
|
"description": acl,
|
|
|
|
"rule": rule,
|
|
|
|
"direction": direction,
|
2019-07-04 23:01:22 -04:00
|
|
|
}
|
|
|
|
return acl_information
|
2018-10-17 00:23:27 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-09-28 20:31:56 -04:00
|
|
|
def isValidMAC(macaddr):
|
2021-11-06 03:02:43 -04:00
|
|
|
allowed = re.compile(
|
|
|
|
r"(^([0-9A-F]{2}[:]){5}([0-9A-F]{2})$)", re.VERBOSE | re.IGNORECASE
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2019-06-24 13:37:56 -04:00
|
|
|
if allowed.match(macaddr):
|
2018-09-28 20:31:56 -04:00
|
|
|
return True
|
2019-06-24 13:37:56 -04:00
|
|
|
else:
|
|
|
|
return False
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-09-28 20:31:56 -04:00
|
|
|
def isValidIP(ipaddr):
|
2018-11-13 01:22:15 -05:00
|
|
|
ip4_blocks = str(ipaddr).split(".")
|
|
|
|
if len(ip4_blocks) == 4:
|
|
|
|
for block in ip4_blocks:
|
2018-09-28 20:31:56 -04:00
|
|
|
# Check if number is digit, if not checked before calling this function
|
|
|
|
if not block.isdigit():
|
2020-11-06 19:26:22 -05:00
|
|
|
return False
|
2018-09-28 20:31:56 -04:00
|
|
|
tmp = int(block)
|
|
|
|
if 0 > tmp > 255:
|
2020-11-06 19:26:22 -05:00
|
|
|
return False
|
2018-09-28 20:31:56 -04:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
#
|
|
|
|
# Direct functions
|
|
|
|
#
|
2021-11-06 03:02:43 -04:00
|
|
|
def add_network(
|
|
|
|
zkhandler,
|
|
|
|
vni,
|
|
|
|
description,
|
|
|
|
nettype,
|
|
|
|
mtu,
|
|
|
|
domain,
|
|
|
|
name_servers,
|
|
|
|
ip4_network,
|
|
|
|
ip4_gateway,
|
|
|
|
ip6_network,
|
|
|
|
ip6_gateway,
|
|
|
|
dhcp4_flag,
|
|
|
|
dhcp4_start,
|
|
|
|
dhcp4_end,
|
|
|
|
):
|
2018-11-13 01:22:15 -05:00
|
|
|
# Ensure start and end DHCP ranges are set if the flag is set
|
2020-11-07 12:58:54 -05:00
|
|
|
if dhcp4_flag and (not dhcp4_start or not dhcp4_end):
|
2021-11-06 03:02:43 -04:00
|
|
|
return (
|
|
|
|
False,
|
|
|
|
"ERROR: DHCPv4 start and end addresses are required for a DHCPv4-enabled network.",
|
|
|
|
)
|
2018-09-29 02:54:48 -04:00
|
|
|
|
2018-10-17 00:23:27 -04:00
|
|
|
# Check if a network with this VNI or description already exists
|
2021-11-06 03:02:43 -04:00
|
|
|
if zkhandler.exists(("network", vni)):
|
2019-07-08 22:37:26 -04:00
|
|
|
return False, 'ERROR: A network with VNI "{}" already exists!'.format(vni)
|
2021-06-12 18:40:25 -04:00
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
for network in zkhandler.children("base.network"):
|
|
|
|
network_description = zkhandler.read(("network", network))
|
2018-10-17 00:23:27 -04:00
|
|
|
if network_description == description:
|
2021-11-06 03:02:43 -04:00
|
|
|
return (
|
|
|
|
False,
|
|
|
|
'ERROR: A network with description "{}" already exists!'.format(
|
|
|
|
description
|
|
|
|
),
|
|
|
|
)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2018-11-13 01:22:15 -05:00
|
|
|
# We're generating the default gateway to be ip6_network::1/YY
|
|
|
|
if ip6_network:
|
2021-11-06 03:02:43 -04:00
|
|
|
dhcp6_flag = "True"
|
2018-11-13 01:22:15 -05:00
|
|
|
if not ip6_gateway:
|
2021-11-06 03:02:43 -04:00
|
|
|
ip6_netpart, ip6_maskpart = ip6_network.split("/")
|
|
|
|
ip6_gateway = "{}1".format(ip6_netpart)
|
2018-11-13 01:22:15 -05:00
|
|
|
else:
|
2021-11-06 03:02:43 -04:00
|
|
|
dhcp6_flag = "False"
|
2018-11-13 01:22:15 -05:00
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
if nettype in ["managed"] and not domain:
|
|
|
|
domain = "{}.local".format(description)
|
2019-06-24 12:59:32 -04:00
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
# Add the new network to Zookeeper
|
2021-11-06 03:02:43 -04:00
|
|
|
result = zkhandler.write(
|
|
|
|
[
|
|
|
|
(("network", vni), description),
|
|
|
|
(("network.type", vni), nettype),
|
|
|
|
(("network.mtu", vni), mtu),
|
|
|
|
(("network.domain", vni), domain),
|
|
|
|
(("network.nameservers", vni), name_servers),
|
|
|
|
(("network.ip6.network", vni), ip6_network),
|
|
|
|
(("network.ip6.gateway", vni), ip6_gateway),
|
|
|
|
(("network.ip6.dhcp", vni), dhcp6_flag),
|
|
|
|
(("network.ip4.network", vni), ip4_network),
|
|
|
|
(("network.ip4.gateway", vni), ip4_gateway),
|
|
|
|
(("network.ip4.dhcp", vni), dhcp4_flag),
|
|
|
|
(("network.ip4.dhcp_start", vni), dhcp4_start),
|
|
|
|
(("network.ip4.dhcp_end", vni), dhcp4_end),
|
|
|
|
(("network.lease", vni), ""),
|
|
|
|
(("network.reservation", vni), ""),
|
|
|
|
(("network.rule", vni), ""),
|
|
|
|
(("network.rule.in", vni), ""),
|
|
|
|
(("network.rule.out", vni), ""),
|
|
|
|
]
|
|
|
|
)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2021-06-13 18:20:40 -04:00
|
|
|
if result:
|
|
|
|
return True, 'Network "{}" added successfully!'.format(description)
|
|
|
|
else:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, "ERROR: Failed to add network."
|
|
|
|
|
|
|
|
|
|
|
|
def modify_network(
|
|
|
|
zkhandler,
|
|
|
|
vni,
|
|
|
|
description=None,
|
|
|
|
mtu=None,
|
|
|
|
domain=None,
|
|
|
|
name_servers=None,
|
|
|
|
ip4_network=None,
|
|
|
|
ip4_gateway=None,
|
|
|
|
ip6_network=None,
|
|
|
|
ip6_gateway=None,
|
|
|
|
dhcp4_flag=None,
|
|
|
|
dhcp4_start=None,
|
|
|
|
dhcp4_end=None,
|
|
|
|
):
|
2019-12-27 12:27:10 -05:00
|
|
|
# Add the modified parameters to Zookeeper
|
2021-05-29 20:53:42 -04:00
|
|
|
update_data = list()
|
2020-12-04 04:15:04 -05:00
|
|
|
if description is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network", vni), description))
|
2021-10-09 17:43:56 -04:00
|
|
|
if mtu is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.mtu", vni), mtu))
|
2020-12-04 04:15:04 -05:00
|
|
|
if domain is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.domain", vni), domain))
|
2020-12-04 04:15:04 -05:00
|
|
|
if name_servers is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.nameservers", vni), name_servers))
|
2020-12-04 04:15:04 -05:00
|
|
|
if ip4_network is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip4.network", vni), ip4_network))
|
2020-12-04 04:15:04 -05:00
|
|
|
if ip4_gateway is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip4.gateway", vni), ip4_gateway))
|
2020-12-04 04:15:04 -05:00
|
|
|
if ip6_network is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip6.network", vni), ip6_network))
|
2020-12-04 04:15:04 -05:00
|
|
|
if ip6_network:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip6.dhcp", vni), "True"))
|
2018-11-13 01:22:15 -05:00
|
|
|
else:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip6.dhcp", vni), "False"))
|
2020-12-04 04:15:04 -05:00
|
|
|
if ip6_gateway is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip6.gateway", vni), ip6_gateway))
|
2018-11-14 00:19:43 -05:00
|
|
|
else:
|
|
|
|
# If we're changing the network, but don't also specify the gateway,
|
|
|
|
# generate a new one automatically
|
2019-12-27 12:27:10 -05:00
|
|
|
if ip6_network:
|
2021-11-06 03:02:43 -04:00
|
|
|
ip6_netpart, ip6_maskpart = ip6_network.split("/")
|
|
|
|
ip6_gateway = "{}1".format(ip6_netpart)
|
|
|
|
update_data.append((("network.ip6.gateway", vni), ip6_gateway))
|
2020-12-04 04:15:04 -05:00
|
|
|
if dhcp4_flag is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip4.dhcp", vni), dhcp4_flag))
|
2020-12-04 04:15:04 -05:00
|
|
|
if dhcp4_start is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip4.dhcp_start", vni), dhcp4_start))
|
2020-12-04 04:15:04 -05:00
|
|
|
if dhcp4_end is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_data.append((("network.ip4.dhcp_end", vni), dhcp4_end))
|
2018-09-29 02:54:48 -04:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
zkhandler.write(update_data)
|
2019-03-15 11:28:49 -04:00
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
return True, 'Network "{}" modified successfully!'.format(vni)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def remove_network(zkhandler, network):
|
2018-09-20 03:25:58 -04:00
|
|
|
# Validate and obtain alternate passed value
|
2021-05-29 20:53:42 -04:00
|
|
|
vni = getNetworkVNI(zkhandler, network)
|
|
|
|
description = getNetworkDescription(zkhandler, network)
|
2018-09-23 15:26:20 -04:00
|
|
|
if not vni:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find network "{}" in the cluster!'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
# Delete the configuration
|
2021-11-06 03:02:43 -04:00
|
|
|
zkhandler.delete([("network", vni)])
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2018-09-23 15:26:20 -04:00
|
|
|
return True, 'Network "{}" removed successfully!'.format(description)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def add_dhcp_reservation(zkhandler, network, ipaddress, macaddress, hostname):
|
2018-09-28 20:31:56 -04:00
|
|
|
# Validate and obtain standard passed value
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = getNetworkVNI(zkhandler, network)
|
2019-06-24 13:37:56 -04:00
|
|
|
if not net_vni:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find network "{}" in the cluster!'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2018-10-03 23:16:31 -04:00
|
|
|
# Use lowercase MAC format exclusively
|
|
|
|
macaddress = macaddress.lower()
|
2018-09-28 20:31:56 -04:00
|
|
|
|
|
|
|
if not isValidMAC(macaddress):
|
2021-11-06 03:02:43 -04:00
|
|
|
return (
|
|
|
|
False,
|
|
|
|
'ERROR: MAC address "{}" is not valid! Always use ":" as a separator.'.format(
|
|
|
|
macaddress
|
|
|
|
),
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
|
|
|
if not isValidIP(ipaddress):
|
|
|
|
return False, 'ERROR: IP address "{}" is not valid!'.format(macaddress)
|
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
if zkhandler.exists(("network.reservation", net_vni, "reservation", macaddress)):
|
|
|
|
return False, 'ERROR: A reservation with MAC "{}" already exists!'.format(
|
|
|
|
macaddress
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2018-09-30 12:43:56 -04:00
|
|
|
# Add the new static lease to ZK
|
2021-11-06 03:02:43 -04:00
|
|
|
zkhandler.write(
|
|
|
|
[
|
|
|
|
(("network.reservation", net_vni, "reservation", macaddress), "static"),
|
|
|
|
(
|
|
|
|
("network.reservation", net_vni, "reservation.hostname", macaddress),
|
|
|
|
hostname,
|
|
|
|
),
|
|
|
|
(("network.reservation", net_vni, "reservation.ip", macaddress), ipaddress),
|
|
|
|
]
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2018-09-30 12:43:56 -04:00
|
|
|
return True, 'DHCP reservation "{}" added successfully!'.format(macaddress)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def remove_dhcp_reservation(zkhandler, network, reservation):
|
2018-09-28 20:31:56 -04:00
|
|
|
# Validate and obtain standard passed value
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = getNetworkVNI(zkhandler, network)
|
2019-06-24 13:37:56 -04:00
|
|
|
if not net_vni:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find network "{}" in the cluster!'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
match_description = ""
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2020-01-05 01:06:03 -05:00
|
|
|
# Check if the reservation matches a static reservation description, a mac, or an IP address currently in the database
|
2021-05-29 20:53:42 -04:00
|
|
|
dhcp4_reservations_list = getNetworkDHCPReservations(zkhandler, net_vni)
|
2018-11-18 00:55:04 -05:00
|
|
|
for macaddr in dhcp4_reservations_list:
|
2021-11-06 03:02:43 -04:00
|
|
|
hostname = zkhandler.read(
|
|
|
|
("network.reservation", net_vni, "reservation.hostname", macaddr)
|
|
|
|
)
|
|
|
|
ipaddress = zkhandler.read(
|
|
|
|
("network.reservation", net_vni, "reservation.ip", macaddr)
|
|
|
|
)
|
|
|
|
if (
|
|
|
|
reservation == macaddr
|
|
|
|
or reservation == hostname
|
|
|
|
or reservation == ipaddress
|
|
|
|
):
|
2018-09-30 11:22:25 -04:00
|
|
|
match_description = macaddr
|
2021-11-06 03:02:43 -04:00
|
|
|
lease_type_zk = "reservation"
|
|
|
|
lease_type_human = "static reservation"
|
2020-01-05 01:06:03 -05:00
|
|
|
|
|
|
|
# Check if the reservation matches a dynamic reservation description, a mac, or an IP address currently in the database
|
2021-05-29 20:53:42 -04:00
|
|
|
dhcp4_leases_list = getNetworkDHCPLeases(zkhandler, net_vni)
|
2020-01-05 01:06:03 -05:00
|
|
|
for macaddr in dhcp4_leases_list:
|
2021-11-06 03:02:43 -04:00
|
|
|
hostname = zkhandler.read(("network.lease", net_vni, "lease.hostname", macaddr))
|
|
|
|
ipaddress = zkhandler.read(("network.lease", net_vni, "lease.ip", macaddr))
|
|
|
|
if (
|
|
|
|
reservation == macaddr
|
|
|
|
or reservation == hostname
|
|
|
|
or reservation == ipaddress
|
|
|
|
):
|
2020-01-05 01:06:03 -05:00
|
|
|
match_description = macaddr
|
2021-11-06 03:02:43 -04:00
|
|
|
lease_type_zk = "lease"
|
|
|
|
lease_type_human = "dynamic lease"
|
2019-03-15 11:28:49 -04:00
|
|
|
|
2018-09-28 20:31:56 -04:00
|
|
|
if not match_description:
|
2021-11-06 03:02:43 -04:00
|
|
|
return (
|
|
|
|
False,
|
|
|
|
'ERROR: No DHCP reservation or lease exists matching "{}"!'.format(
|
|
|
|
reservation
|
|
|
|
),
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
|
|
|
# Remove the entry from zookeeper
|
2021-11-06 03:02:43 -04:00
|
|
|
zkhandler.delete(
|
|
|
|
[
|
|
|
|
(
|
|
|
|
f"network.{lease_type_zk}",
|
|
|
|
net_vni,
|
|
|
|
f"{lease_type_zk}",
|
|
|
|
match_description,
|
|
|
|
),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
return True, 'DHCP {} "{}" removed successfully!'.format(
|
|
|
|
lease_type_human, match_description
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def add_acl(zkhandler, network, direction, description, rule, order):
|
2018-10-17 00:23:27 -04:00
|
|
|
# Validate and obtain standard passed value
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = getNetworkVNI(zkhandler, network)
|
2019-06-24 13:37:56 -04:00
|
|
|
if not net_vni:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find network "{}" in the cluster!'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
2019-12-22 22:31:44 -05:00
|
|
|
# Check if the ACL matches a description currently in the database
|
2021-11-06 03:02:43 -04:00
|
|
|
match_description = ""
|
|
|
|
full_acl_list = getNetworkACLs(zkhandler, net_vni, "both")
|
2019-12-22 22:31:44 -05:00
|
|
|
for acl in full_acl_list:
|
2021-11-06 03:02:43 -04:00
|
|
|
if acl["description"] == description:
|
|
|
|
match_description = acl["description"]
|
2019-12-22 22:31:44 -05:00
|
|
|
|
|
|
|
if match_description:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: A rule with description "{}" already exists!'.format(
|
|
|
|
description
|
|
|
|
)
|
2019-12-22 22:31:44 -05:00
|
|
|
|
2018-10-17 00:23:27 -04:00
|
|
|
# Change direction to something more usable
|
|
|
|
if direction:
|
2019-12-22 22:31:44 -05:00
|
|
|
direction = "in"
|
2018-10-17 00:23:27 -04:00
|
|
|
else:
|
|
|
|
direction = "out"
|
|
|
|
|
|
|
|
# Handle reordering
|
2021-05-29 20:53:42 -04:00
|
|
|
full_acl_list = getNetworkACLs(zkhandler, net_vni, direction)
|
2018-10-17 00:23:27 -04:00
|
|
|
acl_list_length = len(full_acl_list)
|
|
|
|
# Set order to len
|
2019-06-24 13:37:56 -04:00
|
|
|
if not order or int(order) > acl_list_length:
|
2018-10-17 00:23:27 -04:00
|
|
|
order = acl_list_length
|
|
|
|
# Convert passed-in order to an integer
|
|
|
|
else:
|
|
|
|
order = int(order)
|
2019-03-15 11:28:49 -04:00
|
|
|
|
2018-10-17 00:23:27 -04:00
|
|
|
# Insert into the array at order-1
|
2021-11-06 03:02:43 -04:00
|
|
|
full_acl_list.insert(
|
|
|
|
order, {"direction": direction, "description": description, "rule": rule}
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
|
|
|
# Update the existing ordering
|
|
|
|
for idx, acl in enumerate(full_acl_list):
|
2021-11-06 03:02:43 -04:00
|
|
|
if acl["description"] == description:
|
2018-10-17 00:23:27 -04:00
|
|
|
continue
|
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
if idx == acl["order"]:
|
2021-05-29 20:53:42 -04:00
|
|
|
continue
|
|
|
|
else:
|
2021-11-06 03:02:43 -04:00
|
|
|
zkhandler.write(
|
|
|
|
[
|
|
|
|
(
|
|
|
|
(
|
|
|
|
f"network.rule.{direction}",
|
|
|
|
net_vni,
|
|
|
|
"rule.order",
|
|
|
|
acl["description"],
|
|
|
|
),
|
|
|
|
idx,
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
|
|
|
# Add the new rule
|
2021-11-06 03:02:43 -04:00
|
|
|
zkhandler.write(
|
|
|
|
[
|
|
|
|
((f"network.rule.{direction}", net_vni, "rule", description), ""),
|
|
|
|
((f"network.rule.{direction}", net_vni, "rule.order", description), order),
|
|
|
|
((f"network.rule.{direction}", net_vni, "rule.rule", description), rule),
|
|
|
|
]
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
|
|
|
return True, 'Firewall rule "{}" added successfully!'.format(description)
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def remove_acl(zkhandler, network, description):
|
2018-10-17 00:23:27 -04:00
|
|
|
# Validate and obtain standard passed value
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = getNetworkVNI(zkhandler, network)
|
2019-06-24 13:37:56 -04:00
|
|
|
if not net_vni:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find network "{}" in the cluster!'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
match_description = ""
|
2018-10-17 00:23:27 -04:00
|
|
|
|
|
|
|
# Check if the ACL matches a description currently in the database
|
2021-11-06 03:02:43 -04:00
|
|
|
acl_list = getNetworkACLs(zkhandler, net_vni, "both")
|
2018-10-17 00:23:27 -04:00
|
|
|
for acl in acl_list:
|
2021-11-06 03:02:43 -04:00
|
|
|
if acl["description"] == description:
|
|
|
|
match_description = acl["description"]
|
|
|
|
match_direction = acl["direction"]
|
2019-03-15 11:28:49 -04:00
|
|
|
|
2018-10-17 00:23:27 -04:00
|
|
|
if not match_description:
|
2021-11-06 03:02:43 -04:00
|
|
|
return (
|
|
|
|
False,
|
|
|
|
'ERROR: No firewall rule exists matching description "{}"!'.format(
|
|
|
|
description
|
|
|
|
),
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
|
|
|
# Remove the entry from zookeeper
|
2021-11-06 03:02:43 -04:00
|
|
|
zkhandler.delete(
|
|
|
|
[(f"network.rule.{match_direction}", net_vni, "rule", match_description)]
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
|
|
|
# Update the existing ordering
|
2021-05-29 20:53:42 -04:00
|
|
|
updated_acl_list = getNetworkACLs(zkhandler, net_vni, match_direction)
|
2018-10-17 20:05:22 -04:00
|
|
|
for idx, acl in enumerate(updated_acl_list):
|
2021-11-06 03:02:43 -04:00
|
|
|
if acl["description"] == description:
|
2021-05-29 20:53:42 -04:00
|
|
|
continue
|
2018-10-17 00:23:27 -04:00
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
if idx == acl["order"]:
|
2021-05-29 20:53:42 -04:00
|
|
|
continue
|
|
|
|
else:
|
2021-11-06 03:02:43 -04:00
|
|
|
zkhandler.write(
|
|
|
|
[
|
|
|
|
(
|
|
|
|
(
|
|
|
|
f"network.rule.{match_direction}",
|
|
|
|
net_vni,
|
|
|
|
"rule.order",
|
|
|
|
acl["description"],
|
|
|
|
),
|
|
|
|
idx,
|
|
|
|
),
|
|
|
|
]
|
|
|
|
)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
|
|
|
return True, 'Firewall rule "{}" removed successfully!'.format(match_description)
|
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def get_info(zkhandler, network):
|
2018-09-20 03:25:58 -04:00
|
|
|
# Validate and obtain alternate passed value
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = getNetworkVNI(zkhandler, network)
|
2019-06-24 13:37:56 -04:00
|
|
|
if not net_vni:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find network "{}" in the cluster!'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
network_information = getNetworkInformation(zkhandler, network)
|
2019-07-04 23:01:22 -04:00
|
|
|
if not network_information:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not get information about network "{}"'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2019-07-04 23:01:22 -04:00
|
|
|
return True, network_information
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def get_list(zkhandler, limit, is_fuzzy=True):
|
2018-09-25 01:47:29 -04:00
|
|
|
net_list = []
|
2021-11-06 03:02:43 -04:00
|
|
|
full_net_list = zkhandler.children("base.network")
|
2018-09-25 02:20:32 -04:00
|
|
|
|
2018-09-25 01:47:29 -04:00
|
|
|
for net in full_net_list:
|
2021-11-06 03:02:43 -04:00
|
|
|
description = zkhandler.read(("network", net))
|
2019-06-24 13:37:56 -04:00
|
|
|
if limit:
|
2018-09-25 01:47:29 -04:00
|
|
|
try:
|
2019-12-22 21:57:18 -05:00
|
|
|
if not is_fuzzy:
|
2021-11-06 03:02:43 -04:00
|
|
|
limit = "^" + limit + "$"
|
2018-09-25 02:20:32 -04:00
|
|
|
|
2019-06-24 13:37:56 -04:00
|
|
|
if re.match(limit, net):
|
2021-05-29 20:53:42 -04:00
|
|
|
net_list.append(getNetworkInformation(zkhandler, net))
|
2019-06-24 13:37:56 -04:00
|
|
|
if re.match(limit, description):
|
2021-05-29 20:53:42 -04:00
|
|
|
net_list.append(getNetworkInformation(zkhandler, net))
|
2018-09-25 01:47:29 -04:00
|
|
|
except Exception as e:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, "Regex Error: {}".format(e)
|
2018-09-25 02:20:32 -04:00
|
|
|
else:
|
2021-05-29 20:53:42 -04:00
|
|
|
net_list.append(getNetworkInformation(zkhandler, net))
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2019-07-04 23:01:22 -04:00
|
|
|
return True, net_list
|
2018-09-25 13:58:52 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def get_list_dhcp(zkhandler, network, limit, only_static=False, is_fuzzy=True):
|
2018-09-28 20:31:56 -04:00
|
|
|
# Validate and obtain alternate passed value
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = getNetworkVNI(zkhandler, network)
|
2019-06-24 13:37:56 -04:00
|
|
|
if not net_vni:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find network "{}" in the cluster!'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2018-10-03 19:23:46 -04:00
|
|
|
dhcp_list = []
|
|
|
|
|
|
|
|
if only_static:
|
2021-05-29 20:53:42 -04:00
|
|
|
full_dhcp_list = getNetworkDHCPReservations(zkhandler, net_vni)
|
2018-10-03 19:23:46 -04:00
|
|
|
else:
|
2021-05-29 20:53:42 -04:00
|
|
|
full_dhcp_list = getNetworkDHCPReservations(zkhandler, net_vni)
|
|
|
|
full_dhcp_list += getNetworkDHCPLeases(zkhandler, net_vni)
|
2018-10-02 00:02:23 -04:00
|
|
|
|
2019-12-22 21:57:18 -05:00
|
|
|
if limit:
|
2018-10-02 00:02:23 -04:00
|
|
|
try:
|
2019-12-22 21:57:18 -05:00
|
|
|
if not is_fuzzy:
|
2021-11-06 03:02:43 -04:00
|
|
|
limit = "^" + limit + "$"
|
2019-12-22 21:57:18 -05:00
|
|
|
|
2018-10-02 00:02:23 -04:00
|
|
|
# Implcitly assume fuzzy limits
|
2021-11-06 03:02:43 -04:00
|
|
|
if not re.match(r"\^.*", limit):
|
|
|
|
limit = ".*" + limit
|
|
|
|
if not re.match(r".*\$", limit):
|
|
|
|
limit = limit + ".*"
|
2018-10-02 00:02:23 -04:00
|
|
|
except Exception as e:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, "Regex Error: {}".format(e)
|
2019-03-15 11:28:49 -04:00
|
|
|
|
2018-10-03 19:23:46 -04:00
|
|
|
for lease in full_dhcp_list:
|
2018-10-02 00:02:23 -04:00
|
|
|
valid_lease = False
|
2018-10-03 19:23:46 -04:00
|
|
|
if limit:
|
2019-06-24 13:37:56 -04:00
|
|
|
if re.match(limit, lease):
|
2018-10-03 19:23:46 -04:00
|
|
|
valid_lease = True
|
2019-06-24 13:37:56 -04:00
|
|
|
if re.match(limit, lease):
|
2018-10-02 00:14:08 -04:00
|
|
|
valid_lease = True
|
2018-10-03 19:23:46 -04:00
|
|
|
else:
|
|
|
|
valid_lease = True
|
2018-10-02 00:02:23 -04:00
|
|
|
|
|
|
|
if valid_lease:
|
2021-05-29 20:53:42 -04:00
|
|
|
dhcp_list.append(getDHCPLeaseInformation(zkhandler, net_vni, lease))
|
2018-09-20 03:25:58 -04:00
|
|
|
|
2019-07-04 23:01:22 -04:00
|
|
|
return True, dhcp_list
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2020-11-07 14:45:24 -05:00
|
|
|
|
2021-05-29 20:53:42 -04:00
|
|
|
def get_list_acl(zkhandler, network, limit, direction, is_fuzzy=True):
|
2018-09-28 20:31:56 -04:00
|
|
|
# Validate and obtain alternate passed value
|
2021-05-29 20:53:42 -04:00
|
|
|
net_vni = getNetworkVNI(zkhandler, network)
|
2019-06-24 13:37:56 -04:00
|
|
|
if not net_vni:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find network "{}" in the cluster!'.format(
|
|
|
|
network
|
|
|
|
)
|
2018-09-28 20:31:56 -04:00
|
|
|
|
2018-10-17 00:23:27 -04:00
|
|
|
# Change direction to something more usable
|
2018-10-17 20:05:22 -04:00
|
|
|
if direction is None:
|
|
|
|
direction = "both"
|
|
|
|
elif direction is True:
|
2018-10-17 00:23:27 -04:00
|
|
|
direction = "in"
|
2018-10-17 20:05:22 -04:00
|
|
|
elif direction is False:
|
2018-10-17 00:23:27 -04:00
|
|
|
direction = "out"
|
|
|
|
|
|
|
|
acl_list = []
|
2021-05-29 20:53:42 -04:00
|
|
|
full_acl_list = getNetworkACLs(zkhandler, net_vni, direction)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
2019-12-22 21:57:18 -05:00
|
|
|
if limit:
|
2018-10-17 00:23:27 -04:00
|
|
|
try:
|
2019-12-22 21:57:18 -05:00
|
|
|
if not is_fuzzy:
|
2021-11-06 03:02:43 -04:00
|
|
|
limit = "^" + limit + "$"
|
2019-12-22 21:57:18 -05:00
|
|
|
|
2018-10-17 00:23:27 -04:00
|
|
|
# Implcitly assume fuzzy limits
|
2021-11-06 03:02:43 -04:00
|
|
|
if not re.match(r"\^.*", limit):
|
|
|
|
limit = ".*" + limit
|
|
|
|
if not re.match(r".*\$", limit):
|
|
|
|
limit = limit + ".*"
|
2018-10-17 00:23:27 -04:00
|
|
|
except Exception as e:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, "Regex Error: {}".format(e)
|
2018-10-17 00:23:27 -04:00
|
|
|
|
2018-10-17 20:05:22 -04:00
|
|
|
for acl in full_acl_list:
|
2018-10-17 00:23:27 -04:00
|
|
|
valid_acl = False
|
|
|
|
if limit:
|
2021-11-06 03:02:43 -04:00
|
|
|
if re.match(limit, acl["description"]):
|
2018-10-17 00:23:27 -04:00
|
|
|
valid_acl = True
|
|
|
|
else:
|
|
|
|
valid_acl = True
|
|
|
|
|
|
|
|
if valid_acl:
|
|
|
|
acl_list.append(acl)
|
|
|
|
|
2019-07-04 23:01:22 -04:00
|
|
|
return True, acl_list
|
2021-06-21 01:42:55 -04:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# SR-IOV functions
|
|
|
|
#
|
|
|
|
# These are separate since they don't work like other network types
|
|
|
|
#
|
|
|
|
def getSRIOVPFInformation(zkhandler, node, pf):
|
2021-11-06 03:02:43 -04:00
|
|
|
mtu = zkhandler.read(("node.sriov.pf", node, "sriov_pf.mtu", pf))
|
2021-06-21 01:42:55 -04:00
|
|
|
|
|
|
|
retcode, vf_list = get_list_sriov_vf(zkhandler, node, pf)
|
|
|
|
if retcode:
|
2021-11-06 03:02:43 -04:00
|
|
|
vfs = common.sortInterfaceNames([vf["phy"] for vf in vf_list if vf["pf"] == pf])
|
2021-06-21 01:42:55 -04:00
|
|
|
else:
|
|
|
|
vfs = []
|
|
|
|
|
|
|
|
# Construct a data structure to represent the data
|
|
|
|
pf_information = {
|
2021-11-06 03:02:43 -04:00
|
|
|
"phy": pf,
|
|
|
|
"mtu": mtu,
|
|
|
|
"vfs": vfs,
|
2021-06-21 01:42:55 -04:00
|
|
|
}
|
|
|
|
return pf_information
|
|
|
|
|
|
|
|
|
|
|
|
def get_info_sriov_pf(zkhandler, node, pf):
|
|
|
|
pf_information = getSRIOVPFInformation(zkhandler, node, pf)
|
|
|
|
if not pf_information:
|
2021-11-06 03:02:43 -04:00
|
|
|
return (
|
|
|
|
False,
|
|
|
|
'ERROR: Could not get information about SR-IOV PF "{}" on node "{}"'.format(
|
|
|
|
pf, node
|
|
|
|
),
|
|
|
|
)
|
2021-06-21 01:42:55 -04:00
|
|
|
|
|
|
|
return True, pf_information
|
|
|
|
|
|
|
|
|
|
|
|
def get_list_sriov_pf(zkhandler, node):
|
|
|
|
pf_list = list()
|
2021-11-06 03:02:43 -04:00
|
|
|
pf_phy_list = zkhandler.children(("node.sriov.pf", node))
|
2021-06-21 01:42:55 -04:00
|
|
|
for phy in pf_phy_list:
|
|
|
|
retcode, pf_information = get_info_sriov_pf(zkhandler, node, phy)
|
|
|
|
if retcode:
|
|
|
|
pf_list.append(pf_information)
|
|
|
|
|
|
|
|
return True, pf_list
|
|
|
|
|
|
|
|
|
|
|
|
def getSRIOVVFInformation(zkhandler, node, vf):
|
2021-11-06 03:02:43 -04:00
|
|
|
if not zkhandler.exists(("node.sriov.vf", node, "sriov_vf", vf)):
|
2021-06-21 18:40:11 -04:00
|
|
|
return []
|
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
pf = zkhandler.read(("node.sriov.vf", node, "sriov_vf.pf", vf))
|
|
|
|
mtu = zkhandler.read(("node.sriov.vf", node, "sriov_vf.mtu", vf))
|
|
|
|
mac = zkhandler.read(("node.sriov.vf", node, "sriov_vf.mac", vf))
|
|
|
|
vlan_id = zkhandler.read(("node.sriov.vf", node, "sriov_vf.config.vlan_id", vf))
|
|
|
|
vlan_qos = zkhandler.read(("node.sriov.vf", node, "sriov_vf.config.vlan_qos", vf))
|
|
|
|
tx_rate_min = zkhandler.read(
|
|
|
|
("node.sriov.vf", node, "sriov_vf.config.tx_rate_min", vf)
|
|
|
|
)
|
|
|
|
tx_rate_max = zkhandler.read(
|
|
|
|
("node.sriov.vf", node, "sriov_vf.config.tx_rate_max", vf)
|
|
|
|
)
|
|
|
|
link_state = zkhandler.read(
|
|
|
|
("node.sriov.vf", node, "sriov_vf.config.link_state", vf)
|
|
|
|
)
|
|
|
|
spoof_check = zkhandler.read(
|
|
|
|
("node.sriov.vf", node, "sriov_vf.config.spoof_check", vf)
|
|
|
|
)
|
|
|
|
trust = zkhandler.read(("node.sriov.vf", node, "sriov_vf.config.trust", vf))
|
|
|
|
query_rss = zkhandler.read(("node.sriov.vf", node, "sriov_vf.config.query_rss", vf))
|
|
|
|
pci_domain = zkhandler.read(("node.sriov.vf", node, "sriov_vf.pci.domain", vf))
|
|
|
|
pci_bus = zkhandler.read(("node.sriov.vf", node, "sriov_vf.pci.bus", vf))
|
|
|
|
pci_slot = zkhandler.read(("node.sriov.vf", node, "sriov_vf.pci.slot", vf))
|
|
|
|
pci_function = zkhandler.read(("node.sriov.vf", node, "sriov_vf.pci.function", vf))
|
|
|
|
used = zkhandler.read(("node.sriov.vf", node, "sriov_vf.used", vf))
|
|
|
|
used_by_domain = zkhandler.read(("node.sriov.vf", node, "sriov_vf.used_by", vf))
|
2021-06-21 01:42:55 -04:00
|
|
|
|
|
|
|
vf_information = {
|
2021-11-06 03:02:43 -04:00
|
|
|
"phy": vf,
|
|
|
|
"pf": pf,
|
|
|
|
"mtu": mtu,
|
|
|
|
"mac": mac,
|
|
|
|
"config": {
|
|
|
|
"vlan_id": vlan_id,
|
|
|
|
"vlan_qos": vlan_qos,
|
|
|
|
"tx_rate_min": tx_rate_min,
|
|
|
|
"tx_rate_max": tx_rate_max,
|
|
|
|
"link_state": link_state,
|
|
|
|
"spoof_check": spoof_check,
|
|
|
|
"trust": trust,
|
|
|
|
"query_rss": query_rss,
|
2021-06-21 01:42:55 -04:00
|
|
|
},
|
2021-11-06 03:02:43 -04:00
|
|
|
"pci": {
|
|
|
|
"domain": pci_domain,
|
|
|
|
"bus": pci_bus,
|
|
|
|
"slot": pci_slot,
|
|
|
|
"function": pci_function,
|
|
|
|
},
|
|
|
|
"usage": {
|
|
|
|
"used": used,
|
|
|
|
"domain": used_by_domain,
|
2021-06-21 20:49:45 -04:00
|
|
|
},
|
2021-06-21 01:42:55 -04:00
|
|
|
}
|
|
|
|
return vf_information
|
|
|
|
|
|
|
|
|
|
|
|
def get_info_sriov_vf(zkhandler, node, vf):
|
2021-06-21 18:40:11 -04:00
|
|
|
# Verify node is valid
|
|
|
|
valid_node = common.verifyNode(zkhandler, node)
|
|
|
|
if not valid_node:
|
|
|
|
return False, 'ERROR: Specified node "{}" is invalid.'.format(node)
|
|
|
|
|
2021-06-21 01:42:55 -04:00
|
|
|
vf_information = getSRIOVVFInformation(zkhandler, node, vf)
|
|
|
|
if not vf_information:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find SR-IOV VF "{}" on node "{}"'.format(
|
|
|
|
vf, node
|
|
|
|
)
|
2021-06-21 01:42:55 -04:00
|
|
|
|
|
|
|
return True, vf_information
|
|
|
|
|
|
|
|
|
|
|
|
def get_list_sriov_vf(zkhandler, node, pf=None):
|
2021-06-21 18:40:11 -04:00
|
|
|
# Verify node is valid
|
|
|
|
valid_node = common.verifyNode(zkhandler, node)
|
|
|
|
if not valid_node:
|
|
|
|
return False, 'ERROR: Specified node "{}" is invalid.'.format(node)
|
|
|
|
|
2021-06-21 01:42:55 -04:00
|
|
|
vf_list = list()
|
2021-11-06 03:02:43 -04:00
|
|
|
vf_phy_list = common.sortInterfaceNames(zkhandler.children(("node.sriov.vf", node)))
|
2021-06-21 01:42:55 -04:00
|
|
|
for phy in vf_phy_list:
|
|
|
|
retcode, vf_information = get_info_sriov_vf(zkhandler, node, phy)
|
|
|
|
if retcode:
|
|
|
|
if pf is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
if vf_information["pf"] == pf:
|
2021-06-21 01:42:55 -04:00
|
|
|
vf_list.append(vf_information)
|
|
|
|
else:
|
|
|
|
vf_list.append(vf_information)
|
|
|
|
|
|
|
|
return True, vf_list
|
|
|
|
|
|
|
|
|
2021-11-06 03:02:43 -04:00
|
|
|
def set_sriov_vf_config(
|
|
|
|
zkhandler,
|
|
|
|
node,
|
|
|
|
vf,
|
|
|
|
vlan_id=None,
|
|
|
|
vlan_qos=None,
|
|
|
|
tx_rate_min=None,
|
|
|
|
tx_rate_max=None,
|
|
|
|
link_state=None,
|
|
|
|
spoof_check=None,
|
|
|
|
trust=None,
|
|
|
|
query_rss=None,
|
|
|
|
):
|
2021-06-21 18:40:11 -04:00
|
|
|
# Verify node is valid
|
|
|
|
valid_node = common.verifyNode(zkhandler, node)
|
|
|
|
if not valid_node:
|
|
|
|
return False, 'ERROR: Specified node "{}" is invalid.'.format(node)
|
|
|
|
|
|
|
|
# Verify VF is valid
|
|
|
|
vf_information = getSRIOVVFInformation(zkhandler, node, vf)
|
|
|
|
if not vf_information:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, 'ERROR: Could not find SR-IOV VF "{}" on node "{}".'.format(
|
|
|
|
vf, node
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
update_list = list()
|
|
|
|
|
|
|
|
if vlan_id is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_list.append(
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.config.vlan_id", vf), vlan_id)
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
if vlan_qos is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_list.append(
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.config.vlan_qos", vf), vlan_qos)
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
if tx_rate_min is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_list.append(
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.config.tx_rate_min", vf), tx_rate_min)
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
if tx_rate_max is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_list.append(
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.config.tx_rate_max", vf), tx_rate_max)
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
if link_state is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_list.append(
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.config.link_state", vf), link_state)
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
if spoof_check is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_list.append(
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.config.spoof_check", vf), spoof_check)
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
if trust is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_list.append(
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.config.trust", vf), trust)
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
if query_rss is not None:
|
2021-11-06 03:02:43 -04:00
|
|
|
update_list.append(
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.config.query_rss", vf), query_rss)
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
if len(update_list) < 1:
|
2021-11-06 03:02:43 -04:00
|
|
|
return False, "ERROR: No changes to apply."
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
result = zkhandler.write(update_list)
|
|
|
|
if result:
|
2021-11-06 03:02:43 -04:00
|
|
|
return (
|
|
|
|
True,
|
|
|
|
'Successfully modified configuration of SR-IOV VF "{}" on node "{}".'.format(
|
|
|
|
vf, node
|
|
|
|
),
|
|
|
|
)
|
2021-06-21 18:40:11 -04:00
|
|
|
else:
|
2021-11-06 03:02:43 -04:00
|
|
|
return (
|
|
|
|
False,
|
|
|
|
'Failed to modify configuration of SR-IOV VF "{}" on node "{}".'.format(
|
|
|
|
vf, node
|
|
|
|
),
|
|
|
|
)
|
2021-06-21 01:42:55 -04:00
|
|
|
|
|
|
|
|
2021-06-21 22:21:54 -04:00
|
|
|
def set_sriov_vf_vm(zkhandler, vm_uuid, node, vf, vf_macaddr, vf_type):
|
2021-06-21 18:40:11 -04:00
|
|
|
# Verify node is valid
|
|
|
|
valid_node = common.verifyNode(zkhandler, node)
|
|
|
|
if not valid_node:
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Verify VF is valid
|
|
|
|
vf_information = getSRIOVVFInformation(zkhandler, node, vf)
|
|
|
|
if not vf_information:
|
|
|
|
return False
|
|
|
|
|
2021-06-21 22:21:54 -04:00
|
|
|
update_list = [
|
2021-11-06 03:02:43 -04:00
|
|
|
(("node.sriov.vf", node, "sriov_vf.used", vf), "True"),
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.used_by", vf), vm_uuid),
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.mac", vf), vf_macaddr),
|
2021-06-21 22:21:54 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
# Hostdev type SR-IOV prevents the guest from live migrating
|
2021-11-06 03:02:43 -04:00
|
|
|
if vf_type == "hostdev":
|
|
|
|
update_list.append((("domain.meta.migrate_method", vm_uuid), "shutdown"))
|
2021-06-21 22:21:54 -04:00
|
|
|
|
|
|
|
zkhandler.write(update_list)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def unset_sriov_vf_vm(zkhandler, node, vf):
|
|
|
|
# Verify node is valid
|
|
|
|
valid_node = common.verifyNode(zkhandler, node)
|
|
|
|
if not valid_node:
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Verify VF is valid
|
|
|
|
vf_information = getSRIOVVFInformation(zkhandler, node, vf)
|
|
|
|
if not vf_information:
|
|
|
|
return False
|
|
|
|
|
2021-06-21 22:21:54 -04:00
|
|
|
update_list = [
|
2021-11-06 03:02:43 -04:00
|
|
|
(("node.sriov.vf", node, "sriov_vf.used", vf), "False"),
|
|
|
|
(("node.sriov.vf", node, "sriov_vf.used_by", vf), ""),
|
|
|
|
(
|
|
|
|
("node.sriov.vf", node, "sriov_vf.mac", vf),
|
|
|
|
zkhandler.read(("node.sriov.vf", node, "sriov_vf.phy_mac", vf)),
|
|
|
|
),
|
2021-06-21 22:21:54 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
zkhandler.write(update_list)
|
2021-06-21 18:40:11 -04:00
|
|
|
|
|
|
|
return True
|