2015-05-08 15:39:06 +00:00
|
|
|
#!/usr/bin/python3
|
2011-09-24 00:36:09 +00:00
|
|
|
#
|
|
|
|
# Live Media Creator
|
|
|
|
#
|
2018-04-27 00:09:05 +00:00
|
|
|
# Copyright (C) 2011-2018 Red Hat, Inc.
|
2011-09-24 00:36:09 +00:00
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
import logging
|
|
|
|
log = logging.getLogger("livemedia-creator")
|
|
|
|
|
2018-05-02 16:55:46 +00:00
|
|
|
import glob
|
2011-09-24 00:36:09 +00:00
|
|
|
import os
|
2018-05-02 16:55:46 +00:00
|
|
|
import selinux
|
2011-09-24 00:36:09 +00:00
|
|
|
import sys
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
# Use the Lorax treebuilder branch for iso creation
|
2018-04-27 00:09:05 +00:00
|
|
|
from pylorax import setup_logging, find_templates, vernum
|
2016-03-18 21:24:31 +00:00
|
|
|
from pylorax.cmdline import lmc_parser
|
2018-06-07 00:08:26 +00:00
|
|
|
from pylorax.creator import run_creator, DRACUT_DEFAULT
|
2018-05-02 16:55:46 +00:00
|
|
|
from pylorax.imgutils import default_image_name
|
2018-04-27 00:09:05 +00:00
|
|
|
from pylorax.sysutils import joinpaths
|
2014-07-30 15:59:27 +00:00
|
|
|
|
|
|
|
|
2014-05-09 00:22:14 +00:00
|
|
|
def main():
|
2018-06-07 00:08:26 +00:00
|
|
|
parser = lmc_parser(DRACUT_DEFAULT)
|
2011-09-24 00:36:09 +00:00
|
|
|
opts = parser.parse_args()
|
|
|
|
|
2015-05-27 17:36:40 +00:00
|
|
|
setup_logging(opts.logfile, log)
|
2011-09-24 00:36:09 +00:00
|
|
|
|
|
|
|
log.debug( opts )
|
|
|
|
|
2017-08-08 22:14:15 +00:00
|
|
|
log.info("livemedia-creator v%s", vernum)
|
|
|
|
|
2016-02-11 18:50:46 +00:00
|
|
|
# Find the lorax templates
|
|
|
|
opts.lorax_templates = find_templates(opts.lorax_templates or "/usr/share/lorax")
|
|
|
|
|
2014-04-03 17:22:54 +00:00
|
|
|
# Check for invalid combinations of options, print all the errors and exit.
|
|
|
|
errors = []
|
|
|
|
if not opts.disk_image and not opts.fs_image and not opts.ks:
|
|
|
|
errors.append("Image creation requires a kickstart file")
|
|
|
|
|
|
|
|
if opts.ks and not os.path.exists(opts.ks[0]):
|
|
|
|
errors.append("kickstart file (%s) is missing." % opts.ks[0])
|
2011-09-24 00:36:09 +00:00
|
|
|
|
2016-02-11 18:50:46 +00:00
|
|
|
if opts.make_iso and not os.path.exists(opts.lorax_templates):
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("The lorax templates directory (%s) doesn't "
|
|
|
|
"exist." % opts.lorax_templates)
|
2011-09-24 00:36:09 +00:00
|
|
|
|
|
|
|
if opts.result_dir and os.path.exists(opts.result_dir):
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("The results_dir (%s) should not exist, please delete or "
|
|
|
|
"move its contents" % opts.result_dir)
|
2011-09-24 00:36:09 +00:00
|
|
|
|
2016-01-07 18:16:07 +00:00
|
|
|
# Default to putting results under tmp
|
|
|
|
if not opts.result_dir:
|
|
|
|
opts.result_dir = opts.tmp
|
|
|
|
|
2014-05-09 16:28:01 +00:00
|
|
|
if opts.iso and not os.path.exists(opts.iso):
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("The iso %s is missing." % opts.iso)
|
2011-09-24 00:36:09 +00:00
|
|
|
|
2014-05-09 16:28:01 +00:00
|
|
|
if opts.disk_image and not os.path.exists(opts.disk_image):
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("The disk image %s is missing." % opts.disk_image)
|
2011-09-24 00:36:09 +00:00
|
|
|
|
2014-05-09 16:28:01 +00:00
|
|
|
if opts.fs_image and not os.path.exists(opts.fs_image):
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("The filesystem image %s is missing." % opts.fs_image)
|
2013-01-30 22:16:25 +00:00
|
|
|
|
|
|
|
is_install = not (opts.disk_image or opts.fs_image)
|
|
|
|
if is_install and not opts.no_virt and not opts.iso:
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("virt install needs an install iso.")
|
2011-09-24 00:36:09 +00:00
|
|
|
|
2012-03-08 01:29:31 +00:00
|
|
|
if opts.volid and len(opts.volid) > 32:
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("the volume id cannot be longer than 32 characters")
|
2012-03-08 01:29:31 +00:00
|
|
|
|
2013-01-30 22:16:25 +00:00
|
|
|
if is_install and not opts.no_virt \
|
2016-01-06 00:49:40 +00:00
|
|
|
and not any(glob.glob("/usr/bin/qemu-system-*")):
|
|
|
|
errors.append("qemu needs to be installed.")
|
2012-05-10 21:21:42 +00:00
|
|
|
|
2013-05-24 19:20:56 +00:00
|
|
|
if is_install and opts.no_virt \
|
2013-01-30 22:16:25 +00:00
|
|
|
and not os.path.exists("/usr/sbin/anaconda"):
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("no-virt requires anaconda to be installed.")
|
2012-05-24 22:55:46 +00:00
|
|
|
|
2016-03-24 21:10:14 +00:00
|
|
|
if is_install and opts.no_virt:
|
|
|
|
if selinux.is_selinux_enabled() and selinux.security_getenforce():
|
|
|
|
errors.append("selinux must be disabled or in Permissive mode.")
|
|
|
|
|
2012-05-24 22:55:46 +00:00
|
|
|
if opts.make_appliance and not opts.app_template:
|
|
|
|
opts.app_template = joinpaths(opts.lorax_templates,
|
|
|
|
"appliance/libvirt.tmpl")
|
|
|
|
|
|
|
|
if opts.make_appliance and not os.path.exists(opts.app_template):
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("The appliance template (%s) doesn't "
|
|
|
|
"exist" % opts.app_template)
|
2012-05-24 22:55:46 +00:00
|
|
|
|
2015-03-20 00:22:16 +00:00
|
|
|
if opts.image_name and os.path.exists(joinpaths(opts.result_dir, opts.image_name)):
|
2014-04-03 17:22:54 +00:00
|
|
|
errors.append("The disk image to be created should not exist.")
|
2012-05-24 22:55:46 +00:00
|
|
|
|
2015-10-19 22:30:33 +00:00
|
|
|
# Vagrant creates a qcow2 inside a tar, turn on qcow2
|
|
|
|
if opts.make_vagrant:
|
2015-12-18 23:30:51 +00:00
|
|
|
opts.image_type = "qcow2"
|
|
|
|
|
|
|
|
# Alias --qcow2 to --image-type=qcow2
|
|
|
|
if opts.qcow2:
|
|
|
|
opts.image_type = "qcow2"
|
2015-10-19 22:30:33 +00:00
|
|
|
|
2015-12-18 23:30:51 +00:00
|
|
|
if opts.image_type and not os.path.exists("/usr/bin/qemu-img"):
|
|
|
|
errors.append("image-type requires the qemu-img utility to be installed." % opts.image_type)
|
2014-03-08 02:43:14 +00:00
|
|
|
|
2015-12-18 23:30:51 +00:00
|
|
|
if opts.image_type and opts.make_iso:
|
|
|
|
errors.append("image-type cannot be used to make a bootable iso.")
|
2014-04-03 17:22:54 +00:00
|
|
|
|
2015-12-18 23:30:51 +00:00
|
|
|
if opts.image_type and opts.make_fsimage:
|
|
|
|
errors.append("image-type cannot be used to make filesystem images.")
|
2014-04-03 17:22:54 +00:00
|
|
|
|
2015-12-18 23:30:51 +00:00
|
|
|
if opts.image_type and opts.make_tar:
|
|
|
|
errors.append("image-type cannot be used to make a tar.")
|
2014-04-04 21:38:51 +00:00
|
|
|
|
2015-10-19 22:35:50 +00:00
|
|
|
if opts.make_oci and not (opts.oci_config and opts.oci_runtime):
|
|
|
|
errors.append("--make-oci requires --oci-config and --oci-runtime")
|
|
|
|
|
2015-10-20 21:23:33 +00:00
|
|
|
if opts.make_oci and not os.path.exists(opts.oci_config):
|
|
|
|
errors.append("oci % file is missing" % opts.oci_config)
|
|
|
|
|
|
|
|
if opts.make_oci and not os.path.exists(opts.oci_runtime):
|
|
|
|
errors.append("oci % file is missing" % opts.oci_runtime)
|
|
|
|
|
2015-10-21 00:28:10 +00:00
|
|
|
if opts.make_vagrant and opts.vagrant_metadata and not os.path.exists(opts.vagrant_metadata):
|
|
|
|
errors.append("Vagrant metadata file %s is missing" % opts.vagrant_metadata)
|
|
|
|
|
2015-11-04 02:03:09 +00:00
|
|
|
if opts.virt_uefi and not os.path.isdir(opts.ovmf_path):
|
|
|
|
errors.append("The OVMF firmware is missing from %s" % opts.ovmf_path)
|
2016-05-17 23:44:22 +00:00
|
|
|
elif opts.virt_uefi and os.path.isdir(opts.ovmf_path):
|
|
|
|
for f in ["OVMF_CODE.fd", "OVMF_VARS.fd"]:
|
|
|
|
if not os.path.exists(joinpaths(opts.ovmf_path, f)):
|
|
|
|
errors.append("OVMF firmware file %s is missing from %s" % (f, opts.ovmf_path))
|
2015-11-04 02:03:09 +00:00
|
|
|
|
2014-04-03 17:22:54 +00:00
|
|
|
if os.getuid() != 0:
|
|
|
|
errors.append("You need to run this as root")
|
2014-03-08 02:43:14 +00:00
|
|
|
|
2014-04-03 17:22:54 +00:00
|
|
|
if errors:
|
2015-05-08 15:39:06 +00:00
|
|
|
list(log.error(e) for e in errors)
|
2014-04-03 17:22:54 +00:00
|
|
|
sys.exit(1)
|
2014-04-02 23:56:28 +00:00
|
|
|
|
2016-01-07 18:16:07 +00:00
|
|
|
if not os.path.exists(opts.result_dir):
|
2015-05-08 15:39:06 +00:00
|
|
|
os.makedirs(opts.result_dir)
|
|
|
|
|
2014-04-02 23:56:28 +00:00
|
|
|
# AMI image is just a fsimage with an AMI label
|
|
|
|
if opts.make_ami:
|
|
|
|
opts.make_fsimage = True
|
|
|
|
if not opts.image_name:
|
|
|
|
opts.image_name = "ami-root.img"
|
|
|
|
if opts.fs_label == "Anaconda":
|
|
|
|
opts.fs_label = "AMI"
|
2014-04-04 21:38:51 +00:00
|
|
|
elif opts.make_tar:
|
|
|
|
if not opts.image_name:
|
2016-03-29 00:20:49 +00:00
|
|
|
opts.image_name = default_image_name(opts.compression, "root.tar")
|
2014-04-04 21:38:51 +00:00
|
|
|
if opts.compression == "xz" and not opts.compress_args:
|
|
|
|
opts.compress_args = ["-9"]
|
2015-10-19 22:35:50 +00:00
|
|
|
elif opts.make_oci:
|
|
|
|
if not opts.image_name:
|
2016-03-29 00:20:49 +00:00
|
|
|
opts.image_name = default_image_name(opts.compression, "bundle.tar")
|
2015-10-19 22:35:50 +00:00
|
|
|
if opts.compression == "xz" and not opts.compress_args:
|
|
|
|
opts.compress_args = ["-9"]
|
2015-10-19 22:30:33 +00:00
|
|
|
elif opts.make_vagrant:
|
|
|
|
if not opts.image_name:
|
2016-03-29 00:20:49 +00:00
|
|
|
opts.image_name = default_image_name(opts.compression, "vagrant.tar")
|
2015-10-19 22:30:33 +00:00
|
|
|
if opts.compression == "xz" and not opts.compress_args:
|
|
|
|
opts.compress_args = ["-9"]
|
2014-04-02 23:56:28 +00:00
|
|
|
|
2012-05-24 22:55:46 +00:00
|
|
|
if opts.app_file:
|
2015-03-20 00:22:16 +00:00
|
|
|
opts.app_file = joinpaths(opts.result_dir, opts.app_file)
|
2012-05-24 22:55:46 +00:00
|
|
|
|
2014-07-30 15:59:27 +00:00
|
|
|
if opts.make_ostree_live:
|
|
|
|
opts.make_pxe_live = True
|
|
|
|
opts.ostree = True
|
|
|
|
else:
|
|
|
|
opts.ostree = False
|
|
|
|
|
2012-05-11 20:12:17 +00:00
|
|
|
tempfile.tempdir = opts.tmp
|
2012-05-24 22:55:46 +00:00
|
|
|
disk_img = None
|
2012-05-11 20:12:17 +00:00
|
|
|
|
2018-05-02 16:55:46 +00:00
|
|
|
try:
|
|
|
|
# TODO - Better API than passing in opts
|
|
|
|
(result_dir, disk_img) = run_creator(opts)
|
|
|
|
except Exception as e: # pylint: disable=broad-except
|
|
|
|
log.error(str(e))
|
|
|
|
sys.exit(1)
|
2011-09-24 00:36:09 +00:00
|
|
|
|
|
|
|
log.info("SUMMARY")
|
|
|
|
log.info("-------")
|
2015-05-01 00:10:08 +00:00
|
|
|
log.info("Logs are in %s", os.path.abspath(os.path.dirname(opts.logfile)))
|
2012-05-24 22:55:46 +00:00
|
|
|
if disk_img:
|
2015-05-01 00:10:08 +00:00
|
|
|
log.info("Disk image is at %s", disk_img)
|
2012-05-24 22:55:46 +00:00
|
|
|
if opts.make_appliance:
|
2015-05-01 00:10:08 +00:00
|
|
|
log.info("Appliance description is in %s", opts.app_file)
|
2016-01-07 18:16:07 +00:00
|
|
|
log.info("Results are in %s", result_dir or opts.result_dir)
|
2011-09-24 00:36:09 +00:00
|
|
|
|
|
|
|
sys.exit( 0 )
|
|
|
|
|
2014-05-09 00:22:14 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|