90393c33f2
This is required to create VMs in process of building Live system, where libvirt isn't running. Additionally there is no udev in the build environment, so needs to manually create /dev/loop*p* based on sysfs info.
214 lines
8.5 KiB
Python
Executable File
214 lines
8.5 KiB
Python
Executable File
#!/usr/bin/python2
|
|
# -*- encoding: utf8 -*-
|
|
#
|
|
# The Qubes OS Project, http://www.qubes-os.org
|
|
#
|
|
# Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
|
|
#
|
|
# 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, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
#
|
|
|
|
from qubes.qubes import QubesVmCollection
|
|
from qubes.qubes import QubesVmLabels
|
|
from qubes.qubes import QubesException
|
|
from optparse import OptionParser;
|
|
import subprocess
|
|
import re
|
|
import os
|
|
import sys
|
|
from qubes.qubes import vmm
|
|
|
|
|
|
def main():
|
|
usage = "usage: %prog [options] <vm-name>"
|
|
parser = OptionParser (usage)
|
|
parser.add_option ("-t", "--template", dest="template",
|
|
help="Specify the TemplateVM to use")
|
|
parser.add_option ("-l", "--label", dest="label",
|
|
help="Specify the label to use for the new VM (e.g. red, yellow, green, ...)")
|
|
parser.add_option ("-p", "--proxy", action="store_true", dest="proxyvm", default=False,
|
|
help="Create ProxyVM")
|
|
parser.add_option ("-H", "--hvm", action="store_true", dest="hvm", default=False,
|
|
help="Create HVM (standalone unless --template option used)")
|
|
parser.add_option ("--hvm-template", action="store_true", dest="hvm_template", default=False,
|
|
help="Create HVM template")
|
|
parser.add_option ("-n", "--net", action="store_true", dest="netvm", default=False,
|
|
help="Create NetVM")
|
|
parser.add_option ("-s", "--standalone", action="store_true", dest="standalone", default=False,
|
|
help="Create standalone VM - independent of template ")
|
|
parser.add_option ("-R", "--root-move-from", dest="root_move", default=None,
|
|
help="Use provided root.img instead of default/empty one (file will be MOVED)")
|
|
parser.add_option ("-r", "--root-copy-from", dest="root_copy", default=None,
|
|
help="Use provided root.img instead of default/empty one (file will be COPIED)")
|
|
parser.add_option ("-m", "--mem", dest="mem", default=None,
|
|
help="Initial memory size (in MB)")
|
|
parser.add_option ("-c", "--vcpus", dest="vcpus", default=None,
|
|
help="VCPUs count")
|
|
parser.add_option ("--offline-mode", dest="offline_mode",
|
|
action="store_true", default=False,
|
|
help="Offline mode")
|
|
parser.add_option ("-i", "--internal", action="store_true", dest="internal", default=False,
|
|
help="Create VM for internal use only (hidden in qubes-manager, no appmenus)")
|
|
parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
|
|
help="Force to run, even with root privileges")
|
|
|
|
parser.add_option ("-q", "--quiet", action="store_false", dest="verbose", default=True)
|
|
(options, args) = parser.parse_args ()
|
|
if (len (args) != 1):
|
|
parser.error ("You must specify VM name!")
|
|
vmname = args[0]
|
|
|
|
if (options.netvm + options.proxyvm + options.hvm + options.hvm_template) > 1:
|
|
parser.error ("You must specify at most one VM type switch")
|
|
|
|
if hasattr(os, "geteuid") and os.geteuid() == 0:
|
|
print >> sys.stderr, "*** Running this tool as root is strongly discouraged, this will lead you in permissions problems."
|
|
if options.force_root:
|
|
print >> sys.stderr, "Continuing as commanded. You have been warned."
|
|
else:
|
|
print >> sys.stderr, "Retry as unprivileged user."
|
|
print >> sys.stderr, "... or use --force-root to continue anyway."
|
|
exit(1)
|
|
|
|
if options.label is None:
|
|
print >> sys.stderr, "You must choose a label for the new VM by passing the --label option."
|
|
print >> sys.stderr, "Possible values are:"
|
|
for l in QubesVmLabels.values():
|
|
print >> sys.stderr, "* {0}".format(l.name)
|
|
exit (1)
|
|
|
|
if options.label not in QubesVmLabels:
|
|
print >> sys.stderr, "Wrong label name, supported values are the following:"
|
|
for l in QubesVmLabels.values():
|
|
print >> sys.stderr, "* {0}".format(l.name)
|
|
exit (1)
|
|
label = QubesVmLabels[options.label]
|
|
|
|
if options.hvm and not options.template:
|
|
options.standalone = True
|
|
|
|
if options.hvm_template:
|
|
options.standalone = True
|
|
|
|
if not options.standalone and any([options.root_copy, options.root_move]):
|
|
print >> sys.stderr, "root.img can be specified only for standalone VMs"
|
|
exit (1)
|
|
|
|
if options.hvm_template and options.template is not None:
|
|
print >> sys.stderr, "Template VM cannot be based on another template"
|
|
exit (1)
|
|
|
|
if options.root_copy and options.root_move:
|
|
print >> sys.stderr, "Only one of --root-move-from and --root-copy from can be specified"
|
|
exit(1)
|
|
|
|
if options.root_copy is not None and not os.path.exists(options.root_copy):
|
|
print >> sys.stderr, "File specified as root.img does not exists"
|
|
exit (1)
|
|
|
|
if options.root_move is not None and not os.path.exists(options.root_move):
|
|
print >> sys.stderr, "File specified as root.img does not exists"
|
|
exit (1)
|
|
|
|
if options.offline_mode:
|
|
vmm.offline_mode = True
|
|
|
|
qvm_collection = QubesVmCollection()
|
|
qvm_collection.lock_db_for_writing()
|
|
qvm_collection.load()
|
|
|
|
if qvm_collection.get_vm_by_name(vmname) is not None:
|
|
print >> sys.stderr, "A VM with the name '{0}' already exists in the system.".format(vmname)
|
|
exit(1)
|
|
|
|
template = None
|
|
if options.template is not None:
|
|
template = qvm_collection.get_vm_by_name(options.template)
|
|
if template is None:
|
|
print >> sys.stderr, "There is no (Template)VM with the name '{0}'".format(options.template)
|
|
exit (1)
|
|
if not template.is_template():
|
|
print >> sys.stderr, "VM '{0}' is not a TemplateVM".format(options.template)
|
|
exit (1)
|
|
if (options.verbose):
|
|
print "--> Using TemplateVM: {0}".format(template.name)
|
|
|
|
elif not options.hvm and not options.hvm_template:
|
|
if qvm_collection.get_default_template() is None:
|
|
print >> sys.stderr, "No default TemplateVM defined!"
|
|
exit (1)
|
|
else:
|
|
template = qvm_collection.get_default_template()
|
|
if (options.verbose):
|
|
print "--> Using default TemplateVM: {0}".format(template.name)
|
|
|
|
if options.standalone:
|
|
new_vm_template = None
|
|
else:
|
|
new_vm_template = template
|
|
|
|
vm = None
|
|
if options.netvm:
|
|
vmtype = "QubesNetVm"
|
|
elif options.proxyvm:
|
|
vmtype = "QubesProxyVm"
|
|
elif options.hvm:
|
|
vmtype = "QubesHVm"
|
|
elif options.hvm_template:
|
|
vmtype = "QubesTemplateHVm"
|
|
else:
|
|
vmtype = "QubesAppVm"
|
|
|
|
try:
|
|
vm = qvm_collection.add_new_vm(vmtype, name=vmname, template=new_vm_template, label = label)
|
|
except QubesException as err:
|
|
print >> sys.stderr, "ERROR: {0}".format(err)
|
|
exit (1)
|
|
|
|
if options.internal:
|
|
vm.internal = True
|
|
|
|
if options.mem is not None:
|
|
vm.memory = options.mem
|
|
|
|
if options.vcpus is not None:
|
|
vm.vcpus = options.vcpus
|
|
|
|
try:
|
|
vm.create_on_disk(verbose=options.verbose, source_template=template)
|
|
if options.root_move:
|
|
if (options.verbose):
|
|
print "--> Replacing root.img with provided file"
|
|
os.unlink(vm.root_img)
|
|
os.rename(options.root_move, vm.root_img)
|
|
elif options.root_copy:
|
|
if (options.verbose):
|
|
print "--> Replacing root.img with provided file"
|
|
os.unlink(vm.root_img)
|
|
# use "cp" to preserve sparse file
|
|
subprocess.check_call(["cp", options.root_copy, vm.root_img])
|
|
|
|
except (IOError, OSError) as err:
|
|
print >> sys.stderr, "ERROR: {0}".format(err)
|
|
exit (1)
|
|
|
|
|
|
qvm_collection.save()
|
|
qvm_collection.unlock_db()
|
|
|
|
|
|
main()
|