Signed-off-by: Michael Tremer michael.tremer@ipfire.org --- man/nitsi.xml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/man/nitsi.xml b/man/nitsi.xml index 5310de66a4d6..9e105ae2ac7d 100644 --- a/man/nitsi.xml +++ b/man/nitsi.xml @@ -39,8 +39,9 @@ <title>Description</title>
<para> - <command>nitsi</command> is a simple, extensible, Integration Test Suite - for the Network code of IPfire written in Python. + <command>nitsi</command> is a simple and extensible + suite for running integration tests for the network + code of IPFire. It is written in pure Python. </para> </refsect1>
@@ -62,21 +63,23 @@
<listitem> <para> - Is the directory where all files of a test are located. - So this dir should contain at least a setting file and a recipe file + The directory where all files of a test are located. + It should contain at least a setting file and a recipe file. </para>
<para> - For further details of the setting file layout and the recipe file layout, please consult the + For further details of the setting file layout and the recipe file layout, + please consult the <citerefentry> - <refentrytitle>nitsi.setting</refentrytitle> + <refentrytitle>nitsi.settings</refentrytitle> <manvolnum>5</manvolnum> </citerefentry> + and <citerefentry> <refentrytitle>nitsi.recipe</refentrytitle> <manvolnum>5</manvolnum> </citerefentry> - manual page. + manual pages. </para> </listitem> </varlistentry> @@ -103,7 +106,7 @@
<para> Please report all bugs to the official bugtracker at - http://bugzilla.ipfire.org/. + https://bugzilla.ipfire.org/. </para> </refsect1>
@@ -112,7 +115,7 @@
<para> <citerefentry> - <refentrytitle>nitsi.setting</refentrytitle> + <refentrytitle>nitsi.settings</refentrytitle> <manvolnum>5</manvolnum> </citerefentry> <citerefentry>
This is the correct category for file formats and is referenced like this in nitsi.1 already.
Signed-off-by: Michael Tremer michael.tremer@ipfire.org --- Makefile.am | 6 +++--- man/nitsi.recipe.xml | 2 +- man/nitsi.settings.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 6344216c4b88..66c41103bb49 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,8 +50,8 @@ man: $(MANPAGES) $(MANPAGES_HTML) if ENABLE_MANPAGES MANPAGES = \ man/nitsi.1 \ - man/nitsi.settings.1 \ - man/nitsi.recipe.1 + man/nitsi.settings.5 \ + man/nitsi.recipe.5
MANPAGES_XML = $(patsubst %.1,%.xml,$(patsubst %.5,%.xml,$(MANPAGES))) MANPAGES_HTML = $(patsubst %.xml,%.html,$(MANPAGES_XML)) @@ -107,4 +107,4 @@ SED_PROCESS = \ < $< > $@
nitsi: nitsi.in Makefile - $(SED_PROCESS) \ No newline at end of file + $(SED_PROCESS) diff --git a/man/nitsi.recipe.xml b/man/nitsi.recipe.xml index 91925d40fcd5..330f33d60b92 100644 --- a/man/nitsi.recipe.xml +++ b/man/nitsi.recipe.xml @@ -19,7 +19,7 @@
<refmeta> <refentrytitle>nitsi.recipe</refentrytitle> - <manvolnum>1</manvolnum> + <manvolnum>5</manvolnum> </refmeta>
<refnamediv> diff --git a/man/nitsi.settings.xml b/man/nitsi.settings.xml index 680a5c0a5d9c..8323044d2bee 100644 --- a/man/nitsi.settings.xml +++ b/man/nitsi.settings.xml @@ -19,7 +19,7 @@
<refmeta> <refentrytitle>nitsi.settings</refentrytitle> - <manvolnum>1</manvolnum> + <manvolnum>5</manvolnum> </refmeta>
<refnamediv>
Signed-off-by: Michael Tremer michael.tremer@ipfire.org --- man/nitsi.settings.xml | 58 +++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 32 deletions(-)
diff --git a/man/nitsi.settings.xml b/man/nitsi.settings.xml index 8323044d2bee..588a667cac0d 100644 --- a/man/nitsi.settings.xml +++ b/man/nitsi.settings.xml @@ -24,7 +24,7 @@
<refnamediv> <refname>nitsi.settings</refname> - <refpurpose>Settings file for a nitsi test</refpurpose> + <refpurpose>Settings file for a NITSI test</refpurpose> </refnamediv>
@@ -32,16 +32,16 @@ <title>Description</title>
<para> - The <filename>settings</filename> file is the main configuration file of the - <command>nitsi</command> test. - This file specifies runtime configuration parameters for the test - and set the virtual environment to use. + The <filename>settings</filename> file is the main configuration file + of a <command>nitsi</command> test. + It specifies runtime configuration parameters for the test + and defines the virtual environment to be used. </para>
<para> The syntax of the configuration file is based on the INI configuration - file format. Lines starting with hash (#) or semi-colon (;) - are ignored. + file format. + Lines starting with hash (#) or semi-colon (;) are comments. </para> </refsect1>
@@ -55,57 +55,54 @@ <variablelist> <varlistentry> <term> - <option>Name = ""</option> + <option>Name</option> </term>
<listitem> <para> This option will configure the name of the test - and can be something more human readbale then the name of the test directory. + and should be in human-readable format. </para> - </listitem> </varlistentry>
<varlistentry> <term> - <option>Description = ""</option> + <option>Description</option> </term>
<listitem> <para> - This can be a short description of the test to explain - what we are trying to test and what results we expect when - we are running the recipe. So when do the test succeed and when do the test fails. + A short short description of the test to explain + what it is trying to test and what results are expected when + running the recipe. </para> - </listitem> </varlistentry>
<varlistentry> <term> - <option>Copy_from = ""</option> + <option>Copy_from</option> </term>
<listitem> <para> - The files or directories which should be copied into all virtual machines. - The paths are relativ to the path of the test directory. + Lists files or directories which should be copied into + all virtual machines. + The paths are relative to the path of the test directory. </para> - </listitem> </varlistentry>
<varlistentry> <term> - <option>Copy_to = ""</option> + <option>Copy_to</option> </term>
<listitem> <para> - The path to which the files should be copied. For example /root/ + The path to which the files should be copied. For example /root. </para> - </listitem> </varlistentry>
@@ -122,27 +119,26 @@ <variablelist> <varlistentry> <term> - <option>Name = ""</option> + <option>Name</option> </term>
<listitem> <para> - The Name of the virtual environment to use. + The name of the virtual environment to use. </para> - </listitem> </varlistentry>
- <varlistentry> + <varlistentry> <term> - <option>path = ""</option> + <option>path</option> </term>
<listitem> <para> - The path of the virtual environment relativ to the path of the test. + The path of the virtual environment relative to + the path of the test directory. </para> - </listitem> </varlistentry> </variablelist> @@ -156,8 +152,7 @@ <simplelist> <member>[DEFAULT]</member> <member>Name = Hello World</member> - <member>Description = This is a - short description.</member> + <member>Description = This is a short description.</member> <member>Copy_from =</member> <member>Copy_to = /root/</member> <member>[VIRTUAL_ENVIRONMENT]</member> @@ -165,7 +160,6 @@ <member>path = ../virtual-environment/basic</member> </simplelist> </example> - </refsect1>
<refsect1>
Signed-off-by: Michael Tremer michael.tremer@ipfire.org --- man/nitsi.recipe.xml | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/man/nitsi.recipe.xml b/man/nitsi.recipe.xml index 330f33d60b92..73c680dfa9e4 100644 --- a/man/nitsi.recipe.xml +++ b/man/nitsi.recipe.xml @@ -33,7 +33,7 @@
<para> The <filename>recipe</filename> file contains the actions for a test. - So it consist of lines which state which command should executed on which machine. + It consists of lines which state what commands should be executed on which machine. </para> </refsect1>
@@ -41,7 +41,7 @@ <title>Basic Syntax</title>
<para> - All lines follows the following syntax: + All lines follow the following syntax: </para>
<variablelist> @@ -52,10 +52,9 @@
<listitem> <para> - The machine name is the first part of the line followed by an ':'. + The machine name is the first part of the line followed by ':'. After the ':' follows the command which should be executed. </para> - </listitem> </varlistentry> </variablelist> @@ -76,10 +75,9 @@
<listitem> <para> - The '!' is similar to the 'not' in python. So this line will fail if the command succeds - and succeds if the command fails. Between the machine name and the '!' must be a space. + The '!' is similar to the 'not' in python. So this line will fail if the command succeeds + and succeeds if the command fails. Between the machine name and the '!' must be a space. </para> - </listitem> </varlistentry>
@@ -92,7 +90,6 @@ <para> This command is executed on all machines of this test. </para> - </listitem> </varlistentry> <varlistentry> @@ -102,13 +99,12 @@
<listitem> <para> - This command is on all machines of the comma seperated list. So on machine1 and on machine2. + This command is on all machines of the comma seperated list. </para> - </listitem> </varlistentry>
- <varlistentry> + <varlistentry> <term> <option>include: ../test2</option> </term> @@ -116,12 +112,11 @@ <listitem> <para> This will include the recipe of test2. - The path is relativ to the directory of the recipe file which contain the include statement. + The path is relative to the directory of the + recipe file which contains the include statement. </para> - </listitem> </varlistentry> - </variablelist> </refsect1>
@@ -139,7 +134,6 @@ <member>include: ../test2</member> </simplelist> </example> - </refsect1>
<refsect1>
This is an example of how the code could take advantage of Python contexts. The with statement will open the context and when it is left (either normally or because of an exception), the __exit__() method is called and can be used to cleanup.
Cleaning up is in this case umounting the image file, but could also be used to shutdown and destroy a virtual machine or network.
Signed-off-by: Michael Tremer michael.tremer@ipfire.org --- src/nitsi/disk.py | 92 +++++++++++++++++++++++++++++--------------- src/nitsi/machine.py | 13 ++----- 2 files changed, 65 insertions(+), 40 deletions(-)
diff --git a/src/nitsi/disk.py b/src/nitsi/disk.py index 29782574282e..5f465956c849 100755 --- a/src/nitsi/disk.py +++ b/src/nitsi/disk.py @@ -8,43 +8,75 @@ import tempfile
logger = logging.getLogger("nitsi.disk")
+class Disk(object): + def __init__(self, path, part_uuid): + self.path = path + self.part_uuid = part_uuid
-class disk(): - def __init__(self, disk): - self.log = logger.getChild(os.path.basename(disk)) - self.log.debug("Initiated a disk class for {}".format(disk)) + self.log = logger.getChild(os.path.basename(self.path)) + self.log.debug("Initiated a disk class for {}".format(self.path)) + + # Create GuestFS object for this disk self.con = guestfs.GuestFS(python_return_dict=True) - self.con.add_drive_opts(disk, format="qcow2") + self.con.add_drive_opts(self.path, format="qcow2")
- def mount(self, uuid, path): - self.log.debug("Trying to mount the partion with uuid: {} under {}".format(uuid, path)) + def __enter__(self): + # Launch the GuestFS backend self.con.launch() - part = self.con.findfs_uuid(uuid) - self.con.mount(part, path)
- def copy_in(self, fr, to): - self.log.debug("Going to copy some files into the image.") - tmp = tempfile.mkstemp() - tmp = tmp[1] + ".tar" - with tarfile.open(tmp, "w") as tar: - for file in fr: - self.log.debug("Adding {} to be copied into the image".format(file)) - tar.add(file, arcname=os.path.basename(file)) + # Find partition to mount + part = self.con.findfs_uuid(self.part_uuid) + if not part: + raise RuntimeError("Could not find partition %s" % self.part_uuid)
- self.log.debug("Going to copy the files into the image") - self.con.tar_in_opts(tmp, to) + # Mounting partition + self._mount(part)
- def umount(self, path): - self.log.debug("Unmounting the image") - self.con.umount_opts(path) + return MountedDisk(self, part)
- def close(self): - self.log.debug("Flush the image and closing the connection") + def __exit__(self, type, value, traceback): + # Umount the disk image + self._umount() + + # Shuts down the GuestFS backend self.con.shutdown() - self.con.close()
-# test = disk("/var/lib/libvirt/images/alice.qcow2") -# test.mount("45598e92-3487-4a1b-961d-79aa3dd42a7d", "/") -# test.copy_in("/home/jonatan/nitsi/libguestfs-test", "/root/") -# test.umount("/") -# test.close() + def _mount(self, part, path="/"): + """ + Mounts the selected partition to path + """ + self.log.debug("Mounting partition %s to %s" % (part, path)) + + self.con.mount(part, path) + + def _umount(self, path="/"): + self.log.debug("Umounting %s" % path) + + self.con.umount_opts(path) + + +class MountedDisk(object): + """ + Provides commands that can only be executed when the disk is mounted. + + Leaving the context will automatically umount the disk. + """ + def __init__(self, disk, part): + self.disk = disk + self.part = part + + def copy_in(self, files, destination): + self.disk.log.debug("Going to copy some files into the image") + + with tempfile.NamedTemporaryFile("wb", suffix=".tar") as f: + with tarfile.open(fileobj=f, mode="w") as t: + for file in files: + self.disk.log.debug("Adding %s" % file) + t.add(file, arcname=os.path.basename(file)) + + self.disk.log.debug("Going to copy the files into the image") + self.disk.con.tar_in_opts(f.name, destination) + + +# with disk("/var/lib/libvirt/images/alice.qcow2", "45598e92-3487-4a1b-961d-79aa3dd42a7d") as test: +# test.copy_in("/home/jonatan/nitsi/libguestfs-test", "/root/") diff --git a/src/nitsi/machine.py b/src/nitsi/machine.py index 0b4617aed8dc..9efa4dde5688 100644 --- a/src/nitsi/machine.py +++ b/src/nitsi/machine.py @@ -40,8 +40,7 @@ class machine(): if not os.path.isfile(self.image): self.log.error("No such file: {}".format(self.image))
- self.root_uid = root_uid - self.disk = disk.disk(image) + self.disk = disk.Disk(image, root_uid)
self.username = username self.password = password @@ -132,11 +131,5 @@ class machine(): return self.serial_con.command(cmd)
def copy_in(self, fr, to): - try: - self.disk.mount(self.root_uid, "/") - self.disk.copy_in(fr, to) - except BaseException as e: - self.log.error(e) - finally: - self.disk.umount("/") - self.disk.close() + with self.disk as d: + d.copy_in(fr, to)
Hi,
I had merged all other patches and will have a closer look at this one later
Jonatan
Am Fr, 18. Mai, 2018 um 3:33 schrieb Michael Tremer michael.tremer@ipfire.org:
This is an example of how the code could take advantage of Python contexts. The with statement will open the context and when it is left (either normally or because of an exception), the __exit__() method is called and can be used to cleanup.
Cleaning up is in this case umounting the image file, but could also be used to shutdown and destroy a virtual machine or network.
Signed-off-by: Michael Tremer michael.tremer@ipfire.org
src/nitsi/disk.py | 92 +++++++++++++++++++++++++++++--------------- src/nitsi/machine.py | 13 ++----- 2 files changed, 65 insertions(+), 40 deletions(-)
diff --git a/src/nitsi/disk.py b/src/nitsi/disk.py index 29782574282e..5f465956c849 100755 --- a/src/nitsi/disk.py +++ b/src/nitsi/disk.py @@ -8,43 +8,75 @@ import tempfile
logger = logging.getLogger("nitsi.disk")
+class Disk(object):
- def __init__(self, path, part_uuid):
self.path = path
self.part_uuid = part_uuid
-class disk():
- def __init__(self, disk):
self.log = logger.getChild(os.path.basename(disk))
self.log.debug("Initiated a disk class for {}".format(disk))
self.log = logger.getChild(os.path.basename(self.path))
self.log.debug("Initiated a disk class for
{}".format(self.path))
# Create GuestFS object for this disk self.con = guestfs.GuestFS(python_return_dict=True)
self.con.add_drive_opts(disk, format="qcow2")
self.con.add_drive_opts(self.path, format="qcow2")
- def mount(self, uuid, path):
self.log.debug("Trying to mount the partion with uuid: {}
under {}".format(uuid, path))
- def __enter__(self):
# Launch the GuestFS backend self.con.launch()
part = self.con.findfs_uuid(uuid)
self.con.mount(part, path)
def copy_in(self, fr, to):
self.log.debug("Going to copy some files into the image.")
tmp = tempfile.mkstemp()
tmp = tmp[1] + ".tar"
with tarfile.open(tmp, "w") as tar:
for file in fr:
self.log.debug("Adding {} to be copied into the
image".format(file))
tar.add(file, arcname=os.path.basename(file))
# Find partition to mount
part = self.con.findfs_uuid(self.part_uuid)
if not part:
raise RuntimeError("Could not find partition %s" %
self.part_uuid)
self.log.debug("Going to copy the files into the image")
self.con.tar_in_opts(tmp, to)
# Mounting partition
self._mount(part)
- def umount(self, path):
self.log.debug("Unmounting the image")
self.con.umount_opts(path)
return MountedDisk(self, part)
- def close(self):
self.log.debug("Flush the image and closing the connection")
- def __exit__(self, type, value, traceback):
# Umount the disk image
self._umount()
# Shuts down the GuestFS backend self.con.shutdown()
self.con.close()
-# test = disk("/var/lib/libvirt/images/alice.qcow2") -# test.mount("45598e92-3487-4a1b-961d-79aa3dd42a7d", "/") -# test.copy_in("/home/jonatan/nitsi/libguestfs-test", "/root/") -# test.umount("/") -# test.close()
- def _mount(self, part, path="/"):
"""
Mounts the selected partition to path
"""
self.log.debug("Mounting partition %s to %s" % (part, path))
self.con.mount(part, path)
- def _umount(self, path="/"):
self.log.debug("Umounting %s" % path)
self.con.umount_opts(path)
+class MountedDisk(object):
- """
Provides commands that can only be executed when the disk is
mounted.
Leaving the context will automatically umount the disk.
- """
- def __init__(self, disk, part):
self.disk = disk
self.part = part
- def copy_in(self, files, destination):
self.disk.log.debug("Going to copy some files into the
image")
with tempfile.NamedTemporaryFile("wb", suffix=".tar") as f:
with tarfile.open(fileobj=f, mode="w") as t:
for file in files:
self.disk.log.debug("Adding %s" % file)
t.add(file, arcname=os.path.basename(file))
self.disk.log.debug("Going to copy the files into the
image")
self.disk.con.tar_in_opts(f.name, destination)
+# with disk("/var/lib/libvirt/images/alice.qcow2", "45598e92-3487-4a1b-961d-79aa3dd42a7d") as test: +# test.copy_in("/home/jonatan/nitsi/libguestfs-test", "/root/") diff --git a/src/nitsi/machine.py b/src/nitsi/machine.py index 0b4617aed8dc..9efa4dde5688 100644 --- a/src/nitsi/machine.py +++ b/src/nitsi/machine.py @@ -40,8 +40,7 @@ class machine(): if not os.path.isfile(self.image): self.log.error("No such file: {}".format(self.image))
self.root_uid = root_uid
self.disk = disk.disk(image)
self.disk = disk.Disk(image, root_uid) self.username = username self.password = password
@@ -132,11 +131,5 @@ class machine(): return self.serial_con.command(cmd)
def copy_in(self, fr, to):
try:
self.disk.mount(self.root_uid, "/")
self.disk.copy_in(fr, to)
except BaseException as e:
self.log.error(e)
finally:
self.disk.umount("/")
self.disk.close()
with self.disk as d:
d.copy_in(fr, to)
-- 2.17.0
Signed-off-by: Michael Tremer michael.tremer@ipfire.org --- .gitignore | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore index 8b229665e586..28eacd91523e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ /Makefile /build-aux /libtool +/man/*.[0-9] +/man/*.html /tmp *.py[co] /*.tar.bz2
Signed-off-by: Michael Tremer michael.tremer@ipfire.org --- .gitignore | 1 + 1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore index 28eacd91523e..8ecd217d5e1e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /libtool /man/*.[0-9] /man/*.html +/nitsi /tmp *.py[co] /*.tar.bz2