daemon: consolidated the code for CoreNode commands into the class itself
This commit is contained in:
parent
b085105a6b
commit
a42697ecce
3 changed files with 16 additions and 119 deletions
|
@ -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:
|
||||
|
|
|
@ -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)
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue