c35e655d66
Allow memory > maxmem, anyway it will be enforced at VM boot. This allows to set memory and maxmem in any order. Also required to increase memory for HVM.
373 lines
12 KiB
Python
Executable File
373 lines
12 KiB
Python
Executable File
#!/usr/bin/python2.6
|
|
#
|
|
# 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 QubesHost
|
|
from qubes.qubes import qubes_kernels_base_dir
|
|
from optparse import OptionParser
|
|
import subprocess
|
|
import os
|
|
import sys
|
|
import re
|
|
|
|
def do_list(vm):
|
|
label_width = 18
|
|
fmt="{{0:<{0}}}: {{1}}".format(label_width)
|
|
|
|
print fmt.format ("name", vm.name)
|
|
print fmt.format ("label", vm.label.name)
|
|
print fmt.format ("type", vm.type)
|
|
if vm.template is not None:
|
|
print fmt.format ("template", vm.template.name)
|
|
if vm.netvm is not None:
|
|
print fmt.format ("netvm", vm.netvm.name)
|
|
print fmt.format ("updateable?", vm.updateable)
|
|
print fmt.format ("installed by RPM?", vm.installed_by_rpm)
|
|
print fmt.format ("include in backups", vm.include_in_backups)
|
|
print fmt.format ("dir", vm.dir_path)
|
|
print fmt.format ("config", vm.conf_file)
|
|
print fmt.format ("pcidevs", vm.pcidevs)
|
|
if vm.template is None:
|
|
print fmt.format ("root img", vm.root_img)
|
|
if vm.is_template():
|
|
print fmt.format ("root COW img", vm.rootcow_img)
|
|
if vm.template is not None:
|
|
print fmt.format ("root img", vm.template.root_img)
|
|
if hasattr(vm, 'volatile_img'):
|
|
print fmt.format ("root volatile img", vm.volatile_img)
|
|
|
|
if hasattr(vm, 'private_img'):
|
|
print fmt.format ("private img", vm.private_img)
|
|
print fmt.format ("vcpus", str(vm.vcpus))
|
|
print fmt.format ("memory", vm.memory)
|
|
if hasattr(vm, 'maxmem'):
|
|
print fmt.format ("maxmem", vm.maxmem)
|
|
print fmt.format ("MAC", "%s%s" % (vm.mac, " (auto)" if vm._mac is None else ""))
|
|
if hasattr(vm, 'kernel'):
|
|
if vm.uses_default_kernel:
|
|
print fmt.format ("kernel", "%s (default)" % vm.kernel)
|
|
else:
|
|
print fmt.format ("kernel", vm.kernel)
|
|
if hasattr(vm, 'kernelopts'):
|
|
if vm.uses_default_kernelopts:
|
|
print fmt.format ("kernelopts", "%s (default)" % vm.kernelopts)
|
|
else:
|
|
print fmt.format ("kernelopts", vm.kernelopts)
|
|
if hasattr(vm, 'debug'):
|
|
print fmt.format("debug", "on" if vm.debug else "off")
|
|
|
|
def set_label(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing label name argument!"
|
|
exit (1)
|
|
|
|
label = args[0]
|
|
if 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)
|
|
|
|
vm.label = QubesVmLabels[label]
|
|
|
|
def set_memory(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing memory argument!"
|
|
exit (1)
|
|
|
|
new_memory = int(args[0])
|
|
|
|
if new_memory <= 0:
|
|
print >>sys.stderr, "Memory size must be positive"
|
|
return False
|
|
|
|
qubes_host = QubesHost()
|
|
if new_memory > qubes_host.memory_total/1024:
|
|
print >> sys.stderr, "This host has only {0} MB of RAM".format(qubes_host.memory_total/1024)
|
|
return False
|
|
|
|
vm.memory = new_memory
|
|
|
|
def set_maxmem(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing maxmem argument!"
|
|
exit (1)
|
|
|
|
new_maxmem = int(args[0])
|
|
|
|
if new_maxmem <= 0:
|
|
print >>sys.stderr, "Memory size must be positive"
|
|
return False
|
|
|
|
qubes_host = QubesHost()
|
|
if new_maxmem > qubes_host.memory_total/1024:
|
|
print >> sys.stderr, "This host has only {0} MB of RAM".format(qubes_host.memory_total/1024)
|
|
return False
|
|
|
|
if new_maxmem < vm.memory:
|
|
print >> sys.stderr, "WARNING: new maxmem smaller than memory property - VM will be able to use only 'maxmem' memory amount"
|
|
|
|
vm.maxmem = new_maxmem
|
|
|
|
def set_mac(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing MAC argument!"
|
|
exit (1)
|
|
|
|
if not re.match("[0-9a-fA-F:]{17}|auto", args[0]):
|
|
print >> sys.stderr, "Invalid MAC argument!"
|
|
print >> sys.stderr, "Possible values:"
|
|
print >> sys.stderr, "1) auto"
|
|
print >> sys.stderr, "2) MAC in format: XX:XX:XX:XX:XX:XX"
|
|
exit (1)
|
|
|
|
mac = args[0]
|
|
if mac == "auto":
|
|
mac = None
|
|
vm.mac = mac
|
|
|
|
def set_pcidevs(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing pcidevs argument!"
|
|
exit (1)
|
|
|
|
vm.pcidevs = list(eval(args[0]))
|
|
|
|
def set_netvm(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing netvm name argument!"
|
|
print >> sys.stderr, "Possible values:"
|
|
print >> sys.stderr, "1) default"
|
|
print >> sys.stderr, "2) none"
|
|
print >> sys.stderr, "3) <vmaname>"
|
|
return
|
|
|
|
netvm = args[0]
|
|
if netvm == "none":
|
|
netvm = None
|
|
vm.uses_default_netvm = False
|
|
elif netvm == "default":
|
|
netvm = vms.get_default_netvm()
|
|
vm.uses_default_netvm = True
|
|
else:
|
|
netvm = vms.get_vm_by_name (netvm)
|
|
if netvm is None:
|
|
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(netvm)
|
|
exit(1)
|
|
if not netvm.is_netvm():
|
|
print >> sys.stderr, "VM '{0}' is not a NetVM".format(netvm)
|
|
exit (1)
|
|
vm.uses_default_netvm = False
|
|
|
|
vm.netvm = netvm
|
|
|
|
def set_kernel(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing kernel version argument!"
|
|
print >> sys.stderr, "Possible values:"
|
|
print >> sys.stderr, "1) default"
|
|
print >> sys.stderr, "2) none (kernels subdir in VM)"
|
|
print >> sys.stderr, "3) <kernel version>, one of:"
|
|
for k in os.listdir(qubes_kernels_base_dir):
|
|
print >> sys.stderr, " -", k
|
|
return
|
|
|
|
kernel = args[0]
|
|
if kernel == "default":
|
|
kernel = vms.get_default_kernel()
|
|
vm.uses_default_kernel = True
|
|
elif kernel == "none":
|
|
kernel = None
|
|
vm.uses_default_kernel = False
|
|
else:
|
|
if not os.path.exists(qubes_kernels_base_dir + '/' + kernel):
|
|
print >> sys.stderr, "Kernel version {0} not installed.".format(kernel)
|
|
exit(1)
|
|
vm.uses_default_kernel = False
|
|
|
|
vm.kernel = kernel
|
|
|
|
def set_template(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing template name argument!"
|
|
return False
|
|
|
|
template_name = args[0];
|
|
template = vms.get_vm_by_name(template_name)
|
|
if template is None or template.qid not in vms:
|
|
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(template_name)
|
|
return False
|
|
|
|
if not template.is_template():
|
|
print >> sys.stderr, "VM '{0}' is not a TemplateVM".format(template_name)
|
|
return False
|
|
|
|
print >> sys.stderr, "Setting template for VM '{0}' to '{1}'...".format (vm.name, template_name)
|
|
vm.template = template
|
|
return True
|
|
|
|
def set_vcpus(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing vcpus count argument!"
|
|
return False
|
|
|
|
vcpus = int(args[0])
|
|
if vcpus <= 0:
|
|
print >> sys.stderr, "A vcpus count must be positive."
|
|
return False
|
|
|
|
qubes_host = QubesHost()
|
|
if vcpus > qubes_host.no_cpus:
|
|
print >> sys.stderr, "This host has only {0} cpus".format(ubes_host.no_cpus)
|
|
return False
|
|
|
|
print >> sys.stderr, "Setting vcpus count for VM '{0}' to '{1}'...".format (vm.name, vcpus)
|
|
vm.vcpus = vcpus
|
|
return True
|
|
|
|
def set_kernelopts(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing kernel opts argument!"
|
|
print >> sys.stderr, "Possible values:"
|
|
print >> sys.stderr, "1) default"
|
|
print >> sys.stderr, "2) <opts>"
|
|
return False
|
|
|
|
if args[0] == 'default':
|
|
vm.uses_default_kernelopts = True
|
|
else:
|
|
vm.uses_default_kernelopts = False
|
|
vm.kernelopts = args[0]
|
|
|
|
return True
|
|
|
|
def set_name(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing new name!"
|
|
return False
|
|
|
|
if args[0] == vm.name:
|
|
return False
|
|
vm.set_name(args[0])
|
|
return True
|
|
|
|
|
|
def set_debug(vms, vm, args):
|
|
if len (args) != 1:
|
|
print >> sys.stderr, "Missing value (True/False or on/off)!"
|
|
return False
|
|
|
|
if args[0].lower() == "on":
|
|
vm.debug = True
|
|
elif args[0].lower() == "off":
|
|
vm.debug = False
|
|
else:
|
|
vm.debug = bool(eval(args[0].capitalize()))
|
|
return True
|
|
|
|
properties = {
|
|
"include_in_backups": set_include_in_backups,
|
|
"pcidevs": set_pcidevs,
|
|
"label" : set_label,
|
|
"netvm" : set_netvm,
|
|
"maxmem" : set_maxmem,
|
|
"memory" : set_memory,
|
|
"kernel" : set_kernel,
|
|
"template" : set_template,
|
|
"vcpus" : set_vcpus,
|
|
"kernelopts": set_kernelopts,
|
|
"name": set_name,
|
|
"mac": set_mac,
|
|
"debug": set_debug,
|
|
}
|
|
|
|
|
|
def do_set(vms, vm, property, args):
|
|
if property not in properties.keys():
|
|
print >> sys.stderr, "ERROR: Wrong property name: '{0}'".format(property)
|
|
return False
|
|
|
|
if not hasattr(vm, property):
|
|
print >> sys.stderr, "ERROR: Property '{0}' not available for this VM".format(property)
|
|
return False
|
|
|
|
return properties[property](vms, vm, args)
|
|
|
|
|
|
def main():
|
|
usage = "usage: %prog -l [options] <vm-name>\n"\
|
|
"usage: %prog -s [options] <vm-name> <property> [...]\n"\
|
|
"List/set various per-VM properties."
|
|
|
|
parser = OptionParser (usage)
|
|
parser.add_option ("-l", "--list", action="store_true", dest="do_list", default=False)
|
|
parser.add_option ("-s", "--set", action="store_true", dest="do_set", default=False)
|
|
|
|
(options, args) = parser.parse_args ()
|
|
if (len (args) < 1):
|
|
parser.error ("You must provide at least the vmname!")
|
|
|
|
vmname = args[0]
|
|
|
|
if options.do_list and options.do_set:
|
|
print >> sys.stderr, "You cannot provide -l and -s at the same time!"
|
|
exit (1)
|
|
|
|
|
|
|
|
if options.do_set:
|
|
qvm_collection = QubesVmCollection()
|
|
qvm_collection.lock_db_for_writing()
|
|
qvm_collection.load()
|
|
else:
|
|
qvm_collection = QubesVmCollection()
|
|
qvm_collection.lock_db_for_reading()
|
|
qvm_collection.load()
|
|
qvm_collection.unlock_db()
|
|
|
|
vm = qvm_collection.get_vm_by_name(vmname)
|
|
if vm is None or vm.qid not in qvm_collection:
|
|
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
|
|
exit(1)
|
|
|
|
if options.do_set:
|
|
if len (args) < 2:
|
|
print >> sys.stderr, "You must specify the property you wish to set..."
|
|
print >> sys.stderr, "Available properties:"
|
|
for p in properties.keys():
|
|
if hasattr(vm, p):
|
|
print >> sys.stderr, "--> '{0}'".format(p)
|
|
exit (1)
|
|
|
|
property = args[1]
|
|
do_set(qvm_collection, vm, property, args[2:])
|
|
qvm_collection.save()
|
|
qvm_collection.unlock_db()
|
|
|
|
|
|
else:
|
|
# do_list
|
|
do_list(vm)
|
|
|
|
main()
|