daemon: consolidated the code for CoreNode commands into the class itself

This commit is contained in:
Blake Harnden 2022-02-28 22:05:01 -08:00
parent b085105a6b
commit a42697ecce
3 changed files with 16 additions and 119 deletions

View file

@ -16,8 +16,7 @@ from core.configservice.dependencies import ConfigServiceDependencies
from core.emulator.data import InterfaceData, LinkData
from core.emulator.enumerations import LinkTypes, MessageFlags, NodeTypes
from core.errors import CoreCommandError, CoreError
from core.executables import MOUNT, TEST, VNODED
from core.nodes.client import VnodeClient
from core.executables import BASH, MOUNT, TEST, VCMD, VNODED
from core.nodes.interface import DEFAULT_MTU, CoreInterface, TunTap, Veth
from core.nodes.netclient import LinuxNetClient, get_net_client
@ -504,7 +503,6 @@ class CoreNode(CoreNodeBase):
super().__init__(session, _id, name, server)
self.directory: Optional[Path] = directory
self.ctrlchnlname: Path = self.session.directory / self.name
self.client: Optional[VnodeClient] = None
self.pid: Optional[int] = None
self.lock: RLock = RLock()
self._mounts: List[Tuple[Path, Path]] = []
@ -546,7 +544,6 @@ class CoreNode(CoreNodeBase):
self.makenodedir()
if self.up:
raise ValueError("starting a node that is already up")
# create a new namespace for this node using vnoded
vnoded = (
f"{VNODED} -v -c {self.ctrlchnlname} -l {self.ctrlchnlname}.log "
@ -557,25 +554,17 @@ class CoreNode(CoreNodeBase):
env = self.session.get_environment(state=False)
env["NODE_NUMBER"] = str(self.id)
env["NODE_NAME"] = str(self.name)
output = self.host_cmd(vnoded, env=env)
self.pid = int(output)
logger.debug("node(%s) pid: %s", self.name, self.pid)
# create vnode client
self.client = VnodeClient(self.name, self.ctrlchnlname)
# bring up the loopback interface
logger.debug("bringing up loopback interface")
self.node_net_client.device_up("lo")
# set hostname for node
logger.debug("setting hostname: %s", self.name)
self.node_net_client.set_hostname(self.name)
# mark node as up
self.up = True
# create private directories
for dir_path in PRIVATE_DIRS:
self.create_dir(dir_path)
@ -609,13 +598,24 @@ class CoreNode(CoreNodeBase):
logger.exception("error removing node directory")
# clear interface data, close client, and mark self and not up
self.ifaces.clear()
self.client.close()
self.up = False
except OSError:
logger.exception("error during shutdown")
finally:
self.rmnodedir()
def _create_cmd(self, args: str, shell: bool = False) -> str:
"""
Create command used to run commands within the context of a node.
:param args: command arguments
:param shell: True to run shell like, False otherwise
:return: node command
"""
if shell:
args = f'{BASH} -c "{args}"'
return f"{VCMD} -c {self.ctrlchnlname} -- {args}"
def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str:
"""
Runs a command that is used to configure and setup the network within a
@ -627,10 +627,10 @@ class CoreNode(CoreNodeBase):
:return: combined stdout and stderr
:raises CoreCommandError: when a non-zero exit status occurs
"""
args = self._create_cmd(args, shell)
if self.server is None:
return self.client.check_cmd(args, wait=wait, shell=shell)
return utils.cmd(args, wait=wait, shell=shell)
else:
args = self.client.create_cmd(args, shell)
return self.server.remote_cmd(args, wait=wait)
def path_exists(self, path: str) -> bool:
@ -653,7 +653,7 @@ class CoreNode(CoreNodeBase):
:param sh: shell to execute command in
:return: str
"""
terminal = self.client.create_cmd(sh)
terminal = self._create_cmd(sh)
if self.server is None:
return terminal
else:

View file

@ -1,70 +0,0 @@
"""
client.py: implementation of the VnodeClient class for issuing commands
over a control channel to the vnoded process running in a network namespace.
The control channel can be accessed via calls using the vcmd shell.
"""
from pathlib import Path
from core import utils
from core.executables import BASH, VCMD
class VnodeClient:
"""
Provides client functionality for interacting with a virtual node.
"""
def __init__(self, name: str, ctrlchnlname: Path) -> None:
"""
Create a VnodeClient instance.
:param name: name for client
:param ctrlchnlname: control channel name
"""
self.name: str = name
self.ctrlchnlname: Path = ctrlchnlname
def _verify_connection(self) -> None:
"""
Checks that the vcmd client is properly connected.
:return: nothing
:raises IOError: when not connected
"""
if not self.connected():
raise IOError("vcmd not connected")
def connected(self) -> bool:
"""
Check if node is connected or not.
:return: True if connected, False otherwise
"""
return True
def close(self) -> None:
"""
Close the client connection.
:return: nothing
"""
pass
def create_cmd(self, args: str, shell: bool = False) -> str:
if shell:
args = f'{BASH} -c "{args}"'
return f"{VCMD} -c {self.ctrlchnlname} -- {args}"
def check_cmd(self, args: str, wait: bool = True, shell: bool = False) -> str:
"""
Run command and return exit status and combined stdout and stderr.
:param args: command to run
:param wait: True to wait for command status, False otherwise
:param shell: True to use shell, False otherwise
:return: combined stdout and stderr
:raises core.CoreCommandError: when there is a non-zero exit status
"""
self._verify_connection()
args = self.create_cmd(args, shell)
return utils.cmd(args, wait=wait, shell=shell)

View file

@ -63,39 +63,6 @@ class TestCore:
status = ping(node1, node2, ip_prefixes)
assert not status
def test_vnode_client(self, request, session: Session, ip_prefixes: IpPrefixes):
"""
Test vnode client methods.
:param request: pytest request
:param session: session for test
:param ip_prefixes: generates ip addresses for nodes
"""
# create ptp
ptp_node = session.add_node(PtpNet)
# create nodes
node1 = session.add_node(CoreNode)
node2 = session.add_node(CoreNode)
# link nodes to ptp net
for node in [node1, node2]:
iface_data = ip_prefixes.create_iface(node)
session.add_link(node.id, ptp_node.id, iface1_data=iface_data)
# get node client for testing
client = node1.client
# instantiate session
session.instantiate()
# check we are connected
assert client.connected()
# validate command
if not request.config.getoption("mock"):
assert client.check_cmd("echo hello") == "hello"
def test_iface(self, session: Session, ip_prefixes: IpPrefixes):
"""
Test interface methods.