ia64/xen-unstable

changeset 1185:a6e98694ed63

bitkeeper revision 1.800 (4055ee59_zI1OKOsC2EKXBIYFm3OtA)

console_client.py, __init__.py, setup.py, Makefile:
new file
Many files:
New console-terminal client in xenctl.console_client Python package. New option to xc_dom_create (-c on cmdline or auto_console in defaults file) to automatically become a console client.
utils.py:
Rename: tools/xc/py/XenoUtil.py -> tools/xenctl/lib/utils.py
author kaf24@scramble.cl.cam.ac.uk
date Mon Mar 15 17:56:41 2004 +0000 (2004-03-15)
parents bb70629cf346
children 9a94605e84aa
files .rootkeys README.CD docs/VBD-HOWTO.txt docs/Xeno-HOWTO.txt tools/Makefile tools/examples/README tools/examples/defaults tools/examples/democd tools/examples/netbsd tools/examples/xc_dom_control.py tools/examples/xc_dom_create.py tools/examples/xc_vd_tool.py tools/xc/py/XenoUtil.py tools/xc/py/setup.py tools/xenctl/Makefile tools/xenctl/lib/__init__.py tools/xenctl/lib/console_client.py tools/xenctl/lib/utils.py tools/xenctl/setup.py
line diff
     1.1 --- a/.rootkeys	Mon Mar 15 15:54:37 2004 +0000
     1.2 +++ b/.rootkeys	Mon Mar 15 17:56:41 2004 +0000
     1.3 @@ -86,8 +86,12 @@ 3fbba6dcoGq9hQlksrBUfC2P5F6sGg tools/xc/
     1.4  3fbba6dc38q-ioRlwSR_quw4G3qUeQ tools/xc/lib/xc_vif.c
     1.5  3fbd0a3dTwnDcfdw0-v46dPbX98zDw tools/xc/py/Makefile
     1.6  3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/xc/py/Xc.c
     1.7 -3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xc/py/XenoUtil.py
     1.8  3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py
     1.9 +4055ee41IfFazrwadCH2J72nz-A9YA tools/xenctl/Makefile
    1.10 +4055ee4b_4Rvns_KzE12csI14EKK6Q tools/xenctl/lib/__init__.py
    1.11 +4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xenctl/lib/console_client.py
    1.12 +3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xenctl/lib/utils.py
    1.13 +4055ee44Bu6oP7U0WxxXypbUt4dNPQ tools/xenctl/setup.py
    1.14  40431ac64Hj4ixUnKmlugZKhXPFE_Q tools/xend/Makefile
    1.15  4055ad95Se-FqttgxollqOAAHB94zA tools/xend/lib/__init__.py
    1.16  4055ad97wMLUj0BZT0e_T0EwQN0Bvw tools/xend/lib/console.py
     2.1 --- a/README.CD	Mon Mar 15 15:54:37 2004 +0000
     2.2 +++ b/README.CD	Mon Mar 15 17:56:41 2004 +0000
     2.3 @@ -464,11 +464,6 @@ You can rebuild Xen and the tools by typ
     2.4  them to the standard directories with 'make install', or into the
     2.5  ../install subtree with 'make dist'.
     2.6  
     2.7 -/usr/local/bin/xc_*   	the domain control tools
     2.8 -/lib/libxc.so		the xc library
     2.9 -/usr/lib/python2.2/site-packages/XenoUtil.py	python util library
    2.10 -/usr/lib/python2.2/site-packages/Xc.c		python xc bindings
    2.11 -
    2.12  If you're using the virtual disk control tools (xc_vd_tool) you'll
    2.13  need the SQLite library and python binding pysqlite.  There's a tar
    2.14  ball containing the necessary binaries on the project downloads page.
     3.1 --- a/docs/VBD-HOWTO.txt	Mon Mar 15 15:54:37 2004 +0000
     3.2 +++ b/docs/VBD-HOWTO.txt	Mon Mar 15 17:56:41 2004 +0000
     3.3 @@ -152,7 +152,7 @@ freespace -	     Get the free space (in 
     3.4  		     new virtual disk extents.
     3.5  
     3.6  The functionality provided by these scripts is also available directly from
     3.7 -Python functions in the XenoUtil module - you can use this functionality in
     3.8 +Python functions in the xenctl.utils module - you can use this functionality in
     3.9  your own scripts.
    3.10  
    3.11  Populating VDs:
     4.1 --- a/docs/Xeno-HOWTO.txt	Mon Mar 15 15:54:37 2004 +0000
     4.2 +++ b/docs/Xeno-HOWTO.txt	Mon Mar 15 17:56:41 2004 +0000
     4.3 @@ -312,10 +312,10 @@ provide access to privileged command ope
     4.4  In this way you can see that the class 'xc' contains useful
     4.5  documentation for you to consult.
     4.6  
     4.7 -A further module of useful routines (XenoUtil) is also installed:
     4.8 +A further package of useful routines (xenctl) is also installed:
     4.9  
    4.10 -# import XenoUtil
    4.11 -# help(XenoUtil)
    4.12 +# import xenctl.utils
    4.13 +# help(xenctl.utils)
    4.14  
    4.15  You can use these modules to write your own custom scripts or you can
    4.16  customise the scripts supplied in the Xen distribution.
     5.1 --- a/tools/Makefile	Mon Mar 15 15:54:37 2004 +0000
     5.2 +++ b/tools/Makefile	Mon Mar 15 17:56:41 2004 +0000
     5.3 @@ -23,6 +23,7 @@ all:
     5.4  	$(MAKE) -C misc
     5.5  	$(MAKE) -C examples
     5.6  	$(MAKE) -C xentrace
     5.7 +	$(MAKE) -C xenctl
     5.8  	$(MAKE) -C xend
     5.9  
    5.10  install: all
    5.11 @@ -31,6 +32,7 @@ install: all
    5.12  	$(MAKE) -C misc install
    5.13  	$(MAKE) -C examples install
    5.14  	$(MAKE) -C xentrace install
    5.15 +	$(MAKE) -C xenctl install
    5.16  	$(MAKE) -C xend install
    5.17  
    5.18  clean:
    5.19 @@ -40,5 +42,6 @@ clean:
    5.20  	$(MAKE) -C examples clean
    5.21  	$(MAKE) -C nsplitd clean
    5.22  	$(MAKE) -C xentrace clean
    5.23 +	$(MAKE) -C xenctl clean
    5.24  	$(MAKE) -C xend clean
    5.25  
     6.1 --- a/tools/examples/README	Mon Mar 15 15:54:37 2004 +0000
     6.2 +++ b/tools/examples/README	Mon Mar 15 17:56:41 2004 +0000
     6.3 @@ -5,7 +5,7 @@ This directory contains a set of example
     6.4  For many operations you will either be able to use these scripts directly, or
     6.5  incorporate code from them into your own scripts.
     6.6  
     6.7 -The Xc and XenoUtil Python modules provide an API for accessing all this
     6.8 +The Xc and xenctl.utils Python modules provide an API for accessing all this
     6.9  functionality - and more - from your own Python programs.  These libraries may
    6.10  contain features for which there aren't yet example scripts written for...
    6.11  
     7.1 --- a/tools/examples/defaults	Mon Mar 15 15:54:37 2004 +0000
     7.2 +++ b/tools/examples/defaults	Mon Mar 15 17:56:41 2004 +0000
     7.3 @@ -42,8 +42,8 @@ domain_name = "This is VM %d" % vmid
     7.4  # appropriately.
     7.5  
     7.6  #vfr_ipaddr = ["111.222.333.444","222.333.444.555"]
     7.7 -vfr_ipaddr  = [XenoUtil.add_offset_to_ip(XenoUtil.get_current_ipaddr(),vmid),
     7.8 -	       XenoUtil.add_offset_to_ip('169.254.1.0',vmid),]
     7.9 +vfr_ipaddr  = [xenctl.utils.add_offset_to_ip(xenctl.utils.get_current_ipaddr(),vmid),
    7.10 +	       xenctl.utils.add_offset_to_ip('169.254.1.0',vmid),]
    7.11  
    7.12  
    7.13  # STEP 5a. Identify any physcial partitions or virtual disks you want the
    7.14 @@ -72,8 +72,8 @@ vbd_expert = 0
    7.15  # You can use 'extrabit' to set the runlevel and custom environment
    7.16  # variables used by custom rc scripts (e.g. VMID=, usr= )
    7.17  
    7.18 -netmask = XenoUtil.get_current_ipmask()
    7.19 -gateway = XenoUtil.get_current_ipgw()
    7.20 +netmask = xenctl.utils.get_current_ipmask()
    7.21 +gateway = xenctl.utils.get_current_ipgw()
    7.22  nfsserv = '169.254.1.0'  
    7.23  
    7.24  cmdline_ip = "ip="+vfr_ipaddr[0]+":"+nfsserv+":"+gateway+":"+netmask+"::eth0:off"
     8.1 --- a/tools/examples/democd	Mon Mar 15 15:54:37 2004 +0000
     8.2 +++ b/tools/examples/democd	Mon Mar 15 17:56:41 2004 +0000
     8.3 @@ -49,7 +49,7 @@ else:
     8.4  # appropriately.
     8.5  
     8.6  #vfr_ipaddr = ["111.222.333.444","222.333.444.555"]
     8.7 -#vfr_ipaddr  = [XenoUtil.add_offset_to_ip(XenoUtil.get_current_ipaddr(),vmid)]
     8.8 +#vfr_ipaddr  = [xenctl.utils.add_offset_to_ip(xenctl.utils.get_current_ipaddr(),vmid)]
     8.9  vfr_ipaddr  = map(socket.gethostbyname,string.split(ip,','))
    8.10  
    8.11  
    8.12 @@ -83,7 +83,7 @@ vbd_expert = 0
    8.13  # see if we have a local IP at all
    8.14  localip=''
    8.15  for i in vfr_ipaddr:
    8.16 -    if XenoUtil.check_subnet(i,'169.254.0.0','255.255.0.0'):
    8.17 +    if xenctl.utils.check_subnet(i,'169.254.0.0','255.255.0.0'):
    8.18  	localip=i
    8.19  	break
    8.20  
    8.21 @@ -99,15 +99,15 @@ try:
    8.22      myip = vfr_ipaddr[0]
    8.23  
    8.24  except NameError:
    8.25 -    netmask = XenoUtil.get_current_ipmask()
    8.26 -    gateway = XenoUtil.get_current_ipgw()
    8.27 +    netmask = xenctl.utils.get_current_ipmask()
    8.28 +    gateway = xenctl.utils.get_current_ipgw()
    8.29  
    8.30  # if we haven't got an address, see if we have one that matches the LAN
    8.31  
    8.32  if not myip:
    8.33      if netmask and gateway:
    8.34  	for i in vfr_ipaddr:
    8.35 -	    if XenoUtil.check_subnet(i,gateway,netmask): 
    8.36 +	    if xenctl.utils.check_subnet(i,gateway,netmask): 
    8.37  		myip=i
    8.38  		break
    8.39  
     9.1 --- a/tools/examples/netbsd	Mon Mar 15 15:54:37 2004 +0000
     9.2 +++ b/tools/examples/netbsd	Mon Mar 15 17:56:41 2004 +0000
     9.3 @@ -57,10 +57,10 @@ except:
     9.4  
     9.5  #vfr_ipaddr = ["111.222.333.444","222.333.444.555"]
     9.6  try:
     9.7 -    vfr_ipaddr = [ip, XenoUtil.add_offset_to_ip('169.254.1.0',vmid),]
     9.8 +    vfr_ipaddr = [ip, xenctl.utils.add_offset_to_ip('169.254.1.0',vmid),]
     9.9  except:
    9.10 -    vfr_ipaddr = [XenoUtil.add_offset_to_ip(XenoUtil.get_current_ipaddr(),vmid),
    9.11 -                  XenoUtil.add_offset_to_ip('169.254.1.0',vmid),]
    9.12 +    vfr_ipaddr = [xenctl.utils.add_offset_to_ip(xenctl.utils.get_current_ipaddr(),vmid),
    9.13 +                  xenctl.utils.add_offset_to_ip('169.254.1.0',vmid),]
    9.14  
    9.15  
    9.16  # STEP 5a. Identify any physcial partitions or virtual disks you want the
    9.17 @@ -89,8 +89,8 @@ vbd_expert = 0
    9.18  # You can use 'extrabit' to set the runlevel and custom environment
    9.19  # variables used by custom rc scripts (e.g. VMID=, usr= )
    9.20  
    9.21 -netmask = XenoUtil.get_current_ipmask()
    9.22 -gateway = XenoUtil.get_current_ipgw()
    9.23 +netmask = xenctl.utils.get_current_ipmask()
    9.24 +gateway = xenctl.utils.get_current_ipgw()
    9.25  try:
    9.26      nfsserv
    9.27  except:
    10.1 --- a/tools/examples/xc_dom_control.py	Mon Mar 15 15:54:37 2004 +0000
    10.2 +++ b/tools/examples/xc_dom_control.py	Mon Mar 15 17:56:41 2004 +0000
    10.3 @@ -184,8 +184,8 @@ elif cmd == 'vif_addip':
    10.4      ip  = sys.argv[4]
    10.5  
    10.6      # XXX This function should be moved to Xc once we sort out the VFR
    10.7 -    import XenoUtil
    10.8 -    XenoUtil.setup_vfr_rules_for_vif( dom, vif, ip )
    10.9 +    import xenctl.utils
   10.10 +    xenctl.utils.setup_vfr_rules_for_vif( dom, vif, ip )
   10.11  
   10.12  elif cmd == 'vif_setsched':
   10.13      if len(sys.argv) < 6:
   10.14 @@ -211,9 +211,9 @@ elif cmd == 'vif_getsched':
   10.15  
   10.16  
   10.17  elif cmd == 'vbd_add':
   10.18 -    import XenoUtil
   10.19 +    import xenctl.utils
   10.20      
   10.21 -    XenoUtil.VBD_EXPERT_LEVEL = 0 # sets the allowed level of potentially unsafe mappings
   10.22 +    xenctl.utils.VBD_EXPERT_LEVEL = 0 # sets the allowed level of potentially unsafe mappings
   10.23  
   10.24      if len(sys.argv) < 6:
   10.25  	usage()
   10.26 @@ -227,17 +227,17 @@ elif cmd == 'vbd_add':
   10.27      if mode == 'rw' or mode == 'w':
   10.28  	writeable = 1;
   10.29  
   10.30 -    segments = XenoUtil.lookup_disk_uname(uname)
   10.31 +    segments = xenctl.utils.lookup_disk_uname(uname)
   10.32  
   10.33      if not segments:
   10.34          print "Lookup Failed"
   10.35          sys.exit(1)
   10.36  
   10.37 -    if XenoUtil.vd_extents_validate(segments,writeable) < 0:
   10.38 +    if xenctl.utils.vd_extents_validate(segments,writeable) < 0:
   10.39  	print "That mapping is too unsafe for the current VBD expertise level"
   10.40  	sys.exit(1)
   10.41  
   10.42 -    virt_dev = XenoUtil.blkdev_name_to_number(dev)
   10.43 +    virt_dev = xenctl.utils.blkdev_name_to_number(dev)
   10.44  
   10.45      xc.vbd_create(dom,virt_dev,writeable)
   10.46  
   10.47 @@ -248,14 +248,14 @@ elif cmd == 'vbd_add':
   10.48      print "Added disk/partition %s to domain %d as device %s (%x)" % (uname, dom, dev, virt_dev)
   10.49  
   10.50  elif cmd == 'vbd_remove':
   10.51 -    import XenoUtil
   10.52 +    import xenctl.utils
   10.53  
   10.54      if len(sys.argv) < 4:
   10.55  	usage()
   10.56  	sys.exit(1)
   10.57  
   10.58      dev = sys.argv[3]
   10.59 -    virt_dev = XenoUtil.blkdev_name_to_number(dev)
   10.60 +    virt_dev = xenctl.utils.blkdev_name_to_number(dev)
   10.61  
   10.62      if not xc.vbd_destroy(dom,virt_dev):
   10.63  	print "Removed disk/partition attached as device %s (%x) in domain %d" % (dev, virt_dev, dom)
    11.1 --- a/tools/examples/xc_dom_create.py	Mon Mar 15 15:54:37 2004 +0000
    11.2 +++ b/tools/examples/xc_dom_create.py	Mon Mar 15 17:56:41 2004 +0000
    11.3 @@ -1,6 +1,7 @@
    11.4  #!/usr/bin/env python
    11.5  
    11.6 -import Xc, XenoUtil, string, sys, os, time, socket, getopt, signal, syslog
    11.7 +import string, sys, os, time, socket, getopt, signal, syslog
    11.8 +import Xc, xenctl.utils, xenctl.console_client
    11.9  
   11.10  config_dir  = '/etc/xc/'
   11.11  config_file = xc_config_file = config_dir + 'defaults'
   11.12 @@ -29,6 +30,7 @@ Arguments to control the parsing of the 
   11.13  def extra_usage ():
   11.14      print >>sys.stderr,"""
   11.15  Arguments to override current config read from '%s':
   11.16 + -c               -- Turn into console terminal after domain is created
   11.17   -k image         -- Path to kernel image ['%s']
   11.18   -r ramdisk       -- Path to ramdisk (or empty) ['%s']
   11.19   -b builder_fn    -- Function to use to build domain ['%s']
   11.20 @@ -86,12 +88,13 @@ mem_size=0; domain_name=''; vfr_ipaddr=[
   11.21  vbd_expert=0; auto_restart=False;
   11.22  vbd_list = []; cmdline_ip = ''; cmdline_root=''; cmdline_extra=''
   11.23  pci_device_list = []
   11.24 +auto_console = False
   11.25  
   11.26  ##### Determine location of defautls file
   11.27  #####
   11.28  
   11.29  try:
   11.30 -    opts, args = getopt.getopt(sys.argv[1:], "h?nqf:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" )
   11.31 +    opts, args = getopt.getopt(sys.argv[1:], "h?nqcf:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" )
   11.32  
   11.33      for opt in opts:
   11.34  	if opt[0] == '-f': config_file= opt[1]
   11.35 @@ -160,6 +163,7 @@ for opt in opts:
   11.36      if opt[0] == '-R': cmdline_root = opt[1]
   11.37      if opt[0] == '-E': cmdline_extra = opt[1]
   11.38      if opt[0] == '-i': x_vfr_ipaddr.append(opt[1])
   11.39 +    if opt[0] == '-c': auto_console = True
   11.40      if opt[0] == '-d':
   11.41  	try:
   11.42  	    vv = string.split(opt[1],';')	    
   11.43 @@ -238,7 +242,7 @@ def make_domain():
   11.44              sys.exit()
   11.45  
   11.46      cmsg = 'new_control_interface(dom='+str(id)+')'
   11.47 -    xend_response = XenoUtil.xend_control_message(cmsg)
   11.48 +    xend_response = xenctl.utils.xend_control_message(cmsg)
   11.49      if not xend_response['success']:
   11.50          print "Error creating initial event channel"
   11.51          print "Error type: " + xend_response['error_type']
   11.52 @@ -251,12 +255,12 @@ def make_domain():
   11.53      # setup the virtual block devices
   11.54  
   11.55      # set the expertise level appropriately
   11.56 -    XenoUtil.VBD_EXPERT_MODE = vbd_expert
   11.57 +    xenctl.utils.VBD_EXPERT_MODE = vbd_expert
   11.58      
   11.59      for ( uname, virt_name, rw ) in vbd_list:
   11.60 -	virt_dev = XenoUtil.blkdev_name_to_number( virt_name )
   11.61 +	virt_dev = xenctl.utils.blkdev_name_to_number( virt_name )
   11.62  
   11.63 -	segments = XenoUtil.lookup_disk_uname( uname )
   11.64 +	segments = xenctl.utils.lookup_disk_uname( uname )
   11.65  	if not segments:
   11.66  	    print "Error looking up %s\n" % uname
   11.67  	    xc.domain_destroy ( dom=id )
   11.68 @@ -264,7 +268,7 @@ def make_domain():
   11.69  
   11.70          # check that setting up this VBD won't violate the sharing
   11.71          # allowed by the current VBD expertise level
   11.72 -        if XenoUtil.vd_extents_validate(segments, rw=='w' or rw=='rw') < 0:
   11.73 +        if xenctl.utils.vd_extents_validate(segments, rw=='w' or rw=='rw') < 0:
   11.74              xc.domain_destroy( dom = id )
   11.75              sys.exit()
   11.76              
   11.77 @@ -282,7 +286,7 @@ def make_domain():
   11.78  
   11.79      # setup virtual firewall rules for all aliases
   11.80      for ip in vfr_ipaddr:
   11.81 -	XenoUtil.setup_vfr_rules_for_vif( id, 0, ip )
   11.82 +	xenctl.utils.setup_vfr_rules_for_vif( id, 0, ip )
   11.83  
   11.84      # check for physical device access
   11.85      for (pci_bus, pci_dev, pci_func) in pci_device_list:
   11.86 @@ -328,6 +332,9 @@ def death_handler(dummy1,dummy2):
   11.87  (current_id, current_port) = make_domain()
   11.88  output("VM started in domain %d. Console I/O available on TCP port %d." % (current_id,current_port))
   11.89  
   11.90 +if auto_console:
   11.91 +    xenctl.console_client.connect('127.0.0.1',int(current_port))
   11.92 +
   11.93  # if the auto_restart flag is set then keep polling to see if the domain is
   11.94  # alive - restart if it is not by calling make_domain() again (it's necessary
   11.95  # to update the id variable, since the new domain may have a new ID)
    12.1 --- a/tools/examples/xc_vd_tool.py	Mon Mar 15 15:54:37 2004 +0000
    12.2 +++ b/tools/examples/xc_vd_tool.py	Mon Mar 15 17:56:41 2004 +0000
    12.3 @@ -1,6 +1,6 @@
    12.4  #!/usr/bin/env python
    12.5  
    12.6 -import XenoUtil, sys, re, string
    12.7 +import xenctl.utils, sys, re, string
    12.8  
    12.9  def usage():
   12.10  
   12.11 @@ -50,7 +50,7 @@ if cmd == 'initialise':
   12.12      print "Device: " + dev
   12.13      print "Extent size: " + str(extent_size) + "MB"
   12.14  
   12.15 -    rc = XenoUtil.vd_format(dev, extent_size)
   12.16 +    rc = xenctl.utils.vd_format(dev, extent_size)
   12.17  
   12.18  elif cmd == 'create':
   12.19   
   12.20 @@ -63,7 +63,7 @@ elif cmd == 'create':
   12.21      print "Size: %d" % size
   12.22      print "Expiry time (seconds from now): %d" % expiry_time
   12.23  
   12.24 -    src = XenoUtil.vd_create(size, expiry_time)
   12.25 +    src = xenctl.utils.vd_create(size, expiry_time)
   12.26  
   12.27  elif cmd == 'enlarge':
   12.28  
   12.29 @@ -71,7 +71,7 @@ elif cmd == 'enlarge':
   12.30  
   12.31      extra_size = int(sys.argv[3])
   12.32  
   12.33 -    rc = XenoUtil.vd_enlarge(id, extra_size)
   12.34 +    rc = xenctl.utils.vd_enlarge(id, extra_size)
   12.35  
   12.36  elif cmd == 'delete':
   12.37  
   12.38 @@ -79,7 +79,7 @@ elif cmd == 'delete':
   12.39  
   12.40      print "Deleting a virtual disk with ID: " + id
   12.41  
   12.42 -    rc = XenoUtil.vd_delete(id)
   12.43 +    rc = xenctl.utils.vd_delete(id)
   12.44  
   12.45  elif cmd == 'import':
   12.46  
   12.47 @@ -90,7 +90,7 @@ elif cmd == 'import':
   12.48  
   12.49      print "Allocate new virtual disk and populate from file : %s" % file
   12.50  
   12.51 -    print XenoUtil.vd_read_from_file(file, expiry_time)
   12.52 +    print xenctl.utils.vd_read_from_file(file, expiry_time)
   12.53  
   12.54  elif cmd == 'export':
   12.55  
   12.56 @@ -99,7 +99,7 @@ elif cmd == 'export':
   12.57  
   12.58      print "Dump contents of virtual disk to file : %s" % file
   12.59  
   12.60 -    rc = XenoUtil.vd_cp_to_file(id, file )
   12.61 +    rc = xenctl.utils.vd_cp_to_file(id, file )
   12.62  
   12.63  elif cmd == 'setexpiry':
   12.64  
   12.65 @@ -112,19 +112,19 @@ elif cmd == 'setexpiry':
   12.66      print "Id: " + id
   12.67      print "Expiry time (seconds from now [or 0]): " + str(expiry_time)
   12.68  
   12.69 -    rc = XenoUtil.vd_refresh(id, expiry_time)
   12.70 +    rc = xenctl.utils.vd_refresh(id, expiry_time)
   12.71  
   12.72  elif cmd == 'list':
   12.73      print 'ID    Size(MB)      Expiry'
   12.74  
   12.75 -    for vbd in XenoUtil.vd_list():
   12.76 +    for vbd in xenctl.utils.vd_list():
   12.77          vbd['size_mb'] = vbd['size'] / 2048
   12.78          vbd['expiry'] = (vbd['expires'] and vbd['expiry_time']) or 'never'
   12.79          print '%(vdisk_id)-4s  %(size_mb)-12d  %(expiry)s' % vbd
   12.80  
   12.81  elif cmd == 'freespace':
   12.82  
   12.83 -    print XenoUtil.vd_freespace()
   12.84 +    print xenctl.utils.vd_freespace()
   12.85  
   12.86  elif cmd == 'undelete':
   12.87  
   12.88 @@ -133,7 +133,7 @@ elif cmd == 'undelete':
   12.89      if len(sys.argv) > 3:
   12.90  	expiry_time = int(sys.argv[3])
   12.91     
   12.92 -    if XenoUtil.vd_undelete(id, expiry_time):
   12.93 +    if xenctl.utils.vd_undelete(id, expiry_time):
   12.94  	print "Undelete operation failed for virtual disk: " + id
   12.95      else:
   12.96  	print "Undelete operation succeeded for virtual disk: " + id
    13.1 --- a/tools/xc/py/XenoUtil.py	Mon Mar 15 15:54:37 2004 +0000
    13.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.3 @@ -1,1014 +0,0 @@
    13.4 -import os, re, socket, string, sys, tempfile
    13.5 -
    13.6 -##### Module variables
    13.7 -
    13.8 -"""Location of the Virtual Disk management database.
    13.9 -   defaults to /var/db/xen_vdisks.sqlite
   13.10 -"""
   13.11 -VD_DB_FILE = "/var/db/xen_vdisks.sqlite"
   13.12 -
   13.13 -"""VBD expertise level - determines the strictness of the sanity checking.
   13.14 -  This mode determines the level of complaints when disk sharing occurs
   13.15 -  through the current VBD mappings.
   13.16 -   0 - only allow shared mappings if both domains have r/o access (always OK)
   13.17 -   1 - also allow sharing with one dom r/w and the other r/o
   13.18 -   2 - allow sharing with both doms r/w
   13.19 -"""
   13.20 -VBD_EXPERT_MODE = 0
   13.21 -
   13.22 -##### Module initialisation
   13.23 -
   13.24 -try:
   13.25 -    # try to import sqlite (not everyone will have it installed)
   13.26 -    import sqlite
   13.27 -except ImportError:
   13.28 -    # on failure, just catch the error, don't do anything
   13.29 -    pass
   13.30 -
   13.31 -
   13.32 -##### Networking-related functions
   13.33 -
   13.34 -def get_current_ipaddr(dev='eth0'):
   13.35 -    """Return a string containing the primary IP address for the given
   13.36 -    network interface (default 'eth0').
   13.37 -    """
   13.38 -    fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
   13.39 -    lines = fd.readlines()
   13.40 -    for line in lines:
   13.41 -        m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
   13.42 -                       line )
   13.43 -        if m:
   13.44 -            return m.group(1)
   13.45 -    return None
   13.46 -
   13.47 -def get_current_ipmask(dev='eth0'):
   13.48 -    """Return a string containing the primary IP netmask for the given
   13.49 -    network interface (default 'eth0').
   13.50 -    """
   13.51 -    fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
   13.52 -    lines = fd.readlines()
   13.53 -    for line in lines:
   13.54 -        m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
   13.55 -                       line )
   13.56 -        if m:
   13.57 -            return m.group(1)
   13.58 -    return None
   13.59 -
   13.60 -def get_current_ipgw(dev='eth0'):
   13.61 -    """Return a string containing the IP gateway for the given
   13.62 -    network interface (default 'eth0').
   13.63 -    """
   13.64 -    fd = os.popen( '/sbin/route -n' )
   13.65 -    lines = fd.readlines()
   13.66 -    for line in lines:
   13.67 -        m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
   13.68 -                       '\s+\S+\s+\S*G.*' + dev + '.*', line )
   13.69 -        if m:
   13.70 -            return m.group(1)
   13.71 -    return None
   13.72 -
   13.73 -def setup_vfr_rules_for_vif(dom,vif,addr):
   13.74 -    """Takes a tuple ( domain-id, vif-id, ip-addr ), where the ip-addr
   13.75 -    is expressed as a textual dotted quad, and set up appropriate routing
   13.76 -    rules in Xen. No return value.
   13.77 -    """
   13.78 -    fd = os.open( '/proc/xen/vfr', os.O_WRONLY )
   13.79 -    if ( re.search( '169\.254', addr) ):
   13.80 -        os.write( fd, 'ADD ACCEPT srcaddr=' + addr +
   13.81 -                  ' srcaddrmask=255.255.255.255' +
   13.82 -                  ' srcdom=' + str(dom) + ' srcidx=' + str(vif) +
   13.83 -                  ' dstdom=0 dstidx=0 proto=any\n' )
   13.84 -    else:
   13.85 -        os.write( fd, 'ADD ACCEPT srcaddr=' + addr +
   13.86 -                  ' srcaddrmask=255.255.255.255' +
   13.87 -                  ' srcdom=' + str(dom) + ' srcidx=' + str(vif) +
   13.88 -                  ' dst=PHYS proto=any\n' )
   13.89 -    os.write( fd, 'ADD ACCEPT dstaddr=' + addr +
   13.90 -              ' dstaddrmask=255.255.255.255' +
   13.91 -              ' src=ANY' +
   13.92 -              ' dstdom=' + str(dom) + ' dstidx=' + str(vif) +
   13.93 -              ' proto=any\n' )
   13.94 -    os.close( fd )
   13.95 -    return None
   13.96 -
   13.97 -def add_offset_to_ip( ip, off ):
   13.98 -    l = string.split(ip,'.')
   13.99 -    a = ( (string.atoi(l[0])<<24) | (string.atoi(l[1])<<16) | 
  13.100 -	  (string.atoi(l[2])<<8)  | string.atoi(l[3]) ) + off
  13.101 -    
  13.102 -    return '%d.%d.%d.%d' % ( ((a>>24)&0xff), ((a>>16)&0xff),
  13.103 -			     ((a>>8)&0xff), (a&0xff) )
  13.104 -
  13.105 -def check_subnet( ip, network, netmask ):
  13.106 -    l = string.split(ip,'.')
  13.107 -    n_ip = ( (string.atoi(l[0])<<24) | (string.atoi(l[1])<<16) | 
  13.108 -	   (string.atoi(l[2])<<8)  | string.atoi(l[3]) ) 
  13.109 -
  13.110 -    l = string.split(network,'.')
  13.111 -    n_net = ( (string.atoi(l[0])<<24) | (string.atoi(l[1])<<16) | 
  13.112 -	   (string.atoi(l[2])<<8)  | string.atoi(l[3]) )
  13.113 -
  13.114 -    l = string.split(netmask,'.')
  13.115 -    n_mask = ( (string.atoi(l[0])<<24) | (string.atoi(l[1])<<16) | 
  13.116 -	   (string.atoi(l[2])<<8)  | string.atoi(l[3]) )
  13.117 -    
  13.118 -    return (n_ip&n_mask)==(n_net&n_mask)
  13.119 -
  13.120 -
  13.121 -##### VBD-related Functions
  13.122 -
  13.123 -def blkdev_name_to_number(name):
  13.124 -    """Take the given textual block-device name (e.g., '/dev/sda1',
  13.125 -    'hda') and return the device number used by the OS. """
  13.126 -
  13.127 -    if not re.match( '/dev/', name ):
  13.128 -        name = '/dev/' + name
  13.129 -        
  13.130 -    return os.stat(name).st_rdev
  13.131 -
  13.132 -# lookup_blkdev_partn_info( '/dev/sda3' )
  13.133 -def lookup_raw_partn(partition):
  13.134 -    """Take the given block-device name (e.g., '/dev/sda1', 'hda')
  13.135 -    and return a dictionary { device, start_sector,
  13.136 -    nr_sectors, type }
  13.137 -        device:       Device number of the given partition
  13.138 -        start_sector: Index of first sector of the partition
  13.139 -        nr_sectors:   Number of sectors comprising this partition
  13.140 -        type:         'Disk' or identifying name for partition type
  13.141 -    """
  13.142 -
  13.143 -    if not re.match( '/dev/', partition ):
  13.144 -        partition = '/dev/' + partition
  13.145 -
  13.146 -    drive = re.split( '[0-9]', partition )[0]
  13.147 -
  13.148 -    if drive == partition:
  13.149 -        fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
  13.150 -        line = fd.readline()
  13.151 -        if line:
  13.152 -            return [ { 'device' : blkdev_name_to_number(drive),
  13.153 -                       'start_sector' : long(0),
  13.154 -                       'nr_sectors' : long(line) * 2,
  13.155 -                       'type' : 'Disk' } ]
  13.156 -        return None
  13.157 -
  13.158 -    # determine position on disk
  13.159 -    fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
  13.160 -
  13.161 -    #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
  13.162 -    lines = fd.readlines()
  13.163 -    for line in lines:
  13.164 -        m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
  13.165 -                       'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
  13.166 -        if m:
  13.167 -            return [ { 'device' : blkdev_name_to_number(drive),
  13.168 -                       'start_sector' : long(m.group(1)),
  13.169 -                       'nr_sectors' : long(m.group(2)),
  13.170 -                       'type' : m.group(3) } ]
  13.171 -    
  13.172 -    return None
  13.173 -
  13.174 -def lookup_disk_uname( uname ):
  13.175 -    """Lookup a list of segments for either a physical or a virtual device.
  13.176 -    uname [string]:  name of the device in the format \'vd:id\' for a virtual
  13.177 -                     disk, or \'phy:dev\' for a physical device
  13.178 -    returns [list of dicts]: list of extents that make up the named device
  13.179 -    """
  13.180 -    ( type, d_name ) = string.split( uname, ':' )
  13.181 -
  13.182 -    if type == "phy":
  13.183 -        segments = lookup_raw_partn( d_name )
  13.184 -    elif type == "vd":
  13.185 -	segments = vd_lookup( d_name )
  13.186 -
  13.187 -    return segments
  13.188 -
  13.189 -
  13.190 -##### Management of the Xen control daemon
  13.191 -##### (c) Keir Fraser, University of Cambridge
  13.192 -
  13.193 -def xend_control_message( message ):
  13.194 -    """Takes a textual control message and sends it to the 'xend' Xen
  13.195 -    control daemon. Returns a dictionary containing the daemon's multi-part
  13.196 -    response."""
  13.197 -    tmpdir = tempfile.mkdtemp()
  13.198 -    try:
  13.199 -        ctl = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
  13.200 -        ctl.bind(tmpdir+'/sock')
  13.201 -        ctl.sendto(message, '/var/run/xend/management_sock')
  13.202 -        data, addr = ctl.recvfrom(2048)
  13.203 -        ctl.close()
  13.204 -    finally:
  13.205 -        if os.path.exists(tmpdir+'/sock'):
  13.206 -            os.unlink(tmpdir+'/sock')
  13.207 -        if os.path.exists(tmpdir):
  13.208 -            os.rmdir(tmpdir)    
  13.209 -    return eval(data)
  13.210 -
  13.211 -
  13.212 -##### VD Management-related functions
  13.213 -
  13.214 -##### By Mark Williamson, <mark.a.williamson@intel.com>
  13.215 -##### (C) Intel Research Cambridge
  13.216 -
  13.217 -# TODO:
  13.218 -#
  13.219 -# Plenty of room for enhancement to this functionality (contributions
  13.220 -# welcome - and then you get to have your name in the source ;-)...
  13.221 -#
  13.222 -# vd_unformat() : want facilities to unallocate virtual disk
  13.223 -# partitions, possibly migrating virtual disks of them, with checks to see if
  13.224 -# it's safe and options to force it anyway
  13.225 -#
  13.226 -# vd_create() : should have an optional argument specifying a physical
  13.227 -# disk preference - useful to allocate for guest doms to do RAID
  13.228 -#
  13.229 -# vd_undelete() : add ability to "best effort" undelete as much of a
  13.230 -# vdisk as is left in the case that some of it has already been
  13.231 -# reallocated.  Some people might still be able to recover some of
  13.232 -# their data this way, even if some of the disk has disappeared.
  13.233 -#
  13.234 -# It'd be nice if we could wipe virtual disks for security purposes -
  13.235 -# should be easy to do this using dev if=/dev/{zero,random} on each
  13.236 -# extent in turn.  There could be another optional flag to vd_create
  13.237 -# in order to allow this.
  13.238 -#
  13.239 -# Error codes could be more expressive - i.e. actually tell why the
  13.240 -# error occurred rather than "it broke".  Currently the code avoids
  13.241 -# using exceptions to make control scripting simpler and more
  13.242 -# accessible to beginners - therefore probably should just use more
  13.243 -# return codes.
  13.244 -#
  13.245 -# Enhancements / additions to the example scripts are also welcome:
  13.246 -# some people will interact with this code mostly through those
  13.247 -# scripts.
  13.248 -#
  13.249 -# More documentation of how this stuff should be used is always nice -
  13.250 -# if you have a novel configuration that you feel isn't discussed
  13.251 -# enough in the HOWTO (which is currently a work in progress), feel
  13.252 -# free to contribute a walkthrough, or something more substantial.
  13.253 -#
  13.254 -
  13.255 -
  13.256 -def __vd_no_database():
  13.257 -    """Called when no database found - exits with an error
  13.258 -    """
  13.259 -    print >> sys.stderr, "ERROR: Could not locate the database file at " + VD_DB_FILE
  13.260 -    sys.exit(1)
  13.261 -
  13.262 -
  13.263 -def vd_format(partition, extent_size_mb):
  13.264 -    """Format a partition or drive for use a virtual disk storage.
  13.265 -    partition [string]: device file representing the partition
  13.266 -    extent_size_mb [string]: extent size in megabytes to use on this disk
  13.267 -    """
  13.268 -
  13.269 -    if not os.path.isfile(VD_DB_FILE):
  13.270 -        vd_init_db(VD_DB_FILE)
  13.271 -    
  13.272 -    if not re.match( '/dev/', partition ):
  13.273 -        partition = '/dev/' + partition
  13.274 -
  13.275 -    cx = sqlite.connect(VD_DB_FILE)
  13.276 -    cu = cx.cursor()
  13.277 -
  13.278 -    cu.execute("select * from vdisk_part where partition = \'"
  13.279 -               + partition + "\'")
  13.280 -    row = cu.fetchone()
  13.281 -
  13.282 -    extent_size = extent_size_mb * 2048 # convert megabytes to sectors
  13.283 -    
  13.284 -    if not row:
  13.285 -        part_info = lookup_raw_partn(partition)[0]
  13.286 -        
  13.287 -        cu.execute("INSERT INTO vdisk_part(partition, part_id, extent_size) " +
  13.288 -                   "VALUES ( \'" + partition + "\', "
  13.289 -                   + str(blkdev_name_to_number(partition))
  13.290 -                   + ", " + str(extent_size) + ")")
  13.291 -
  13.292 -
  13.293 -        cu.execute("SELECT max(vdisk_extent_no) FROM vdisk_extents "
  13.294 -                   + "WHERE vdisk_id = 0")
  13.295 -        
  13.296 -        max_id, = cu.fetchone()
  13.297 -
  13.298 -        if max_id != None:
  13.299 -            new_id = max_id + 1
  13.300 -        else:
  13.301 -            new_id = 0
  13.302 -
  13.303 -        num_extents = part_info['nr_sectors'] / extent_size
  13.304 -
  13.305 -        for i in range(num_extents):
  13.306 -            sql ="""INSERT INTO vdisk_extents(vdisk_extent_no, vdisk_id,
  13.307 -                                              part_id, part_extent_no)
  13.308 -                    VALUES ("""+ str(new_id + i) + ", 0, "\
  13.309 -                               + str(blkdev_name_to_number(partition))\
  13.310 -                               + ", " + str(num_extents - (i + 1)) + ")"
  13.311 -            cu.execute(sql)
  13.312 -
  13.313 -    cx.commit()
  13.314 -    cx.close()
  13.315 -    return 0
  13.316 -
  13.317 -
  13.318 -def vd_create(size_mb, expiry):
  13.319 -    """Create a new virtual disk.
  13.320 -    size_mb [int]: size in megabytes for the new virtual disk
  13.321 -    expiry [int]: expiry time in seconds from now
  13.322 -    """
  13.323 -
  13.324 -    if not os.path.isfile(VD_DB_FILE):
  13.325 -        __vd_no_database()
  13.326 -
  13.327 -    cx = sqlite.connect(VD_DB_FILE)
  13.328 -    cu = cx.cursor()
  13.329 -
  13.330 -    size = size_mb * 2048
  13.331 -
  13.332 -    cu.execute("SELECT max(vdisk_id) FROM vdisks")
  13.333 -    max_id, = cu.fetchone()
  13.334 -    new_id = int(max_id) + 1
  13.335 -
  13.336 -    # fetch a list of extents from the expired disks, along with information
  13.337 -    # about their size
  13.338 -    cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
  13.339 -                         vdisk_extents.part_id, extent_size
  13.340 -                  FROM vdisks NATURAL JOIN vdisk_extents
  13.341 -                                                  NATURAL JOIN vdisk_part
  13.342 -                  WHERE expires AND expiry_time <= datetime('now')
  13.343 -                  ORDER BY expiry_time ASC, vdisk_extent_no DESC
  13.344 -               """)  # aims to reuse the last extents
  13.345 -                     # from the longest-expired disks first
  13.346 -
  13.347 -    allocated = 0
  13.348 -
  13.349 -    if expiry:
  13.350 -        expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
  13.351 -        expires = 1
  13.352 -    else:
  13.353 -        expiry_ts = "NULL"
  13.354 -        expires = 0
  13.355 -
  13.356 -    # we'll use this to build the SQL statement we want
  13.357 -    building_sql = "INSERT INTO vdisks(vdisk_id, size, expires, expiry_time)" \
  13.358 -                   +" VALUES ("+str(new_id)+", "+str(size)+ ", "              \
  13.359 -                   + str(expires) + ", " + expiry_ts + "); "
  13.360 -
  13.361 -    counter = 0
  13.362 -
  13.363 -    while allocated < size:
  13.364 -        row = cu.fetchone()
  13.365 -        if not row:
  13.366 -            print "ran out of space, having allocated %d meg of %d" % (allocated, size)
  13.367 -            cx.close()
  13.368 -            return -1
  13.369 -        
  13.370 -
  13.371 -        (vdisk_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
  13.372 -        allocated += extent_size
  13.373 -        building_sql += "UPDATE vdisk_extents SET vdisk_id = " + str(new_id) \
  13.374 -                        + ", " + "vdisk_extent_no = " + str(counter)         \
  13.375 -                        + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
  13.376 -                        + " AND vdisk_id = " + str(vdisk_id) + "; "
  13.377 -
  13.378 -        counter += 1
  13.379 -        
  13.380 -
  13.381 -    # this will execute the SQL query we build to store details of the new
  13.382 -    # virtual disk and allocate space to it print building_sql
  13.383 -    cu.execute(building_sql)
  13.384 -    
  13.385 -    cx.commit()
  13.386 -    cx.close()
  13.387 -    return str(new_id)
  13.388 -
  13.389 -
  13.390 -def vd_lookup(id):
  13.391 -    """Lookup a Virtual Disk by ID.
  13.392 -    id [string]: a virtual disk identifier
  13.393 -    Returns [list of dicts]: a list of extents as dicts, containing fields:
  13.394 -                             device : Linux device number of host disk
  13.395 -                             start_sector : within the device
  13.396 -                             nr_sectors : size of this extent
  13.397 -                             type : set to \'VD Extent\'
  13.398 -                             
  13.399 -                             part_device : Linux device no of host partition
  13.400 -                             part_start_sector : within the partition
  13.401 -    """
  13.402 -
  13.403 -    if not os.path.isfile(VD_DB_FILE):
  13.404 -        __vd_no_database()
  13.405 -
  13.406 -    cx = sqlite.connect(VD_DB_FILE)
  13.407 -    cu = cx.cursor()
  13.408 -
  13.409 -    cu.execute("-- types int")
  13.410 -    cu.execute("""SELECT COUNT(*)
  13.411 -                  FROM vdisks
  13.412 -                  WHERE (expiry_time > datetime('now') OR NOT expires)
  13.413 -                              AND vdisk_id = """ + id)
  13.414 -    count, = cu.fetchone()
  13.415 -
  13.416 -    if not count:
  13.417 -        cx.close()
  13.418 -        return None
  13.419 -
  13.420 -    cu.execute("SELECT size from vdisks WHERE vdisk_id = " + id)
  13.421 -    real_size, = cu.fetchone()
  13.422 -  
  13.423 -    # This query tells PySQLite how to convert the data returned from the
  13.424 -    # following query - the use of the multiplication confuses it otherwise ;-)
  13.425 -    # This row is significant to PySQLite but is syntactically an SQL comment.
  13.426 -
  13.427 -    cu.execute("-- types str, int, int, int")
  13.428 -
  13.429 -    # This SQL statement is designed so that when the results are fetched they
  13.430 -    # will be in the right format to return immediately.
  13.431 -    cu.execute("""SELECT partition, vdisk_part.part_id,
  13.432 -                         round(part_extent_no * extent_size) as start,
  13.433 -                         extent_size
  13.434 -                         
  13.435 -                  FROM vdisks NATURAL JOIN vdisk_extents
  13.436 -                                             NATURAL JOIN vdisk_part
  13.437 -                                                
  13.438 -                  WHERE vdisk_extents.vdisk_id = """ + id
  13.439 -               + " ORDER BY vdisk_extents.vdisk_extent_no ASC"
  13.440 -               )
  13.441 -
  13.442 -    extent_tuples = cu.fetchall()
  13.443 -
  13.444 -    # use this function to map the results from the database into a dict
  13.445 -    # list of extents, for consistency with the rest of the code
  13.446 -    def transform ((partition, part_device, part_offset, nr_sectors)):
  13.447 -        return {
  13.448 -                 # the disk device this extent is on - for passing to Xen
  13.449 -                 'device' : lookup_raw_partn(partition)[0]['device'],
  13.450 -                 # the offset of this extent within the disk - for passing to Xen
  13.451 -                 'start_sector' : long(part_offset + lookup_raw_partn(partition)[0]['start_sector']),
  13.452 -                 # extent size, in sectors
  13.453 -                 'nr_sectors' : nr_sectors,
  13.454 -                 # partition device this extent is on (useful to know for XenoUtil fns)
  13.455 -                 'part_device' : part_device,
  13.456 -                 # start sector within this partition (useful to know for XenoUtil fns)
  13.457 -                 'part_start_sector' : part_offset,
  13.458 -                 # type of this extent - handy to know
  13.459 -                 'type' : 'VD Extent' }
  13.460 -
  13.461 -    cx.commit()
  13.462 -    cx.close()
  13.463 -
  13.464 -    extent_dicts = map(transform, extent_tuples)
  13.465 -
  13.466 -    # calculate the over-allocation in sectors (happens because
  13.467 -    # we allocate whole extents)
  13.468 -    allocated_size = 0
  13.469 -    for i in extent_dicts:
  13.470 -        allocated_size += i['nr_sectors']
  13.471 -
  13.472 -    over_allocation = allocated_size - real_size
  13.473 -
  13.474 -    # trim down the last extent's length so the resulting VBD will be the
  13.475 -    # size requested, rather than being rounded up to the nearest extent
  13.476 -    extent_dicts[len(extent_dicts) - 1]['nr_sectors'] -= over_allocation
  13.477 -
  13.478 -    return extent_dicts
  13.479 -
  13.480 -
  13.481 -def vd_enlarge(vdisk_id, extra_size_mb):
  13.482 -    """Create a new virtual disk.
  13.483 -    vdisk_id [string]   :    ID of the virtual disk to enlarge
  13.484 -    extra_size_mb  [int]:    size in megabytes to increase the allocation by
  13.485 -    returns  [int]      :    0 on success, otherwise non-zero
  13.486 -    """
  13.487 -
  13.488 -    if not os.path.isfile(VD_DB_FILE):
  13.489 -        __vd_no_database()
  13.490 -
  13.491 -    cx = sqlite.connect(VD_DB_FILE)
  13.492 -    cu = cx.cursor()
  13.493 -
  13.494 -    extra_size = extra_size_mb * 2048
  13.495 -
  13.496 -    cu.execute("-- types int")
  13.497 -    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id
  13.498 -               + " AND (expiry_time > datetime('now') OR NOT expires)")
  13.499 -    count, = cu.fetchone()
  13.500 -
  13.501 -    if not count: # no such vdisk
  13.502 -        cx.close()
  13.503 -        return -1
  13.504 -
  13.505 -    cu.execute("-- types int")
  13.506 -    cu.execute("""SELECT SUM(extent_size)
  13.507 -                  FROM vdisks NATURAL JOIN vdisk_extents
  13.508 -                                         NATURAL JOIN vdisk_part
  13.509 -                  WHERE vdisks.vdisk_id = """ + vdisk_id)
  13.510 -
  13.511 -    real_size, = cu.fetchone() # get the true allocated size
  13.512 -
  13.513 -    cu.execute("-- types int")
  13.514 -    cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id)
  13.515 -
  13.516 -    old_size, = cu.fetchone()
  13.517 -
  13.518 -
  13.519 -    cu.execute("--- types int")
  13.520 -    cu.execute("""SELECT MAX(vdisk_extent_no)
  13.521 -                  FROM vdisk_extents
  13.522 -                  WHERE vdisk_id = """ + vdisk_id)
  13.523 -
  13.524 -    counter = cu.fetchone()[0] + 1 # this stores the extent numbers
  13.525 -
  13.526 -
  13.527 -    # because of the extent-based allocation, the VD may already have more
  13.528 -    # allocated space than they asked for.  Find out how much we really
  13.529 -    # need to add.
  13.530 -    add_size = extra_size + old_size - real_size
  13.531 -
  13.532 -    # fetch a list of extents from the expired disks, along with information
  13.533 -    # about their size
  13.534 -    cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
  13.535 -                         vdisk_extents.part_id, extent_size
  13.536 -                  FROM vdisks NATURAL JOIN vdisk_extents
  13.537 -                                                  NATURAL JOIN vdisk_part
  13.538 -                  WHERE expires AND expiry_time <= datetime('now')
  13.539 -                  ORDER BY expiry_time ASC, vdisk_extent_no DESC
  13.540 -               """)  # aims to reuse the last extents
  13.541 -                     # from the longest-expired disks first
  13.542 -
  13.543 -    allocated = 0
  13.544 -
  13.545 -    building_sql = "UPDATE vdisks SET size = " + str(old_size + extra_size)\
  13.546 -                   + " WHERE vdisk_id = " + vdisk_id + "; "
  13.547 -
  13.548 -    while allocated < add_size:
  13.549 -        row = cu.fetchone()
  13.550 -        if not row:
  13.551 -            cx.close()
  13.552 -            return -1
  13.553 -
  13.554 -        (dead_vd_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
  13.555 -        allocated += extent_size
  13.556 -        building_sql += "UPDATE vdisk_extents SET vdisk_id = " + vdisk_id    \
  13.557 -                        + ", " + "vdisk_extent_no = " + str(counter)         \
  13.558 -                        + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
  13.559 -                        + " AND vdisk_id = " + str(dead_vd_id) + "; "
  13.560 -
  13.561 -        counter += 1
  13.562 -        
  13.563 -
  13.564 -    # this will execute the SQL query we build to store details of the new
  13.565 -    # virtual disk and allocate space to it print building_sql
  13.566 -    cu.execute(building_sql)
  13.567 -    
  13.568 -    cx.commit()
  13.569 -    cx.close()
  13.570 -    return 0
  13.571 -
  13.572 -
  13.573 -def vd_undelete(vdisk_id, expiry_time):
  13.574 -    """Create a new virtual disk.
  13.575 -    vdisk_id      [int]: size in megabytes for the new virtual disk
  13.576 -    expiry_time   [int]: expiry time, in seconds from now
  13.577 -    returns       [int]: zero on success, non-zero on failure
  13.578 -    """
  13.579 -
  13.580 -    if not os.path.isfile(VD_DB_FILE):
  13.581 -        __vd_no_database()
  13.582 -
  13.583 -    if vdisk_id == '0': #  undeleting vdisk 0 isn't sane!
  13.584 -        return -1
  13.585 -
  13.586 -    cx = sqlite.connect(VD_DB_FILE)
  13.587 -    cu = cx.cursor()
  13.588 -
  13.589 -    cu.execute("-- types int")
  13.590 -    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id)
  13.591 -    count, = cu.fetchone()
  13.592 -
  13.593 -    if not count:
  13.594 -        cx.close()
  13.595 -        return -1
  13.596 -
  13.597 -    cu.execute("-- types int")
  13.598 -    cu.execute("""SELECT SUM(extent_size)
  13.599 -                  FROM vdisks NATURAL JOIN vdisk_extents
  13.600 -                                         NATURAL JOIN vdisk_part
  13.601 -                  WHERE vdisks.vdisk_id = """ + vdisk_id)
  13.602 -
  13.603 -    real_size, = cu.fetchone() # get the true allocated size
  13.604 -
  13.605 -
  13.606 -    cu.execute("-- types int")
  13.607 -    cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id)
  13.608 -
  13.609 -    old_size, = cu.fetchone()
  13.610 -
  13.611 -    if real_size < old_size:
  13.612 -        cx.close()
  13.613 -        return -1
  13.614 -
  13.615 -    if expiry_time == 0:
  13.616 -        expires = '0'
  13.617 -    else:
  13.618 -        expires = '1'
  13.619 -
  13.620 -    # this will execute the SQL query we build to store details of the new
  13.621 -    # virtual disk and allocate space to it print building_sql
  13.622 -    cu.execute("UPDATE vdisks SET expiry_time = datetime('now','"
  13.623 -               + str(expiry_time) + " seconds'), expires = " + expires
  13.624 -               + " WHERE vdisk_id = " + vdisk_id)
  13.625 -    
  13.626 -    cx.commit()
  13.627 -    cx.close()
  13.628 -    return 0
  13.629 -
  13.630 -
  13.631 -
  13.632 -
  13.633 -def vd_list():
  13.634 -    """Lists all the virtual disks registered in the system.
  13.635 -    returns [list of dicts]
  13.636 -    """
  13.637 -    
  13.638 -    if not os.path.isfile(VD_DB_FILE):
  13.639 -        __vd_no_database()
  13.640 -
  13.641 -    cx = sqlite.connect(VD_DB_FILE)
  13.642 -    cu = cx.cursor()
  13.643 -
  13.644 -    cu.execute("""SELECT vdisk_id, size, expires, expiry_time
  13.645 -                  FROM vdisks
  13.646 -                  WHERE (NOT expires) OR expiry_time > datetime('now')
  13.647 -               """)
  13.648 -
  13.649 -    ret = cu.fetchall()
  13.650 -
  13.651 -    cx.close()
  13.652 -
  13.653 -    def makedicts((vdisk_id, size, expires, expiry_time)):
  13.654 -        return { 'vdisk_id' : str(vdisk_id), 'size': size,
  13.655 -                 'expires' : expires, 'expiry_time' : expiry_time }
  13.656 -
  13.657 -    return map(makedicts, ret)
  13.658 -
  13.659 -
  13.660 -def vd_refresh(id, expiry):
  13.661 -    """Change the expiry time of a virtual disk.
  13.662 -    id [string]  : a virtual disk identifier
  13.663 -    expiry [int] : expiry time in seconds from now (0 = never expire)
  13.664 -    returns [int]: zero on success, non-zero on failure
  13.665 -    """
  13.666 -
  13.667 -    if not os.path.isfile(VD_DB_FILE):
  13.668 -        __vd_no_database()
  13.669 -    
  13.670 -    cx = sqlite.connect(VD_DB_FILE)
  13.671 -    cu = cx.cursor()
  13.672 -
  13.673 -    cu.execute("-- types int")
  13.674 -    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id
  13.675 -               + " AND (expiry_time > datetime('now') OR NOT expires)")
  13.676 -    count, = cu.fetchone()
  13.677 -
  13.678 -    if not count:
  13.679 -        cx.close()
  13.680 -        return -1
  13.681 -
  13.682 -    if expiry:
  13.683 -        expires = 1
  13.684 -        expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
  13.685 -    else:
  13.686 -        expires = 0
  13.687 -        expiry_ts = "NULL"
  13.688 -
  13.689 -    cu.execute("UPDATE vdisks SET expires = " + str(expires)
  13.690 -               + ", expiry_time = " + expiry_ts
  13.691 -               + " WHERE (expiry_time > datetime('now') OR NOT expires)"
  13.692 -               + " AND vdisk_id = " + id)
  13.693 -
  13.694 -    cx.commit()
  13.695 -    cx.close()
  13.696 -    
  13.697 -    return 0
  13.698 -
  13.699 -
  13.700 -def vd_delete(id):
  13.701 -    """Deletes a Virtual Disk, making its extents available for future VDs.
  13.702 -       id [string]   : identifier for the virtual disk to delete
  13.703 -       returns [int] : 0 on success, -1 on failure (VD not found
  13.704 -                       or already deleted)
  13.705 -    """
  13.706 -
  13.707 -    if not os.path.isfile(VD_DB_FILE):
  13.708 -        __vd_no_database()
  13.709 -    
  13.710 -    cx = sqlite.connect(VD_DB_FILE)
  13.711 -    cu = cx.cursor()
  13.712 -
  13.713 -    cu.execute("-- types int")
  13.714 -    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id
  13.715 -               + " AND (expiry_time > datetime('now') OR NOT expires)")
  13.716 -    count, = cu.fetchone()
  13.717 -
  13.718 -    if not count:
  13.719 -        cx.close()
  13.720 -        return -1
  13.721 -
  13.722 -    cu.execute("UPDATE vdisks SET expires = 1, expiry_time = datetime('now')"
  13.723 -               + " WHERE vdisk_id = " + id)
  13.724 -
  13.725 -    cx.commit()
  13.726 -    cx.close()
  13.727 -    
  13.728 -    return 0
  13.729 -
  13.730 -
  13.731 -def vd_freespace():
  13.732 -    """Returns the amount of free space available for new virtual disks, in MB
  13.733 -    returns [int] : free space for VDs in MB
  13.734 -    """
  13.735 -
  13.736 -    if not os.path.isfile(VD_DB_FILE):
  13.737 -        __vd_no_database()
  13.738 - 
  13.739 -    cx = sqlite.connect(VD_DB_FILE)
  13.740 -    cu = cx.cursor()
  13.741 -
  13.742 -    cu.execute("-- types int")
  13.743 -
  13.744 -    cu.execute("""SELECT SUM(extent_size)
  13.745 -                  FROM vdisks NATURAL JOIN vdisk_extents
  13.746 -                                           NATURAL JOIN vdisk_part
  13.747 -                  WHERE expiry_time <= datetime('now') AND expires""")
  13.748 -
  13.749 -    sum, = cu.fetchone()
  13.750 -
  13.751 -    cx.close()
  13.752 -
  13.753 -    return sum / 2048
  13.754 -
  13.755 -
  13.756 -def vd_init_db(path):
  13.757 -    """Initialise the VD SQLite database
  13.758 -    path [string]: path to the SQLite database file
  13.759 -    """
  13.760 -
  13.761 -    cx = sqlite.connect(path)
  13.762 -    cu = cx.cursor()
  13.763 -
  13.764 -    cu.execute(
  13.765 -        """CREATE TABLE vdisk_extents
  13.766 -                           ( vdisk_extent_no INT,
  13.767 -                             vdisk_id INT,
  13.768 -                             part_id INT,
  13.769 -                             part_extent_no INT )
  13.770 -        """)
  13.771 -
  13.772 -    cu.execute(
  13.773 -        """CREATE TABLE vdisk_part
  13.774 -                           ( part_id INT,
  13.775 -                             partition VARCHAR,
  13.776 -                             extent_size INT )
  13.777 -        """)
  13.778 -
  13.779 -    cu.execute(
  13.780 -        """CREATE TABLE vdisks
  13.781 -                           ( vdisk_id INT,
  13.782 -                             size INT,
  13.783 -                             expires BOOLEAN,
  13.784 -                             expiry_time TIMESTAMP )
  13.785 -        """)
  13.786 -
  13.787 -
  13.788 -    cu.execute(
  13.789 -        """INSERT INTO vdisks ( vdisk_id, size, expires, expiry_time )
  13.790 -                       VALUES ( 0,        0,    1,       datetime('now') )
  13.791 -        """)
  13.792 -
  13.793 -    cx.commit()
  13.794 -    cx.close()
  13.795 -
  13.796 -    VD_DB_FILE = path
  13.797 -
  13.798 -
  13.799 -
  13.800 -def vd_cp_to_file(vdisk_id,filename):
  13.801 -    """Writes the contents of a specified vdisk out into a disk file, leaving
  13.802 -    the original copy in the virtual disk pool."""
  13.803 -
  13.804 -    cx = sqlite.connect(VD_DB_FILE)
  13.805 -    cu = cx.cursor()
  13.806 -
  13.807 -    extents = vd_lookup(vdisk_id)
  13.808 -
  13.809 -    if not extents:
  13.810 -        return -1
  13.811 -    
  13.812 -    file_idx = 0 # index into source file, in sectors
  13.813 -
  13.814 -    for i in extents:
  13.815 -        cu.execute("""SELECT partition, extent_size FROM vdisk_part
  13.816 -                      WHERE part_id =  """ + str(i['part_device']))
  13.817 -
  13.818 -        (partition, extent_size) = cu.fetchone()
  13.819 -
  13.820 -        os.system("dd bs=1b if=" + partition + " of=" + filename
  13.821 -                  + " skip=" + str(i['part_start_sector'])
  13.822 -                  + " seek=" + str(file_idx)
  13.823 -                  + " count=" + str(i['nr_sectors'])
  13.824 -                  + " > /dev/null")
  13.825 -
  13.826 -        file_idx += i['nr_sectors']
  13.827 -
  13.828 -    cx.close()
  13.829 -
  13.830 -    return 0 # should return -1 if something breaks
  13.831 -    
  13.832 -
  13.833 -def vd_mv_to_file(vdisk_id,filename):
  13.834 -    """Writes a vdisk out into a disk file and frees the space originally
  13.835 -    taken within the virtual disk pool.
  13.836 -    vdisk_id [string]: ID of the vdisk to write out
  13.837 -    filename [string]: file to write vdisk contents out to
  13.838 -    returns [int]: zero on success, nonzero on failure
  13.839 -    """
  13.840 -
  13.841 -    if vd_cp_to_file(vdisk_id,filename):
  13.842 -        return -1
  13.843 -
  13.844 -    if vd_delete(vdisk_id):
  13.845 -        return -1
  13.846 -
  13.847 -    return 0
  13.848 -
  13.849 -
  13.850 -def vd_read_from_file(filename,expiry):
  13.851 -    """Reads the contents of a file directly into a vdisk, which is
  13.852 -    automatically allocated to fit.
  13.853 -    filename [string]: file to read disk contents from
  13.854 -    returns [string] : vdisk ID for the destination vdisk
  13.855 -    """
  13.856 -
  13.857 -    size_bytes = os.stat(filename).st_size
  13.858 -
  13.859 -    (size_mb,leftover) =  divmod(size_bytes,1048580) # size in megabytes
  13.860 -    if leftover > 0: size_mb += 1 # round up if not an exact number of MB
  13.861 -
  13.862 -    vdisk_id = vd_create(size_mb, expiry)
  13.863 -
  13.864 -    if vdisk_id < 0:
  13.865 -        return -1
  13.866 -
  13.867 -    cx = sqlite.connect(VD_DB_FILE)
  13.868 -    cu = cx.cursor()
  13.869 -
  13.870 -    cu.execute("""SELECT partition, extent_size, part_extent_no
  13.871 -                  FROM vdisk_part NATURAL JOIN vdisk_extents
  13.872 -                  WHERE vdisk_id =  """ + vdisk_id + """
  13.873 -                  ORDER BY vdisk_extent_no ASC""")
  13.874 -
  13.875 -    extents = cu.fetchall()
  13.876 -
  13.877 -    size_sectors = size_mb * 2048 # for feeding to dd
  13.878 -
  13.879 -    file_idx = 0 # index into source file, in sectors
  13.880 -
  13.881 -    def write_extent_to_vd((partition, extent_size, part_extent_no),
  13.882 -                           file_idx, filename):
  13.883 -        """Write an extent out to disk and update file_idx"""
  13.884 -
  13.885 -        os.system("dd bs=512 if=" + filename + " of=" + partition
  13.886 -                  + " skip=" + str(file_idx)
  13.887 -                  + " seek=" + str(part_extent_no * extent_size)
  13.888 -                  + " count=" + str(min(extent_size, size_sectors - file_idx))
  13.889 -                  + " > /dev/null")
  13.890 -
  13.891 -        return extent_size
  13.892 -
  13.893 -    for i in extents:
  13.894 -        file_idx += write_extent_to_vd(i, file_idx, filename)
  13.895 -
  13.896 -    cx.close()
  13.897 -
  13.898 -    return vdisk_id
  13.899 -    
  13.900 -
  13.901 -
  13.902 -
  13.903 -def vd_extents_validate(new_extents,new_writeable):
  13.904 -    """Validate the extents against the existing extents.
  13.905 -    Complains if the list supplied clashes against the extents that
  13.906 -    are already in use in the system.
  13.907 -    new_extents [list of dicts]: list of new extents, as dicts
  13.908 -    new_writeable [int]: 1 if they are to be writeable, 0 otherwise
  13.909 -    returns [int]: either the expertise level of the mapping if it doesn't
  13.910 -                   exceed VBD_EXPERT_MODE or -1 if it does (error)
  13.911 -    """
  13.912 -
  13.913 -    import Xc # this is only needed in this function
  13.914 -
  13.915 -    xc = Xc.new()
  13.916 -
  13.917 -    ##### Probe for explicitly created virtual disks and build a list
  13.918 -    ##### of extents for comparison with the ones that are being added
  13.919 -
  13.920 -    probe = xc.vbd_probe()
  13.921 -
  13.922 -    old_extents = [] # this will hold a list of all existing extents and
  13.923 -                     # their writeable status, as a list of (device,
  13.924 -                     # start, size, writeable?) tuples
  13.925 -
  13.926 -    for vbd in probe:
  13.927 -        this_vbd_extents = xc.vbd_getextents(vbd['dom'],vbd['vbd'])
  13.928 -        for vbd_ext in this_vbd_extents:
  13.929 -            vbd_ext['writeable'] = vbd['writeable']
  13.930 -            old_extents.append(vbd_ext)
  13.931 -            
  13.932 -    ##### Now scan /proc/mounts for compile a list of extents corresponding to
  13.933 -    ##### any devices mounted in DOM0.  This list is added on to old_extents
  13.934 -
  13.935 -    regexp = re.compile("/dev/(\S*) \S* \S* (..).*")
  13.936 -    fd = open('/proc/mounts', "r")
  13.937 -
  13.938 -    while True:
  13.939 -        line = fd.readline()
  13.940 -        if not line: # if we've run out of lines then stop reading
  13.941 -            break
  13.942 -        
  13.943 -        m = regexp.match(line)
  13.944 -
  13.945 -        # if the regexp didn't match then it's probably a line we don't
  13.946 -        # care about - skip to next line
  13.947 -        if not m:
  13.948 -            continue
  13.949 -
  13.950 -        # lookup the device
  13.951 -        ext_list = lookup_raw_partn(m.group(1))
  13.952 -
  13.953 -        # if lookup failed, skip to next mounted device
  13.954 -        if not ext_list:
  13.955 -            continue
  13.956 -
  13.957 -        # set a writeable flag as appropriate
  13.958 -        for ext in ext_list:
  13.959 -            ext['writeable'] = m.group(2) == 'rw'
  13.960 -
  13.961 -        # now we've got here, the contents of ext_list are in a
  13.962 -        # suitable format to be added onto the old_extents list, ready
  13.963 -        # for checking against the new extents
  13.964 -
  13.965 -        old_extents.extend(ext_list)
  13.966 -
  13.967 -    fd.close() # close /proc/mounts
  13.968 -
  13.969 -    ##### By this point, old_extents contains a list of extents, in
  13.970 -    ##### dictionary format corresponding to every extent of physical
  13.971 -    ##### disk that's either part of an explicitly created VBD, or is
  13.972 -    ##### mounted under DOM0.  We now check these extents against the
  13.973 -    ##### proposed additions in new_extents, to see if a conflict will
  13.974 -    ##### happen if they are added with write status new_writeable
  13.975 -
  13.976 -    level = 0 # this'll accumulate the max warning level
  13.977 -
  13.978 -    # Search for clashes between the new extents and the old ones
  13.979 -    # Takes time O(len(new_extents) * len(old_extents))
  13.980 -    for new_ext in new_extents:
  13.981 -        for old_ext in old_extents:
  13.982 -            if(new_ext['device'] == old_ext['device']):
  13.983 -
  13.984 -                new_ext_start = new_ext['start_sector']
  13.985 -                new_ext_end = new_ext_start + new_ext['nr_sectors'] - 1
  13.986 -                
  13.987 -                old_ext_start = old_ext['start_sector']
  13.988 -                old_ext_end = old_ext_start + old_ext['nr_sectors'] - 1
  13.989 -                
  13.990 -                if((old_ext_start <= new_ext_start <= old_ext_end) or
  13.991 -                   (old_ext_start <= new_ext_end <= old_ext_end)):
  13.992 -                    if (not old_ext['writeable']) and new_writeable:
  13.993 -                        level = max(1,level)
  13.994 -                    elif old_ext['writeable'] and (not new_writeable):
  13.995 -                        level = max(1,level)
  13.996 -                    elif old_ext['writeable'] and new_writeable:
  13.997 -                        level = max(2,level)
  13.998 -
  13.999 -
 13.1000 -    ##### level now holds the warning level incurred by the current
 13.1001 -    ##### VBD setup and we complain appropriately to the user
 13.1002 -
 13.1003 -
 13.1004 -    if level == 1:
 13.1005 -        print >> sys.stderr, """Warning: one or more hard disk extents
 13.1006 -         writeable by one domain are also readable by another."""
 13.1007 -    elif level == 2:
 13.1008 -        print >> sys.stderr, """Warning: one or more hard disk extents are
 13.1009 -         writeable by two or more domains simultaneously."""
 13.1010 -
 13.1011 -    if level > VBD_EXPERT_MODE:
 13.1012 -        print >> sys.stderr, """ERROR: This kind of disk sharing is not allowed
 13.1013 -        at the current safety level (%d).""" % VBD_EXPERT_MODE
 13.1014 -        level = -1
 13.1015 -
 13.1016 -    return level
 13.1017 -
    14.1 --- a/tools/xc/py/setup.py	Mon Mar 15 15:54:37 2004 +0000
    14.2 +++ b/tools/xc/py/setup.py	Mon Mar 15 17:56:41 2004 +0000
    14.3 @@ -8,5 +8,3 @@ module = Extension("Xc",
    14.4                     sources              = ["Xc.c"])
    14.5  
    14.6  setup(name = "Xc", version = "1.0", ext_modules = [module])
    14.7 -
    14.8 -setup(name = "XenoUtil", version = "1.0", py_modules = ["XenoUtil"])
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/tools/xenctl/Makefile	Mon Mar 15 17:56:41 2004 +0000
    15.3 @@ -0,0 +1,10 @@
    15.4 +
    15.5 +all:
    15.6 +	python setup.py build
    15.7 +
    15.8 +install: all
    15.9 +	if [ "$(prefix)" = "" ]; then python setup.py install; \
   15.10 +	else python setup.py install --home="$(prefix)"; fi
   15.11 +
   15.12 +clean:
   15.13 +	rm -rf build *.pyc *.pyo *.o *.a *~
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/tools/xenctl/lib/console_client.py	Mon Mar 15 17:56:41 2004 +0000
    17.3 @@ -0,0 +1,60 @@
    17.4 +
    17.5 +##############################################
    17.6 +# Console client for Xen guest OSes
    17.7 +# Copyright (c) 2004, K A Fraser
    17.8 +##############################################
    17.9 +
   17.10 +import errno, os, signal, socket, struct, sys, termios
   17.11 +
   17.12 +def __child_death(signum, frame):
   17.13 +    global stop
   17.14 +    stop = True
   17.15 +
   17.16 +def __recv_from_sock(sock):
   17.17 +    global stop
   17.18 +    stop = False
   17.19 +    print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********"
   17.20 +    while not stop:
   17.21 +        try:
   17.22 +            data = sock.recv(1)
   17.23 +            os.write(1, data)
   17.24 +        except socket.error, error:
   17.25 +            if error[0] != errno.EINTR:
   17.26 +                raise
   17.27 +    print
   17.28 +    print "************ REMOTE CONSOLE EXITED *****************"
   17.29 +    os.wait()
   17.30 +
   17.31 +def __send_to_sock(sock):
   17.32 +    while 1:
   17.33 +        data = os.read(0,1)
   17.34 +        if ord(data[0]) == ord(']')-64:
   17.35 +            break
   17.36 +        sock.send(data)
   17.37 +    sys.exit(0)
   17.38 +
   17.39 +def connect(host,port):
   17.40 +    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
   17.41 +    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
   17.42 +    sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
   17.43 +                    struct.pack('ii', 0, 0))
   17.44 +    sock.connect((host,port))
   17.45 +
   17.46 +    oattrs = termios.tcgetattr(0)
   17.47 +    nattrs = termios.tcgetattr(0)
   17.48 +    nattrs[3] = nattrs[3] & ~(termios.ECHO | termios.ICANON)
   17.49 +    nattrs[6][termios.VMIN] = 1
   17.50 +    nattrs[6][termios.VTIME] = 0
   17.51 +    termios.tcsetattr(0, termios.TCSAFLUSH, nattrs)
   17.52 +
   17.53 +    try:
   17.54 +        if os.fork():
   17.55 +            signal.signal(signal.SIGCHLD, __child_death)
   17.56 +            __recv_from_sock(sock)
   17.57 +        else:
   17.58 +            __send_to_sock(sock)
   17.59 +    finally:
   17.60 +        termios.tcsetattr(0, termios.TCSAFLUSH, oattrs)
   17.61 +
   17.62 +if __name__ == '__main__':
   17.63 +    main(str(sys.argv[1]),int(sys.argv[2]))
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tools/xenctl/lib/utils.py	Mon Mar 15 17:56:41 2004 +0000
    18.3 @@ -0,0 +1,1014 @@
    18.4 +import os, re, socket, string, sys, tempfile
    18.5 +
    18.6 +##### Module variables
    18.7 +
    18.8 +"""Location of the Virtual Disk management database.
    18.9 +   defaults to /var/db/xen_vdisks.sqlite
   18.10 +"""
   18.11 +VD_DB_FILE = "/var/db/xen_vdisks.sqlite"
   18.12 +
   18.13 +"""VBD expertise level - determines the strictness of the sanity checking.
   18.14 +  This mode determines the level of complaints when disk sharing occurs
   18.15 +  through the current VBD mappings.
   18.16 +   0 - only allow shared mappings if both domains have r/o access (always OK)
   18.17 +   1 - also allow sharing with one dom r/w and the other r/o
   18.18 +   2 - allow sharing with both doms r/w
   18.19 +"""
   18.20 +VBD_EXPERT_MODE = 0
   18.21 +
   18.22 +##### Module initialisation
   18.23 +
   18.24 +try:
   18.25 +    # try to import sqlite (not everyone will have it installed)
   18.26 +    import sqlite
   18.27 +except ImportError:
   18.28 +    # on failure, just catch the error, don't do anything
   18.29 +    pass
   18.30 +
   18.31 +
   18.32 +##### Networking-related functions
   18.33 +
   18.34 +def get_current_ipaddr(dev='eth0'):
   18.35 +    """Return a string containing the primary IP address for the given
   18.36 +    network interface (default 'eth0').
   18.37 +    """
   18.38 +    fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
   18.39 +    lines = fd.readlines()
   18.40 +    for line in lines:
   18.41 +        m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
   18.42 +                       line )
   18.43 +        if m:
   18.44 +            return m.group(1)
   18.45 +    return None
   18.46 +
   18.47 +def get_current_ipmask(dev='eth0'):
   18.48 +    """Return a string containing the primary IP netmask for the given
   18.49 +    network interface (default 'eth0').
   18.50 +    """
   18.51 +    fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
   18.52 +    lines = fd.readlines()
   18.53 +    for line in lines:
   18.54 +        m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
   18.55 +                       line )
   18.56 +        if m:
   18.57 +            return m.group(1)
   18.58 +    return None
   18.59 +
   18.60 +def get_current_ipgw(dev='eth0'):
   18.61 +    """Return a string containing the IP gateway for the given
   18.62 +    network interface (default 'eth0').
   18.63 +    """
   18.64 +    fd = os.popen( '/sbin/route -n' )
   18.65 +    lines = fd.readlines()
   18.66 +    for line in lines:
   18.67 +        m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
   18.68 +                       '\s+\S+\s+\S*G.*' + dev + '.*', line )
   18.69 +        if m:
   18.70 +            return m.group(1)
   18.71 +    return None
   18.72 +
   18.73 +def setup_vfr_rules_for_vif(dom,vif,addr):
   18.74 +    """Takes a tuple ( domain-id, vif-id, ip-addr ), where the ip-addr
   18.75 +    is expressed as a textual dotted quad, and set up appropriate routing
   18.76 +    rules in Xen. No return value.
   18.77 +    """
   18.78 +    fd = os.open( '/proc/xen/vfr', os.O_WRONLY )
   18.79 +    if ( re.search( '169\.254', addr) ):
   18.80 +        os.write( fd, 'ADD ACCEPT srcaddr=' + addr +
   18.81 +                  ' srcaddrmask=255.255.255.255' +
   18.82 +                  ' srcdom=' + str(dom) + ' srcidx=' + str(vif) +
   18.83 +                  ' dstdom=0 dstidx=0 proto=any\n' )
   18.84 +    else:
   18.85 +        os.write( fd, 'ADD ACCEPT srcaddr=' + addr +
   18.86 +                  ' srcaddrmask=255.255.255.255' +
   18.87 +                  ' srcdom=' + str(dom) + ' srcidx=' + str(vif) +
   18.88 +                  ' dst=PHYS proto=any\n' )
   18.89 +    os.write( fd, 'ADD ACCEPT dstaddr=' + addr +
   18.90 +              ' dstaddrmask=255.255.255.255' +
   18.91 +              ' src=ANY' +
   18.92 +              ' dstdom=' + str(dom) + ' dstidx=' + str(vif) +
   18.93 +              ' proto=any\n' )
   18.94 +    os.close( fd )
   18.95 +    return None
   18.96 +
   18.97 +def add_offset_to_ip( ip, off ):
   18.98 +    l = string.split(ip,'.')
   18.99 +    a = ( (string.atoi(l[0])<<24) | (string.atoi(l[1])<<16) | 
  18.100 +	  (string.atoi(l[2])<<8)  | string.atoi(l[3]) ) + off
  18.101 +    
  18.102 +    return '%d.%d.%d.%d' % ( ((a>>24)&0xff), ((a>>16)&0xff),
  18.103 +			     ((a>>8)&0xff), (a&0xff) )
  18.104 +
  18.105 +def check_subnet( ip, network, netmask ):
  18.106 +    l = string.split(ip,'.')
  18.107 +    n_ip = ( (string.atoi(l[0])<<24) | (string.atoi(l[1])<<16) | 
  18.108 +	   (string.atoi(l[2])<<8)  | string.atoi(l[3]) ) 
  18.109 +
  18.110 +    l = string.split(network,'.')
  18.111 +    n_net = ( (string.atoi(l[0])<<24) | (string.atoi(l[1])<<16) | 
  18.112 +	   (string.atoi(l[2])<<8)  | string.atoi(l[3]) )
  18.113 +
  18.114 +    l = string.split(netmask,'.')
  18.115 +    n_mask = ( (string.atoi(l[0])<<24) | (string.atoi(l[1])<<16) | 
  18.116 +	   (string.atoi(l[2])<<8)  | string.atoi(l[3]) )
  18.117 +    
  18.118 +    return (n_ip&n_mask)==(n_net&n_mask)
  18.119 +
  18.120 +
  18.121 +##### VBD-related Functions
  18.122 +
  18.123 +def blkdev_name_to_number(name):
  18.124 +    """Take the given textual block-device name (e.g., '/dev/sda1',
  18.125 +    'hda') and return the device number used by the OS. """
  18.126 +
  18.127 +    if not re.match( '/dev/', name ):
  18.128 +        name = '/dev/' + name
  18.129 +        
  18.130 +    return os.stat(name).st_rdev
  18.131 +
  18.132 +# lookup_blkdev_partn_info( '/dev/sda3' )
  18.133 +def lookup_raw_partn(partition):
  18.134 +    """Take the given block-device name (e.g., '/dev/sda1', 'hda')
  18.135 +    and return a dictionary { device, start_sector,
  18.136 +    nr_sectors, type }
  18.137 +        device:       Device number of the given partition
  18.138 +        start_sector: Index of first sector of the partition
  18.139 +        nr_sectors:   Number of sectors comprising this partition
  18.140 +        type:         'Disk' or identifying name for partition type
  18.141 +    """
  18.142 +
  18.143 +    if not re.match( '/dev/', partition ):
  18.144 +        partition = '/dev/' + partition
  18.145 +
  18.146 +    drive = re.split( '[0-9]', partition )[0]
  18.147 +
  18.148 +    if drive == partition:
  18.149 +        fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
  18.150 +        line = fd.readline()
  18.151 +        if line:
  18.152 +            return [ { 'device' : blkdev_name_to_number(drive),
  18.153 +                       'start_sector' : long(0),
  18.154 +                       'nr_sectors' : long(line) * 2,
  18.155 +                       'type' : 'Disk' } ]
  18.156 +        return None
  18.157 +
  18.158 +    # determine position on disk
  18.159 +    fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
  18.160 +
  18.161 +    #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
  18.162 +    lines = fd.readlines()
  18.163 +    for line in lines:
  18.164 +        m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
  18.165 +                       'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
  18.166 +        if m:
  18.167 +            return [ { 'device' : blkdev_name_to_number(drive),
  18.168 +                       'start_sector' : long(m.group(1)),
  18.169 +                       'nr_sectors' : long(m.group(2)),
  18.170 +                       'type' : m.group(3) } ]
  18.171 +    
  18.172 +    return None
  18.173 +
  18.174 +def lookup_disk_uname( uname ):
  18.175 +    """Lookup a list of segments for either a physical or a virtual device.
  18.176 +    uname [string]:  name of the device in the format \'vd:id\' for a virtual
  18.177 +                     disk, or \'phy:dev\' for a physical device
  18.178 +    returns [list of dicts]: list of extents that make up the named device
  18.179 +    """
  18.180 +    ( type, d_name ) = string.split( uname, ':' )
  18.181 +
  18.182 +    if type == "phy":
  18.183 +        segments = lookup_raw_partn( d_name )
  18.184 +    elif type == "vd":
  18.185 +	segments = vd_lookup( d_name )
  18.186 +
  18.187 +    return segments
  18.188 +
  18.189 +
  18.190 +##### Management of the Xen control daemon
  18.191 +##### (c) Keir Fraser, University of Cambridge
  18.192 +
  18.193 +def xend_control_message( message ):
  18.194 +    """Takes a textual control message and sends it to the 'xend' Xen
  18.195 +    control daemon. Returns a dictionary containing the daemon's multi-part
  18.196 +    response."""
  18.197 +    tmpdir = tempfile.mkdtemp()
  18.198 +    try:
  18.199 +        ctl = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
  18.200 +        ctl.bind(tmpdir+'/sock')
  18.201 +        ctl.sendto(message, '/var/run/xend/management_sock')
  18.202 +        data, addr = ctl.recvfrom(2048)
  18.203 +        ctl.close()
  18.204 +    finally:
  18.205 +        if os.path.exists(tmpdir+'/sock'):
  18.206 +            os.unlink(tmpdir+'/sock')
  18.207 +        if os.path.exists(tmpdir):
  18.208 +            os.rmdir(tmpdir)    
  18.209 +    return eval(data)
  18.210 +
  18.211 +
  18.212 +##### VD Management-related functions
  18.213 +
  18.214 +##### By Mark Williamson, <mark.a.williamson@intel.com>
  18.215 +##### (C) Intel Research Cambridge
  18.216 +
  18.217 +# TODO:
  18.218 +#
  18.219 +# Plenty of room for enhancement to this functionality (contributions
  18.220 +# welcome - and then you get to have your name in the source ;-)...
  18.221 +#
  18.222 +# vd_unformat() : want facilities to unallocate virtual disk
  18.223 +# partitions, possibly migrating virtual disks of them, with checks to see if
  18.224 +# it's safe and options to force it anyway
  18.225 +#
  18.226 +# vd_create() : should have an optional argument specifying a physical
  18.227 +# disk preference - useful to allocate for guest doms to do RAID
  18.228 +#
  18.229 +# vd_undelete() : add ability to "best effort" undelete as much of a
  18.230 +# vdisk as is left in the case that some of it has already been
  18.231 +# reallocated.  Some people might still be able to recover some of
  18.232 +# their data this way, even if some of the disk has disappeared.
  18.233 +#
  18.234 +# It'd be nice if we could wipe virtual disks for security purposes -
  18.235 +# should be easy to do this using dev if=/dev/{zero,random} on each
  18.236 +# extent in turn.  There could be another optional flag to vd_create
  18.237 +# in order to allow this.
  18.238 +#
  18.239 +# Error codes could be more expressive - i.e. actually tell why the
  18.240 +# error occurred rather than "it broke".  Currently the code avoids
  18.241 +# using exceptions to make control scripting simpler and more
  18.242 +# accessible to beginners - therefore probably should just use more
  18.243 +# return codes.
  18.244 +#
  18.245 +# Enhancements / additions to the example scripts are also welcome:
  18.246 +# some people will interact with this code mostly through those
  18.247 +# scripts.
  18.248 +#
  18.249 +# More documentation of how this stuff should be used is always nice -
  18.250 +# if you have a novel configuration that you feel isn't discussed
  18.251 +# enough in the HOWTO (which is currently a work in progress), feel
  18.252 +# free to contribute a walkthrough, or something more substantial.
  18.253 +#
  18.254 +
  18.255 +
  18.256 +def __vd_no_database():
  18.257 +    """Called when no database found - exits with an error
  18.258 +    """
  18.259 +    print >> sys.stderr, "ERROR: Could not locate the database file at " + VD_DB_FILE
  18.260 +    sys.exit(1)
  18.261 +
  18.262 +
  18.263 +def vd_format(partition, extent_size_mb):
  18.264 +    """Format a partition or drive for use a virtual disk storage.
  18.265 +    partition [string]: device file representing the partition
  18.266 +    extent_size_mb [string]: extent size in megabytes to use on this disk
  18.267 +    """
  18.268 +
  18.269 +    if not os.path.isfile(VD_DB_FILE):
  18.270 +        vd_init_db(VD_DB_FILE)
  18.271 +    
  18.272 +    if not re.match( '/dev/', partition ):
  18.273 +        partition = '/dev/' + partition
  18.274 +
  18.275 +    cx = sqlite.connect(VD_DB_FILE)
  18.276 +    cu = cx.cursor()
  18.277 +
  18.278 +    cu.execute("select * from vdisk_part where partition = \'"
  18.279 +               + partition + "\'")
  18.280 +    row = cu.fetchone()
  18.281 +
  18.282 +    extent_size = extent_size_mb * 2048 # convert megabytes to sectors
  18.283 +    
  18.284 +    if not row:
  18.285 +        part_info = lookup_raw_partn(partition)[0]
  18.286 +        
  18.287 +        cu.execute("INSERT INTO vdisk_part(partition, part_id, extent_size) " +
  18.288 +                   "VALUES ( \'" + partition + "\', "
  18.289 +                   + str(blkdev_name_to_number(partition))
  18.290 +                   + ", " + str(extent_size) + ")")
  18.291 +
  18.292 +
  18.293 +        cu.execute("SELECT max(vdisk_extent_no) FROM vdisk_extents "
  18.294 +                   + "WHERE vdisk_id = 0")
  18.295 +        
  18.296 +        max_id, = cu.fetchone()
  18.297 +
  18.298 +        if max_id != None:
  18.299 +            new_id = max_id + 1
  18.300 +        else:
  18.301 +            new_id = 0
  18.302 +
  18.303 +        num_extents = part_info['nr_sectors'] / extent_size
  18.304 +
  18.305 +        for i in range(num_extents):
  18.306 +            sql ="""INSERT INTO vdisk_extents(vdisk_extent_no, vdisk_id,
  18.307 +                                              part_id, part_extent_no)
  18.308 +                    VALUES ("""+ str(new_id + i) + ", 0, "\
  18.309 +                               + str(blkdev_name_to_number(partition))\
  18.310 +                               + ", " + str(num_extents - (i + 1)) + ")"
  18.311 +            cu.execute(sql)
  18.312 +
  18.313 +    cx.commit()
  18.314 +    cx.close()
  18.315 +    return 0
  18.316 +
  18.317 +
  18.318 +def vd_create(size_mb, expiry):
  18.319 +    """Create a new virtual disk.
  18.320 +    size_mb [int]: size in megabytes for the new virtual disk
  18.321 +    expiry [int]: expiry time in seconds from now
  18.322 +    """
  18.323 +
  18.324 +    if not os.path.isfile(VD_DB_FILE):
  18.325 +        __vd_no_database()
  18.326 +
  18.327 +    cx = sqlite.connect(VD_DB_FILE)
  18.328 +    cu = cx.cursor()
  18.329 +
  18.330 +    size = size_mb * 2048
  18.331 +
  18.332 +    cu.execute("SELECT max(vdisk_id) FROM vdisks")
  18.333 +    max_id, = cu.fetchone()
  18.334 +    new_id = int(max_id) + 1
  18.335 +
  18.336 +    # fetch a list of extents from the expired disks, along with information
  18.337 +    # about their size
  18.338 +    cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
  18.339 +                         vdisk_extents.part_id, extent_size
  18.340 +                  FROM vdisks NATURAL JOIN vdisk_extents
  18.341 +                                                  NATURAL JOIN vdisk_part
  18.342 +                  WHERE expires AND expiry_time <= datetime('now')
  18.343 +                  ORDER BY expiry_time ASC, vdisk_extent_no DESC
  18.344 +               """)  # aims to reuse the last extents
  18.345 +                     # from the longest-expired disks first
  18.346 +
  18.347 +    allocated = 0
  18.348 +
  18.349 +    if expiry:
  18.350 +        expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
  18.351 +        expires = 1
  18.352 +    else:
  18.353 +        expiry_ts = "NULL"
  18.354 +        expires = 0
  18.355 +
  18.356 +    # we'll use this to build the SQL statement we want
  18.357 +    building_sql = "INSERT INTO vdisks(vdisk_id, size, expires, expiry_time)" \
  18.358 +                   +" VALUES ("+str(new_id)+", "+str(size)+ ", "              \
  18.359 +                   + str(expires) + ", " + expiry_ts + "); "
  18.360 +
  18.361 +    counter = 0
  18.362 +
  18.363 +    while allocated < size:
  18.364 +        row = cu.fetchone()
  18.365 +        if not row:
  18.366 +            print "ran out of space, having allocated %d meg of %d" % (allocated, size)
  18.367 +            cx.close()
  18.368 +            return -1
  18.369 +        
  18.370 +
  18.371 +        (vdisk_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
  18.372 +        allocated += extent_size
  18.373 +        building_sql += "UPDATE vdisk_extents SET vdisk_id = " + str(new_id) \
  18.374 +                        + ", " + "vdisk_extent_no = " + str(counter)         \
  18.375 +                        + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
  18.376 +                        + " AND vdisk_id = " + str(vdisk_id) + "; "
  18.377 +
  18.378 +        counter += 1
  18.379 +        
  18.380 +
  18.381 +    # this will execute the SQL query we build to store details of the new
  18.382 +    # virtual disk and allocate space to it print building_sql
  18.383 +    cu.execute(building_sql)
  18.384 +    
  18.385 +    cx.commit()
  18.386 +    cx.close()
  18.387 +    return str(new_id)
  18.388 +
  18.389 +
  18.390 +def vd_lookup(id):
  18.391 +    """Lookup a Virtual Disk by ID.
  18.392 +    id [string]: a virtual disk identifier
  18.393 +    Returns [list of dicts]: a list of extents as dicts, containing fields:
  18.394 +                             device : Linux device number of host disk
  18.395 +                             start_sector : within the device
  18.396 +                             nr_sectors : size of this extent
  18.397 +                             type : set to \'VD Extent\'
  18.398 +                             
  18.399 +                             part_device : Linux device no of host partition
  18.400 +                             part_start_sector : within the partition
  18.401 +    """
  18.402 +
  18.403 +    if not os.path.isfile(VD_DB_FILE):
  18.404 +        __vd_no_database()
  18.405 +
  18.406 +    cx = sqlite.connect(VD_DB_FILE)
  18.407 +    cu = cx.cursor()
  18.408 +
  18.409 +    cu.execute("-- types int")
  18.410 +    cu.execute("""SELECT COUNT(*)
  18.411 +                  FROM vdisks
  18.412 +                  WHERE (expiry_time > datetime('now') OR NOT expires)
  18.413 +                              AND vdisk_id = """ + id)
  18.414 +    count, = cu.fetchone()
  18.415 +
  18.416 +    if not count:
  18.417 +        cx.close()
  18.418 +        return None
  18.419 +
  18.420 +    cu.execute("SELECT size from vdisks WHERE vdisk_id = " + id)
  18.421 +    real_size, = cu.fetchone()
  18.422 +  
  18.423 +    # This query tells PySQLite how to convert the data returned from the
  18.424 +    # following query - the use of the multiplication confuses it otherwise ;-)
  18.425 +    # This row is significant to PySQLite but is syntactically an SQL comment.
  18.426 +
  18.427 +    cu.execute("-- types str, int, int, int")
  18.428 +
  18.429 +    # This SQL statement is designed so that when the results are fetched they
  18.430 +    # will be in the right format to return immediately.
  18.431 +    cu.execute("""SELECT partition, vdisk_part.part_id,
  18.432 +                         round(part_extent_no * extent_size) as start,
  18.433 +                         extent_size
  18.434 +                         
  18.435 +                  FROM vdisks NATURAL JOIN vdisk_extents
  18.436 +                                             NATURAL JOIN vdisk_part
  18.437 +                                                
  18.438 +                  WHERE vdisk_extents.vdisk_id = """ + id
  18.439 +               + " ORDER BY vdisk_extents.vdisk_extent_no ASC"
  18.440 +               )
  18.441 +
  18.442 +    extent_tuples = cu.fetchall()
  18.443 +
  18.444 +    # use this function to map the results from the database into a dict
  18.445 +    # list of extents, for consistency with the rest of the code
  18.446 +    def transform ((partition, part_device, part_offset, nr_sectors)):
  18.447 +        return {
  18.448 +                 # the disk device this extent is on - for passing to Xen
  18.449 +                 'device' : lookup_raw_partn(partition)[0]['device'],
  18.450 +                 # the offset of this extent within the disk - for passing to Xen
  18.451 +                 'start_sector' : long(part_offset + lookup_raw_partn(partition)[0]['start_sector']),
  18.452 +                 # extent size, in sectors
  18.453 +                 'nr_sectors' : nr_sectors,
  18.454 +                 # partition device this extent is on (useful to know for xenctl.utils fns)
  18.455 +                 'part_device' : part_device,
  18.456 +                 # start sector within this partition (useful to know for xenctl.utils fns)
  18.457 +                 'part_start_sector' : part_offset,
  18.458 +                 # type of this extent - handy to know
  18.459 +                 'type' : 'VD Extent' }
  18.460 +
  18.461 +    cx.commit()
  18.462 +    cx.close()
  18.463 +
  18.464 +    extent_dicts = map(transform, extent_tuples)
  18.465 +
  18.466 +    # calculate the over-allocation in sectors (happens because
  18.467 +    # we allocate whole extents)
  18.468 +    allocated_size = 0
  18.469 +    for i in extent_dicts:
  18.470 +        allocated_size += i['nr_sectors']
  18.471 +
  18.472 +    over_allocation = allocated_size - real_size
  18.473 +
  18.474 +    # trim down the last extent's length so the resulting VBD will be the
  18.475 +    # size requested, rather than being rounded up to the nearest extent
  18.476 +    extent_dicts[len(extent_dicts) - 1]['nr_sectors'] -= over_allocation
  18.477 +
  18.478 +    return extent_dicts
  18.479 +
  18.480 +
  18.481 +def vd_enlarge(vdisk_id, extra_size_mb):
  18.482 +    """Create a new virtual disk.
  18.483 +    vdisk_id [string]   :    ID of the virtual disk to enlarge
  18.484 +    extra_size_mb  [int]:    size in megabytes to increase the allocation by
  18.485 +    returns  [int]      :    0 on success, otherwise non-zero
  18.486 +    """
  18.487 +
  18.488 +    if not os.path.isfile(VD_DB_FILE):
  18.489 +        __vd_no_database()
  18.490 +
  18.491 +    cx = sqlite.connect(VD_DB_FILE)
  18.492 +    cu = cx.cursor()
  18.493 +
  18.494 +    extra_size = extra_size_mb * 2048
  18.495 +
  18.496 +    cu.execute("-- types int")
  18.497 +    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id
  18.498 +               + " AND (expiry_time > datetime('now') OR NOT expires)")
  18.499 +    count, = cu.fetchone()
  18.500 +
  18.501 +    if not count: # no such vdisk
  18.502 +        cx.close()
  18.503 +        return -1
  18.504 +
  18.505 +    cu.execute("-- types int")
  18.506 +    cu.execute("""SELECT SUM(extent_size)
  18.507 +                  FROM vdisks NATURAL JOIN vdisk_extents
  18.508 +                                         NATURAL JOIN vdisk_part
  18.509 +                  WHERE vdisks.vdisk_id = """ + vdisk_id)
  18.510 +
  18.511 +    real_size, = cu.fetchone() # get the true allocated size
  18.512 +
  18.513 +    cu.execute("-- types int")
  18.514 +    cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id)
  18.515 +
  18.516 +    old_size, = cu.fetchone()
  18.517 +
  18.518 +
  18.519 +    cu.execute("--- types int")
  18.520 +    cu.execute("""SELECT MAX(vdisk_extent_no)
  18.521 +                  FROM vdisk_extents
  18.522 +                  WHERE vdisk_id = """ + vdisk_id)
  18.523 +
  18.524 +    counter = cu.fetchone()[0] + 1 # this stores the extent numbers
  18.525 +
  18.526 +
  18.527 +    # because of the extent-based allocation, the VD may already have more
  18.528 +    # allocated space than they asked for.  Find out how much we really
  18.529 +    # need to add.
  18.530 +    add_size = extra_size + old_size - real_size
  18.531 +
  18.532 +    # fetch a list of extents from the expired disks, along with information
  18.533 +    # about their size
  18.534 +    cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
  18.535 +                         vdisk_extents.part_id, extent_size
  18.536 +                  FROM vdisks NATURAL JOIN vdisk_extents
  18.537 +                                                  NATURAL JOIN vdisk_part
  18.538 +                  WHERE expires AND expiry_time <= datetime('now')
  18.539 +                  ORDER BY expiry_time ASC, vdisk_extent_no DESC
  18.540 +               """)  # aims to reuse the last extents
  18.541 +                     # from the longest-expired disks first
  18.542 +
  18.543 +    allocated = 0
  18.544 +
  18.545 +    building_sql = "UPDATE vdisks SET size = " + str(old_size + extra_size)\
  18.546 +                   + " WHERE vdisk_id = " + vdisk_id + "; "
  18.547 +
  18.548 +    while allocated < add_size:
  18.549 +        row = cu.fetchone()
  18.550 +        if not row:
  18.551 +            cx.close()
  18.552 +            return -1
  18.553 +
  18.554 +        (dead_vd_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
  18.555 +        allocated += extent_size
  18.556 +        building_sql += "UPDATE vdisk_extents SET vdisk_id = " + vdisk_id    \
  18.557 +                        + ", " + "vdisk_extent_no = " + str(counter)         \
  18.558 +                        + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
  18.559 +                        + " AND vdisk_id = " + str(dead_vd_id) + "; "
  18.560 +
  18.561 +        counter += 1
  18.562 +        
  18.563 +
  18.564 +    # this will execute the SQL query we build to store details of the new
  18.565 +    # virtual disk and allocate space to it print building_sql
  18.566 +    cu.execute(building_sql)
  18.567 +    
  18.568 +    cx.commit()
  18.569 +    cx.close()
  18.570 +    return 0
  18.571 +
  18.572 +
  18.573 +def vd_undelete(vdisk_id, expiry_time):
  18.574 +    """Create a new virtual disk.
  18.575 +    vdisk_id      [int]: size in megabytes for the new virtual disk
  18.576 +    expiry_time   [int]: expiry time, in seconds from now
  18.577 +    returns       [int]: zero on success, non-zero on failure
  18.578 +    """
  18.579 +
  18.580 +    if not os.path.isfile(VD_DB_FILE):
  18.581 +        __vd_no_database()
  18.582 +
  18.583 +    if vdisk_id == '0': #  undeleting vdisk 0 isn't sane!
  18.584 +        return -1
  18.585 +
  18.586 +    cx = sqlite.connect(VD_DB_FILE)
  18.587 +    cu = cx.cursor()
  18.588 +
  18.589 +    cu.execute("-- types int")
  18.590 +    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id)
  18.591 +    count, = cu.fetchone()
  18.592 +
  18.593 +    if not count:
  18.594 +        cx.close()
  18.595 +        return -1
  18.596 +
  18.597 +    cu.execute("-- types int")
  18.598 +    cu.execute("""SELECT SUM(extent_size)
  18.599 +                  FROM vdisks NATURAL JOIN vdisk_extents
  18.600 +                                         NATURAL JOIN vdisk_part
  18.601 +                  WHERE vdisks.vdisk_id = """ + vdisk_id)
  18.602 +
  18.603 +    real_size, = cu.fetchone() # get the true allocated size
  18.604 +
  18.605 +
  18.606 +    cu.execute("-- types int")
  18.607 +    cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id)
  18.608 +
  18.609 +    old_size, = cu.fetchone()
  18.610 +
  18.611 +    if real_size < old_size:
  18.612 +        cx.close()
  18.613 +        return -1
  18.614 +
  18.615 +    if expiry_time == 0:
  18.616 +        expires = '0'
  18.617 +    else:
  18.618 +        expires = '1'
  18.619 +
  18.620 +    # this will execute the SQL query we build to store details of the new
  18.621 +    # virtual disk and allocate space to it print building_sql
  18.622 +    cu.execute("UPDATE vdisks SET expiry_time = datetime('now','"
  18.623 +               + str(expiry_time) + " seconds'), expires = " + expires
  18.624 +               + " WHERE vdisk_id = " + vdisk_id)
  18.625 +    
  18.626 +    cx.commit()
  18.627 +    cx.close()
  18.628 +    return 0
  18.629 +
  18.630 +
  18.631 +
  18.632 +
  18.633 +def vd_list():
  18.634 +    """Lists all the virtual disks registered in the system.
  18.635 +    returns [list of dicts]
  18.636 +    """
  18.637 +    
  18.638 +    if not os.path.isfile(VD_DB_FILE):
  18.639 +        __vd_no_database()
  18.640 +
  18.641 +    cx = sqlite.connect(VD_DB_FILE)
  18.642 +    cu = cx.cursor()
  18.643 +
  18.644 +    cu.execute("""SELECT vdisk_id, size, expires, expiry_time
  18.645 +                  FROM vdisks
  18.646 +                  WHERE (NOT expires) OR expiry_time > datetime('now')
  18.647 +               """)
  18.648 +
  18.649 +    ret = cu.fetchall()
  18.650 +
  18.651 +    cx.close()
  18.652 +
  18.653 +    def makedicts((vdisk_id, size, expires, expiry_time)):
  18.654 +        return { 'vdisk_id' : str(vdisk_id), 'size': size,
  18.655 +                 'expires' : expires, 'expiry_time' : expiry_time }
  18.656 +
  18.657 +    return map(makedicts, ret)
  18.658 +
  18.659 +
  18.660 +def vd_refresh(id, expiry):
  18.661 +    """Change the expiry time of a virtual disk.
  18.662 +    id [string]  : a virtual disk identifier
  18.663 +    expiry [int] : expiry time in seconds from now (0 = never expire)
  18.664 +    returns [int]: zero on success, non-zero on failure
  18.665 +    """
  18.666 +
  18.667 +    if not os.path.isfile(VD_DB_FILE):
  18.668 +        __vd_no_database()
  18.669 +    
  18.670 +    cx = sqlite.connect(VD_DB_FILE)
  18.671 +    cu = cx.cursor()
  18.672 +
  18.673 +    cu.execute("-- types int")
  18.674 +    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id
  18.675 +               + " AND (expiry_time > datetime('now') OR NOT expires)")
  18.676 +    count, = cu.fetchone()
  18.677 +
  18.678 +    if not count:
  18.679 +        cx.close()
  18.680 +        return -1
  18.681 +
  18.682 +    if expiry:
  18.683 +        expires = 1
  18.684 +        expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
  18.685 +    else:
  18.686 +        expires = 0
  18.687 +        expiry_ts = "NULL"
  18.688 +
  18.689 +    cu.execute("UPDATE vdisks SET expires = " + str(expires)
  18.690 +               + ", expiry_time = " + expiry_ts
  18.691 +               + " WHERE (expiry_time > datetime('now') OR NOT expires)"
  18.692 +               + " AND vdisk_id = " + id)
  18.693 +
  18.694 +    cx.commit()
  18.695 +    cx.close()
  18.696 +    
  18.697 +    return 0
  18.698 +
  18.699 +
  18.700 +def vd_delete(id):
  18.701 +    """Deletes a Virtual Disk, making its extents available for future VDs.
  18.702 +       id [string]   : identifier for the virtual disk to delete
  18.703 +       returns [int] : 0 on success, -1 on failure (VD not found
  18.704 +                       or already deleted)
  18.705 +    """
  18.706 +
  18.707 +    if not os.path.isfile(VD_DB_FILE):
  18.708 +        __vd_no_database()
  18.709 +    
  18.710 +    cx = sqlite.connect(VD_DB_FILE)
  18.711 +    cu = cx.cursor()
  18.712 +
  18.713 +    cu.execute("-- types int")
  18.714 +    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id
  18.715 +               + " AND (expiry_time > datetime('now') OR NOT expires)")
  18.716 +    count, = cu.fetchone()
  18.717 +
  18.718 +    if not count:
  18.719 +        cx.close()
  18.720 +        return -1
  18.721 +
  18.722 +    cu.execute("UPDATE vdisks SET expires = 1, expiry_time = datetime('now')"
  18.723 +               + " WHERE vdisk_id = " + id)
  18.724 +
  18.725 +    cx.commit()
  18.726 +    cx.close()
  18.727 +    
  18.728 +    return 0
  18.729 +
  18.730 +
  18.731 +def vd_freespace():
  18.732 +    """Returns the amount of free space available for new virtual disks, in MB
  18.733 +    returns [int] : free space for VDs in MB
  18.734 +    """
  18.735 +
  18.736 +    if not os.path.isfile(VD_DB_FILE):
  18.737 +        __vd_no_database()
  18.738 + 
  18.739 +    cx = sqlite.connect(VD_DB_FILE)
  18.740 +    cu = cx.cursor()
  18.741 +
  18.742 +    cu.execute("-- types int")
  18.743 +
  18.744 +    cu.execute("""SELECT SUM(extent_size)
  18.745 +                  FROM vdisks NATURAL JOIN vdisk_extents
  18.746 +                                           NATURAL JOIN vdisk_part
  18.747 +                  WHERE expiry_time <= datetime('now') AND expires""")
  18.748 +
  18.749 +    sum, = cu.fetchone()
  18.750 +
  18.751 +    cx.close()
  18.752 +
  18.753 +    return sum / 2048
  18.754 +
  18.755 +
  18.756 +def vd_init_db(path):
  18.757 +    """Initialise the VD SQLite database
  18.758 +    path [string]: path to the SQLite database file
  18.759 +    """
  18.760 +
  18.761 +    cx = sqlite.connect(path)
  18.762 +    cu = cx.cursor()
  18.763 +
  18.764 +    cu.execute(
  18.765 +        """CREATE TABLE vdisk_extents
  18.766 +                           ( vdisk_extent_no INT,
  18.767 +                             vdisk_id INT,
  18.768 +                             part_id INT,
  18.769 +                             part_extent_no INT )
  18.770 +        """)
  18.771 +
  18.772 +    cu.execute(
  18.773 +        """CREATE TABLE vdisk_part
  18.774 +                           ( part_id INT,
  18.775 +                             partition VARCHAR,
  18.776 +                             extent_size INT )
  18.777 +        """)
  18.778 +
  18.779 +    cu.execute(
  18.780 +        """CREATE TABLE vdisks
  18.781 +                           ( vdisk_id INT,
  18.782 +                             size INT,
  18.783 +                             expires BOOLEAN,
  18.784 +                             expiry_time TIMESTAMP )
  18.785 +        """)
  18.786 +
  18.787 +
  18.788 +    cu.execute(
  18.789 +        """INSERT INTO vdisks ( vdisk_id, size, expires, expiry_time )
  18.790 +                       VALUES ( 0,        0,    1,       datetime('now') )
  18.791 +        """)
  18.792 +
  18.793 +    cx.commit()
  18.794 +    cx.close()
  18.795 +
  18.796 +    VD_DB_FILE = path
  18.797 +
  18.798 +
  18.799 +
  18.800 +def vd_cp_to_file(vdisk_id,filename):
  18.801 +    """Writes the contents of a specified vdisk out into a disk file, leaving
  18.802 +    the original copy in the virtual disk pool."""
  18.803 +
  18.804 +    cx = sqlite.connect(VD_DB_FILE)
  18.805 +    cu = cx.cursor()
  18.806 +
  18.807 +    extents = vd_lookup(vdisk_id)
  18.808 +
  18.809 +    if not extents:
  18.810 +        return -1
  18.811 +    
  18.812 +    file_idx = 0 # index into source file, in sectors
  18.813 +
  18.814 +    for i in extents:
  18.815 +        cu.execute("""SELECT partition, extent_size FROM vdisk_part
  18.816 +                      WHERE part_id =  """ + str(i['part_device']))
  18.817 +
  18.818 +        (partition, extent_size) = cu.fetchone()
  18.819 +
  18.820 +        os.system("dd bs=1b if=" + partition + " of=" + filename
  18.821 +                  + " skip=" + str(i['part_start_sector'])
  18.822 +                  + " seek=" + str(file_idx)
  18.823 +                  + " count=" + str(i['nr_sectors'])
  18.824 +                  + " > /dev/null")
  18.825 +
  18.826 +        file_idx += i['nr_sectors']
  18.827 +
  18.828 +    cx.close()
  18.829 +
  18.830 +    return 0 # should return -1 if something breaks
  18.831 +    
  18.832 +
  18.833 +def vd_mv_to_file(vdisk_id,filename):
  18.834 +    """Writes a vdisk out into a disk file and frees the space originally
  18.835 +    taken within the virtual disk pool.
  18.836 +    vdisk_id [string]: ID of the vdisk to write out
  18.837 +    filename [string]: file to write vdisk contents out to
  18.838 +    returns [int]: zero on success, nonzero on failure
  18.839 +    """
  18.840 +
  18.841 +    if vd_cp_to_file(vdisk_id,filename):
  18.842 +        return -1
  18.843 +
  18.844 +    if vd_delete(vdisk_id):
  18.845 +        return -1
  18.846 +
  18.847 +    return 0
  18.848 +
  18.849 +
  18.850 +def vd_read_from_file(filename,expiry):
  18.851 +    """Reads the contents of a file directly into a vdisk, which is
  18.852 +    automatically allocated to fit.
  18.853 +    filename [string]: file to read disk contents from
  18.854 +    returns [string] : vdisk ID for the destination vdisk
  18.855 +    """
  18.856 +
  18.857 +    size_bytes = os.stat(filename).st_size
  18.858 +
  18.859 +    (size_mb,leftover) =  divmod(size_bytes,1048580) # size in megabytes
  18.860 +    if leftover > 0: size_mb += 1 # round up if not an exact number of MB
  18.861 +
  18.862 +    vdisk_id = vd_create(size_mb, expiry)
  18.863 +
  18.864 +    if vdisk_id < 0:
  18.865 +        return -1
  18.866 +
  18.867 +    cx = sqlite.connect(VD_DB_FILE)
  18.868 +    cu = cx.cursor()
  18.869 +
  18.870 +    cu.execute("""SELECT partition, extent_size, part_extent_no
  18.871 +                  FROM vdisk_part NATURAL JOIN vdisk_extents
  18.872 +                  WHERE vdisk_id =  """ + vdisk_id + """
  18.873 +                  ORDER BY vdisk_extent_no ASC""")
  18.874 +
  18.875 +    extents = cu.fetchall()
  18.876 +
  18.877 +    size_sectors = size_mb * 2048 # for feeding to dd
  18.878 +
  18.879 +    file_idx = 0 # index into source file, in sectors
  18.880 +
  18.881 +    def write_extent_to_vd((partition, extent_size, part_extent_no),
  18.882 +                           file_idx, filename):
  18.883 +        """Write an extent out to disk and update file_idx"""
  18.884 +
  18.885 +        os.system("dd bs=512 if=" + filename + " of=" + partition
  18.886 +                  + " skip=" + str(file_idx)
  18.887 +                  + " seek=" + str(part_extent_no * extent_size)
  18.888 +                  + " count=" + str(min(extent_size, size_sectors - file_idx))
  18.889 +                  + " > /dev/null")
  18.890 +
  18.891 +        return extent_size
  18.892 +
  18.893 +    for i in extents:
  18.894 +        file_idx += write_extent_to_vd(i, file_idx, filename)
  18.895 +
  18.896 +    cx.close()
  18.897 +
  18.898 +    return vdisk_id
  18.899 +    
  18.900 +
  18.901 +
  18.902 +
  18.903 +def vd_extents_validate(new_extents,new_writeable):
  18.904 +    """Validate the extents against the existing extents.
  18.905 +    Complains if the list supplied clashes against the extents that
  18.906 +    are already in use in the system.
  18.907 +    new_extents [list of dicts]: list of new extents, as dicts
  18.908 +    new_writeable [int]: 1 if they are to be writeable, 0 otherwise
  18.909 +    returns [int]: either the expertise level of the mapping if it doesn't
  18.910 +                   exceed VBD_EXPERT_MODE or -1 if it does (error)
  18.911 +    """
  18.912 +
  18.913 +    import Xc # this is only needed in this function
  18.914 +
  18.915 +    xc = Xc.new()
  18.916 +
  18.917 +    ##### Probe for explicitly created virtual disks and build a list
  18.918 +    ##### of extents for comparison with the ones that are being added
  18.919 +
  18.920 +    probe = xc.vbd_probe()
  18.921 +
  18.922 +    old_extents = [] # this will hold a list of all existing extents and
  18.923 +                     # their writeable status, as a list of (device,
  18.924 +                     # start, size, writeable?) tuples
  18.925 +
  18.926 +    for vbd in probe:
  18.927 +        this_vbd_extents = xc.vbd_getextents(vbd['dom'],vbd['vbd'])
  18.928 +        for vbd_ext in this_vbd_extents:
  18.929 +            vbd_ext['writeable'] = vbd['writeable']
  18.930 +            old_extents.append(vbd_ext)
  18.931 +            
  18.932 +    ##### Now scan /proc/mounts for compile a list of extents corresponding to
  18.933 +    ##### any devices mounted in DOM0.  This list is added on to old_extents
  18.934 +
  18.935 +    regexp = re.compile("/dev/(\S*) \S* \S* (..).*")
  18.936 +    fd = open('/proc/mounts', "r")
  18.937 +
  18.938 +    while True:
  18.939 +        line = fd.readline()
  18.940 +        if not line: # if we've run out of lines then stop reading
  18.941 +            break
  18.942 +        
  18.943 +        m = regexp.match(line)
  18.944 +
  18.945 +        # if the regexp didn't match then it's probably a line we don't
  18.946 +        # care about - skip to next line
  18.947 +        if not m:
  18.948 +            continue
  18.949 +
  18.950 +        # lookup the device
  18.951 +        ext_list = lookup_raw_partn(m.group(1))
  18.952 +
  18.953 +        # if lookup failed, skip to next mounted device
  18.954 +        if not ext_list:
  18.955 +            continue
  18.956 +
  18.957 +        # set a writeable flag as appropriate
  18.958 +        for ext in ext_list:
  18.959 +            ext['writeable'] = m.group(2) == 'rw'
  18.960 +
  18.961 +        # now we've got here, the contents of ext_list are in a
  18.962 +        # suitable format to be added onto the old_extents list, ready
  18.963 +        # for checking against the new extents
  18.964 +
  18.965 +        old_extents.extend(ext_list)
  18.966 +
  18.967 +    fd.close() # close /proc/mounts
  18.968 +
  18.969 +    ##### By this point, old_extents contains a list of extents, in
  18.970 +    ##### dictionary format corresponding to every extent of physical
  18.971 +    ##### disk that's either part of an explicitly created VBD, or is
  18.972 +    ##### mounted under DOM0.  We now check these extents against the
  18.973 +    ##### proposed additions in new_extents, to see if a conflict will
  18.974 +    ##### happen if they are added with write status new_writeable
  18.975 +
  18.976 +    level = 0 # this'll accumulate the max warning level
  18.977 +
  18.978 +    # Search for clashes between the new extents and the old ones
  18.979 +    # Takes time O(len(new_extents) * len(old_extents))
  18.980 +    for new_ext in new_extents:
  18.981 +        for old_ext in old_extents:
  18.982 +            if(new_ext['device'] == old_ext['device']):
  18.983 +
  18.984 +                new_ext_start = new_ext['start_sector']
  18.985 +                new_ext_end = new_ext_start + new_ext['nr_sectors'] - 1
  18.986 +                
  18.987 +                old_ext_start = old_ext['start_sector']
  18.988 +                old_ext_end = old_ext_start + old_ext['nr_sectors'] - 1
  18.989 +                
  18.990 +                if((old_ext_start <= new_ext_start <= old_ext_end) or
  18.991 +                   (old_ext_start <= new_ext_end <= old_ext_end)):
  18.992 +                    if (not old_ext['writeable']) and new_writeable:
  18.993 +                        level = max(1,level)
  18.994 +                    elif old_ext['writeable'] and (not new_writeable):
  18.995 +                        level = max(1,level)
  18.996 +                    elif old_ext['writeable'] and new_writeable:
  18.997 +                        level = max(2,level)
  18.998 +
  18.999 +
 18.1000 +    ##### level now holds the warning level incurred by the current
 18.1001 +    ##### VBD setup and we complain appropriately to the user
 18.1002 +
 18.1003 +
 18.1004 +    if level == 1:
 18.1005 +        print >> sys.stderr, """Warning: one or more hard disk extents
 18.1006 +         writeable by one domain are also readable by another."""
 18.1007 +    elif level == 2:
 18.1008 +        print >> sys.stderr, """Warning: one or more hard disk extents are
 18.1009 +         writeable by two or more domains simultaneously."""
 18.1010 +
 18.1011 +    if level > VBD_EXPERT_MODE:
 18.1012 +        print >> sys.stderr, """ERROR: This kind of disk sharing is not allowed
 18.1013 +        at the current safety level (%d).""" % VBD_EXPERT_MODE
 18.1014 +        level = -1
 18.1015 +
 18.1016 +    return level
 18.1017 +
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tools/xenctl/setup.py	Mon Mar 15 17:56:41 2004 +0000
    19.3 @@ -0,0 +1,8 @@
    19.4 +
    19.5 +from distutils.core import setup, Extension
    19.6 +
    19.7 +setup(name = "xenctl",
    19.8 +      version = "1.0",
    19.9 +      packages = ["xenctl"],
   19.10 +      package_dir = { "xenctl" : "lib" },
   19.11 +      )