bitkeeper revision 1.1010.1.10 (40dfd40bszbCgYF9OJJKWOo1n7X8hw)

Rename xenctl, move things around.
This commit is contained in:
mjw@wray-m-3.hpl.hp.com committed 2004-06-28 08:17:15 +00:00
1 parent 9bdbe09f07
commit af551a1bda
17 files changed
+117 -1237

No files matched your search

+7 -9
View File
@@ -162,10 +162,9 @@
40278d91ZjLhxdjjrGe8HEdwHLj5xQ tools/examples/netbsd
401d7e16NpnVrFSsR7lKKKfTwCYvWA tools/examples/xc_dom_control.py
401d7e16RJj-lbtsVEjua6HYAIiKiA tools/examples/xc_dom_create.py
403b7cf7J7FsSSoEPGhx6gXR4pIdZg tools/examples/xc_physinfo.py
40c9c4684Wfg8VgMKtRFa_ULi2e_tQ tools/examples/xm_dom_control.py
40c9c468pXANclL7slGaoD0kSrIwoQ tools/examples/xm_dom_create.py
40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmdefaults
40dfd40auJwNnb8NoiSnRkvZaaXkUg tools/examples/xmnetbsd
3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen
3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
@@ -200,6 +199,11 @@
3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/py/setup.py
40c9c468icGyC5RAF1bRKsCXPDCvsA tools/xen/Makefile
40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/xen/lib/__init__.py
40dfd40aMOhnw_cQLve9462UR5yYxQ tools/xen/lib/ext/__init__.py
40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/xen/lib/util/__init__.py
4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xen/lib/util/console_client.py
40c9c468IienauFHQ_xJIcqnPJ8giQ tools/xen/lib/util/ip.py
4059c6a0pnxhG8hwSOivXybbGOwuXw tools/xen/lib/util/tempfile.py
40c9c468SNuObE_YWARyS0hzTPSzKg tools/xen/lib/xend/Args.py
40c9c468Um_qc66OQeLEceIz1pgD5g tools/xen/lib/xend/EventServer.py
40c9c468U8EVl0d3G--8YXVg6VJD3g tools/xen/lib/xend/EventTypes.py
@@ -250,13 +254,6 @@
40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/xen/setup.py
40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/xen/xend
40cf2937dqM1jWW87O5OoOYND8leuA tools/xen/xm
4055ee41IfFazrwadCH2J72nz-A9YA tools/xenctl/Makefile
4055ee4b_4Rvns_KzE12csI14EKK6Q tools/xenctl/lib/__init__.py
4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xenctl/lib/console_client.py
40c9c468IienauFHQ_xJIcqnPJ8giQ tools/xenctl/lib/ip.py
4059c6a0pnxhG8hwSOivXybbGOwuXw tools/xenctl/lib/tempfile.py
3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xenctl/lib/utils.py
4055ee44Bu6oP7U0WxxXypbUt4dNPQ tools/xenctl/setup.py
40431ac64Hj4ixUnKmlugZKhXPFE_Q tools/xend-old/Makefile
4055ad95Se-FqttgxollqOAAHB94zA tools/xend-old/lib/__init__.py
4092738fMRGC9fFBcPRCWaJaj9U3ag tools/xend-old/lib/blkif.py
@@ -274,6 +271,7 @@
403a3edbVpV2E_wq1zeEkJ_n4Uu2eg tools/xentrace/xentrace.c
403a3edblCUrzSj0mmKhO5HOPrOrSQ tools/xentrace/xentrace_format
4050c413NtuyIq5lsYJV4P7KIjujXw tools/xentrace/xentrace_format.1
40dfd40a0QtsSGigB9TCpVGWZmhlNA tools/xu/Makefile
40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/xu/lib/__init__.py
40dc4076pVeE1kEEWzcUaNZin65kCA tools/xu/lib/domain_controller.h
40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/xu/lib/xu.c
-4
View File
@@ -5,17 +5,14 @@ all:
$(MAKE) -C misc
$(MAKE) -C examples
$(MAKE) -C xentrace
$(MAKE) -C xenctl
$(MAKE) -C xen
install: all
$(MAKE) -C xc install
$(MAKE) -C xu install
$(MAKE) -C misc install
$(MAKE) -C xenctl install
$(MAKE) -C examples install
$(MAKE) -C xentrace install
$(MAKE) -C xenctl install
$(MAKE) -C xen install
dist: $(TARGET)
@@ -28,6 +25,5 @@ clean:
$(MAKE) -C misc clean
$(MAKE) -C examples clean
$(MAKE) -C xentrace clean
$(MAKE) -C xenctl clean
$(MAKE) -C xen clean
-20
View File
@@ -1,20 +0,0 @@
#!/usr/bin/env python
# Get information about the physical host machine
import Xc
xc = Xc.new()
info = xc.physinfo()
fmt_info = [ ( 'CPU cores', info['cores']),
('Hyperthreads per core', info['ht_per_core']),
('CPU Speed (MHz)', info['cpu_khz'] / 1000),
('Total physical mem (MB)', info['total_pages'] / 256),
('Free physical mem (MB)', info['free_pages'] / 256) ]
for (item, val) in fmt_info:
print "%-23s" % item, ':', val
-235
View File
@@ -1,235 +0,0 @@
#!/usr/bin/env python
import sys
import re
import string
import time
import os
import os.path
import signal
from xenmgr import sxp
from xenmgr.XendClient import server
# usage: xc_dom_control [command] <params>
#
# this script isn't very smart, but it'll do for now.
#
def usage (rc=0):
if rc:
out = sys.stderr
else:
out = sys.stdout
print >> out, """
Usage: %s [command] <params>
help -- print usage
pause [dom] -- pause a domain
unpause [dom] -- un-pause a domain
shutdown [dom] [[-w]] -- request a domain to shutdown (can specify 'all')
(optionally wait for complete shutdown)
destroy [dom] -- immediately terminate a domain
pincpu [dom] [cpu] -- pin a domain to the specified CPU
suspend [dom] [file] -- write domain's memory to a file and terminate
(resume by re-running xc_dom_create with -L option)
unwatch [dom] -- kill the auto-restart daemon for a domain
list -- print info about all domains
listvbds -- print info about all virtual block devs
cpu_bvtset [dom] [mcuadv] [warp] [warpl] [warpu]
-- set BVT scheduling parameters for domain
cpu_bvtslice [slice] -- set default BVT scheduler slice
cpu_atropos_set [dom] [period] [slice] [latency] [xtratime]
-- set Atropos scheduling parameters for domain
cpu_rrobin_slice [slice] -- set Round Robin scheduler slice
vif_stats [dom] [vif] -- get stats for a given network vif
vif_addip [dom] [vif] [ip] -- add an IP address to a given vif
vif_setsched [dom] [vif] [bytes] [usecs] -- rate limit vif bandwidth
vif_getsched [dom] [vif] -- print vif's scheduling parameters
vbd_add [dom] [uname] [dev] [mode] -- make disk/partition uname available to
domain as dev e.g. 'vbd_add 2 phy:sda3 hda1 w'
vbd_remove [dom] [dev] -- remove disk or partition attached as 'dev'
""" % sys.argv[0]
if rc: sys.exit(rc)
if len(sys.argv) < 2: usage(1)
cmd = sys.argv[1]
#todo: replace all uses of xc with the new api.
import Xc; xc = Xc.new()
rc = ''
dom = None
def auto_restart_pid_file(dom):
# The auto-restart daemon's pid file.
return '/var/run/xendomains/%d.pid' % dom
def auto_restart_pid(dom):
watcher = auto_restart_pid_file(dom)
if os.path.isfile(watcher):
fd = open(watcher,'r')
pid = int(fd.readline())
else:
pid = None
return pid
def auto_restart_kill(dom):
#todo: replace this - tell xend not to restart any more.
# Kill a domain's auto restart daemon.
pid = auto_restart_pid(dom)
if pid:
os.kill(pid, signal.SIGTERM)
if len( sys.argv ) > 2 and re.match('\d+$', sys.argv[2]):
dom = long(sys.argv[2])
if cmd == "help":
usage()
elif cmd == 'pause':
rc = server.xend_domain_pause(dom)
elif cmd == 'unpause':
rc = server.xend_domain_unpause(dom)
elif cmd == 'shutdown':
doms = []
shutdown = []
if dom != None:
doms = [ dom ]
elif sys.argv[2] == 'all':
doms = server.xend_domains()
doms.remove('0')
for d in doms:
ret = server.xend_domain_shutdown(d)
if ret == 0:
shutdown.append(d)
else:
rc = ret
wait = (len(sys.argv) == 4 and sys.argv[3] == "-w")
if wait:
# wait for all domains we shut down to terminate
for dom in shutdown:
while True:
info = server.xend_domain(dom)
if not info: break
time.sleep(1)
elif cmd == 'destroy':
rc = server.xend_domain_halt(dom)
elif cmd == 'pincpu':
if len(sys.argv) < 4: usage(1)
cpu = int(sys.argv[3])
rc = server.xend_domain_pincpu(dom, cpu)
elif cmd == 'list':
print 'Dom Name Mem(MB) CPU State Time(s)'
doms = server.xend_domains()
doms.sort()
for dom in doms:
info = server.xend_domain(dom)
d = {}
d['dom'] = int(dom)
d['name'] = sxp.child_value(info, 'name', '??')
d['mem'] = int(sxp.child_value(info, 'memory', '0'))
d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
d['state'] = sxp.child_value(info, 'state', '??')
d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)8.2f" % d)
elif cmd == 'unwatch':
auto_restart_kill(dom)
elif cmd == 'listvbds':
print 'Dom Dev Mode Size(MB)'
for dom in server.xend_domains():
for vbd in server.xend_domain_vbds(dom):
info = server.xend_domain_vbd(vbd)
v['vbd'] = vbd
v['size'] = int(sxp.get_child_value(info, 'size', '0'))
v['mode'] = sxp.get_child_value(info, 'mode', '??')
vbd['size_mb'] = vbd['nr_sectors'] / 2048
print ('%(dom)-4d %(vbd)04x %(mode)-2s %(size)d' % v)
elif cmd == 'suspend':
if len(sys.argv) < 4: usage(1)
file = os.path.abspath(sys.argv[3])
auto_restart_kill(dom)
rc = server.xend_domain_save(dom, file, progress=1)
elif cmd == 'cpu_bvtslice':
if len(sys.argv) < 3: usage(1)
slice = sys.argv[2]
rc = server.xend_node_cpu_bvt_slice_set(slice)
elif cmd == 'cpu_bvtset':
if len(sys.argv) < 7: usage(1)
(mcuadv, warp, warpl, warpu) = map(int, sys.argv[3:7])
rc = server.xend_domain_cpu_bvt_set(dom, mcuadv, warp, warpl, warpu)
elif cmd == 'vif_stats':
if len(sys.argv) < 4: usage(1)
vif = int(sys.argv[3])
print server.xend_domain_vif_stats(dom, vif)
elif cmd == 'vif_addip':
if len(sys.argv) < 5: usage(1)
vif = int(sys.argv[3])
ip = sys.argv[4]
rc = server.xend_domain_vif_addip(dom, vif, ip)
elif cmd == 'vif_setsched':
if len(sys.argv) < 6: usage(1)
(vif, bytes, usecs) = map(int, sys.argv[3:6])
rc = server.xend_domain_vif_scheduler_set(dom, vif, bytes, usecs)
elif cmd == 'vif_getsched':
if len(sys.argv) < 4: usage(1)
vif = int(sys.argv[3])
print server.xend_domain_vif_scheduler_get(dom, vif)
elif cmd == 'vbd_add':
if len(sys.argv) < 6: usage(1)
uname = sys.argv[3]
dev = sys.argv[4]
mode = sys.argv[5]
try:
vbd = server.xend_domain_vbd_add(dom, uname, dev, mode)
except StandardError, ex:
print "Error:", ex
sys.exit(1)
print "Added disk/partition %s to domain %d as device %s (%x)" % (uname, dom, dev, vbd)
elif cmd == 'vbd_remove':
if len(sys.argv) < 4: usage(1)
dev = sys.argv[3]
vbd = server.xend_domain_vbd_remove(dom, dev)
if vbd < 0:
print "Failed"
sys.exit(1)
else:
print "Removed disk/partition attached as device %s (%x) in domain %d" % (dev, vbd, dom)
elif cmd == 'cpu_atropos_set': # args: dom period slice latency xtratime
if len(sys.argv) < 6: usage(1)
(period, slice, latency, xtratime) = map(int, sys.argv[3:7])
rc = server.xend_domain_cpu_atropos_set(
dom, period, slice, latency, xtratime)
elif cmd == 'cpu_rrobin_slice':
if len(sys.argv) < 3: usage(1)
slice = int(sys.argv[2])
rc = server.xend_node_rrobin_set(slice=slice)
else:
usage(1)
if rc != '':
print "return code %d" % rc
+3 -4
View File
@@ -44,10 +44,9 @@ cpu = vmid # set based on vmid (mod number of CPUs)
# Number of network interfaces. Default is 1.
#nics=1
# List of MAC addresses for the network interfaces.
# If there aren't enough addresses for all the interfaces
# the rest get random MACs.
#mac = [ "aa:00:00:00:00:11" ]
# Optionally define mac and/or bridge for the network interfaces.
# Random MACs are assigned if not given.
#vif = [ 'mac=aa:00:00:00:00:11, bridge=nbe-br' ]
#----------------------------------------------------------------------------
# Define the disk devices you want the domain to have access to, and
+102
View File
@@ -0,0 +1,102 @@
# -*- mode: python; -*-
#============================================================================
# Python defaults setup for 'xm create'.
# Edit this file to reflect the configuration of your system.
# This file expects the variable 'vmid' to be set.
#============================================================================
def config_usage ():
print >>sys.stderr,"""
The config file '%s' requires the following variable to be defined:
vmid -- Numeric identifier for the new domain, used to calculate
the VM's IP address and root partition. E.g. -Dvmid=1
""" % config_file
try:
vmid = int(vmid) # convert to integer
except:
raise ValueError, "Variable 'vmid' must be an integer"
if vmid <= 0:
raise ValueError, "Variable 'vmid' must be greater than 0"
#----------------------------------------------------------------------------
# Kernel image file.
image = "/boot/netbsd"
# The domain build function.
builder='netbsd'
# Initial memory allocation (in megabytes) for the new domain.
memory = 16
# A handy name for your new domain.
name = "NetBSD VM %d" % vmid
#----------------------------------------------------------------------------
# Define network interfaces.
# Number of network interfaces. Default is 1.
#nics=1
# Optionally define mac and/or bridge for the network interfaces.
# Random MACs are assigned if not given.
#vif = [ 'mac=aa:00:00:00:00:11, bridge=nbe-br' ]
# Specify IP address(es), for the new domain. You need to
# configure IP addrs within the domain just as you do normally. This
# is just to let Xen know about them so it can route packets
# appropriately.
#ipaddr = [ xenctl.utils.add_offset_to_ip(xenctl.utils.get_current_ipaddr(),vmid),
# xenctl.utils.add_offset_to_ip('169.254.1.0',vmid),
# ]
#----------------------------------------------------------------------------
# Define the disk devices you want the domain to have access to, and
# what you want them accessible as.
# Each disk entry is of the form phy:DEV,VDEV,MODE
# where DEV is the device, VDEV is the device name the domain will see,
# and MODE is r for read-only, w for read-write.
#disk = [ 'phy:sda%d,sda1,w' % (7+vmid),
# 'phy:sda6,sda6,r' ]
#----------------------------------------------------------------------------
# Set the kernel command line for the new domain.
# You only need to define the IP parameters and hostname if the domain's
# IP config doesn't, e.g. in ifcfg-eth0 or via DHCP.
# You can use 'extra' to set the runlevel and custom environment
# variables used by custom rc scripts (e.g. VMID=, usr= ).
# Set if you want dhcp to allocate the IP address.
#dhcp="dhcp"
# Set netmask.
#netmask=
# Set default gateway.
#gateway=
# Set the hostname.
#hostname= "vm%d" % vmid
# Set root device.
root = "/dev/sda1 ro"
# Root device for nfs.
#root = "/dev/nfs"
# The nfs server.
#nfs_server = '169.254.1.0'
# Root directory on the nfs server.
#nfs_root = '/full/path/to/root/directory'
# Sets runlevel 4 and the device for /usr.
#extra = "4 VMID=%d usr=/dev/sda6" % vmid
extra = "4 VMID=%d bootdev=xennet0" % vmid
#----------------------------------------------------------------------------
# Set according to whether you want the domain restarted when it exits.
# The default is False.
#restart = True
#============================================================================
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1 -1
View File
@@ -439,7 +439,7 @@ class ProgConsole(Prog):
if not console:
self.err("No console information")
port = sxp.child_value(console, "port")
from xenctl import console_client
from xen.util import console_client
console_client.connect("localhost", int(port))
xm.prog(ProgConsole)
+1
View File
@@ -8,6 +8,7 @@ setup(name = 'xen',
author_email = 'mike.wray@hp.com',
packages = ['xen',
'xen.ext',
'xen.util',
'xen.xend',
'xen.xend.server',
'xen.xm',
View File
Whitespace-only changes.
-944
View File
@@ -1,944 +0,0 @@
import os, re, socket, string, sys, tempfile, xenctl.ip
##### Module variables
"""Location of the Virtual Disk management database.
defaults to /var/db/xen_vdisks.sqlite
"""
VD_DB_FILE = "/var/db/xen_vdisks.sqlite"
"""VBD expertise level - determines the strictness of the sanity checking.
This mode determines the level of complaints when disk sharing occurs
through the current VBD mappings.
0 - only allow shared mappings if both domains have r/o access (always OK)
1 - also allow sharing with one dom r/w and the other r/o
2 - allow sharing with both doms r/w
"""
VBD_EXPERT_MODE = 0
##### Module initialisation
try:
# try to import sqlite (not everyone will have it installed)
import sqlite
except ImportError:
# on failure, just catch the error, don't do anything
pass
##### Networking-related functions
def get_current_ipaddr(dev='eth0'):
return xenctl.ip.get_current_ipaddr(dev)
def get_current_ipmask(dev='eth0'):
return xenctl.ip.get_current_ipmask(dev)
def get_current_ipgw(dev='eth0'):
return xenctl.ip.get_current_ipgw(dev)
def setup_vfr_rules_for_vif(dom,vif,addr):
return xenctl.ip.setup_vfr_rules_for_vif(dom,vif,addr)
def inet_aton(addr):
return xenctl.ip.inet_aton(addr)
def inet_ntoa(n):
return xenctl.ip.inet_ntoa(n)
def add_offset_to_ip(addr, offset):
return xenctl.ip.add_offset_to_ip(addr, offset)
def check_subnet( ip, network, netmask ):
return xenctl.ip.check_subnet( ip, network, netmask )
##### VBD-related Functions
def blkdev_name_to_number(name):
"""Take the given textual block-device name (e.g., '/dev/sda1',
'hda') and return the device number used by the OS. """
if not re.match( '/dev/', name ):
name = '/dev/' + name
return os.stat(name).st_rdev
# lookup_blkdev_partn_info( '/dev/sda3' )
def lookup_raw_partn(partition):
"""Take the given block-device name (e.g., '/dev/sda1', 'hda')
and return a dictionary { device, start_sector,
nr_sectors, type }
device: Device number of the given partition
start_sector: Index of first sector of the partition
nr_sectors: Number of sectors comprising this partition
type: 'Disk' or identifying name for partition type
"""
if not re.match( '/dev/', partition ):
partition = '/dev/' + partition
drive = re.split( '[0-9]', partition )[0]
if drive == partition:
fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
line = fd.readline()
if line:
return [ { 'device' : blkdev_name_to_number(drive),
'start_sector' : long(0),
'nr_sectors' : long(line) * 2,
'type' : 'Disk' } ]
return None
# determine position on disk
fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
#['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
lines = fd.readlines()
for line in lines:
m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
if m:
return [ { 'device' : blkdev_name_to_number(drive),
'start_sector' : long(m.group(1)),
'nr_sectors' : long(m.group(2)),
'type' : m.group(3) } ]
return None
def lookup_disk_uname( uname ):
"""Lookup a list of segments for either a physical or a virtual device.
uname [string]: name of the device in the format \'vd:id\' for a virtual
disk, or \'phy:dev\' for a physical device
returns [list of dicts]: list of extents that make up the named device
"""
( type, d_name ) = string.split( uname, ':' )
if type == "phy":
segments = lookup_raw_partn( d_name )
elif type == "vd":
segments = vd_lookup( d_name )
return segments
##### Management of the Xen control daemon
##### (c) Keir Fraser, University of Cambridge
def xend_control_message( message ):
"""Takes a textual control message and sends it to the 'xend' Xen
control daemon. Returns a dictionary containing the daemon's multi-part
response."""
tmpdir = tempfile.mkdtemp()
try:
ctl = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM, 0)
ctl.bind(tmpdir+'/sock')
ctl.sendto(message, '/var/run/xend/management_sock')
data, addr = ctl.recvfrom(2048)
ctl.close()
finally:
if os.path.exists(tmpdir+'/sock'):
os.unlink(tmpdir+'/sock')
if os.path.exists(tmpdir):
os.rmdir(tmpdir)
return eval(data)
##### VD Management-related functions
##### By Mark Williamson, <mark.a.williamson@intel.com>
##### (C) Intel Research Cambridge
# TODO:
#
# Plenty of room for enhancement to this functionality (contributions
# welcome - and then you get to have your name in the source ;-)...
#
# vd_unformat() : want facilities to unallocate virtual disk
# partitions, possibly migrating virtual disks of them, with checks to see if
# it's safe and options to force it anyway
#
# vd_create() : should have an optional argument specifying a physical
# disk preference - useful to allocate for guest doms to do RAID
#
# vd_undelete() : add ability to "best effort" undelete as much of a
# vdisk as is left in the case that some of it has already been
# reallocated. Some people might still be able to recover some of
# their data this way, even if some of the disk has disappeared.
#
# It'd be nice if we could wipe virtual disks for security purposes -
# should be easy to do this using dev if=/dev/{zero,random} on each
# extent in turn. There could be another optional flag to vd_create
# in order to allow this.
#
# Error codes could be more expressive - i.e. actually tell why the
# error occurred rather than "it broke". Currently the code avoids
# using exceptions to make control scripting simpler and more
# accessible to beginners - therefore probably should just use more
# return codes.
#
# Enhancements / additions to the example scripts are also welcome:
# some people will interact with this code mostly through those
# scripts.
#
# More documentation of how this stuff should be used is always nice -
# if you have a novel configuration that you feel isn't discussed
# enough in the HOWTO (which is currently a work in progress), feel
# free to contribute a walkthrough, or something more substantial.
#
def __vd_no_database():
"""Called when no database found - exits with an error
"""
print >> sys.stderr, "ERROR: Could not locate the database file at " + VD_DB_FILE
sys.exit(1)
def vd_format(partition, extent_size_mb):
"""Format a partition or drive for use a virtual disk storage.
partition [string]: device file representing the partition
extent_size_mb [string]: extent size in megabytes to use on this disk
"""
if not os.path.isfile(VD_DB_FILE):
vd_init_db(VD_DB_FILE)
if not re.match( '/dev/', partition ):
partition = '/dev/' + partition
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
cu.execute("select * from vdisk_part where partition = \'"
+ partition + "\'")
row = cu.fetchone()
extent_size = extent_size_mb * 2048 # convert megabytes to sectors
if not row:
part_info = lookup_raw_partn(partition)[0]
cu.execute("INSERT INTO vdisk_part(partition, part_id, extent_size) " +
"VALUES ( \'" + partition + "\', "
+ str(blkdev_name_to_number(partition))
+ ", " + str(extent_size) + ")")
cu.execute("SELECT max(vdisk_extent_no) FROM vdisk_extents "
+ "WHERE vdisk_id = 0")
max_id, = cu.fetchone()
if max_id != None:
new_id = max_id + 1
else:
new_id = 0
num_extents = part_info['nr_sectors'] / extent_size
for i in range(num_extents):
sql ="""INSERT INTO vdisk_extents(vdisk_extent_no, vdisk_id,
part_id, part_extent_no)
VALUES ("""+ str(new_id + i) + ", 0, "\
+ str(blkdev_name_to_number(partition))\
+ ", " + str(num_extents - (i + 1)) + ")"
cu.execute(sql)
cx.commit()
cx.close()
return 0
def vd_create(size_mb, expiry):
"""Create a new virtual disk.
size_mb [int]: size in megabytes for the new virtual disk
expiry [int]: expiry time in seconds from now
"""
if not os.path.isfile(VD_DB_FILE):
__vd_no_database()
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
size = size_mb * 2048
cu.execute("SELECT max(vdisk_id) FROM vdisks")
max_id, = cu.fetchone()
new_id = int(max_id) + 1
# fetch a list of extents from the expired disks, along with information
# about their size
cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
vdisk_extents.part_id, extent_size
FROM vdisks NATURAL JOIN vdisk_extents
NATURAL JOIN vdisk_part
WHERE expires AND expiry_time <= datetime('now')
ORDER BY expiry_time ASC, vdisk_extent_no DESC
""") # aims to reuse the last extents
# from the longest-expired disks first
allocated = 0
if expiry:
expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
expires = 1
else:
expiry_ts = "NULL"
expires = 0
# we'll use this to build the SQL statement we want
building_sql = "INSERT INTO vdisks(vdisk_id, size, expires, expiry_time)" \
+" VALUES ("+str(new_id)+", "+str(size)+ ", " \
+ str(expires) + ", " + expiry_ts + "); "
counter = 0
while allocated < size:
row = cu.fetchone()
if not row:
print "ran out of space, having allocated %d meg of %d" % (allocated, size)
cx.close()
return -1
(vdisk_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
allocated += extent_size
building_sql += "UPDATE vdisk_extents SET vdisk_id = " + str(new_id) \
+ ", " + "vdisk_extent_no = " + str(counter) \
+ " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
+ " AND vdisk_id = " + str(vdisk_id) + "; "
counter += 1
# this will execute the SQL query we build to store details of the new
# virtual disk and allocate space to it print building_sql
cu.execute(building_sql)
cx.commit()
cx.close()
return str(new_id)
def vd_lookup(id):
"""Lookup a Virtual Disk by ID.
id [string]: a virtual disk identifier
Returns [list of dicts]: a list of extents as dicts, containing fields:
device : Linux device number of host disk
start_sector : within the device
nr_sectors : size of this extent
type : set to \'VD Extent\'
part_device : Linux device no of host partition
part_start_sector : within the partition
"""
if not os.path.isfile(VD_DB_FILE):
__vd_no_database()
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
cu.execute("-- types int")
cu.execute("""SELECT COUNT(*)
FROM vdisks
WHERE (expiry_time > datetime('now') OR NOT expires)
AND vdisk_id = """ + id)
count, = cu.fetchone()
if not count:
cx.close()
return None
cu.execute("SELECT size from vdisks WHERE vdisk_id = " + id)
real_size, = cu.fetchone()
# This query tells PySQLite how to convert the data returned from the
# following query - the use of the multiplication confuses it otherwise ;-)
# This row is significant to PySQLite but is syntactically an SQL comment.
cu.execute("-- types str, int, int, int")
# This SQL statement is designed so that when the results are fetched they
# will be in the right format to return immediately.
cu.execute("""SELECT partition, vdisk_part.part_id,
round(part_extent_no * extent_size) as start,
extent_size
FROM vdisks NATURAL JOIN vdisk_extents
NATURAL JOIN vdisk_part
WHERE vdisk_extents.vdisk_id = """ + id
+ " ORDER BY vdisk_extents.vdisk_extent_no ASC"
)
extent_tuples = cu.fetchall()
# use this function to map the results from the database into a dict
# list of extents, for consistency with the rest of the code
def transform ((partition, part_device, part_offset, nr_sectors)):
return {
# the disk device this extent is on - for passing to Xen
'device' : lookup_raw_partn(partition)[0]['device'],
# the offset of this extent within the disk - for passing to Xen
'start_sector' : long(part_offset + lookup_raw_partn(partition)[0]['start_sector']),
# extent size, in sectors
'nr_sectors' : nr_sectors,
# partition device this extent is on (useful to know for xenctl.utils fns)
'part_device' : part_device,
# start sector within this partition (useful to know for xenctl.utils fns)
'part_start_sector' : part_offset,
# type of this extent - handy to know
'type' : 'VD Extent' }
cx.commit()
cx.close()
extent_dicts = map(transform, extent_tuples)
# calculate the over-allocation in sectors (happens because
# we allocate whole extents)
allocated_size = 0
for i in extent_dicts:
allocated_size += i['nr_sectors']
over_allocation = allocated_size - real_size
# trim down the last extent's length so the resulting VBD will be the
# size requested, rather than being rounded up to the nearest extent
extent_dicts[len(extent_dicts) - 1]['nr_sectors'] -= over_allocation
return extent_dicts
def vd_enlarge(vdisk_id, extra_size_mb):
"""Create a new virtual disk.
vdisk_id [string] : ID of the virtual disk to enlarge
extra_size_mb [int]: size in megabytes to increase the allocation by
returns [int] : 0 on success, otherwise non-zero
"""
if not os.path.isfile(VD_DB_FILE):
__vd_no_database()
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
extra_size = extra_size_mb * 2048
cu.execute("-- types int")
cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id
+ " AND (expiry_time > datetime('now') OR NOT expires)")
count, = cu.fetchone()
if not count: # no such vdisk
cx.close()
return -1
cu.execute("-- types int")
cu.execute("""SELECT SUM(extent_size)
FROM vdisks NATURAL JOIN vdisk_extents
NATURAL JOIN vdisk_part
WHERE vdisks.vdisk_id = """ + vdisk_id)
real_size, = cu.fetchone() # get the true allocated size
cu.execute("-- types int")
cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id)
old_size, = cu.fetchone()
cu.execute("--- types int")
cu.execute("""SELECT MAX(vdisk_extent_no)
FROM vdisk_extents
WHERE vdisk_id = """ + vdisk_id)
counter = cu.fetchone()[0] + 1 # this stores the extent numbers
# because of the extent-based allocation, the VD may already have more
# allocated space than they asked for. Find out how much we really
# need to add.
add_size = extra_size + old_size - real_size
# fetch a list of extents from the expired disks, along with information
# about their size
cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
vdisk_extents.part_id, extent_size
FROM vdisks NATURAL JOIN vdisk_extents
NATURAL JOIN vdisk_part
WHERE expires AND expiry_time <= datetime('now')
ORDER BY expiry_time ASC, vdisk_extent_no DESC
""") # aims to reuse the last extents
# from the longest-expired disks first
allocated = 0
building_sql = "UPDATE vdisks SET size = " + str(old_size + extra_size)\
+ " WHERE vdisk_id = " + vdisk_id + "; "
while allocated < add_size:
row = cu.fetchone()
if not row:
cx.close()
return -1
(dead_vd_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
allocated += extent_size
building_sql += "UPDATE vdisk_extents SET vdisk_id = " + vdisk_id \
+ ", " + "vdisk_extent_no = " + str(counter) \
+ " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
+ " AND vdisk_id = " + str(dead_vd_id) + "; "
counter += 1
# this will execute the SQL query we build to store details of the new
# virtual disk and allocate space to it print building_sql
cu.execute(building_sql)
cx.commit()
cx.close()
return 0
def vd_undelete(vdisk_id, expiry_time):
"""Create a new virtual disk.
vdisk_id [int]: size in megabytes for the new virtual disk
expiry_time [int]: expiry time, in seconds from now
returns [int]: zero on success, non-zero on failure
"""
if not os.path.isfile(VD_DB_FILE):
__vd_no_database()
if vdisk_id == '0': # undeleting vdisk 0 isn't sane!
return -1
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
cu.execute("-- types int")
cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id)
count, = cu.fetchone()
if not count:
cx.close()
return -1
cu.execute("-- types int")
cu.execute("""SELECT SUM(extent_size)
FROM vdisks NATURAL JOIN vdisk_extents
NATURAL JOIN vdisk_part
WHERE vdisks.vdisk_id = """ + vdisk_id)
real_size, = cu.fetchone() # get the true allocated size
cu.execute("-- types int")
cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id)
old_size, = cu.fetchone()
if real_size < old_size:
cx.close()
return -1
if expiry_time == 0:
expires = '0'
else:
expires = '1'
# this will execute the SQL query we build to store details of the new
# virtual disk and allocate space to it print building_sql
cu.execute("UPDATE vdisks SET expiry_time = datetime('now','"
+ str(expiry_time) + " seconds'), expires = " + expires
+ " WHERE vdisk_id = " + vdisk_id)
cx.commit()
cx.close()
return 0
def vd_list():
"""Lists all the virtual disks registered in the system.
returns [list of dicts]
"""
if not os.path.isfile(VD_DB_FILE):
__vd_no_database()
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
cu.execute("""SELECT vdisk_id, size, expires, expiry_time
FROM vdisks
WHERE (NOT expires) OR expiry_time > datetime('now')
""")
ret = cu.fetchall()
cx.close()
def makedicts((vdisk_id, size, expires, expiry_time)):
return { 'vdisk_id' : str(vdisk_id), 'size': size,
'expires' : expires, 'expiry_time' : expiry_time }
return map(makedicts, ret)
def vd_refresh(id, expiry):
"""Change the expiry time of a virtual disk.
id [string] : a virtual disk identifier
expiry [int] : expiry time in seconds from now (0 = never expire)
returns [int]: zero on success, non-zero on failure
"""
if not os.path.isfile(VD_DB_FILE):
__vd_no_database()
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
cu.execute("-- types int")
cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id
+ " AND (expiry_time > datetime('now') OR NOT expires)")
count, = cu.fetchone()
if not count:
cx.close()
return -1
if expiry:
expires = 1
expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
else:
expires = 0
expiry_ts = "NULL"
cu.execute("UPDATE vdisks SET expires = " + str(expires)
+ ", expiry_time = " + expiry_ts
+ " WHERE (expiry_time > datetime('now') OR NOT expires)"
+ " AND vdisk_id = " + id)
cx.commit()
cx.close()
return 0
def vd_delete(id):
"""Deletes a Virtual Disk, making its extents available for future VDs.
id [string] : identifier for the virtual disk to delete
returns [int] : 0 on success, -1 on failure (VD not found
or already deleted)
"""
if not os.path.isfile(VD_DB_FILE):
__vd_no_database()
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
cu.execute("-- types int")
cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id
+ " AND (expiry_time > datetime('now') OR NOT expires)")
count, = cu.fetchone()
if not count:
cx.close()
return -1
cu.execute("UPDATE vdisks SET expires = 1, expiry_time = datetime('now')"
+ " WHERE vdisk_id = " + id)
cx.commit()
cx.close()
return 0
def vd_freespace():
"""Returns the amount of free space available for new virtual disks, in MB
returns [int] : free space for VDs in MB
"""
if not os.path.isfile(VD_DB_FILE):
__vd_no_database()
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
cu.execute("-- types int")
cu.execute("""SELECT SUM(extent_size)
FROM vdisks NATURAL JOIN vdisk_extents
NATURAL JOIN vdisk_part
WHERE expiry_time <= datetime('now') AND expires""")
sum, = cu.fetchone()
cx.close()
return sum / 2048
def vd_init_db(path):
"""Initialise the VD SQLite database
path [string]: path to the SQLite database file
"""
cx = sqlite.connect(path)
cu = cx.cursor()
cu.execute(
"""CREATE TABLE vdisk_extents
( vdisk_extent_no INT,
vdisk_id INT,
part_id INT,
part_extent_no INT )
""")
cu.execute(
"""CREATE TABLE vdisk_part
( part_id INT,
partition VARCHAR,
extent_size INT )
""")
cu.execute(
"""CREATE TABLE vdisks
( vdisk_id INT,
size INT,
expires BOOLEAN,
expiry_time TIMESTAMP )
""")
cu.execute(
"""INSERT INTO vdisks ( vdisk_id, size, expires, expiry_time )
VALUES ( 0, 0, 1, datetime('now') )
""")
cx.commit()
cx.close()
VD_DB_FILE = path
def vd_cp_to_file(vdisk_id,filename):
"""Writes the contents of a specified vdisk out into a disk file, leaving
the original copy in the virtual disk pool."""
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
extents = vd_lookup(vdisk_id)
if not extents:
return -1
file_idx = 0 # index into source file, in sectors
for i in extents:
cu.execute("""SELECT partition, extent_size FROM vdisk_part
WHERE part_id = """ + str(i['part_device']))
(partition, extent_size) = cu.fetchone()
os.system("dd bs=1b if=" + partition + " of=" + filename
+ " skip=" + str(i['part_start_sector'])
+ " seek=" + str(file_idx)
+ " count=" + str(i['nr_sectors'])
+ " > /dev/null")
file_idx += i['nr_sectors']
cx.close()
return 0 # should return -1 if something breaks
def vd_mv_to_file(vdisk_id,filename):
"""Writes a vdisk out into a disk file and frees the space originally
taken within the virtual disk pool.
vdisk_id [string]: ID of the vdisk to write out
filename [string]: file to write vdisk contents out to
returns [int]: zero on success, nonzero on failure
"""
if vd_cp_to_file(vdisk_id,filename):
return -1
if vd_delete(vdisk_id):
return -1
return 0
def vd_read_from_file(filename,expiry):
"""Reads the contents of a file directly into a vdisk, which is
automatically allocated to fit.
filename [string]: file to read disk contents from
returns [string] : vdisk ID for the destination vdisk
"""
size_bytes = os.stat(filename).st_size
(size_mb,leftover) = divmod(size_bytes,1048580) # size in megabytes
if leftover > 0: size_mb += 1 # round up if not an exact number of MB
vdisk_id = vd_create(size_mb, expiry)
if vdisk_id < 0:
return -1
cx = sqlite.connect(VD_DB_FILE)
cu = cx.cursor()
cu.execute("""SELECT partition, extent_size, part_extent_no
FROM vdisk_part NATURAL JOIN vdisk_extents
WHERE vdisk_id = """ + vdisk_id + """
ORDER BY vdisk_extent_no ASC""")
extents = cu.fetchall()
size_sectors = size_mb * 2048 # for feeding to dd
file_idx = 0 # index into source file, in sectors
def write_extent_to_vd((partition, extent_size, part_extent_no),
file_idx, filename):
"""Write an extent out to disk and update file_idx"""
os.system("dd bs=512 if=" + filename + " of=" + partition
+ " skip=" + str(file_idx)
+ " seek=" + str(part_extent_no * extent_size)
+ " count=" + str(min(extent_size, size_sectors - file_idx))
+ " > /dev/null")
return extent_size
for i in extents:
file_idx += write_extent_to_vd(i, file_idx, filename)
cx.close()
return vdisk_id
def vd_extents_validate(new_extents,new_writeable):
"""Validate the extents against the existing extents.
Complains if the list supplied clashes against the extents that
are already in use in the system.
new_extents [list of dicts]: list of new extents, as dicts
new_writeable [int]: 1 if they are to be writeable, 0 otherwise
returns [int]: either the expertise level of the mapping if it doesn't
exceed VBD_EXPERT_MODE or -1 if it does (error)
"""
import Xc # this is only needed in this function
xc = Xc.new()
##### Probe for explicitly created virtual disks and build a list
##### of extents for comparison with the ones that are being added
probe = xc.vbd_probe()
old_extents = [] # this will hold a list of all existing extents and
# their writeable status, as a list of (device,
# start, size, writeable?) tuples
for vbd in probe:
this_vbd_extents = xc.vbd_getextents(vbd['dom'],vbd['vbd'])
for vbd_ext in this_vbd_extents:
vbd_ext['writeable'] = vbd['writeable']
old_extents.append(vbd_ext)
##### Now scan /proc/mounts for compile a list of extents corresponding to
##### any devices mounted in DOM0. This list is added on to old_extents
regexp = re.compile("/dev/(\S*) \S* \S* (..).*")
fd = open('/proc/mounts', "r")
while True:
line = fd.readline()
if not line: # if we've run out of lines then stop reading
break
m = regexp.match(line)
# if the regexp didn't match then it's probably a line we don't
# care about - skip to next line
if not m:
continue
# lookup the device
ext_list = lookup_raw_partn(m.group(1))
# if lookup failed, skip to next mounted device
if not ext_list:
continue
# set a writeable flag as appropriate
for ext in ext_list:
ext['writeable'] = m.group(2) == 'rw'
# now we've got here, the contents of ext_list are in a
# suitable format to be added onto the old_extents list, ready
# for checking against the new extents
old_extents.extend(ext_list)
fd.close() # close /proc/mounts
##### By this point, old_extents contains a list of extents, in
##### dictionary format corresponding to every extent of physical
##### disk that's either part of an explicitly created VBD, or is
##### mounted under DOM0. We now check these extents against the
##### proposed additions in new_extents, to see if a conflict will
##### happen if they are added with write status new_writeable
level = 0 # this'll accumulate the max warning level
# Search for clashes between the new extents and the old ones
# Takes time O(len(new_extents) * len(old_extents))
for new_ext in new_extents:
for old_ext in old_extents:
if(new_ext['device'] == old_ext['device']):
new_ext_start = new_ext['start_sector']
new_ext_end = new_ext_start + new_ext['nr_sectors'] - 1
old_ext_start = old_ext['start_sector']
old_ext_end = old_ext_start + old_ext['nr_sectors'] - 1
if((old_ext_start <= new_ext_start <= old_ext_end) or
(old_ext_start <= new_ext_end <= old_ext_end)):
if (not old_ext['writeable']) and new_writeable:
level = max(1,level)
elif old_ext['writeable'] and (not new_writeable):
level = max(1,level)
elif old_ext['writeable'] and new_writeable:
level = max(2,level)
##### level now holds the warning level incurred by the current
##### VBD setup and we complain appropriately to the user
if level == 1:
print >> sys.stderr, """Warning: one or more hard disk extents
writeable by one domain are also readable by another."""
elif level == 2:
print >> sys.stderr, """Warning: one or more hard disk extents are
writeable by two or more domains simultaneously."""
if level > VBD_EXPERT_MODE:
print >> sys.stderr, """ERROR: This kind of disk sharing is not allowed
at the current safety level (%d).""" % VBD_EXPERT_MODE
level = -1
return level
-19
View File
@@ -1,19 +0,0 @@
from distutils.core import setup, Extension
import sys
modules = [ 'xenctl.console_client', 'xenctl.utils', 'xenctl.ip' ]
# We need the 'tempfile' module from Python 2.3. We install this ourselves
# if the installed Python is older than 2.3.
major = sys.version_info[0]
minor = sys.version_info[1]
if major == 2 and minor < 3:
modules.append('xenctl.tempfile')
setup(name = 'xenctl',
version = '1.0',
py_modules = modules,
package_dir = { 'xenctl' : 'lib' },
)
+1 -1
View File
@@ -12,4 +12,4 @@ install: all
fi
clean:
rm -rf build *.pyc *.pyo *.o *.a *~
rm -rf build *.pyc *.pyo *.a *.so *.o *~ *.rpm
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.