livemedia-creator: Cleanup docstrings
Start using Sphinx style docstrings.
This commit is contained in:
parent
833d64d1f7
commit
1807a39ace
@ -76,8 +76,14 @@ class InstallError(Exception):
|
|||||||
class LogRequestHandler(SocketServer.BaseRequestHandler):
|
class LogRequestHandler(SocketServer.BaseRequestHandler):
|
||||||
"""
|
"""
|
||||||
Handle monitoring and saving the logfiles from the virtual install
|
Handle monitoring and saving the logfiles from the virtual install
|
||||||
|
|
||||||
|
Incoming data is written to self.server.log_path and each line is checked
|
||||||
|
for patterns that would indicate that the installation failed.
|
||||||
|
self.server.log_error is set True when this happens.
|
||||||
"""
|
"""
|
||||||
def setup(self):
|
def setup(self):
|
||||||
|
"""Start writing to self.server.log_path"""
|
||||||
|
|
||||||
if self.server.log_path:
|
if self.server.log_path:
|
||||||
self.fp = open(self.server.log_path, "w") # pylint: disable=attribute-defined-outside-init
|
self.fp = open(self.server.log_path, "w") # pylint: disable=attribute-defined-outside-init
|
||||||
else:
|
else:
|
||||||
@ -86,9 +92,12 @@ class LogRequestHandler(SocketServer.BaseRequestHandler):
|
|||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
"""
|
"""
|
||||||
Handle writing incoming data to a logfile and
|
Write incoming data to a logfile and check for errors
|
||||||
checking the logs for any Tracebacks or other errors that indicate
|
|
||||||
that the install failed.
|
Split incoming data into lines and check for any Tracebacks or other
|
||||||
|
errors that indicate that the install failed.
|
||||||
|
|
||||||
|
Loops until self.server.kill is True
|
||||||
"""
|
"""
|
||||||
line = ""
|
line = ""
|
||||||
while True:
|
while True:
|
||||||
@ -123,7 +132,9 @@ class LogRequestHandler(SocketServer.BaseRequestHandler):
|
|||||||
|
|
||||||
def iserror(self, line):
|
def iserror(self, line):
|
||||||
"""
|
"""
|
||||||
Check a line to see if it contains an error indicating install failure
|
Check a line to see if it contains an error indicating installation failure
|
||||||
|
|
||||||
|
:param str line: log line to check for failure
|
||||||
"""
|
"""
|
||||||
simple_tests = ["Traceback (",
|
simple_tests = ["Traceback (",
|
||||||
"Out of memory:",
|
"Out of memory:",
|
||||||
@ -141,29 +152,45 @@ class LogRequestHandler(SocketServer.BaseRequestHandler):
|
|||||||
|
|
||||||
|
|
||||||
class LogServer(SocketServer.TCPServer):
|
class LogServer(SocketServer.TCPServer):
|
||||||
"""
|
"""A TCP Server that listens for log data"""
|
||||||
Add path to logfile
|
|
||||||
Add log error flag
|
|
||||||
Add a kill switch
|
|
||||||
"""
|
|
||||||
def __init__(self, log_path, *args, **kwargs):
|
def __init__(self, log_path, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Setup the log server
|
||||||
|
|
||||||
|
:param str log_path: Path to the log file to write
|
||||||
|
"""
|
||||||
self.kill = False
|
self.kill = False
|
||||||
self.log_error = False
|
self.log_error = False
|
||||||
self.log_path = log_path
|
self.log_path = log_path
|
||||||
SocketServer.TCPServer.__init__(self, *args, **kwargs)
|
SocketServer.TCPServer.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
def log_check(self):
|
def log_check(self):
|
||||||
|
"""
|
||||||
|
Check to see if an error has been found in the log
|
||||||
|
|
||||||
|
:returns: True if there has been an error
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
return self.log_error
|
return self.log_error
|
||||||
|
|
||||||
|
|
||||||
class LogMonitor(object):
|
class LogMonitor(object):
|
||||||
"""
|
"""
|
||||||
Contains all the stuff needed to setup a thread to listen to the logs
|
Setup a server to monitor the logs output by the installation
|
||||||
from the virtual install
|
|
||||||
|
This needs to be running before the virt-install runs, it expects
|
||||||
|
there to be a listener on the port used for the virtio log port.
|
||||||
"""
|
"""
|
||||||
def __init__(self, log_path, host="localhost", port=0):
|
def __init__(self, log_path, host="localhost", port=0):
|
||||||
"""
|
"""
|
||||||
Fire up the thread listening for logs
|
Start a thread to monitor the logs.
|
||||||
|
|
||||||
|
:param str log_path: Path to the logfile to write
|
||||||
|
:param str host: Host to bind to. Default is localhost.
|
||||||
|
:param int port: Port to listen to or 0 to pick a port
|
||||||
|
|
||||||
|
If 0 is passed for the port the dynamically assigned port will be
|
||||||
|
available as self.port
|
||||||
"""
|
"""
|
||||||
self.server = LogServer(log_path, (host, port), LogRequestHandler)
|
self.server = LogServer(log_path, (host, port), LogRequestHandler)
|
||||||
self.host, self.port = self.server.server_address
|
self.host, self.port = self.server.server_address
|
||||||
@ -173,24 +200,31 @@ class LogMonitor(object):
|
|||||||
self.server_thread.start()
|
self.server_thread.start()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
|
"""Force shutdown of the monitoring thread"""
|
||||||
self.server.kill = True
|
self.server.kill = True
|
||||||
self.server_thread.join()
|
self.server_thread.join()
|
||||||
|
|
||||||
|
|
||||||
class IsoMountpoint(object):
|
class IsoMountpoint(object):
|
||||||
"""
|
"""
|
||||||
Mount the iso on a temporary directory and check to make sure the
|
Mount the iso and check to make sure the vmlinuz and initrd.img files exist
|
||||||
vmlinuz and initrd.img files exist
|
|
||||||
Check the iso for a LiveOS directory and set a flag.
|
|
||||||
Extract the iso's label.
|
|
||||||
|
|
||||||
initrd_path can be used to point to a boot.iso tree with a newer
|
Also check the iso for a LiveOS directory and set a flag and extract the
|
||||||
initrd.img than the iso has. The iso is still used for stage2.
|
iso's label.
|
||||||
"""
|
"""
|
||||||
def __init__( self, iso_path, initrd_path=None ):
|
def __init__(self, iso_path, initrd_path=None):
|
||||||
""" iso_path is the path to a boot.iso
|
"""
|
||||||
initrd_path overrides mounting the iso for access to
|
Mount the iso
|
||||||
initrd and vmlinuz.
|
|
||||||
|
:param str iso_path: Path to the iso to mount
|
||||||
|
:param str initrd_path: Optional path to initrd
|
||||||
|
|
||||||
|
initrd_path can be used to point to a tree with a newer
|
||||||
|
initrd.img than the iso has. The iso is still used for stage2.
|
||||||
|
|
||||||
|
self.kernel and self.initrd point to the kernel and initrd.
|
||||||
|
self.liveos is set to True if there is a LiveOS/ directory
|
||||||
|
self.repo is the path to the mounted iso if there is a /repodata dir.
|
||||||
"""
|
"""
|
||||||
self.label = None
|
self.label = None
|
||||||
self.iso_path = iso_path
|
self.iso_path = iso_path
|
||||||
@ -221,12 +255,15 @@ class IsoMountpoint(object):
|
|||||||
self.get_iso_label()
|
self.get_iso_label()
|
||||||
|
|
||||||
def umount( self ):
|
def umount( self ):
|
||||||
|
"""Unmount the iso"""
|
||||||
if not self.initrd_path:
|
if not self.initrd_path:
|
||||||
umount(self.mount_dir)
|
umount(self.mount_dir)
|
||||||
|
|
||||||
def get_iso_label(self):
|
def get_iso_label(self):
|
||||||
"""
|
"""
|
||||||
Get the iso's label using isoinfo
|
Get the iso's label using isoinfo
|
||||||
|
|
||||||
|
Sets self.label if one is found
|
||||||
"""
|
"""
|
||||||
isoinfo_output = execWithCapture("isoinfo", ["-d", "-i", self.iso_path])
|
isoinfo_output = execWithCapture("isoinfo", ["-d", "-i", self.iso_path])
|
||||||
log.debug(isoinfo_output)
|
log.debug(isoinfo_output)
|
||||||
@ -238,24 +275,30 @@ class IsoMountpoint(object):
|
|||||||
|
|
||||||
class VirtualInstall(object):
|
class VirtualInstall(object):
|
||||||
"""
|
"""
|
||||||
Run virt-install using an iso and kickstart(s)
|
Run virt-install using an iso and a kickstart
|
||||||
"""
|
"""
|
||||||
def __init__(self, iso, ks_paths, disk_img, img_size=2048,
|
def __init__(self, iso, ks_paths, disk_img, img_size=2048,
|
||||||
kernel_args=None, memory=1024, vnc=None, arch=None,
|
kernel_args=None, memory=1024, vnc=None, arch=None,
|
||||||
log_check=None, virtio_host="127.0.0.1", virtio_port=6080,
|
log_check=None, virtio_host="127.0.0.1", virtio_port=6080,
|
||||||
qcow2=False):
|
qcow2=False):
|
||||||
"""
|
"""
|
||||||
iso is an instance of IsoMountpoint
|
Start the installation
|
||||||
ks_paths is a list of paths to a kickstart files. All are injected, the
|
|
||||||
first one is the one executed.
|
:param iso: Information about the iso to use for the installation
|
||||||
disk_img is the path to a disk image (doesn't need to exist)
|
:type iso: IsoMountpoint
|
||||||
img_size is the size, in MiB, of the image if it doesn't exist
|
:param list ks_paths: Paths to kickstart files. All are injected, the
|
||||||
kernel_args are extra arguments to pass on the kernel cmdline
|
first one is the one executed.
|
||||||
memory is the amount of ram to assign to the virt
|
:param str disk_img: Path to a disk image, created it it doesn't exist
|
||||||
vnc is passed to the --graphics command verbatim
|
:param int img_size: The image size, in MiB, to create if it doesn't exist
|
||||||
arch is the optional architecture to use in the virt
|
:param str kernel_args: Extra kernel arguments to pass on the kernel cmdline
|
||||||
log_check is a method that returns True of the log indicates an error
|
:param int memory: Amount of RAM to assign to the virt, in MiB
|
||||||
virtio_host and virtio_port are used to communicate with the log monitor
|
:param str vnc: Arguments to pass to virt-install --graphics
|
||||||
|
:param str arch: Optional architecture to use in the virt
|
||||||
|
:param log_check: Method that returns True if the installation fails
|
||||||
|
:type log_check: method
|
||||||
|
:param str virtio_host: Hostname to connect virtio log to
|
||||||
|
:param int virtio_port: Port to connect virtio log to
|
||||||
|
:param bool qcow2: Set to True if disk_img is a qcow2
|
||||||
"""
|
"""
|
||||||
self.virt_name = "LiveOS-"+str(uuid.uuid4())
|
self.virt_name = "LiveOS-"+str(uuid.uuid4())
|
||||||
# add --graphics none later
|
# add --graphics none later
|
||||||
@ -346,7 +389,10 @@ class VirtualInstall(object):
|
|||||||
|
|
||||||
def is_image_mounted(disk_img):
|
def is_image_mounted(disk_img):
|
||||||
"""
|
"""
|
||||||
Return True if the disk_img is mounted
|
Check to see if the disk_img is mounted
|
||||||
|
|
||||||
|
:returns: True if disk_img is in /proc/mounts
|
||||||
|
:rtype: bool
|
||||||
"""
|
"""
|
||||||
with open("/proc/mounts") as mounts:
|
with open("/proc/mounts") as mounts:
|
||||||
for mnt in mounts:
|
for mnt in mounts:
|
||||||
@ -357,8 +403,11 @@ def is_image_mounted(disk_img):
|
|||||||
|
|
||||||
|
|
||||||
def get_arch(mount_dir):
|
def get_arch(mount_dir):
|
||||||
""" Return the arch of the first kernel at <mount_dir>/boot/
|
"""
|
||||||
or return i386
|
Get the kernel arch
|
||||||
|
|
||||||
|
:returns: Arch of first kernel found at mount_dir/boot/ or i386
|
||||||
|
:rtype: str
|
||||||
"""
|
"""
|
||||||
kernels = findkernels(mount_dir)
|
kernels = findkernels(mount_dir)
|
||||||
if not kernels:
|
if not kernels:
|
||||||
@ -372,17 +421,17 @@ def make_appliance(disk_img, name, template, outfile, networks=None, ram=1024,
|
|||||||
"""
|
"""
|
||||||
Generate an appliance description file
|
Generate an appliance description file
|
||||||
|
|
||||||
disk_img Full path of the disk image
|
:param str disk_img: Full path of the disk image
|
||||||
name Name of the appliance, passed to the template
|
:param str name: Name of the appliance, passed to the template
|
||||||
template Full path of Mako template
|
:param str template: Full path of Mako template
|
||||||
outfile Full path of file to write, using template
|
:param str outfile: Full path of file to write, using template
|
||||||
networks List of networks from the kickstart
|
:param list networks: List of networks(str) from the kickstart
|
||||||
ram Ram, in MB, passed to template. Default is 1024
|
:param int ram: Ram, in MiB, passed to template. Default is 1024
|
||||||
vcpus CPUs, passed to template. Default is 1
|
:param int vcpus: CPUs, passed to template. Default is 1
|
||||||
arch CPU architecture. Default is 'x86_64'
|
:param str arch: CPU architecture. Default is 'x86_64'
|
||||||
title Title, passed to template. Default is 'Linux'
|
:param str title: Title, passed to template. Default is 'Linux'
|
||||||
project Project, passed to template. Default is 'Linux'
|
:param str project: Project, passed to template. Default is 'Linux'
|
||||||
releasever Release version, passed to template. Default is 17
|
:param str releasever: Release version, passed to template. Default is 17
|
||||||
"""
|
"""
|
||||||
if not (disk_img and template and outfile):
|
if not (disk_img and template and outfile):
|
||||||
return None
|
return None
|
||||||
@ -420,10 +469,11 @@ def make_fsimage(diskimage, fsimage, img_size=None, label="Anaconda"):
|
|||||||
Copy the / partition of a partitioned disk image to an un-partitioned
|
Copy the / partition of a partitioned disk image to an un-partitioned
|
||||||
disk image.
|
disk image.
|
||||||
|
|
||||||
diskimage is the full path to partitioned disk image with a /
|
:param str diskimage: The full path to partitioned disk image with a /
|
||||||
fsimage is the full path of the output fs image file
|
:param str fsimage: The full path of the output fs image file
|
||||||
img_size is the size of the fsimage in MiB or None to make it as small as possible
|
:param int img_size: Optional size of the fsimage in MiB or None to make
|
||||||
label is the label to apply to the image. Defaults to "Anaconda"
|
it as small as possible
|
||||||
|
:param str label: The label to apply to the image. Defaults to "Anaconda"
|
||||||
"""
|
"""
|
||||||
with PartitionMount(diskimage) as img_mount:
|
with PartitionMount(diskimage) as img_mount:
|
||||||
if not img_mount or not img_mount.mount_dir:
|
if not img_mount or not img_mount.mount_dir:
|
||||||
@ -441,7 +491,10 @@ def make_runtime(opts, mount_dir, work_dir):
|
|||||||
"""
|
"""
|
||||||
Make the squashfs image from a directory
|
Make the squashfs image from a directory
|
||||||
|
|
||||||
Result is in work_dir+RUNTIME
|
:param opts: options passed to livemedia-creator
|
||||||
|
:type opts: argparse options
|
||||||
|
:param str mount_dir: Directory tree to compress
|
||||||
|
:param str work_dir: Output compressed image to work_dir+images/install.img
|
||||||
"""
|
"""
|
||||||
kernel_arch = get_arch(mount_dir)
|
kernel_arch = get_arch(mount_dir)
|
||||||
|
|
||||||
@ -466,16 +519,16 @@ def make_livecd(opts, mount_dir, work_dir):
|
|||||||
"""
|
"""
|
||||||
Take the content from the disk image and make a livecd out of it
|
Take the content from the disk image and make a livecd out of it
|
||||||
|
|
||||||
|
:param opts: options passed to livemedia-creator
|
||||||
|
:type opts: argparse options
|
||||||
|
:param str mount_dir: Directory tree to compress
|
||||||
|
:param str work_dir: Output compressed image to work_dir+images/install.img
|
||||||
|
|
||||||
This uses wwood's squashfs live initramfs method:
|
This uses wwood's squashfs live initramfs method:
|
||||||
* put the real / into LiveOS/rootfs.img
|
* put the real / into LiveOS/rootfs.img
|
||||||
* make a squashfs of the LiveOS/rootfs.img tree
|
* make a squashfs of the LiveOS/rootfs.img tree
|
||||||
* make a simple initramfs with the squashfs.img and /etc/cmdline in it
|
* This is loaded by dracut when the cmdline is passed to the kernel:
|
||||||
* make a cpio of that tree
|
root=live:CDLABEL=<volid> rd.live.image
|
||||||
* append the squashfs.cpio to a dracut initramfs for each kernel installed
|
|
||||||
|
|
||||||
Then on boot dracut reads /etc/cmdline which points to the squashfs.img
|
|
||||||
mounts that and then mounts LiveOS/rootfs.img as /
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
kernel_arch = get_arch(mount_dir)
|
kernel_arch = get_arch(mount_dir)
|
||||||
|
|
||||||
@ -527,9 +580,15 @@ def novirt_install(opts, disk_img, disk_size, repo_url):
|
|||||||
"""
|
"""
|
||||||
Use Anaconda to install to a disk image
|
Use Anaconda to install to a disk image
|
||||||
|
|
||||||
disk_img is the full path to the disk image to be created
|
:param opts: options passed to livemedia-creator
|
||||||
disk_size is the size in MiB
|
:type opts: argparse options
|
||||||
repo_url is the url of the repository to use for the installation
|
:param str disk_img: The full path to the disk image to be created
|
||||||
|
:param int disk_size: The size of the disk_img in MiB
|
||||||
|
:param str repo_url: The url of the repository to use for the installation
|
||||||
|
|
||||||
|
This method makes sure SELinux is permissive during the install, runs anaconda
|
||||||
|
to create the image and then based on the opts passed create a qcow2 image
|
||||||
|
or tarfile.
|
||||||
"""
|
"""
|
||||||
import selinux
|
import selinux
|
||||||
|
|
||||||
@ -635,9 +694,14 @@ def virt_install(opts, install_log, disk_img, disk_size):
|
|||||||
"""
|
"""
|
||||||
Use virt-install to install to a disk image
|
Use virt-install to install to a disk image
|
||||||
|
|
||||||
install_log is the path to write the log from virt-install
|
:param opts: options passed to livemedia-creator
|
||||||
disk_img is the full path to the final disk or filesystem image
|
:type opts: argparse options
|
||||||
disk_size is the size of the disk to create in MiB
|
:param str install_log: The path to write the log from virt-install
|
||||||
|
:param str disk_img: The full path to the disk image to be created
|
||||||
|
:param int disk_size: The size of the disk_img in MiB
|
||||||
|
|
||||||
|
This uses virt-install with a boot.iso and a kickstart to create a disk
|
||||||
|
image and then optionally, based on the opts passed, creates tarfile.
|
||||||
"""
|
"""
|
||||||
iso_mount = IsoMountpoint(opts.iso, opts.location)
|
iso_mount = IsoMountpoint(opts.iso, opts.location)
|
||||||
log_monitor = LogMonitor(install_log)
|
log_monitor = LogMonitor(install_log)
|
||||||
@ -694,8 +758,14 @@ def virt_install(opts, install_log, disk_img, disk_size):
|
|||||||
|
|
||||||
def make_squashfs(disk_img, work_dir, compression="xz"):
|
def make_squashfs(disk_img, work_dir, compression="xz"):
|
||||||
"""
|
"""
|
||||||
|
Create a squashfs image of an unpartitioned filesystem disk image
|
||||||
|
|
||||||
|
:param str disk_img: Path to the unpartitioned filesystem disk image
|
||||||
|
:param str work_dir: Output compressed image to work_dir+images/install.img
|
||||||
|
:param str compression: Compression type to use
|
||||||
|
|
||||||
Take disk_img and put it into LiveOS/rootfs.img and squashfs this
|
Take disk_img and put it into LiveOS/rootfs.img and squashfs this
|
||||||
tree into work_dir+RUNTIME
|
tree into work_dir+images/install.img
|
||||||
"""
|
"""
|
||||||
liveos_dir = joinpaths(work_dir, "runtime/LiveOS")
|
liveos_dir = joinpaths(work_dir, "runtime/LiveOS")
|
||||||
os.makedirs(liveos_dir)
|
os.makedirs(liveos_dir)
|
||||||
@ -712,11 +782,15 @@ def make_squashfs(disk_img, work_dir, compression="xz"):
|
|||||||
|
|
||||||
def make_image(opts, ks):
|
def make_image(opts, ks):
|
||||||
"""
|
"""
|
||||||
Install to an image
|
Install to a disk image
|
||||||
|
|
||||||
Use virt or anaconda to install to an image.
|
:param opts: options passed to livemedia-creator
|
||||||
|
:type opts: argparse options
|
||||||
|
:param str ks: Path to the kickstart to use for the installation
|
||||||
|
:returns: Path of the image created
|
||||||
|
:rtype: str
|
||||||
|
|
||||||
Returns the full path of of the image created.
|
Use virt-install or anaconda to install to a disk image.
|
||||||
"""
|
"""
|
||||||
disk_size = 1 + sum(p.size for p in ks.handler.partition.partitions)
|
disk_size = 1 + sum(p.size for p in ks.handler.partition.partitions)
|
||||||
log.info("disk_size = %sMiB", disk_size)
|
log.info("disk_size = %sMiB", disk_size)
|
||||||
@ -747,6 +821,12 @@ def make_image(opts, ks):
|
|||||||
|
|
||||||
|
|
||||||
def setup_logging(opts):
|
def setup_logging(opts):
|
||||||
|
"""
|
||||||
|
Setup the various logs
|
||||||
|
|
||||||
|
:param opts: options passed to livemedia-creator
|
||||||
|
:type opts: argparse options
|
||||||
|
"""
|
||||||
# Setup logging to console and to logfile
|
# Setup logging to console and to logfile
|
||||||
log.setLevel(logging.DEBUG)
|
log.setLevel(logging.DEBUG)
|
||||||
pylorax_log.setLevel(logging.DEBUG)
|
pylorax_log.setLevel(logging.DEBUG)
|
||||||
|
Loading…
Reference in New Issue
Block a user