1496 lines
47 KiB
Python
1496 lines
47 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# network.py - PVC CLI client function library, Network functions
|
|
# Part of the Parallel Virtual Cluster (PVC) system
|
|
#
|
|
# Copyright (C) 2018-2024 Joshua M. Boniface <joshua@boniface.me>
|
|
#
|
|
# 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
|
|
# the Free Software Foundation, version 3.
|
|
#
|
|
# 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
|
|
import pvc.lib.ansiprint as ansiprint
|
|
from pvc.lib.common import call_api
|
|
|
|
|
|
def isValidMAC(macaddr):
|
|
allowed = re.compile(
|
|
r"""
|
|
(
|
|
^([0-9A-F]{2}[:]){5}([0-9A-F]{2})$
|
|
)
|
|
""",
|
|
re.VERBOSE | re.IGNORECASE,
|
|
)
|
|
|
|
if allowed.match(macaddr):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def isValidIP(ipaddr):
|
|
ip4_blocks = str(ipaddr).split(".")
|
|
if len(ip4_blocks) == 4:
|
|
for block in ip4_blocks:
|
|
# Check if number is digit, if not checked before calling this function
|
|
if not block.isdigit():
|
|
return False
|
|
tmp = int(block)
|
|
if 0 > tmp > 255:
|
|
return False
|
|
return True
|
|
return False
|
|
|
|
|
|
#
|
|
# Primary functions
|
|
#
|
|
def net_info(config, net):
|
|
"""
|
|
Get information about network
|
|
|
|
API endpoint: GET /api/v1/network/{net}
|
|
API arguments:
|
|
API schema: {json_data_object}
|
|
"""
|
|
response = call_api(config, "get", "/network/{net}".format(net=net))
|
|
|
|
if response.status_code == 200:
|
|
if isinstance(response.json(), list) and len(response.json()) != 1:
|
|
# No exact match; return not found
|
|
return False, "Network not found."
|
|
else:
|
|
# Return a single instance if the response is a list
|
|
if isinstance(response.json(), list):
|
|
return True, response.json()[0]
|
|
# This shouldn't happen, but is here just in case
|
|
else:
|
|
return True, response.json()
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
def net_list(config, limit):
|
|
"""
|
|
Get list information about networks (limited by {limit})
|
|
|
|
API endpoint: GET /api/v1/network
|
|
API arguments: limit={limit}
|
|
API schema: [{json_data_object},{json_data_object},etc.]
|
|
"""
|
|
params = dict()
|
|
if limit:
|
|
params["limit"] = limit
|
|
|
|
response = call_api(config, "get", "/network", params=params)
|
|
|
|
if response.status_code == 200:
|
|
return True, response.json()
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
def net_add(
|
|
config,
|
|
vni,
|
|
description,
|
|
nettype,
|
|
mtu,
|
|
domain,
|
|
name_servers,
|
|
ip4_network,
|
|
ip4_gateway,
|
|
ip6_network,
|
|
ip6_gateway,
|
|
dhcp4_flag,
|
|
dhcp4_start,
|
|
dhcp4_end,
|
|
):
|
|
"""
|
|
Add new network
|
|
|
|
API endpoint: POST /api/v1/network
|
|
API arguments: lots
|
|
API schema: {"message":"{data}"}
|
|
"""
|
|
params = {
|
|
"vni": vni,
|
|
"description": description,
|
|
"nettype": nettype,
|
|
"mtu": mtu,
|
|
"domain": domain,
|
|
"name_servers": name_servers,
|
|
"ip4_network": ip4_network,
|
|
"ip4_gateway": ip4_gateway,
|
|
"ip6_network": ip6_network,
|
|
"ip6_gateway": ip6_gateway,
|
|
"dhcp4": dhcp4_flag,
|
|
"dhcp4_start": dhcp4_start,
|
|
"dhcp4_end": dhcp4_end,
|
|
}
|
|
response = call_api(config, "post", "/network", params=params)
|
|
|
|
if response.status_code == 200:
|
|
retstatus = True
|
|
else:
|
|
retstatus = False
|
|
|
|
return retstatus, response.json().get("message", "")
|
|
|
|
|
|
def net_modify(
|
|
config,
|
|
net,
|
|
description,
|
|
mtu,
|
|
domain,
|
|
name_servers,
|
|
ip4_network,
|
|
ip4_gateway,
|
|
ip6_network,
|
|
ip6_gateway,
|
|
dhcp4_flag,
|
|
dhcp4_start,
|
|
dhcp4_end,
|
|
):
|
|
"""
|
|
Modify a network
|
|
|
|
API endpoint: POST /api/v1/network/{net}
|
|
API arguments: lots
|
|
API schema: {"message":"{data}"}
|
|
"""
|
|
params = dict()
|
|
if description is not None:
|
|
params["description"] = description
|
|
if mtu is not None:
|
|
params["mtu"] = mtu
|
|
if domain is not None:
|
|
params["domain"] = domain
|
|
if name_servers is not None:
|
|
params["name_servers"] = name_servers
|
|
if ip4_network is not None:
|
|
params["ip4_network"] = ip4_network
|
|
if ip4_gateway is not None:
|
|
params["ip4_gateway"] = ip4_gateway
|
|
if ip6_network is not None:
|
|
params["ip6_network"] = ip6_network
|
|
if ip6_gateway is not None:
|
|
params["ip6_gateway"] = ip6_gateway
|
|
if dhcp4_flag is not None:
|
|
params["dhcp4"] = dhcp4_flag
|
|
if dhcp4_start is not None:
|
|
params["dhcp4_start"] = dhcp4_start
|
|
if dhcp4_end is not None:
|
|
params["dhcp4_end"] = dhcp4_end
|
|
|
|
response = call_api(config, "put", "/network/{net}".format(net=net), params=params)
|
|
|
|
if response.status_code == 200:
|
|
retstatus = True
|
|
else:
|
|
retstatus = False
|
|
|
|
return retstatus, response.json().get("message", "")
|
|
|
|
|
|
def net_remove(config, net):
|
|
"""
|
|
Remove a network
|
|
|
|
API endpoint: DELETE /api/v1/network/{net}
|
|
API arguments:
|
|
API schema: {"message":"{data}"}
|
|
"""
|
|
response = call_api(config, "delete", "/network/{net}".format(net=net))
|
|
|
|
if response.status_code == 200:
|
|
retstatus = True
|
|
else:
|
|
retstatus = False
|
|
|
|
return retstatus, response.json().get("message", "")
|
|
|
|
|
|
#
|
|
# DHCP lease functions
|
|
#
|
|
def net_dhcp_info(config, net, mac):
|
|
"""A
|
|
Get information about network DHCP lease
|
|
|
|
API endpoint: GET /api/v1/network/{net}/lease/{mac}
|
|
API arguments:
|
|
API schema: {json_data_object}
|
|
"""
|
|
response = call_api(
|
|
config, "get", "/network/{net}/lease/{mac}".format(net=net, mac=mac)
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
if isinstance(response.json(), list) and len(response.json()) != 1:
|
|
# No exact match; return not found
|
|
return False, "Lease not found."
|
|
else:
|
|
# Return a single instance if the response is a list
|
|
if isinstance(response.json(), list):
|
|
return True, response.json()[0]
|
|
# This shouldn't happen, but is here just in case
|
|
else:
|
|
return True, response.json()
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
def net_dhcp_list(config, net, limit, only_static=False):
|
|
"""
|
|
Get list information about leases (limited by {limit})
|
|
|
|
API endpoint: GET /api/v1/network/{net}/lease
|
|
API arguments: limit={limit}, static={only_static}
|
|
API schema: [{json_data_object},{json_data_object},etc.]
|
|
"""
|
|
params = dict()
|
|
if limit:
|
|
params["limit"] = limit
|
|
|
|
if only_static:
|
|
params["static"] = True
|
|
else:
|
|
params["static"] = False
|
|
|
|
response = call_api(
|
|
config, "get", "/network/{net}/lease".format(net=net), params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
return True, response.json()
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
def net_dhcp_add(config, net, ipaddr, macaddr, hostname):
|
|
"""
|
|
Add new network DHCP lease
|
|
|
|
API endpoint: POST /api/v1/network/{net}/lease
|
|
API arguments: macaddress=macaddr, ipaddress=ipaddr, hostname=hostname
|
|
API schema: {"message":"{data}"}
|
|
"""
|
|
params = {"macaddress": macaddr, "ipaddress": ipaddr, "hostname": hostname}
|
|
response = call_api(
|
|
config, "post", "/network/{net}/lease".format(net=net), params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
retstatus = True
|
|
else:
|
|
retstatus = False
|
|
|
|
return retstatus, response.json().get("message", "")
|
|
|
|
|
|
def net_dhcp_remove(config, net, mac):
|
|
"""
|
|
Remove a network DHCP lease
|
|
|
|
API endpoint: DELETE /api/v1/network/{vni}/lease/{mac}
|
|
API arguments:
|
|
API schema: {"message":"{data}"}
|
|
"""
|
|
response = call_api(
|
|
config, "delete", "/network/{net}/lease/{mac}".format(net=net, mac=mac)
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
retstatus = True
|
|
else:
|
|
retstatus = False
|
|
|
|
return retstatus, response.json().get("message", "")
|
|
|
|
|
|
#
|
|
# ACL functions
|
|
#
|
|
def net_acl_info(config, net, description):
|
|
"""
|
|
Get information about network ACL
|
|
|
|
API endpoint: GET /api/v1/network/{net}/acl/{description}
|
|
API arguments:
|
|
API schema: {json_data_object}
|
|
"""
|
|
response = call_api(
|
|
config,
|
|
"get",
|
|
"/network/{net}/acl/{description}".format(net=net, description=description),
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
if isinstance(response.json(), list) and len(response.json()) != 1:
|
|
# No exact match; return not found
|
|
return False, "ACL not found."
|
|
else:
|
|
# Return a single instance if the response is a list
|
|
if isinstance(response.json(), list):
|
|
return True, response.json()[0]
|
|
# This shouldn't happen, but is here just in case
|
|
else:
|
|
return True, response.json()
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
def net_acl_list(config, net, limit, direction):
|
|
"""
|
|
Get list information about ACLs (limited by {limit})
|
|
|
|
API endpoint: GET /api/v1/network/{net}/acl
|
|
API arguments: limit={limit}, direction={direction}
|
|
API schema: [{json_data_object},{json_data_object},etc.]
|
|
"""
|
|
params = dict()
|
|
if limit:
|
|
params["limit"] = limit
|
|
if direction is not None:
|
|
params["direction"] = direction
|
|
|
|
response = call_api(
|
|
config, "get", "/network/{net}/acl".format(net=net), params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
return True, response.json()
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
def net_acl_add(config, net, direction, description, rule, order):
|
|
"""
|
|
Add new network acl
|
|
|
|
API endpoint: POST /api/v1/network/{net}/acl
|
|
API arguments: description=description, direction=direction, order=order, rule=rule
|
|
API schema: {"message":"{data}"}
|
|
"""
|
|
params = dict()
|
|
params["description"] = description
|
|
params["direction"] = direction
|
|
params["rule"] = rule
|
|
if order is not None:
|
|
params["order"] = order
|
|
|
|
response = call_api(
|
|
config, "post", "/network/{net}/acl".format(net=net), params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
retstatus = True
|
|
else:
|
|
retstatus = False
|
|
|
|
return retstatus, response.json().get("message", "")
|
|
|
|
|
|
def net_acl_remove(config, net, description):
|
|
"""
|
|
Remove a network ACL
|
|
|
|
API endpoint: DELETE /api/v1/network/{vni}/acl/{description}
|
|
API arguments:
|
|
API schema: {"message":"{data}"}
|
|
"""
|
|
response = call_api(
|
|
config,
|
|
"delete",
|
|
"/network/{net}/acl/{description}".format(net=net, description=description),
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
retstatus = True
|
|
else:
|
|
retstatus = False
|
|
|
|
return retstatus, response.json().get("message", "")
|
|
|
|
|
|
#
|
|
# SR-IOV functions
|
|
#
|
|
def net_sriov_pf_list(config, node):
|
|
"""
|
|
List all PFs on NODE
|
|
|
|
API endpoint: GET /api/v1/sriov/pf/<node>
|
|
API arguments: node={node}
|
|
API schema: [{json_data_object},{json_data_object},etc.]
|
|
"""
|
|
response = call_api(config, "get", "/sriov/pf/{}".format(node))
|
|
|
|
if response.status_code == 200:
|
|
return True, response.json()
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
def net_sriov_vf_set(
|
|
config,
|
|
node,
|
|
vf,
|
|
vlan_id,
|
|
vlan_qos,
|
|
tx_rate_min,
|
|
tx_rate_max,
|
|
link_state,
|
|
spoof_check,
|
|
trust,
|
|
query_rss,
|
|
):
|
|
"""
|
|
Mdoify configuration of a SR-IOV VF
|
|
|
|
API endpoint: PUT /api/v1/sriov/vf/<node>/<vf>
|
|
API arguments: 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}
|
|
API schema: {"message": "{data}"}
|
|
"""
|
|
params = dict()
|
|
|
|
# Update any params that we've sent
|
|
if vlan_id is not None:
|
|
params["vlan_id"] = vlan_id
|
|
|
|
if vlan_qos is not None:
|
|
params["vlan_qos"] = vlan_qos
|
|
|
|
if tx_rate_min is not None:
|
|
params["tx_rate_min"] = tx_rate_min
|
|
|
|
if tx_rate_max is not None:
|
|
params["tx_rate_max"] = tx_rate_max
|
|
|
|
if link_state is not None:
|
|
params["link_state"] = link_state
|
|
|
|
if spoof_check is not None:
|
|
params["spoof_check"] = spoof_check
|
|
|
|
if trust is not None:
|
|
params["trust"] = trust
|
|
|
|
if query_rss is not None:
|
|
params["query_rss"] = query_rss
|
|
|
|
# Write the new configuration to the API
|
|
response = call_api(
|
|
config, "put", "/sriov/vf/{node}/{vf}".format(node=node, vf=vf), params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
retstatus = True
|
|
else:
|
|
retstatus = False
|
|
|
|
return retstatus, response.json().get("message", "")
|
|
|
|
|
|
def net_sriov_vf_list(config, node, pf=None):
|
|
"""
|
|
List all VFs on NODE, optionally limited by PF
|
|
|
|
API endpoint: GET /api/v1/sriov/vf/<node>
|
|
API arguments: node={node}, pf={pf}
|
|
API schema: [{json_data_object},{json_data_object},etc.]
|
|
"""
|
|
params = dict()
|
|
params["pf"] = pf
|
|
|
|
response = call_api(config, "get", "/sriov/vf/{}".format(node), params=params)
|
|
|
|
if response.status_code == 200:
|
|
return True, response.json()
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
def net_sriov_vf_info(config, node, vf):
|
|
"""
|
|
Get info about VF on NODE
|
|
|
|
API endpoint: GET /api/v1/sriov/vf/<node>/<vf>
|
|
API arguments:
|
|
API schema: [{json_data_object}]
|
|
"""
|
|
response = call_api(config, "get", "/sriov/vf/{}/{}".format(node, vf))
|
|
|
|
if response.status_code == 200:
|
|
if isinstance(response.json(), list) and len(response.json()) != 1:
|
|
# No exact match; return not found
|
|
return False, "VF not found."
|
|
else:
|
|
# Return a single instance if the response is a list
|
|
data = dict()
|
|
data["node"] = node
|
|
if isinstance(response.json(), list):
|
|
data = dict()
|
|
data["vf_information"] = response.json()[0]
|
|
return True, data
|
|
# This shouldn't happen, but is here just in case
|
|
else:
|
|
data["vf_information"] = response.json()
|
|
return True, data
|
|
else:
|
|
return False, response.json().get("message", "")
|
|
|
|
|
|
#
|
|
# Output display functions
|
|
#
|
|
def getColour(value):
|
|
if value in ["False", "None"]:
|
|
return ansiprint.blue()
|
|
else:
|
|
return ansiprint.green()
|
|
|
|
|
|
def getOutputColours(network_information):
|
|
v6_flag_colour = getColour(network_information["ip6"]["network"])
|
|
v4_flag_colour = getColour(network_information["ip4"]["network"])
|
|
dhcp6_flag_colour = getColour(network_information["ip6"]["dhcp_flag"])
|
|
dhcp4_flag_colour = getColour(network_information["ip4"]["dhcp_flag"])
|
|
|
|
return v6_flag_colour, v4_flag_colour, dhcp6_flag_colour, dhcp4_flag_colour
|
|
|
|
|
|
def format_info(config, network_information, long_output):
|
|
if not network_information:
|
|
return "No network found"
|
|
|
|
(
|
|
v6_flag_colour,
|
|
v4_flag_colour,
|
|
dhcp6_flag_colour,
|
|
dhcp4_flag_colour,
|
|
) = getOutputColours(network_information)
|
|
|
|
# Format a nice output: do this line-by-line then concat the elements at the end
|
|
ainformation = []
|
|
ainformation.append(
|
|
"{}Virtual network information:{}".format(ansiprint.bold(), ansiprint.end())
|
|
)
|
|
ainformation.append("")
|
|
# Basic information
|
|
ainformation.append(
|
|
"{}VNI:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), network_information["vni"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}Type:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), network_information["type"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}MTU:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), network_information["mtu"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}Description:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), network_information["description"]
|
|
)
|
|
)
|
|
if network_information["type"] == "managed":
|
|
ainformation.append(
|
|
"{}Domain:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), network_information["domain"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}DNS Servers:{} {}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
", ".join(network_information["name_servers"]),
|
|
)
|
|
)
|
|
if network_information["ip6"]["network"] != "None":
|
|
ainformation.append("")
|
|
ainformation.append(
|
|
"{}IPv6 network:{} {}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
network_information["ip6"]["network"],
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}IPv6 gateway:{} {}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
network_information["ip6"]["gateway"],
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}DHCPv6 enabled:{} {}{}{}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
dhcp6_flag_colour,
|
|
network_information["ip6"]["dhcp_flag"],
|
|
ansiprint.end(),
|
|
)
|
|
)
|
|
if network_information["ip4"]["network"] != "None":
|
|
ainformation.append("")
|
|
ainformation.append(
|
|
"{}IPv4 network:{} {}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
network_information["ip4"]["network"],
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}IPv4 gateway:{} {}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
network_information["ip4"]["gateway"],
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}DHCPv4 enabled:{} {}{}{}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
dhcp4_flag_colour,
|
|
network_information["ip4"]["dhcp_flag"],
|
|
ansiprint.end(),
|
|
)
|
|
)
|
|
if network_information["ip4"]["dhcp_flag"] == "True":
|
|
ainformation.append(
|
|
"{}DHCPv4 range:{} {} - {}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
network_information["ip4"]["dhcp_start"],
|
|
network_information["ip4"]["dhcp_end"],
|
|
)
|
|
)
|
|
|
|
if long_output:
|
|
retcode, dhcp4_reservations_list = net_dhcp_list(
|
|
config, network_information["vni"], None
|
|
)
|
|
if dhcp4_reservations_list:
|
|
ainformation.append("")
|
|
ainformation.append(
|
|
"{}Client DHCPv4 reservations:{}".format(
|
|
ansiprint.bold(), ansiprint.end()
|
|
)
|
|
)
|
|
ainformation.append("")
|
|
if retcode:
|
|
dhcp4_reservations_string = format_list_dhcp(
|
|
config, dhcp4_reservations_list
|
|
)
|
|
for line in dhcp4_reservations_string.split("\n"):
|
|
ainformation.append(line)
|
|
else:
|
|
ainformation.append("No leases found")
|
|
|
|
retcode, firewall_rules_list = net_acl_list(
|
|
config, network_information["vni"], None, None
|
|
)
|
|
if firewall_rules_list:
|
|
ainformation.append("")
|
|
ainformation.append(
|
|
"{}Network firewall rules:{}".format(
|
|
ansiprint.bold(), ansiprint.end()
|
|
)
|
|
)
|
|
ainformation.append("")
|
|
if retcode:
|
|
firewall_rules_string = format_list_acl(config, firewall_rules_list)
|
|
for line in firewall_rules_string.split("\n"):
|
|
ainformation.append(line)
|
|
else:
|
|
ainformation.append("No ACLs found")
|
|
|
|
# Join it all together
|
|
return "\n".join(ainformation)
|
|
|
|
|
|
def format_list(config, network_list):
|
|
if not network_list:
|
|
return "No network found"
|
|
|
|
network_list_output = []
|
|
|
|
# Determine optimal column widths
|
|
net_vni_length = 5
|
|
net_description_length = 12
|
|
net_nettype_length = 8
|
|
net_mtu_length = 4
|
|
net_domain_length = 6
|
|
net_v6_flag_length = 6
|
|
net_dhcp6_flag_length = 7
|
|
net_v4_flag_length = 6
|
|
net_dhcp4_flag_length = 7
|
|
for network_information in network_list:
|
|
# vni column
|
|
_net_vni_length = len(str(network_information["vni"])) + 1
|
|
if _net_vni_length > net_vni_length:
|
|
net_vni_length = _net_vni_length
|
|
# description column
|
|
_net_description_length = len(network_information["description"]) + 1
|
|
if _net_description_length > net_description_length:
|
|
net_description_length = _net_description_length
|
|
# mtu column
|
|
_net_mtu_length = len(str(network_information["mtu"])) + 1
|
|
if _net_mtu_length > net_mtu_length:
|
|
net_mtu_length = _net_mtu_length
|
|
# domain column
|
|
_net_domain_length = len(network_information["domain"]) + 1
|
|
if _net_domain_length > net_domain_length:
|
|
net_domain_length = _net_domain_length
|
|
|
|
# Format the string (header)
|
|
network_list_output.append(
|
|
"{bold}{networks_header: <{networks_header_length}} {config_header: <{config_header_length}}{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
networks_header_length=net_vni_length + net_description_length + 1,
|
|
config_header_length=net_nettype_length
|
|
+ net_mtu_length
|
|
+ net_domain_length
|
|
+ net_v6_flag_length
|
|
+ net_dhcp6_flag_length
|
|
+ net_v4_flag_length
|
|
+ net_dhcp4_flag_length
|
|
+ 7,
|
|
networks_header="Networks "
|
|
+ "".join(["-" for _ in range(9, net_vni_length + net_description_length)]),
|
|
config_header="Config "
|
|
+ "".join(
|
|
[
|
|
"-"
|
|
for _ in range(
|
|
7,
|
|
net_nettype_length
|
|
+ net_mtu_length
|
|
+ net_domain_length
|
|
+ net_v6_flag_length
|
|
+ net_dhcp6_flag_length
|
|
+ net_v4_flag_length
|
|
+ net_dhcp4_flag_length
|
|
+ 6,
|
|
)
|
|
]
|
|
),
|
|
)
|
|
)
|
|
network_list_output.append(
|
|
"{bold}\
|
|
{net_vni: <{net_vni_length}} \
|
|
{net_description: <{net_description_length}} \
|
|
{net_nettype: <{net_nettype_length}} \
|
|
{net_mtu: <{net_mtu_length}} \
|
|
{net_domain: <{net_domain_length}} \
|
|
{net_v6_flag: <{net_v6_flag_length}} \
|
|
{net_dhcp6_flag: <{net_dhcp6_flag_length}} \
|
|
{net_v4_flag: <{net_v4_flag_length}} \
|
|
{net_dhcp4_flag: <{net_dhcp4_flag_length}} \
|
|
{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
net_vni_length=net_vni_length,
|
|
net_description_length=net_description_length,
|
|
net_nettype_length=net_nettype_length,
|
|
net_mtu_length=net_mtu_length,
|
|
net_domain_length=net_domain_length,
|
|
net_v6_flag_length=net_v6_flag_length,
|
|
net_dhcp6_flag_length=net_dhcp6_flag_length,
|
|
net_v4_flag_length=net_v4_flag_length,
|
|
net_dhcp4_flag_length=net_dhcp4_flag_length,
|
|
net_vni="VNI",
|
|
net_description="Description",
|
|
net_nettype="Type",
|
|
net_mtu="MTU",
|
|
net_domain="Domain",
|
|
net_v6_flag="IPv6",
|
|
net_dhcp6_flag="DHCPv6",
|
|
net_v4_flag="IPv4",
|
|
net_dhcp4_flag="DHCPv4",
|
|
)
|
|
)
|
|
|
|
for network_information in sorted(network_list, key=lambda n: int(n["vni"])):
|
|
(
|
|
v6_flag_colour,
|
|
v4_flag_colour,
|
|
dhcp6_flag_colour,
|
|
dhcp4_flag_colour,
|
|
) = getOutputColours(network_information)
|
|
if network_information["ip4"]["network"] != "None":
|
|
v4_flag = "True"
|
|
else:
|
|
v4_flag = "False"
|
|
|
|
if network_information["ip6"]["network"] != "None":
|
|
v6_flag = "True"
|
|
else:
|
|
v6_flag = "False"
|
|
|
|
network_list_output.append(
|
|
"{bold}\
|
|
{net_vni: <{net_vni_length}} \
|
|
{net_description: <{net_description_length}} \
|
|
{net_nettype: <{net_nettype_length}} \
|
|
{net_mtu: <{net_mtu_length}} \
|
|
{net_domain: <{net_domain_length}} \
|
|
{v6_flag_colour}{net_v6_flag: <{net_v6_flag_length}}{colour_off} \
|
|
{dhcp6_flag_colour}{net_dhcp6_flag: <{net_dhcp6_flag_length}}{colour_off} \
|
|
{v4_flag_colour}{net_v4_flag: <{net_v4_flag_length}}{colour_off} \
|
|
{dhcp4_flag_colour}{net_dhcp4_flag: <{net_dhcp4_flag_length}}{colour_off} \
|
|
{end_bold}".format(
|
|
bold="",
|
|
end_bold="",
|
|
net_vni_length=net_vni_length,
|
|
net_description_length=net_description_length,
|
|
net_nettype_length=net_nettype_length,
|
|
net_mtu_length=net_mtu_length,
|
|
net_domain_length=net_domain_length,
|
|
net_v6_flag_length=net_v6_flag_length,
|
|
net_dhcp6_flag_length=net_dhcp6_flag_length,
|
|
net_v4_flag_length=net_v4_flag_length,
|
|
net_dhcp4_flag_length=net_dhcp4_flag_length,
|
|
net_vni=network_information["vni"],
|
|
net_description=network_information["description"],
|
|
net_nettype=network_information["type"],
|
|
net_mtu=network_information["mtu"],
|
|
net_domain=network_information["domain"],
|
|
net_v6_flag=v6_flag,
|
|
v6_flag_colour=v6_flag_colour,
|
|
net_dhcp6_flag=network_information["ip6"]["dhcp_flag"],
|
|
dhcp6_flag_colour=dhcp6_flag_colour,
|
|
net_v4_flag=v4_flag,
|
|
v4_flag_colour=v4_flag_colour,
|
|
net_dhcp4_flag=network_information["ip4"]["dhcp_flag"],
|
|
dhcp4_flag_colour=dhcp4_flag_colour,
|
|
colour_off=ansiprint.end(),
|
|
)
|
|
)
|
|
|
|
return "\n".join(network_list_output)
|
|
|
|
|
|
def format_list_dhcp(config, dhcp_lease_list):
|
|
dhcp_lease_list_output = []
|
|
|
|
# Determine optimal column widths
|
|
lease_hostname_length = 9
|
|
lease_ip4_address_length = 11
|
|
lease_mac_address_length = 13
|
|
lease_timestamp_length = 10
|
|
for dhcp_lease_information in dhcp_lease_list:
|
|
# hostname column
|
|
_lease_hostname_length = len(str(dhcp_lease_information["hostname"])) + 1
|
|
if _lease_hostname_length > lease_hostname_length:
|
|
lease_hostname_length = _lease_hostname_length
|
|
# ip4_address column
|
|
_lease_ip4_address_length = len(str(dhcp_lease_information["ip4_address"])) + 1
|
|
if _lease_ip4_address_length > lease_ip4_address_length:
|
|
lease_ip4_address_length = _lease_ip4_address_length
|
|
# mac_address column
|
|
_lease_mac_address_length = len(str(dhcp_lease_information["mac_address"])) + 1
|
|
if _lease_mac_address_length > lease_mac_address_length:
|
|
lease_mac_address_length = _lease_mac_address_length
|
|
# timestamp column
|
|
_lease_timestamp_length = len(str(dhcp_lease_information["timestamp"])) + 1
|
|
if _lease_timestamp_length > lease_timestamp_length:
|
|
lease_timestamp_length = _lease_timestamp_length
|
|
|
|
# Format the string (header)
|
|
dhcp_lease_list_output.append(
|
|
"{bold}{lease_header: <{lease_header_length}}{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
lease_header_length=lease_hostname_length
|
|
+ lease_ip4_address_length
|
|
+ lease_mac_address_length
|
|
+ lease_timestamp_length
|
|
+ 3,
|
|
lease_header="Leases "
|
|
+ "".join(
|
|
[
|
|
"-"
|
|
for _ in range(
|
|
7,
|
|
lease_hostname_length
|
|
+ lease_ip4_address_length
|
|
+ lease_mac_address_length
|
|
+ lease_timestamp_length
|
|
+ 2,
|
|
)
|
|
]
|
|
),
|
|
)
|
|
)
|
|
|
|
dhcp_lease_list_output.append(
|
|
"{bold}\
|
|
{lease_hostname: <{lease_hostname_length}} \
|
|
{lease_ip4_address: <{lease_ip4_address_length}} \
|
|
{lease_mac_address: <{lease_mac_address_length}} \
|
|
{lease_timestamp: <{lease_timestamp_length}} \
|
|
{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
lease_hostname_length=lease_hostname_length,
|
|
lease_ip4_address_length=lease_ip4_address_length,
|
|
lease_mac_address_length=lease_mac_address_length,
|
|
lease_timestamp_length=lease_timestamp_length,
|
|
lease_hostname="Hostname",
|
|
lease_ip4_address="IP Address",
|
|
lease_mac_address="MAC Address",
|
|
lease_timestamp="Timestamp",
|
|
)
|
|
)
|
|
|
|
for dhcp_lease_information in sorted(
|
|
dhcp_lease_list, key=lambda lease: lease["hostname"]
|
|
):
|
|
dhcp_lease_list_output.append(
|
|
"{bold}\
|
|
{lease_hostname: <{lease_hostname_length}} \
|
|
{lease_ip4_address: <{lease_ip4_address_length}} \
|
|
{lease_mac_address: <{lease_mac_address_length}} \
|
|
{lease_timestamp: <{lease_timestamp_length}} \
|
|
{end_bold}".format(
|
|
bold="",
|
|
end_bold="",
|
|
lease_hostname_length=lease_hostname_length,
|
|
lease_ip4_address_length=lease_ip4_address_length,
|
|
lease_mac_address_length=lease_mac_address_length,
|
|
lease_timestamp_length=12,
|
|
lease_hostname=str(dhcp_lease_information["hostname"]),
|
|
lease_ip4_address=str(dhcp_lease_information["ip4_address"]),
|
|
lease_mac_address=str(dhcp_lease_information["mac_address"]),
|
|
lease_timestamp=str(dhcp_lease_information["timestamp"]),
|
|
)
|
|
)
|
|
|
|
return "\n".join(dhcp_lease_list_output)
|
|
|
|
|
|
def format_list_acl(config, acl_list):
|
|
# Handle when we get an empty entry
|
|
if not acl_list:
|
|
acl_list = list()
|
|
|
|
acl_list_output = []
|
|
|
|
# Determine optimal column widths
|
|
acl_direction_length = 10
|
|
acl_order_length = 6
|
|
acl_description_length = 12
|
|
acl_rule_length = 5
|
|
for acl_information in acl_list:
|
|
# order column
|
|
_acl_order_length = len(str(acl_information["order"])) + 1
|
|
if _acl_order_length > acl_order_length:
|
|
acl_order_length = _acl_order_length
|
|
# description column
|
|
_acl_description_length = len(acl_information["description"]) + 1
|
|
if _acl_description_length > acl_description_length:
|
|
acl_description_length = _acl_description_length
|
|
# rule column
|
|
_acl_rule_length = len(acl_information["rule"]) + 1
|
|
if _acl_rule_length > acl_rule_length:
|
|
acl_rule_length = _acl_rule_length
|
|
|
|
# Format the string (header)
|
|
acl_list_output.append(
|
|
"{bold}{acl_header: <{acl_header_length}}{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
acl_header_length=acl_direction_length
|
|
+ acl_order_length
|
|
+ acl_description_length
|
|
+ acl_rule_length
|
|
+ 3,
|
|
acl_header="ACLs "
|
|
+ "".join(
|
|
[
|
|
"-"
|
|
for _ in range(
|
|
5,
|
|
acl_direction_length
|
|
+ acl_order_length
|
|
+ acl_description_length
|
|
+ acl_rule_length
|
|
+ 2,
|
|
)
|
|
]
|
|
),
|
|
)
|
|
)
|
|
|
|
acl_list_output.append(
|
|
"{bold}\
|
|
{acl_direction: <{acl_direction_length}} \
|
|
{acl_order: <{acl_order_length}} \
|
|
{acl_description: <{acl_description_length}} \
|
|
{acl_rule: <{acl_rule_length}} \
|
|
{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
acl_direction_length=acl_direction_length,
|
|
acl_order_length=acl_order_length,
|
|
acl_description_length=acl_description_length,
|
|
acl_rule_length=acl_rule_length,
|
|
acl_direction="Direction",
|
|
acl_order="Order",
|
|
acl_description="Description",
|
|
acl_rule="Rule",
|
|
)
|
|
)
|
|
|
|
for acl_information in sorted(
|
|
acl_list, key=lambda acl: acl["direction"] + str(acl["order"])
|
|
):
|
|
acl_list_output.append(
|
|
"{bold}\
|
|
{acl_direction: <{acl_direction_length}} \
|
|
{acl_order: <{acl_order_length}} \
|
|
{acl_description: <{acl_description_length}} \
|
|
{acl_rule: <{acl_rule_length}} \
|
|
{end_bold}".format(
|
|
bold="",
|
|
end_bold="",
|
|
acl_direction_length=acl_direction_length,
|
|
acl_order_length=acl_order_length,
|
|
acl_description_length=acl_description_length,
|
|
acl_rule_length=acl_rule_length,
|
|
acl_direction=acl_information["direction"],
|
|
acl_order=acl_information["order"],
|
|
acl_description=acl_information["description"],
|
|
acl_rule=acl_information["rule"],
|
|
)
|
|
)
|
|
|
|
return "\n".join(acl_list_output)
|
|
|
|
|
|
def format_list_sriov_pf(config, pf_list):
|
|
# The maximum column width of the VFs column
|
|
max_vfs_length = 70
|
|
|
|
# Handle when we get an empty entry
|
|
if not pf_list:
|
|
pf_list = list()
|
|
|
|
pf_list_output = []
|
|
|
|
# Determine optimal column widths
|
|
pf_phy_length = 6
|
|
pf_mtu_length = 4
|
|
pf_vfs_length = 4
|
|
|
|
for pf_information in pf_list:
|
|
# phy column
|
|
_pf_phy_length = len(str(pf_information["phy"])) + 1
|
|
if _pf_phy_length > pf_phy_length:
|
|
pf_phy_length = _pf_phy_length
|
|
# mtu column
|
|
_pf_mtu_length = len(str(pf_information["mtu"])) + 1
|
|
if _pf_mtu_length > pf_mtu_length:
|
|
pf_mtu_length = _pf_mtu_length
|
|
# vfs column
|
|
_pf_vfs_length = len(str(", ".join(pf_information["vfs"]))) + 1
|
|
if _pf_vfs_length > pf_vfs_length:
|
|
pf_vfs_length = _pf_vfs_length
|
|
|
|
# We handle columnizing very long lists later
|
|
if pf_vfs_length > max_vfs_length:
|
|
pf_vfs_length = max_vfs_length
|
|
|
|
# Format the string (header)
|
|
pf_list_output.append(
|
|
"{bold}{pf_header: <{pf_header_length}}{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
pf_header_length=pf_phy_length + pf_mtu_length + pf_vfs_length + 2,
|
|
pf_header="PFs "
|
|
+ "".join(
|
|
[
|
|
"-"
|
|
for _ in range(4, pf_phy_length + pf_mtu_length + pf_vfs_length + 1)
|
|
]
|
|
),
|
|
)
|
|
)
|
|
|
|
pf_list_output.append(
|
|
"{bold}\
|
|
{pf_phy: <{pf_phy_length}} \
|
|
{pf_mtu: <{pf_mtu_length}} \
|
|
{pf_vfs: <{pf_vfs_length}} \
|
|
{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
pf_phy_length=pf_phy_length,
|
|
pf_mtu_length=pf_mtu_length,
|
|
pf_vfs_length=pf_vfs_length,
|
|
pf_phy="Device",
|
|
pf_mtu="MTU",
|
|
pf_vfs="VFs",
|
|
)
|
|
)
|
|
|
|
for pf_information in sorted(pf_list, key=lambda p: p["phy"]):
|
|
# Figure out how to nicely columnize our list
|
|
nice_vfs_list = [list()]
|
|
vfs_lines = 0
|
|
cur_vfs_length = 0
|
|
for vfs in pf_information["vfs"]:
|
|
vfs_len = len(vfs)
|
|
cur_vfs_length += vfs_len + 2 # for the comma and space
|
|
if cur_vfs_length > max_vfs_length:
|
|
cur_vfs_length = 0
|
|
vfs_lines += 1
|
|
nice_vfs_list.append(list())
|
|
nice_vfs_list[vfs_lines].append(vfs)
|
|
|
|
# Append the lines
|
|
pf_list_output.append(
|
|
"{bold}\
|
|
{pf_phy: <{pf_phy_length}} \
|
|
{pf_mtu: <{pf_mtu_length}} \
|
|
{pf_vfs: <{pf_vfs_length}} \
|
|
{end_bold}".format(
|
|
bold="",
|
|
end_bold="",
|
|
pf_phy_length=pf_phy_length,
|
|
pf_mtu_length=pf_mtu_length,
|
|
pf_vfs_length=pf_vfs_length,
|
|
pf_phy=pf_information["phy"],
|
|
pf_mtu=pf_information["mtu"],
|
|
pf_vfs=", ".join(nice_vfs_list[0]),
|
|
)
|
|
)
|
|
|
|
if len(nice_vfs_list) > 1:
|
|
for idx in range(1, len(nice_vfs_list)):
|
|
pf_list_output.append(
|
|
"{bold}\
|
|
{pf_phy: <{pf_phy_length}} \
|
|
{pf_mtu: <{pf_mtu_length}} \
|
|
{pf_vfs: <{pf_vfs_length}} \
|
|
{end_bold}".format(
|
|
bold="",
|
|
end_bold="",
|
|
pf_phy_length=pf_phy_length,
|
|
pf_mtu_length=pf_mtu_length,
|
|
pf_vfs_length=pf_vfs_length,
|
|
pf_phy="",
|
|
pf_mtu="",
|
|
pf_vfs=", ".join(nice_vfs_list[idx]),
|
|
)
|
|
)
|
|
|
|
return "\n".join(pf_list_output)
|
|
|
|
|
|
def format_list_sriov_vf(config, vf_list):
|
|
# Handle when we get an empty entry
|
|
if not vf_list:
|
|
vf_list = list()
|
|
|
|
vf_list_output = []
|
|
|
|
# Determine optimal column widths
|
|
vf_phy_length = 4
|
|
vf_pf_length = 3
|
|
vf_mtu_length = 4
|
|
vf_mac_length = 11
|
|
vf_used_length = 5
|
|
vf_domain_length = 5
|
|
|
|
for vf_information in vf_list:
|
|
# phy column
|
|
_vf_phy_length = len(str(vf_information["phy"])) + 1
|
|
if _vf_phy_length > vf_phy_length:
|
|
vf_phy_length = _vf_phy_length
|
|
# pf column
|
|
_vf_pf_length = len(str(vf_information["pf"])) + 1
|
|
if _vf_pf_length > vf_pf_length:
|
|
vf_pf_length = _vf_pf_length
|
|
# mtu column
|
|
_vf_mtu_length = len(str(vf_information["mtu"])) + 1
|
|
if _vf_mtu_length > vf_mtu_length:
|
|
vf_mtu_length = _vf_mtu_length
|
|
# mac column
|
|
_vf_mac_length = len(str(vf_information["mac"])) + 1
|
|
if _vf_mac_length > vf_mac_length:
|
|
vf_mac_length = _vf_mac_length
|
|
# used column
|
|
_vf_used_length = len(str(vf_information["usage"]["used"])) + 1
|
|
if _vf_used_length > vf_used_length:
|
|
vf_used_length = _vf_used_length
|
|
# domain column
|
|
_vf_domain_length = len(str(vf_information["usage"]["domain"])) + 1
|
|
if _vf_domain_length > vf_domain_length:
|
|
vf_domain_length = _vf_domain_length
|
|
|
|
# Format the string (header)
|
|
vf_list_output.append(
|
|
"{bold}{vf_header: <{vf_header_length}}{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
vf_header_length=vf_phy_length
|
|
+ vf_pf_length
|
|
+ vf_mtu_length
|
|
+ vf_mac_length
|
|
+ vf_used_length
|
|
+ vf_domain_length
|
|
+ 5,
|
|
vf_header="VFs "
|
|
+ "".join(
|
|
[
|
|
"-"
|
|
for _ in range(
|
|
4,
|
|
vf_phy_length
|
|
+ vf_pf_length
|
|
+ vf_mtu_length
|
|
+ vf_mac_length
|
|
+ vf_used_length
|
|
+ vf_domain_length
|
|
+ 4,
|
|
)
|
|
]
|
|
),
|
|
)
|
|
)
|
|
|
|
vf_list_output.append(
|
|
"{bold}\
|
|
{vf_phy: <{vf_phy_length}} \
|
|
{vf_pf: <{vf_pf_length}} \
|
|
{vf_mtu: <{vf_mtu_length}} \
|
|
{vf_mac: <{vf_mac_length}} \
|
|
{vf_used: <{vf_used_length}} \
|
|
{vf_domain: <{vf_domain_length}} \
|
|
{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
vf_phy_length=vf_phy_length,
|
|
vf_pf_length=vf_pf_length,
|
|
vf_mtu_length=vf_mtu_length,
|
|
vf_mac_length=vf_mac_length,
|
|
vf_used_length=vf_used_length,
|
|
vf_domain_length=vf_domain_length,
|
|
vf_phy="Device",
|
|
vf_pf="PF",
|
|
vf_mtu="MTU",
|
|
vf_mac="MAC Address",
|
|
vf_used="Used",
|
|
vf_domain="Domain",
|
|
)
|
|
)
|
|
|
|
for vf_information in sorted(vf_list, key=lambda v: v["phy"]):
|
|
vf_domain = vf_information["usage"]["domain"]
|
|
if not vf_domain:
|
|
vf_domain = "N/A"
|
|
|
|
vf_list_output.append(
|
|
"{bold}\
|
|
{vf_phy: <{vf_phy_length}} \
|
|
{vf_pf: <{vf_pf_length}} \
|
|
{vf_mtu: <{vf_mtu_length}} \
|
|
{vf_mac: <{vf_mac_length}} \
|
|
{vf_used: <{vf_used_length}} \
|
|
{vf_domain: <{vf_domain_length}} \
|
|
{end_bold}".format(
|
|
bold=ansiprint.bold(),
|
|
end_bold=ansiprint.end(),
|
|
vf_phy_length=vf_phy_length,
|
|
vf_pf_length=vf_pf_length,
|
|
vf_mtu_length=vf_mtu_length,
|
|
vf_mac_length=vf_mac_length,
|
|
vf_used_length=vf_used_length,
|
|
vf_domain_length=vf_domain_length,
|
|
vf_phy=vf_information["phy"],
|
|
vf_pf=vf_information["pf"],
|
|
vf_mtu=vf_information["mtu"],
|
|
vf_mac=vf_information["mac"],
|
|
vf_used=vf_information["usage"]["used"],
|
|
vf_domain=vf_domain,
|
|
)
|
|
)
|
|
|
|
return "\n".join(vf_list_output)
|
|
|
|
|
|
def format_info_sriov_vf(config, data):
|
|
if not data or not data["vf_information"]:
|
|
return "No VF found"
|
|
|
|
node = data["node"]
|
|
vf_information = data["vf_information"]
|
|
|
|
# Get information on the using VM if applicable
|
|
if vf_information["usage"]["used"] == "True" and vf_information["usage"]["domain"]:
|
|
vm_information = call_api(
|
|
config, "get", "/vm/{vm}".format(vm=vf_information["usage"]["domain"])
|
|
).json()
|
|
if isinstance(vm_information, list) and len(vm_information) > 0:
|
|
vm_information = vm_information[0]
|
|
else:
|
|
vm_information = None
|
|
|
|
# Format a nice output: do this line-by-line then concat the elements at the end
|
|
ainformation = []
|
|
ainformation.append(
|
|
"{}SR-IOV VF information:{}".format(ansiprint.bold(), ansiprint.end())
|
|
)
|
|
ainformation.append("")
|
|
# Basic information
|
|
ainformation.append(
|
|
"{}PHY:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["phy"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}PF:{} {} @ {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["pf"], node
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}MTU:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["mtu"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}MAC Address:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["mac"]
|
|
)
|
|
)
|
|
ainformation.append("")
|
|
# Configuration information
|
|
ainformation.append(
|
|
"{}vLAN ID:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["config"]["vlan_id"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}vLAN QOS priority:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["config"]["vlan_qos"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}Minimum TX Rate:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["config"]["tx_rate_min"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}Maximum TX Rate:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["config"]["tx_rate_max"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}Link State:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["config"]["link_state"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}Spoof Checking:{} {}{}{}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
getColour(vf_information["config"]["spoof_check"]),
|
|
vf_information["config"]["spoof_check"],
|
|
ansiprint.end(),
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}VF User Trust:{} {}{}{}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
getColour(vf_information["config"]["trust"]),
|
|
vf_information["config"]["trust"],
|
|
ansiprint.end(),
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}Query RSS Config:{} {}{}{}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
getColour(vf_information["config"]["query_rss"]),
|
|
vf_information["config"]["query_rss"],
|
|
ansiprint.end(),
|
|
)
|
|
)
|
|
ainformation.append("")
|
|
# PCIe bus information
|
|
ainformation.append(
|
|
"{}PCIe domain:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["pci"]["domain"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}PCIe bus:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["pci"]["bus"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}PCIe slot:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["pci"]["slot"]
|
|
)
|
|
)
|
|
ainformation.append(
|
|
"{}PCIe function:{} {}".format(
|
|
ansiprint.purple(), ansiprint.end(), vf_information["pci"]["function"]
|
|
)
|
|
)
|
|
ainformation.append("")
|
|
# Usage information
|
|
ainformation.append(
|
|
"{}VF Used:{} {}{}{}".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
getColour(vf_information["usage"]["used"]),
|
|
vf_information["usage"]["used"],
|
|
ansiprint.end(),
|
|
)
|
|
)
|
|
if vf_information["usage"]["used"] == "True" and vm_information is not None:
|
|
ainformation.append(
|
|
"{}Using Domain:{} {} ({}) ({}{}{})".format(
|
|
ansiprint.purple(),
|
|
ansiprint.end(),
|
|
vf_information["usage"]["domain"],
|
|
vm_information["name"],
|
|
getColour(vm_information["state"]),
|
|
vm_information["state"],
|
|
ansiprint.end(),
|
|
)
|
|
)
|
|
else:
|
|
ainformation.append(
|
|
"{}Using Domain:{} N/A".format(ansiprint.purple(), ansiprint.end())
|
|
)
|
|
|
|
# Join it all together
|
|
return "\n".join(ainformation)
|