daemon: added capability to config services to shadow directory structures, from a given path, or from a local source, files may be templates or a straight copy and can be sourced from node named unique paths for node specific files, also refactored and renamed file creation related functions for nodes

This commit is contained in:
Blake Harnden 2021-09-17 14:34:37 -07:00
parent b96dc621cd
commit bd896d1336
10 changed files with 212 additions and 130 deletions

View file

@ -237,7 +237,17 @@ class CoreNodeBase(NodeBase):
raise NotImplementedError
@abc.abstractmethod
def nodefile(self, file_path: Path, contents: str, mode: int = 0o644) -> None:
def create_dir(self, dir_path: Path) -> None:
"""
Create a node private directory.
:param dir_path: path to create
:return: nothing
"""
raise NotImplementedError
@abc.abstractmethod
def create_file(self, file_path: Path, contents: str, mode: int = 0o644) -> None:
"""
Create a node file with a given mode.
@ -248,6 +258,19 @@ class CoreNodeBase(NodeBase):
"""
raise NotImplementedError
@abc.abstractmethod
def copy_file(self, src_path: Path, dst_path: Path, mode: int = None) -> None:
"""
Copy source file to node host destination, updating the file mode when
provided.
:param src_path: source file to copy
:param dst_path: node host destination
:param mode: file mode
:return: nothing
"""
raise NotImplementedError
@abc.abstractmethod
def addfile(self, src_path: Path, file_path: Path) -> None:
"""
@ -567,7 +590,7 @@ class CoreNode(CoreNodeBase):
# create private directories
for dir_path in PRIVATE_DIRS:
self.privatedir(dir_path)
self.create_dir(dir_path)
def shutdown(self) -> None:
"""
@ -648,19 +671,23 @@ class CoreNode(CoreNodeBase):
else:
return f"ssh -X -f {self.server.host} xterm -e {terminal}"
def privatedir(self, dir_path: Path) -> None:
def create_dir(self, dir_path: Path) -> None:
"""
Create a private directory.
Create a node private directory.
:param dir_path: path to create
:return: nothing
"""
logger.info("creating private directory: %s", dir_path)
if not str(dir_path).startswith("/"):
if not dir_path.is_absolute():
raise CoreError(f"private directory path not fully qualified: {dir_path}")
host_path = self.host_path(dir_path, is_dir=True)
self.host_cmd(f"mkdir -p {host_path}")
self.mount(host_path, dir_path)
logger.debug("node(%s) creating private directory: %s", self.name, dir_path)
parent_path = self._find_parent_path(dir_path)
if parent_path:
self.host_cmd(f"mkdir -p {parent_path}")
else:
host_path = self.host_path(dir_path, is_dir=True)
self.host_cmd(f"mkdir -p {host_path}")
self.mount(host_path, dir_path)
def mount(self, src_path: Path, target_path: Path) -> None:
"""
@ -880,16 +907,40 @@ class CoreNode(CoreNodeBase):
self.host_cmd(f"mkdir -p {directory}")
self.server.remote_put(src_path, file_path)
def nodefile(self, file_path: Path, contents: str, mode: int = 0o644) -> None:
def _find_parent_path(self, path: Path) -> Optional[Path]:
"""
Create a node file with a given mode.
Check if there is an existing mounted parent directory created for this node.
:param file_path: name of file to create
:param path: existing parent path to use
:return: exist parent path if exists, None otherwise
"""
logger.debug("looking for existing parent: %s", path)
existing_path = None
for parent in path.parents:
node_path = self.host_path(parent, is_dir=True)
if node_path == self.directory:
break
if self.path_exists(str(node_path)):
relative_path = path.relative_to(parent)
existing_path = node_path / relative_path
break
return existing_path
def create_file(self, file_path: Path, contents: str, mode: int = 0o644) -> None:
"""
Create file within a node at the given path, using contents and mode.
:param file_path: desired path for file
:param contents: contents of file
:param mode: mode for file
:param mode: mode to create file with
:return: nothing
"""
host_path = self.host_path(file_path)
logger.debug("node(%s) create file(%s) mode(%o)", self.name, file_path, mode)
host_path = self._find_parent_path(file_path)
if host_path:
self.host_cmd(f"mkdir -p {host_path.parent}")
else:
host_path = self.host_path(file_path)
directory = host_path.parent
if self.server is None:
if not directory.exists():
@ -901,26 +952,35 @@ class CoreNode(CoreNodeBase):
self.host_cmd(f"mkdir -m {0o755:o} -p {directory}")
self.server.remote_put_temp(host_path, contents)
self.host_cmd(f"chmod {mode:o} {host_path}")
logger.debug("node(%s) added file: %s; mode: 0%o", self.name, host_path, mode)
def nodefilecopy(self, file_path: Path, src_path: Path, mode: int = None) -> None:
def copy_file(self, src_path: Path, dst_path: Path, mode: int = None) -> None:
"""
Copy a file to a node, following symlinks and preserving metadata.
Change file mode if specified.
Copy source file to node host destination, updating the file mode when
provided.
:param file_path: file name to copy file to
:param src_path: file to copy
:param mode: mode to copy to
:param src_path: source file to copy
:param dst_path: node host destination
:param mode: file mode
:return: nothing
"""
host_path = self.host_path(file_path)
logger.debug(
"node(%s) copying file src(%s) to dst(%s) mode(%o)",
self.name,
src_path,
dst_path,
mode or 0,
)
host_path = self._find_parent_path(dst_path)
if host_path:
self.host_cmd(f"mkdir -p {host_path.parent}")
else:
host_path = self.host_path(dst_path)
if self.server is None:
shutil.copy2(src_path, host_path)
else:
self.server.remote_put(src_path, host_path)
if mode is not None:
self.host_cmd(f"chmod {mode:o} {host_path}")
logger.info("node(%s) copied file: %s; mode: %s", self.name, host_path, mode)
class CoreNetworkBase(NodeBase):

View file

@ -164,7 +164,7 @@ class DockerNode(CoreNode):
"""
return f"docker exec -it {self.name} bash"
def privatedir(self, dir_path: str) -> None:
def create_dir(self, dir_path: Path) -> None:
"""
Create a private directory.
@ -187,7 +187,7 @@ class DockerNode(CoreNode):
logger.debug("mounting source(%s) target(%s)", src_path, target_path)
raise Exception("not supported")
def nodefile(self, file_path: Path, contents: str, mode: int = 0o644) -> None:
def create_file(self, file_path: Path, contents: str, mode: int = 0o644) -> None:
"""
Create a node file with a given mode.
@ -196,7 +196,7 @@ class DockerNode(CoreNode):
:param mode: mode for file
:return: nothing
"""
logger.debug("nodefile filename(%s) mode(%s)", file_path, mode)
logger.debug("node(%s) create file(%s) mode(%o)", self.name, file_path, mode)
temp = NamedTemporaryFile(delete=False)
temp.write(contents.encode("utf-8"))
temp.close()
@ -211,26 +211,26 @@ class DockerNode(CoreNode):
if self.server is not None:
self.host_cmd(f"rm -f {temp_path}")
temp_path.unlink()
logger.debug("node(%s) added file: %s; mode: 0%o", self.name, file_path, mode)
def nodefilecopy(self, file_path: Path, src_path: Path, mode: int = None) -> None:
def copy_file(self, src_path: Path, dst_path: Path, mode: int = None) -> None:
"""
Copy a file to a node, following symlinks and preserving metadata.
Change file mode if specified.
:param file_path: file name to copy file to
:param dst_path: file name to copy file to
:param src_path: file to copy
:param mode: mode to copy to
:return: nothing
"""
logger.info(
"node file copy file(%s) source(%s) mode(%s)", file_path, src_path, mode
"node file copy file(%s) source(%s) mode(%o)", dst_path, src_path, mode or 0
)
self.cmd(f"mkdir -p {file_path.parent}")
self.cmd(f"mkdir -p {dst_path.parent}")
if self.server:
temp = NamedTemporaryFile(delete=False)
temp_path = Path(temp.name)
src_path = temp_path
self.server.remote_put(src_path, temp_path)
self.client.copy_file(src_path, file_path)
self.cmd(f"chmod {mode:o} {file_path}")
self.client.copy_file(src_path, dst_path)
if mode is not None:
self.cmd(f"chmod {mode:o} {dst_path}")

View file

@ -140,7 +140,7 @@ class LxcNode(CoreNode):
"""
return f"lxc exec {self.name} -- {sh}"
def privatedir(self, dir_path: Path) -> None:
def create_dir(self, dir_path: Path) -> None:
"""
Create a private directory.
@ -163,7 +163,7 @@ class LxcNode(CoreNode):
logger.debug("mounting source(%s) target(%s)", src_path, target_path)
raise Exception("not supported")
def nodefile(self, file_path: Path, contents: str, mode: int = 0o644) -> None:
def create_file(self, file_path: Path, contents: str, mode: int = 0o644) -> None:
"""
Create a node file with a given mode.
@ -172,7 +172,7 @@ class LxcNode(CoreNode):
:param mode: mode for file
:return: nothing
"""
logger.debug("nodefile filename(%s) mode(%s)", file_path, mode)
logger.debug("node(%s) create file(%s) mode(%o)", self.name, file_path, mode)
temp = NamedTemporaryFile(delete=False)
temp.write(contents.encode("utf-8"))
temp.close()
@ -189,27 +189,28 @@ class LxcNode(CoreNode):
temp_path.unlink()
logger.debug("node(%s) added file: %s; mode: 0%o", self.name, file_path, mode)
def nodefilecopy(self, file_path: Path, src_path: Path, mode: int = None) -> None:
def copy_file(self, src_path: Path, dst_path: Path, mode: int = None) -> None:
"""
Copy a file to a node, following symlinks and preserving metadata.
Change file mode if specified.
:param file_path: file name to copy file to
:param dst_path: file name to copy file to
:param src_path: file to copy
:param mode: mode to copy to
:return: nothing
"""
logger.info(
"node file copy file(%s) source(%s) mode(%s)", file_path, src_path, mode
"node file copy file(%s) source(%s) mode(%o)", dst_path, src_path, mode or 0
)
self.cmd(f"mkdir -p {file_path.parent}")
self.cmd(f"mkdir -p {dst_path.parent}")
if self.server:
temp = NamedTemporaryFile(delete=False)
temp_path = Path(temp.name)
src_path = temp_path
self.server.remote_put(src_path, temp_path)
self.client.copy_file(src_path, file_path)
self.cmd(f"chmod {mode:o} {file_path}")
self.client.copy_file(src_path, dst_path)
if mode is not None:
self.cmd(f"chmod {mode:o} {dst_path}")
def add_iface(self, iface: CoreInterface, iface_id: int) -> None:
super().add_iface(iface, iface_id)