def follow_node_log(config, node, lines=10): """ Return and follow node log lines from the API API endpoint: GET /node/{node}/log API arguments: lines={lines} API schema: {"name":"{nodename}","data":"{node_log}"} """ # We always grab 200 to match the follow call, but only _show_ `lines` number params = {"lines": 200} response = call_api(config, "get", "/node/{node}/log".format(node=node), params=params) if response.status_code != 200: return False, response.json().get("message", "") # Shrink the log buffer to length lines node_log = response.json()["data"] shrunk_log = node_log.split("\n")[-int(lines):] loglines = "\n".join(shrunk_log) # Print the initial data and begin following print(loglines, end="") print("\n", end="") while True: # Grab the next line set (200 is a reasonable number of lines per half-second; any more are skipped) try: params = {"lines": 200} response = call_api(config, "get", "/node/{node}/log".format(node=node), params=params) new_node_log = response.json()["data"] except Exception: break # Split the new and old log strings into constitutent lines old_node_loglines = node_log.split("\n") new_node_loglines = new_node_log.split("\n") # Set the node log to the new log value for the next iteration node_log = new_node_log # Get the difference between the two sets of lines old_node_loglines_set = set(old_node_loglines) diff_node_loglines = [ x for x in new_node_loglines if x not in old_node_loglines_set ] # If there's a difference, print it out if len(diff_node_loglines) > 0: print("\n".join(diff_node_loglines), end="") print("\n", end="") # Wait half a second time.sleep(0.5) return True, ""
def node_list(config, limit, target_daemon_state, target_coordinator_state, target_domain_state): """ Get list information about nodes (limited by {limit}) API endpoint: GET /api/v1/node API arguments: limit={limit} API schema: [{json_data_object},{json_data_object},etc.] """ params = dict() if limit: params["limit"] = limit if target_daemon_state: params["daemon_state"] = target_daemon_state if target_coordinator_state: params["coordinator_state"] = target_coordinator_state if target_domain_state: params["domain_state"] = target_domain_state response = call_api(config, "get", "/node", params=params) if response.status_code == 200: return True, response.json() else: return False, response.json().get("message", "")
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_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_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_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_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 get_info(config): """ Get status of the PVC cluster API endpoint: GET /api/v1/status API arguments: API schema: {json_data_object} """ response = call_api(config, "get", "/status") if response.status_code == 200: return True, response.json() else: return False, response.json().get("message", "")
def backup(config): """ Get a JSON backup of the cluster API endpoint: GET /api/v1/backup API arguments: API schema: {json_data_object} """ response = call_api(config, "get", "/backup") if response.status_code == 200: return True, response.json() else: return False, response.json().get("message", "")
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_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", "")
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 maintenance_mode(config, state): """ Enable or disable PVC cluster maintenance mode API endpoint: POST /api/v1/status API arguments: {state}={state} API schema: {json_data_object} """ params = {"state": state} response = call_api(config, "post", "/status", params=params) if response.status_code == 200: retstatus = True else: retstatus = False return retstatus, response.json().get("message", "")
def initialize(config, overwrite=False): """ Initialize the PVC cluster API endpoint: GET /api/v1/initialize API arguments: overwrite, yes-i-really-mean-it API schema: {json_data_object} """ params = {"yes-i-really-mean-it": "yes", "overwrite": overwrite} response = call_api(config, "post", "/initialize", params=params) if response.status_code == 200: retstatus = True else: retstatus = False return retstatus, 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 restore(config, cluster_data): """ Restore a JSON backup to the cluster API endpoint: POST /api/v1/restore API arguments: yes-i-really-mean-it API schema: {json_data_object} """ cluster_data_json = json.dumps(cluster_data) params = {"yes-i-really-mean-it": "yes"} data = {"cluster_data": cluster_data_json} response = call_api(config, "post", "/restore", params=params, data=data) 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_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 node_domain_state(config, node, action, wait): """ Set node domain state state (flush/ready) API endpoint: POST /api/v1/node/{node}/domain-state API arguments: action={action}, wait={wait} API schema: {"message": "{data}"} """ params = {"state": action, "wait": str(wait).lower()} response = call_api(config, "post", "/node/{node}/domain-state".format(node=node), params=params) if response.status_code == 200: retstatus = True else: retstatus = False return retstatus, response.json().get("message", "")
def node_coordinator_state(config, node, action): """ Set node coordinator state state (primary/secondary) API endpoint: POST /api/v1/node/{node}/coordinator-state API arguments: action={action} API schema: {"message": "{data}"} """ params = {"state": action} response = call_api( config, "post", "/node/{node}/coordinator-state".format(node=node), params=params, ) if response.status_code == 200: retstatus = True else: retstatus = False return retstatus, 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 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 node_info(config, node): """ Get information about node API endpoint: GET /api/v1/node/{node} API arguments: API schema: {json_data_object} """ response = call_api(config, "get", "/node/{node}".format(node=node)) if response.status_code == 200: if isinstance(response.json(), list) and len(response.json()) != 1: # No exact match, return not found return False, "Node 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 view_node_log(config, node, lines=100): """ Return node log lines from the API (and display them in a pager in the main CLI) API endpoint: GET /node/{node}/log API arguments: lines={lines} API schema: {"name":"{node}","data":"{node_log}"} """ params = {"lines": lines} response = call_api(config, "get", "/node/{node}/log".format(node=node), params=params) if response.status_code != 200: return False, response.json().get("message", "") node_log = response.json()["data"] # Shrink the log buffer to length lines shrunk_log = node_log.split("\n")[-lines:] loglines = "\n".join(shrunk_log) return True, loglines
def format_info_sriov_vf(config, vf_information, node): if not vf_information: return "No VF found" # 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)