bitkeeper revision 1.1026.1.8 (40e1b09foCFBM0EuIgrSA1uLJrWuzA)

Restructuring the python code and libs - first stage.
This commit is contained in:
mjw@wray-m-3.hpl.hp.com committed 2004-06-29 18:10:39 +00:00
1 parent 4db27a4b7a
commit 48e9a9c636
136 files changed
+367 -651

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
all:
python setup.py build
install: all
if [ "$(prefix)" = "" ]; then \
python setup.py install; \
elif [ "$(dist)" = "yes" ]; then \
python setup.py install --home="$(prefix)"; \
else \
python setup.py install --root="$(prefix)"; \
fi
clean:
rm -rf build *.pyc *.pyo *.o *.a *~
+48
View File
@@ -0,0 +1,48 @@
from distutils.core import setup, Extension
XEN_ROOT = "../.."
extra_compile_args = ["-fno-strict-aliasing"]
include_dirs = [ XEN_ROOT + "/xen/include/hypervisor-ifs",
XEN_ROOT + "/linux-xen-sparse/include",
XEN_ROOT + "/tools/python/xen/ext/xu",
XEN_ROOT + "/tools/libxc",
XEN_ROOT + "/tools/libxutil",
]
library_dirs = [ XEN_ROOT + "/tools/libxc",
XEN_ROOT + "/tools/libxutil",
]
libraries = [ "xc", "xutil" ]
xc = Extension("xc",
extra_compile_args = extra_compile_args,
include_dirs = include_dirs + [ "xen/ext/xc" ],
library_dirs = library_dirs,
libraries = libraries,
sources = [ "xen/ext/xc/xc.c" ])
xu = Extension("xu",
extra_compile_args = extra_compile_args,
include_dirs = include_dirs + [ "xen/ext/xu" ],
library_dirs = library_dirs,
libraries = libraries,
sources = [ "xen/ext/xu/xu.c" ])
setup(name = 'xen',
version = '2.0',
description = 'Xen',
packages = ['xen',
'xen.ext',
'xen.util',
'xen.xend',
'xen.xend.server',
'xen.xm',
],
ext_package = "xen.ext",
ext_modules = [ xc, xu ]
)
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -0,0 +1 @@
+15
View File
@@ -0,0 +1,15 @@
all:
python setup.py build
install: all
if [ "$(prefix)" = "" ]; then \
python setup.py install; \
elif [ "$(dist)" = "yes" ]; then \
python setup.py install --home="$(prefix)"; \
else \
python setup.py install --root="$(prefix)"; \
fi
clean:
rm -rf build *.pyc *.pyo *.o *.a *~
+19
View File
@@ -0,0 +1,19 @@
from distutils.core import setup, Extension
module = Extension("xc",
extra_compile_args = ["-fno-strict-aliasing"],
include_dirs = ["../lib",
"../../../xen/include/hypervisor-ifs",
"../../../linux-xen-sparse/include",
"../../xu/lib",
"../../lib" ],
library_dirs = ["../lib",
"../../lib" ],
libraries = ["xc"],
sources = ["Xc.c"])
setup(name = "xc",
version = "2.0",
ext_package = "xen.ext",
ext_modules = [module])
File diff suppressed because it is too large. Load diff
View File
Whitespace-only changes.
+532
View File
@@ -0,0 +1,532 @@
/******************************************************************************
* domain_controller.h
*
* Interface to server controller (e.g., 'xend'). This header file defines the
* interface that is shared with guest OSes.
*
* Copyright (c) 2004, K A Fraser
*/
#ifndef __DOMAIN_CONTROLLER_H__
#define __DOMAIN_CONTROLLER_H__
#ifndef BASIC_START_INFO
#error "Xen header file hypervisor-if.h must already be included here."
#endif
/*
* EXTENDED BOOTSTRAP STRUCTURE FOR NEW DOMAINS.
*/
typedef struct {
BASIC_START_INFO;
u16 domain_controller_evtchn; /* 320 */
} PACKED extended_start_info_t; /* 322 bytes */
#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */
#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */
/*
* Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be
* interpreted by control software to determine the appropriate action. These
* are only really advisories: the controller can actually do as it likes.
*/
#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
/*
* CONTROLLER MESSAGING INTERFACE.
*/
typedef struct {
u8 type; /* 0: echoed in response */
u8 subtype; /* 1: echoed in response */
u8 id; /* 2: echoed in response */
u8 length; /* 3: number of bytes in 'msg' */
u8 msg[60]; /* 4: type-specific message data */
} PACKED control_msg_t; /* 64 bytes */
#define CONTROL_RING_SIZE 8
typedef u32 CONTROL_RING_IDX;
#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1))
typedef struct {
control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */
control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */
CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */
CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */
} PACKED control_if_t; /* 1040 bytes */
/*
* Top-level command types.
*/
#define CMSG_CONSOLE 0 /* Console */
#define CMSG_BLKIF_BE 1 /* Block-device backend */
#define CMSG_BLKIF_FE 2 /* Block-device frontend */
#define CMSG_NETIF_BE 3 /* Network-device backend */
#define CMSG_NETIF_FE 4 /* Network-device frontend */
#define CMSG_SHUTDOWN 6 /* Shutdown messages */
/******************************************************************************
* CONSOLE DEFINITIONS
*/
/*
* Subtypes for console messages.
*/
#define CMSG_CONSOLE_DATA 0
/******************************************************************************
* BLOCK-INTERFACE FRONTEND DEFINITIONS
*/
/* Messages from domain controller to guest. */
#define CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED 0
/* Messages from guest to domain controller. */
#define CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED 32
#define CMSG_BLKIF_FE_INTERFACE_CONNECT 33
#define CMSG_BLKIF_FE_INTERFACE_DISCONNECT 34
/* These are used by both front-end and back-end drivers. */
#define blkif_vdev_t u16
#define blkif_pdev_t u16
#define blkif_sector_t u64
/*
* CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED:
* Notify a guest about a status change on one of its block interfaces.
* If the interface is DESTROYED or DOWN then the interface is disconnected:
* 1. The shared-memory frame is available for reuse.
* 2. Any unacknowledged messgaes pending on the interface were dropped.
*/
#define BLKIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
#define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
#define BLKIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
typedef struct {
u32 handle; /* 0 */
u32 status; /* 4 */
u16 evtchn; /* 8: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */
} PACKED blkif_fe_interface_status_changed_t; /* 10 bytes */
/*
* CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the front-end driver is DOWN or UP.
* When the driver goes DOWN then the controller will send no more
* status-change notifications. When the driver comes UP then the controller
* will send a notification for each interface that currently exists.
* If the driver goes DOWN while interfaces are still UP, the domain
* will automatically take the interfaces DOWN.
*/
#define BLKIF_DRIVER_STATUS_DOWN 0
#define BLKIF_DRIVER_STATUS_UP 1
typedef struct {
/* IN */
u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
/* OUT */
/*
* Tells driver how many interfaces it should expect to immediately
* receive notifications about.
*/
u32 nr_interfaces; /* 4 */
} PACKED blkif_fe_driver_status_changed_t; /* 8 bytes */
/*
* CMSG_BLKIF_FE_INTERFACE_CONNECT:
* If successful, the domain controller will acknowledge with a
* STATUS_CONNECTED message.
*/
typedef struct {
u32 handle; /* 0 */
u32 __pad;
memory_t shmem_frame; /* 8 */
MEMORY_PADDING;
} PACKED blkif_fe_interface_connect_t; /* 16 bytes */
/*
* CMSG_BLKIF_FE_INTERFACE_DISCONNECT:
* If successful, the domain controller will acknowledge with a
* STATUS_DISCONNECTED message.
*/
typedef struct {
u32 handle; /* 0 */
} PACKED blkif_fe_interface_disconnect_t; /* 4 bytes */
/******************************************************************************
* BLOCK-INTERFACE BACKEND DEFINITIONS
*/
/* Messages from domain controller. */
#define CMSG_BLKIF_BE_CREATE 0 /* Create a new block-device interface. */
#define CMSG_BLKIF_BE_DESTROY 1 /* Destroy a block-device interface. */
#define CMSG_BLKIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
#define CMSG_BLKIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
#define CMSG_BLKIF_BE_VBD_CREATE 4 /* Create a new VBD for an interface. */
#define CMSG_BLKIF_BE_VBD_DESTROY 5 /* Delete a VBD from an interface. */
#define CMSG_BLKIF_BE_VBD_GROW 6 /* Append an extent to a given VBD. */
#define CMSG_BLKIF_BE_VBD_SHRINK 7 /* Remove last extent from a given VBD. */
/* Messages to domain controller. */
#define CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED 32
/*
* Message request/response definitions for block-device messages.
*/
typedef struct {
blkif_sector_t sector_start; /* 0 */
blkif_sector_t sector_length; /* 8 */
blkif_pdev_t device; /* 16 */
u16 __pad; /* 18 */
} PACKED blkif_extent_t; /* 20 bytes */
/* Non-specific 'okay' return. */
#define BLKIF_BE_STATUS_OKAY 0
/* Non-specific 'error' return. */
#define BLKIF_BE_STATUS_ERROR 1
/* The following are specific error returns. */
#define BLKIF_BE_STATUS_INTERFACE_EXISTS 2
#define BLKIF_BE_STATUS_INTERFACE_NOT_FOUND 3
#define BLKIF_BE_STATUS_INTERFACE_CONNECTED 4
#define BLKIF_BE_STATUS_VBD_EXISTS 5
#define BLKIF_BE_STATUS_VBD_NOT_FOUND 6
#define BLKIF_BE_STATUS_OUT_OF_MEMORY 7
#define BLKIF_BE_STATUS_EXTENT_NOT_FOUND 8
#define BLKIF_BE_STATUS_MAPPING_ERROR 9
/* This macro can be used to create an array of descriptive error strings. */
#define BLKIF_BE_STATUS_ERRORS { \
"Okay", \
"Non-specific error", \
"Interface already exists", \
"Interface not found", \
"Interface is still connected", \
"VBD already exists", \
"VBD not found", \
"Out of memory", \
"Extent not found for VBD", \
"Could not map domain memory" }
/*
* CMSG_BLKIF_BE_CREATE:
* When the driver sends a successful response then the interface is fully
* created. The controller will send a DOWN notification to the front-end
* driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 blkif_handle; /* 4: Domain-specific interface handle. */
/* OUT */
u32 status; /* 8 */
} PACKED blkif_be_create_t; /* 12 bytes */
/*
* CMSG_BLKIF_BE_DESTROY:
* When the driver sends a successful response then the interface is fully
* torn down. The controller will send a DESTROYED notification to the
* front-end driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Identify interface to be destroyed. */
u32 blkif_handle; /* 4: ...ditto... */
/* OUT */
u32 status; /* 8 */
} PACKED blkif_be_destroy_t; /* 12 bytes */
/*
* CMSG_BLKIF_BE_CONNECT:
* When the driver sends a successful response then the interface is fully
* connected. The controller will send a CONNECTED notification to the
* front-end driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 blkif_handle; /* 4: Domain-specific interface handle. */
memory_t shmem_frame; /* 8: Page cont. shared comms window. */
MEMORY_PADDING;
u32 evtchn; /* 16: Event channel for notifications. */
/* OUT */
u32 status; /* 20 */
} PACKED blkif_be_connect_t; /* 24 bytes */
/*
* CMSG_BLKIF_BE_DISCONNECT:
* When the driver sends a successful response then the interface is fully
* disconnected. The controller will send a DOWN notification to the front-end
* driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 blkif_handle; /* 4: Domain-specific interface handle. */
/* OUT */
u32 status; /* 8 */
} PACKED blkif_be_disconnect_t; /* 12 bytes */
/* CMSG_BLKIF_BE_VBD_CREATE */
typedef struct {
/* IN */
domid_t domid; /* 0: Identify blkdev interface. */
u32 blkif_handle; /* 4: ...ditto... */
blkif_vdev_t vdevice; /* 8: Interface-specific id for this VBD. */
u16 readonly; /* 10: Non-zero -> VBD isn't writeable. */
/* OUT */
u32 status; /* 12 */
} PACKED blkif_be_vbd_create_t; /* 16 bytes */
/* CMSG_BLKIF_BE_VBD_DESTROY */
typedef struct {
/* IN */
domid_t domid; /* 0: Identify blkdev interface. */
u32 blkif_handle; /* 4: ...ditto... */
blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */
u16 __pad; /* 10 */
/* OUT */
u32 status; /* 12 */
} PACKED blkif_be_vbd_destroy_t; /* 16 bytes */
/* CMSG_BLKIF_BE_VBD_GROW */
typedef struct {
/* IN */
domid_t domid; /* 0: Identify blkdev interface. */
u32 blkif_handle; /* 4: ...ditto... */
blkif_extent_t extent; /* 8: Physical extent to append to VBD. */
blkif_vdev_t vdevice; /* 28: Interface-specific id of the VBD. */
u16 __pad; /* 30 */
/* OUT */
u32 status; /* 32 */
} PACKED blkif_be_vbd_grow_t; /* 36 bytes */
/* CMSG_BLKIF_BE_VBD_SHRINK */
typedef struct {
/* IN */
domid_t domid; /* 0: Identify blkdev interface. */
u32 blkif_handle; /* 4: ...ditto... */
blkif_vdev_t vdevice; /* 8: Interface-specific id of the VBD. */
u16 __pad; /* 10 */
/* OUT */
u32 status; /* 12 */
} PACKED blkif_be_vbd_shrink_t; /* 16 bytes */
/*
* CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the back-end driver is DOWN or UP.
* If the driver goes DOWN while interfaces are still UP, the controller
* will automatically send DOWN notifications.
*/
typedef struct {
u32 status; /* 0: BLKIF_DRIVER_STATUS_??? */
} PACKED blkif_be_driver_status_changed_t; /* 4 bytes */
/******************************************************************************
* NETWORK-INTERFACE FRONTEND DEFINITIONS
*/
/* Messages from domain controller to guest. */
#define CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED 0
/* Messages from guest to domain controller. */
#define CMSG_NETIF_FE_DRIVER_STATUS_CHANGED 32
#define CMSG_NETIF_FE_INTERFACE_CONNECT 33
#define CMSG_NETIF_FE_INTERFACE_DISCONNECT 34
/*
* CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
* Notify a guest about a status change on one of its network interfaces.
* If the interface is DESTROYED or DOWN then the interface is disconnected:
* 1. The shared-memory frame is available for reuse.
* 2. Any unacknowledged messgaes pending on the interface were dropped.
*/
#define NETIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
#define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
#define NETIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
typedef struct {
u32 handle; /* 0 */
u32 status; /* 4 */
u16 evtchn; /* 8: status == NETIF_INTERFACE_STATUS_CONNECTED */
u8 mac[6]; /* 10: status == NETIF_INTERFACE_STATUS_CONNECTED */
} PACKED netif_fe_interface_status_changed_t; /* 16 bytes */
/*
* CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the front-end driver is DOWN or UP.
* When the driver goes DOWN then the controller will send no more
* status-change notifications. When the driver comes UP then the controller
* will send a notification for each interface that currently exists.
* If the driver goes DOWN while interfaces are still UP, the domain
* will automatically take the interfaces DOWN.
*/
#define NETIF_DRIVER_STATUS_DOWN 0
#define NETIF_DRIVER_STATUS_UP 1
typedef struct {
/* IN */
u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
/* OUT */
/*
* Tells driver how many interfaces it should expect to immediately
* receive notifications about.
*/
u32 nr_interfaces; /* 4 */
} PACKED netif_fe_driver_status_changed_t; /* 8 bytes */
/*
* CMSG_NETIF_FE_INTERFACE_CONNECT:
* If successful, the domain controller will acknowledge with a
* STATUS_CONNECTED message.
*/
typedef struct {
u32 handle; /* 0 */
u32 __pad; /* 4 */
memory_t tx_shmem_frame; /* 8 */
MEMORY_PADDING;
memory_t rx_shmem_frame; /* 16 */
MEMORY_PADDING;
} PACKED netif_fe_interface_connect_t; /* 24 bytes */
/*
* CMSG_NETIF_FE_INTERFACE_DISCONNECT:
* If successful, the domain controller will acknowledge with a
* STATUS_DISCONNECTED message.
*/
typedef struct {
u32 handle; /* 0 */
} PACKED netif_fe_interface_disconnect_t; /* 4 bytes */
/******************************************************************************
* NETWORK-INTERFACE BACKEND DEFINITIONS
*/
/* Messages from domain controller. */
#define CMSG_NETIF_BE_CREATE 0 /* Create a new net-device interface. */
#define CMSG_NETIF_BE_DESTROY 1 /* Destroy a net-device interface. */
#define CMSG_NETIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
#define CMSG_NETIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
/* Messages to domain controller. */
#define CMSG_NETIF_BE_DRIVER_STATUS_CHANGED 32
/*
* Message request/response definitions for net-device messages.
*/
/* Non-specific 'okay' return. */
#define NETIF_BE_STATUS_OKAY 0
/* Non-specific 'error' return. */
#define NETIF_BE_STATUS_ERROR 1
/* The following are specific error returns. */
#define NETIF_BE_STATUS_INTERFACE_EXISTS 2
#define NETIF_BE_STATUS_INTERFACE_NOT_FOUND 3
#define NETIF_BE_STATUS_INTERFACE_CONNECTED 4
#define NETIF_BE_STATUS_OUT_OF_MEMORY 5
#define NETIF_BE_STATUS_MAPPING_ERROR 6
/* This macro can be used to create an array of descriptive error strings. */
#define NETIF_BE_STATUS_ERRORS { \
"Okay", \
"Non-specific error", \
"Interface already exists", \
"Interface not found", \
"Interface is still connected", \
"Out of memory", \
"Could not map domain memory" }
/*
* CMSG_NETIF_BE_CREATE:
* When the driver sends a successful response then the interface is fully
* created. The controller will send a DOWN notification to the front-end
* driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 netif_handle; /* 4: Domain-specific interface handle. */
u8 mac[6]; /* 8 */
u16 __pad; /* 14 */
/* OUT */
u32 status; /* 16 */
} PACKED netif_be_create_t; /* 20 bytes */
/*
* CMSG_NETIF_BE_DESTROY:
* When the driver sends a successful response then the interface is fully
* torn down. The controller will send a DESTROYED notification to the
* front-end driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Identify interface to be destroyed. */
u32 netif_handle; /* 4: ...ditto... */
/* OUT */
u32 status; /* 8 */
} PACKED netif_be_destroy_t; /* 12 bytes */
/*
* CMSG_NETIF_BE_CONNECT:
* When the driver sends a successful response then the interface is fully
* connected. The controller will send a CONNECTED notification to the
* front-end driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 netif_handle; /* 4: Domain-specific interface handle. */
memory_t tx_shmem_frame; /* 8: Page cont. tx shared comms window. */
MEMORY_PADDING;
memory_t rx_shmem_frame; /* 16: Page cont. rx shared comms window. */
MEMORY_PADDING;
u16 evtchn; /* 24: Event channel for notifications. */
u16 __pad; /* 26 */
/* OUT */
u32 status; /* 28 */
} PACKED netif_be_connect_t; /* 32 bytes */
/*
* CMSG_NETIF_BE_DISCONNECT:
* When the driver sends a successful response then the interface is fully
* disconnected. The controller will send a DOWN notification to the front-end
* driver.
*/
typedef struct {
/* IN */
domid_t domid; /* 0: Domain attached to new interface. */
u32 netif_handle; /* 4: Domain-specific interface handle. */
/* OUT */
u32 status; /* 8 */
} PACKED netif_be_disconnect_t; /* 12 bytes */
/*
* CMSG_NETIF_BE_DRIVER_STATUS_CHANGED:
* Notify the domain controller that the back-end driver is DOWN or UP.
* If the driver goes DOWN while interfaces are still UP, the domain
* will automatically send DOWN notifications.
*/
typedef struct {
u32 status; /* 0: NETIF_DRIVER_STATUS_??? */
} PACKED netif_be_driver_status_changed_t; /* 4 bytes */
/******************************************************************************
* SHUTDOWN DEFINITIONS
*/
/*
* Subtypes for shutdown messages.
*/
#define CMSG_SHUTDOWN_POWEROFF 0 /* Clean shutdown (SHUTDOWN_poweroff). */
#define CMSG_SHUTDOWN_REBOOT 1 /* Clean shutdown (SHUTDOWN_reboot). */
#define CMSG_SHUTDOWN_SUSPEND 2 /* Create suspend info, then */
/* SHUTDOWN_suspend. */
#endif /* __DOMAIN_CONTROLLER_H__ */
File diff suppressed because it is too large. Load diff
+160
View File
@@ -0,0 +1,160 @@
"""Bridge control utilities.
"""
import os
import os.path
import re
import sys
os.defpath = os.defpath + ':/sbin:/usr/sbin:/usr/local/sbin'
CMD_IFCONFIG = 'ifconfig'
CMD_ROUTE = 'route'
CMD_BRCTL = 'brctl'
CMD_IPTABLES = "iptables"
opts = None
class Opts:
def __init__(self, defaults):
for (k, v) in defaults.items():
setattr(self, k, v)
pass
def cmd(p, s):
"""Print and execute command 'p' with args 's'.
"""
global opts
c = p + ' ' + s
if opts.verbose: print c
if not opts.dryrun:
os.system(c)
def vif_bridge_add(params):
"""Add the network interface for vif on dom to a bridge.
"""
cmd(CMD_BRCTL, 'addif %(bridge)s %(vif)s' % params)
def vif_bridge_rem(params):
"""Remove the network interface for vif on dom from a bridge.
"""
cmd(CMD_BRCTL, 'delif %(bridge)s %(vif)s' % params)
def vif_restrict_addr(vif, addr, delete=0):
d = { 'vif': vif, 'addr': addr}
if delete:
d['flag'] = '-D'
else:
d['flag'] = '-A'
cmd(CMD_IPTABLES, '-P FORWARD DROP')
cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-in %(vif)s -s %(addr)s -j ACCEPT' % d)
cmd(CMD_IPTABLES, '%(flag)s FORWARD -m physdev --physdev-out %(vif)s -d %(addr)s -j ACCEPT' % d)
def bridge_create(bridge, **kwd):
"""Create a bridge.
Defaults hello time to 0, forward delay to 0 and stp off.
"""
cmd(CMD_BRCTL, 'addbr %s' % bridge)
if kwd.get('hello', None) is None:
kwd['hello'] = 0
if kwd.get('fd', None) is None:
kwd['fd'] = 0
if kwd.get('stp', None) is None:
kwd['stp'] = 'off'
bridge_set(bridge, **kwd)
def bridge_set(bridge, hello=None, fd=None, stp=None):
"""Set bridge parameters.
"""
if hello is not None:
cmd(CMD_BRCTL, 'sethello %s %d' % (bridge, hello))
if fd is not None:
cmd(CMD_BRCTL, 'setfd %s %d' % (bridge, fd))
if stp is not None:
cmd(CMD_BRCTL, 'stp %s %s' % (bridge, stp))
def bridge_del(bridge):
"""Delete a bridge.
"""
cmd(CMD_BRCTL, 'delbr %s' % bridge)
def routes():
"""Return a list of the routes.
"""
fin = os.popen(CMD_ROUTE + ' -n', 'r')
routes = []
for x in fin:
if x.startswith('Kernel'): continue
if x.startswith('Destination'): continue
x = x.strip()
y = x.split()
z = { 'destination': y[0],
'gateway' : y[1],
'mask' : y[2],
'flags' : y[3],
'metric' : y[4],
'ref' : y[5],
'use' : y[6],
'interface' : y[7] }
routes.append(z)
return routes
def ifconfig(interface):
"""Return the ip config for an interface,
"""
fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r')
inetre = re.compile('\s*inet\s*addr:(?P<address>\S*)\s*Bcast:(?P<broadcast>\S*)\s*Mask:(?P<mask>\S*)')
info = None
for x in fin:
m = inetre.match(x)
if not m: continue
info = m.groupdict()
info['interface'] = interface
break
return info
def reconfigure(interface, bridge):
"""Reconfigure an interface to be attached to a bridge, and give the bridge
the IP address etc. from interface. Move the default route to the interface
to the bridge.
"""
global opts
intf_info = ifconfig(interface)
if not intf_info:
print >>sys.stderr, 'Interface not found:', interface
return
#bridge_info = ifconfig(bridge)
#if not bridge_info:
# print >>sys.stderr, 'Bridge not found:', bridge
# return
route_info = routes()
intf_info['bridge'] = bridge
intf_info['gateway'] = None
for r in route_info:
if (r['destination'] == '0.0.0.0' and
'G' in r['flags'] and
r['interface'] == interface):
intf_info['gateway'] = r['gateway']
if not intf_info['gateway']:
print >>sys.stderr, 'Gateway not found: ', interface
return
cmd(CMD_IFCONFIG,
'%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up'
% intf_info)
cmd(CMD_ROUTE,
'add default gateway %(gateway)s dev %(bridge)s'
% intf_info)
cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info)
cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info)
defaults = {
'verbose' : 1,
'dryrun' : 0,
}
opts = Opts(defaults)
def set_opts(val):
global opts
opts = val
return opts
+1
View File
@@ -0,0 +1 @@
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env python
##############################################
# Console client for Xen guest OSes
# Copyright (c) 2004, K A Fraser
##############################################
import errno, os, signal, socket, struct, sys
from termios import *
# Indexes into termios.tcgetattr() list.
IFLAG = 0
OFLAG = 1
CFLAG = 2
LFLAG = 3
ISPEED = 4
OSPEED = 5
CC = 6
def __child_death(signum, frame):
global stop
stop = True
def __recv_from_sock(sock):
global stop
stop = False
while not stop:
try:
data = sock.recv(1024)
os.write(1, data)
except socket.error, error:
if error[0] != errno.EINTR:
raise
os.wait()
def __send_to_sock(sock):
while 1:
data = os.read(0,1024)
if ord(data[0]) == ord(']')-64:
break
try:
sock.send(data)
except socket.error, error:
if error[0] == errno.EPIPE:
sys.exit(0)
if error[0] != errno.EINTR:
raise
sys.exit(0)
def connect(host,port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock.connect((host,port))
oattrs = tcgetattr(0)
nattrs = tcgetattr(0)
nattrs[IFLAG] = nattrs[IFLAG] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON)
nattrs[OFLAG] = nattrs[OFLAG] & ~(OPOST)
nattrs[CFLAG] = nattrs[CFLAG] & ~(CSIZE | PARENB)
nattrs[CFLAG] = nattrs[CFLAG] | CS8
nattrs[LFLAG] = nattrs[LFLAG] & ~(ECHO | ICANON | IEXTEN | ISIG)
nattrs[CC][VMIN] = 1
nattrs[CC][VTIME] = 0
if os.fork():
signal.signal(signal.SIGCHLD, __child_death)
print "************ REMOTE CONSOLE: CTRL-] TO QUIT ********"
tcsetattr(0, TCSAFLUSH, nattrs)
try:
__recv_from_sock(sock)
finally:
tcsetattr(0, TCSAFLUSH, oattrs)
print
print "************ REMOTE CONSOLE EXITED *****************"
else:
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
__send_to_sock(sock)
if __name__ == '__main__':
if len(sys.argv) != 3:
print sys.argv[0] + " <host> <port>"
sys.exit(1)
connect(str(sys.argv[1]),int(sys.argv[2]))
+113
View File
@@ -0,0 +1,113 @@
import os
import re
import socket
import struct
def readlines(fd):
"""Version of readlines safe against EINTR.
"""
import errno
lines = []
while 1:
try:
line = fd.readline()
except IOError, ex:
if ex.errno == errno.EINTR:
continue
else:
raise
if line == '': break
lines.append(line)
return lines
def readline(fd):
"""Version of readline safe against EINTR.
"""
while 1:
try:
return fd.readline()
except IOError, ex:
if ex.errno == errno.EINTR:
continue
else:
raise
##### Networking-related functions
"""Bridge for network backend.
When bridging is used, eth0 may not have an IP address,
as it may have been moved onto the bridge.
"""
NBE_BRIDGE = 'nbe-br'
def get_current_ipaddr(dev='eth0'):
"""Return a string containing the primary IP address for the given
network interface (default 'eth0').
"""
fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
lines = readlines(fd)
for line in lines:
m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
line )
if m:
return m.group(1)
if dev == 'eth0':
return get_current_ipaddr(NBE_BRIDGE)
return None
def get_current_ipmask(dev='eth0'):
"""Return a string containing the primary IP netmask for the given
network interface (default 'eth0').
"""
fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
lines = readlines(fd)
for line in lines:
m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
line )
if m:
return m.group(1)
if dev == 'eth0':
return get_current_ipmask(NBE_BRIDGE)
return None
def get_current_ipgw(dev='eth0'):
"""Return a string containing the IP gateway for the given
network interface (default 'eth0').
"""
fd = os.popen( '/sbin/route -n' )
lines = readlines(fd)
for line in lines:
m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
'\s+\S+\s+\S*G.*' + dev + '.*', line )
if m:
return m.group(1)
if dev == 'eth0':
return get_current_ipgw(NBE_BRIDGE)
return None
def inet_aton(addr):
"""Convert an IP addr in IPv4 dot notation into an int.
"""
b = socket.inet_aton(addr)
return struct.unpack('!I', b)[0]
def inet_ntoa(n):
"""Convert an int into an IP addr in IPv4 dot notation.
"""
b = struct.pack('!I', n)
return socket.inet_ntoa(b)
def add_offset_to_ip(addr, offset):
"""Add a numerical offset to an IP addr in IPv4 dot notation.
"""
n = inet_aton(addr)
n += offset
return inet_ntoa(n)
def check_subnet( ip, network, netmask ):
n_ip = inet_aton(ip)
n_net = inet_aton(network)
n_mask = inet_aton(netmask)
return (n_ip & n_mask) == (n_net & n_mask)
+451
View File
@@ -0,0 +1,451 @@
"""Temporary files.
This module provides generic, low- and high-level interfaces for
creating temporary files and directories. The interfaces listed
as "safe" just below can be used without fear of race conditions.
Those listed as "unsafe" cannot, and are provided for backward
compatibility only.
This module also provides some data items to the user:
TMP_MAX - maximum number of names that will be tried before
giving up.
template - the default prefix for all temporary names.
You may change this to control the default prefix.
tempdir - If this is set to a string before the first use of
any routine from this module, it will be considered as
another candidate location to store temporary files.
"""
__all__ = [
"NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
"mkstemp", "mkdtemp", # low level safe interfaces
"mktemp", # deprecated unsafe interface
"TMP_MAX", "gettempprefix", # constants
"tempdir", "gettempdir"
]
# Imports.
import os as _os
import errno as _errno
from random import Random as _Random
if _os.name == 'mac':
import Carbon.Folder as _Folder
import Carbon.Folders as _Folders
try:
import fcntl as _fcntl
# If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets
# imported, and we don't get an ImportError then. Provoke
# an AttributeError instead in that case.
_fcntl.fcntl
except (ImportError, AttributeError):
def _set_cloexec(fd):
pass
else:
def _set_cloexec(fd):
flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
if flags >= 0:
# flags read successfully, modify
flags |= _fcntl.FD_CLOEXEC
_fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
try:
import thread as _thread
except ImportError:
import dummy_thread as _thread
_allocate_lock = _thread.allocate_lock
_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
if hasattr(_os, 'O_NOINHERIT'):
_text_openflags |= _os.O_NOINHERIT
if hasattr(_os, 'O_NOFOLLOW'):
_text_openflags |= _os.O_NOFOLLOW
_bin_openflags = _text_openflags
if hasattr(_os, 'O_BINARY'):
_bin_openflags |= _os.O_BINARY
if hasattr(_os, 'TMP_MAX'):
TMP_MAX = _os.TMP_MAX
else:
TMP_MAX = 10000
template = "tmp"
tempdir = None
# Internal routines.
_once_lock = _allocate_lock()
class _RandomNameSequence:
"""An instance of _RandomNameSequence generates an endless
sequence of unpredictable strings which can safely be incorporated
into file names. Each string is six characters long. Multiple
threads can safely use the same instance at the same time.
_RandomNameSequence is an iterator."""
characters = ("abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"0123456789-_")
def __init__(self):
self.mutex = _allocate_lock()
self.rng = _Random()
self.normcase = _os.path.normcase
def __iter__(self):
return self
def next(self):
m = self.mutex
c = self.characters
choose = self.rng.choice
m.acquire()
try:
letters = [choose(c) for dummy in "123456"]
finally:
m.release()
return self.normcase(''.join(letters))
def _candidate_tempdir_list():
"""Generate a list of candidate temporary directories which
_get_default_tempdir will try."""
dirlist = []
# First, try the environment.
for envname in 'TMPDIR', 'TEMP', 'TMP':
dirname = _os.getenv(envname)
if dirname: dirlist.append(dirname)
# Failing that, try OS-specific locations.
if _os.name == 'mac':
try:
fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk,
_Folders.kTemporaryFolderType, 1)
dirname = fsr.as_pathname()
dirlist.append(dirname)
except _Folder.error:
pass
elif _os.name == 'riscos':
dirname = _os.getenv('Wimp$ScrapDir')
if dirname: dirlist.append(dirname)
elif _os.name == 'nt':
dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])
else:
dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])
# As a last resort, the current directory.
try:
dirlist.append(_os.getcwd())
except (AttributeError, _os.error):
dirlist.append(_os.curdir)
return dirlist
def _get_default_tempdir():
"""Calculate the default directory to use for temporary files.
This routine should be called exactly once.
We determine whether or not a candidate temp dir is usable by
trying to create and write to a file in that directory. If this
is successful, the test file is deleted. To prevent denial of
service, the name of the test file must be randomized."""
namer = _RandomNameSequence()
dirlist = _candidate_tempdir_list()
flags = _text_openflags
for dir in dirlist:
if dir != _os.curdir:
dir = _os.path.normcase(_os.path.abspath(dir))
# Try only a few names per directory.
for seq in xrange(100):
name = namer.next()
filename = _os.path.join(dir, name)
try:
fd = _os.open(filename, flags, 0600)
fp = _os.fdopen(fd, 'w')
fp.write('blat')
fp.close()
_os.unlink(filename)
del fp, fd
return dir
except (OSError, IOError), e:
if e[0] != _errno.EEXIST:
break # no point trying more names in this directory
pass
raise IOError, (_errno.ENOENT,
("No usable temporary directory found in %s" % dirlist))
_name_sequence = None
def _get_candidate_names():
"""Common setup sequence for all user-callable interfaces."""
global _name_sequence
if _name_sequence is None:
_once_lock.acquire()
try:
if _name_sequence is None:
_name_sequence = _RandomNameSequence()
finally:
_once_lock.release()
return _name_sequence
def _mkstemp_inner(dir, pre, suf, flags):
"""Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
names = _get_candidate_names()
for seq in xrange(TMP_MAX):
name = names.next()
file = _os.path.join(dir, pre + name + suf)
try:
fd = _os.open(file, flags, 0600)
_set_cloexec(fd)
return (fd, file)
except OSError, e:
if e.errno == _errno.EEXIST:
continue # try again
raise
raise IOError, (_errno.EEXIST, "No usable temporary file name found")
# User visible interfaces.
def gettempprefix():
"""Accessor for tempdir.template."""
return template
tempdir = None
def gettempdir():
"""Accessor for tempdir.tempdir."""
global tempdir
if tempdir is None:
_once_lock.acquire()
try:
if tempdir is None:
tempdir = _get_default_tempdir()
finally:
_once_lock.release()
return tempdir
def mkstemp(suffix="", prefix=template, dir=None, text=False):
"""mkstemp([suffix, [prefix, [dir, [text]]]])
User-callable function to create and return a unique temporary
file. The return value is a pair (fd, name) where fd is the
file descriptor returned by os.open, and name is the filename.
If 'suffix' is specified, the file name will end with that suffix,
otherwise there will be no suffix.
If 'prefix' is specified, the file name will begin with that prefix,
otherwise a default prefix is used.
If 'dir' is specified, the file will be created in that directory,
otherwise a default directory is used.
If 'text' is specified and true, the file is opened in text
mode. Else (the default) the file is opened in binary mode. On
some operating systems, this makes no difference.
The file is readable and writable only by the creating user ID.
If the operating system uses permission bits to indicate whether a
file is executable, the file is executable by no one. The file
descriptor is not inherited by children of this process.
Caller is responsible for deleting the file when done with it.
"""
if dir is None:
dir = gettempdir()
if text:
flags = _text_openflags
else:
flags = _bin_openflags
return _mkstemp_inner(dir, prefix, suffix, flags)
def mkdtemp(suffix="", prefix=template, dir=None):
"""mkdtemp([suffix, [prefix, [dir]]])
User-callable function to create and return a unique temporary
directory. The return value is the pathname of the directory.
Arguments are as for mkstemp, except that the 'text' argument is
not accepted.
The directory is readable, writable, and searchable only by the
creating user.
Caller is responsible for deleting the directory when done with it.
"""
if dir is None:
dir = gettempdir()
names = _get_candidate_names()
for seq in xrange(TMP_MAX):
name = names.next()
file = _os.path.join(dir, prefix + name + suffix)
try:
_os.mkdir(file, 0700)
return file
except OSError, e:
if e.errno == _errno.EEXIST:
continue # try again
raise
raise IOError, (_errno.EEXIST, "No usable temporary directory name found")
def mktemp(suffix="", prefix=template, dir=None):
"""mktemp([suffix, [prefix, [dir]]])
User-callable function to return a unique temporary file name. The
file is not created.
Arguments are as for mkstemp, except that the 'text' argument is
not accepted.
This function is unsafe and should not be used. The file name
refers to a file that did not exist at some point, but by the time
you get around to creating it, someone else may have beaten you to
the punch.
"""
## from warnings import warn as _warn
## _warn("mktemp is a potential security risk to your program",
## RuntimeWarning, stacklevel=2)
if dir is None:
dir = gettempdir()
names = _get_candidate_names()
for seq in xrange(TMP_MAX):
name = names.next()
file = _os.path.join(dir, prefix + name + suffix)
if not _os.path.exists(file):
return file
raise IOError, (_errno.EEXIST, "No usable temporary filename found")
class _TemporaryFileWrapper:
"""Temporary file wrapper
This class provides a wrapper around files opened for
temporary use. In particular, it seeks to automatically
remove the file when it is no longer needed.
"""
def __init__(self, file, name):
self.file = file
self.name = name
self.close_called = False
def __getattr__(self, name):
file = self.__dict__['file']
a = getattr(file, name)
if type(a) != type(0):
setattr(self, name, a)
return a
# NT provides delete-on-close as a primitive, so we don't need
# the wrapper to do anything special. We still use it so that
# file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
if _os.name != 'nt':
# Cache the unlinker so we don't get spurious errors at
# shutdown when the module-level "os" is None'd out. Note
# that this must be referenced as self.unlink, because the
# name TemporaryFileWrapper may also get None'd out before
# __del__ is called.
unlink = _os.unlink
def close(self):
if not self.close_called:
self.close_called = True
self.file.close()
self.unlink(self.name)
def __del__(self):
self.close()
def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
prefix=template, dir=None):
"""Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'dir' -- as for mkstemp.
'mode' -- the mode argument to os.fdopen (default "w+b").
'bufsize' -- the buffer size argument to os.fdopen (default -1).
The file is created as mkstemp() would do it.
Returns a file object; the name of the file is accessible as
file.name. The file will be automatically deleted when it is
closed.
"""
if dir is None:
dir = gettempdir()
if 'b' in mode:
flags = _bin_openflags
else:
flags = _text_openflags
# Setting O_TEMPORARY in the flags causes the OS to delete
# the file when it is closed. This is only supported by Windows.
if _os.name == 'nt':
flags |= _os.O_TEMPORARY
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
file = _os.fdopen(fd, mode, bufsize)
return _TemporaryFileWrapper(file, name)
if _os.name != 'posix' or _os.sys.platform == 'cygwin':
# On non-POSIX and Cygwin systems, assume that we cannot unlink a file
# while it is open.
TemporaryFile = NamedTemporaryFile
else:
def TemporaryFile(mode='w+b', bufsize=-1, suffix="",
prefix=template, dir=None):
"""Create and return a temporary file.
Arguments:
'prefix', 'suffix', 'directory' -- as for mkstemp.
'mode' -- the mode argument to os.fdopen (default "w+b").
'bufsize' -- the buffer size argument to os.fdopen (default -1).
The file is created as mkstemp() would do it.
Returns a file object. The file has no name, and will cease to
exist when it is closed.
"""
if dir is None:
dir = gettempdir()
if 'b' in mode:
flags = _bin_openflags
else:
flags = _text_openflags
(fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
try:
_os.unlink(name)
return _os.fdopen(fd, mode, bufsize)
except:
_os.close(fd)
raise
+126
View File
@@ -0,0 +1,126 @@
import sxp
class ArgError(StandardError):
pass
class Args:
"""Argument encoding support for HTTP.
"""
def __init__(self, paramspec, keyspec):
self.arg_ord = []
self.arg_dict = {}
self.key_ord = []
self.key_dict = {}
for (name, type) in paramspec:
self.arg_ord.append(name)
self.arg_dict[name] = type
for (name, type) in keyspec:
self.key_ord.append(name)
self.key_dict[name] = type
def get_args(self, d, xargs=None):
args = {}
keys = {}
params = []
if xargs:
self.split_args(xargs, args, keys)
self.split_args(d, args, keys)
for a in self.arg_ord:
if a in args:
params.append(args[a])
else:
raise ArgError('Missing parameter: %s' % a)
return (params, keys)
def split_args(self, d, args, keys):
for (k, v) in d.items():
if k in self.arg_dict:
type = self.arg_dict[k]
val = self.coerce(type, v)
args[k] = val
elif k in self.key_dict:
type = self.key_dict[k]
val = self.coerce(type, v)
keys[k] = val
else:
raise ArgError('Invalid parameter: %s' % k)
def get_form_args(self, f, xargs=None):
d = {}
for (k, v) in f.items():
n = len(v)
if ((k not in self.arg_dict) and
(k not in self.key_dict)):
continue
if n == 0:
continue
elif n == 1:
d[k] = v[0]
else:
raise ArgError('Too many values for %s' % k)
return self.get_args(d, xargs=xargs)
def coerce(self, type, v):
try:
if type == 'int':
return int(v)
if type == 'str':
return str(v)
if type == 'sxpr':
return self.sxpr(v)
except ArgError:
raise
except StandardError, ex:
raise ArgError(str(ex))
def sxpr(self, v):
if instanceof(v, types.ListType):
return v
if instanceof(v, types.File) or hasattr(v, 'readline'):
return sxpr_file(v)
if instanceof(v, types.StringType):
return sxpr_file(StringIO(v))
return str(v)
def sxpr_file(self, fin):
try:
vals = sxp.parse(fin)
except:
raise ArgError('Coercion to sxpr failed')
if len(vals) == 1:
return vals[0]
else:
raise ArgError('Too many sxprs')
def call_with_args(self, fn, args, xargs=None):
(params, keys) = self.get_args(args, xargs=xargs)
fn(*params, **keys)
def call_with_form_args(self, fn, fargs, xargs=None):
(params, keys) = self.get_form_args(fargs, xargs=xargs)
fn(*params, **keys)
class ArgFn(Args):
"""Represent a remote HTTP operation as a function.
Used on the client.
"""
def __init__(self, fn, paramspec, keyspec={}):
Args.__init__(self, paramspec, keyspec)
self.fn = fn
def __call__(self, fargs, xargs=None):
return self.call_with_args(self.fn, fargs, xargs=xargs)
class FormFn(Args):
"""Represent an operation as a function over a form.
Used in the HTTP server.
"""
def __init__(self, fn, paramspec, keyspec={}):
Args.__init__(self, paramspec, keyspec)
self.fn = fn
def __call__(self, fargs, xargs=None):
return self.call_with_form_args(self.fn, fargs, xargs=xargs)
+215
View File
@@ -0,0 +1,215 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Simple publish/subscribe event server.
"""
import string
from twisted.internet import reactor
# subscribe a.b.c h: map a.b.c -> h
# subscribe a.b.* h: map a.b.* -> h
# subscribe a.b.? h: map a.b.? -> h
#
# for event a.b.c.d:
#
# lookup a.b.c.d, call handlers
#
# lookup a.b.c.?, call handlers
#
# lookup a.b.c.d.*, call handlers
# lookup a.b.c.*, call handlers
# lookup a.b.*, call handlers
# lookup a.*, call handlers
# lookup *, call handlers
# a.b.c.d = (a b c d)
# a.b.c.? = (a b c _)
# a.b.c.* = (a b c . _)
class EventServer:
DOT = '.'
QUERY = '?'
DOT_QUERY = DOT + QUERY
STAR = '*'
DOT_STAR = DOT + STAR
def __init__(self, run=0):
self.handlers = {}
self.run = run
self.queue = []
def start(self):
"""Enable event handling. Sends any queued events.
"""
self.run = 1
for (e,v) in self.queue:
self.inject(e, v)
self.queue = []
def stop(self):
"""Suspend event handling. Events injected while suspended
are queued until we are started again.
"""
self.run = 0
def subscribe(self, event, handler):
"""Subscribe to an event. For example 'a.b.c.d'.
A subcription like 'a.b.c.?' ending in '?' matches any value
for the '?'. A subscription like 'a.b.c.*' ending in '*' matches
any event type with the same prefix, 'a.b.c' in this case.
event event name
handler event handler fn(event, val)
"""
hl = self.handlers.get(event)
if hl is None:
self.handlers[event] = [handler]
else:
hl.append(handler)
def unsubscribe_all(self, event=None):
"""Unsubscribe all handlers for a given event, or all handlers.
event event (optional)
"""
if event == None:
self.handlers.clear()
elif event in self.handlers:
del self.handlers[event]
def unsubscribe(self, event, handler):
"""Unsubscribe a given event and handler.
event event
handler handler
"""
hl = self.handlers.get(event)
if hl is None:
return
if handler in hl:
hl.remove(handler)
def inject(self, event, val, async=1):
"""Inject an event. Handlers for it are called if running, otherwise
it is queued.
event event type
val event value
"""
if self.run:
if async:
reactor.callLater(0, self.call_handlers, event, val)
else:
self.notify_handlers(event, val)
else:
self.queue.append( (event, val) )
def call_handlers(self, event, val):
"""Internal method to call event handlers.
"""
#print ">event", event, val
self.call_event_handlers(event, event, val)
self.call_query_handlers(event, val)
self.call_star_handlers(event, val)
def call_event_handlers(self, key, event, val):
"""Call the handlers for an event.
It is safe for handlers to subscribe or unsubscribe.
key key for handler list
event event type
val event value
"""
hl = self.handlers.get(key)
if hl is None:
return
# Copy the handler list so that handlers can call
# subscribe/unsubscribe safely - python list iteration
# is not safe against list modification.
for h in hl[:]:
try:
h(event, val)
except:
pass
def call_query_handlers(self, event, val):
"""Call regex handlers for events matching 'event' that end in '?'.
event event type
val event value
"""
dot_idx = event.rfind(self.DOT)
if dot_idx == -1:
self.call_event_handlers(self.QUERY, event, val)
else:
event_query = event[0:dot_idx] + self.DOT_QUERY
self.call_event_handlers(event_query, event, val)
def call_star_handlers(self, event, val):
"""Call regex handlers for events matching 'event' that end in '*'.
event event type
val event value
"""
etype = string.split(event, self.DOT)
for i in range(len(etype), 0, -1):
event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR
self.call_event_handlers(event_star, event, val)
self.call_event_handlers(self.STAR, event, val)
def instance():
global inst
try:
inst
except:
inst = EventServer()
inst.start()
return inst
def main():
def sys_star(event, val):
print 'sys_star', event, val
def sys_foo(event, val):
print 'sys_foo', event, val
s.unsubscribe('sys.foo', sys_foo)
def sys_foo2(event, val):
print 'sys_foo2', event, val
def sys_bar(event, val):
print 'sys_bar', event, val
def sys_foo_bar(event, val):
print 'sys_foo_bar', event, val
def foo_bar(event, val):
print 'foo_bar', event, val
s = EventServer()
s.start()
s.subscribe('sys.*', sys_star)
s.subscribe('sys.foo', sys_foo)
s.subscribe('sys.foo', sys_foo2)
s.subscribe('sys.bar', sys_bar)
s.subscribe('sys.foo.bar', sys_foo_bar)
s.subscribe('foo.bar', foo_bar)
s.inject('sys.foo', 'hello')
print
s.inject('sys.bar', 'hello again')
print
s.inject('sys.foo.bar', 'hello again')
print
s.inject('foo.bar', 'hello again')
print
s.inject('foo', 'hello again')
print
s.start()
s.unsubscribe('sys.*', sys_star)
s.unsubscribe_all('sys.*')
s.inject('sys.foo', 'hello')
if __name__ == "__main__":
main()
+34
View File
@@ -0,0 +1,34 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
## XEND_DOMAIN_CREATE = "xend.domain.create": dom
## create:
## xend.domain.destroy: dom, reason:died/crashed
## xend.domain.up ?
## xend.domain.unpause: dom
## xend.domain.pause: dom
## xend.domain.shutdown: dom
## xend.domain.destroy: dom
## xend.domain.migrate.begin: dom, to
## Begin tells: src host, src domain uri, dst host. Dst id known?
## err: src host, src domain uri, dst host, dst id if known, status (of domain: ok, dead,...), reason
## end: src host, src domain uri, dst host, dst uri
## Events for both ends of migrate: for exporter and importer?
## Include migrate id so can tie together.
## Have uri /xend/migrate/<id> for migrate info (migrations in progress).
## (xend.domain.migrate.begin (src <host>) (src.domain <id>)
## (dst <host>) (id <migrate id>))
## xend.domain.migrate.end:
## (xend.domain.migrate.end (domain <id>) (to <host>)
## xend.node.up: xend uri
## xend.node.down: xend uri
## xend.error ?
## format:
+299
View File
@@ -0,0 +1,299 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""General pretty-printer, including support for SXP.
"""
import sys
import types
import StringIO
import sxp
class PrettyItem:
def __init__(self, width):
self.width = width
def insert(self, block):
block.addtoline(self)
def get_width(self):
return self.width
def output(self, out):
print '***PrettyItem>output>', self
pass
def prettyprint(self, out, width):
print '***PrettyItem>prettyprint>', self
return width
class PrettyString(PrettyItem):
def __init__(self, x):
PrettyItem.__init__(self, len(x))
self.value = x
def output(self, out):
out.write(self.value)
def prettyprint(self, line):
line.output(self)
def show(self, out):
print >> out, ("(string (width %d) '%s')" % (self.width, self.value))
class PrettySpace(PrettyItem):
def output(self, out):
out.write(' ' * self.width)
def prettyprint(self, line):
line.output(self)
def show(self, out):
print >> out, ("(space (width %d))" % self.width)
class PrettyBreak(PrettyItem):
def __init__(self, width, indent):
PrettyItem.__init__(self, width)
self.indent = indent
self.space = 0
self.active = 0
def output(self, out):
out.write(' ' * self.width)
def prettyprint(self, line):
if line.breaks(self.space):
self.active = 1
line.newline(self.indent)
else:
line.output(self)
def show(self, out):
print >> out, ("(break (width %d) (indent %d) (space %d) (active %d))"
% (self.width, self.indent, self.space, self.lspace, self.active))
class PrettyNewline(PrettySpace):
def __init__(self, indent):
PrettySpace.__init__(self, indent)
def insert(self, block):
block.newline()
block.addtoline(self)
def output(self, out):
out.write(' ' * self.width)
def prettyprint(self, line):
line.newline(0)
line.output(self)
def show(self, out):
print >> out, ("(nl (indent %d))" % self.indent)
class PrettyLine(PrettyItem):
def __init__(self):
PrettyItem.__init__(self, 0)
self.content = []
def write(self, x):
self.content.append(x)
def end(self):
width = 0
lastwidth = 0
lastbreak = None
for x in self.content:
if isinstance(x, PrettyBreak):
if lastbreak:
lastbreak.space = (width - lastwidth)
lastbreak = x
lastwidth = width
width += x.get_width()
if lastbreak:
lastbreak.space = (width - lastwidth)
self.width = width
def prettyprint(self, line):
for x in self.content:
x.prettyprint(line)
def show(self, out):
print >> out, '(LINE (width %d)' % self.width
for x in self.content:
x.show(out)
print >> out, ')'
class PrettyBlock(PrettyItem):
def __init__(self, all=0, parent=None):
self.width = 0
self.lines = []
self.parent = parent
self.indent = 0
self.all = all
self.broken = 0
self.newline()
def add(self, item):
item.insert(self)
def end(self):
self.width = 0
for l in self.lines:
l.end()
if self.width < l.width:
self.width = l.width
def breaks(self, n):
return self.all and self.broken
def newline(self):
self.lines.append(PrettyLine())
def addtoline(self, x):
self.lines[-1].write(x)
def prettyprint(self, line):
self.indent = line.used
line.block = self
if not line.fits(self.width):
self.broken = 1
for l in self.lines:
l.prettyprint(line)
line.block = self.parent
def show(self, out):
print >> out, ('(BLOCK (width %d) (indent %d) (all %d) (broken %d)' %
(self.width, self.indent, self.all, self.broken))
for l in self.lines:
l.show(out)
print >> out, ')'
class Line:
def __init__(self, out, width):
self.out = out
self.width = width
self.used = 0
self.space = self.width
def newline(self, indent):
indent += self.block.indent
self.out.write('\n')
self.out.write(' ' * indent)
self.used = indent
self.space = self.width - self.used
def fits(self, n):
return self.space - n >= 0
def breaks(self, n):
return self.block.breaks(n) or not self.fits(n)
def output(self, x):
n = x.get_width()
self.space -= n
self.used += n
if self.space < 0:
self.space = 0
x.output(self.out)
class PrettyPrinter:
"""A prettyprinter based on what I remember of Derek Oppen's
prettyprint algorithm from TOPLAS way back.
"""
def __init__(self, width=40):
self.width = width
self.block = None
self.top = None
def write(self, x):
self.block.add(PrettyString(x))
def add(self, item):
self.block.add(item)
def addbreak(self, width=1, indent=4):
self.add(PrettyBreak(width, indent))
def addspace(self, width=1):
self.add(PrettySpace(width))
def addnl(self, indent=0):
self.add(PrettyNewline(indent))
def begin(self, all=0):
block = PrettyBlock(all=all, parent=self.block)
self.block = block
def end(self):
self.block.end()
if self.block.parent:
self.block.parent.add(self.block)
else:
self.top = self.block
self.block = self.block.parent
def prettyprint(self, out=sys.stdout):
line = Line(out, self.width)
self.top.prettyprint(line)
class SXPPrettyPrinter(PrettyPrinter):
"""An SXP prettyprinter.
"""
def pstring(self, x):
io = StringIO.StringIO()
sxp.show(x, out=io)
io.seek(0)
val = io.getvalue()
io.close()
return val
def pprint(self, l):
if isinstance(l, types.ListType):
self.begin(all=1)
self.write('(')
i = 0
for x in l:
if(i): self.addbreak()
self.pprint(x)
i += 1
self.addbreak(width=0, indent=0)
self.write(')')
self.end()
else:
self.write(self.pstring(l))
def prettyprint(sxpr, out=sys.stdout, width=80):
"""Prettyprint an SXP form.
sxpr s-expression
out destination
width maximum output width
"""
if isinstance(sxpr, types.ListType):
pp = SXPPrettyPrinter(width=width)
pp.pprint(sxpr)
pp.prettyprint(out=out)
else:
sxp.show(sxpr, out=out)
print >> out
def main():
pin = sxp.Parser()
while 1:
buf = sys.stdin.read(100)
pin.input(buf)
if buf == '': break
l = pin.get_val()
prettyprint(l, width=80)
if __name__ == "__main__":
main()
+28
View File
@@ -0,0 +1,28 @@
import os
import os.path
import sys
VIFCTL = '/etc/xen/xend/vifctl'
def init():
os.system(VIFCTL + ' init ')
def up(vif, mac=None, bridge=None, ipaddr=[]):
args = ['vif=%s' % vif]
if mac:
args.append('mac=%s' % mac)
if bridge:
args.append('bridge=%s' % bridge)
if ipaddr:
args.append('ipaddr=%s' % ','.join(ipaddr))
os.system(VIFCTL + ' up ' + ' '.join(args))
def down(vif, mac=None, bridge=None, ipaddr=[]):
args = ['vif=%s' % vif]
if mac:
args.append('mac=%s' % mac)
if bridge:
args.append('bridge=%s' % bridge)
if ipaddr:
args.append('ipaddr=%s' % ','.join(ipaddr))
os.system(VIFCTL + ' down ' + ' '.join(args))
+311
View File
@@ -0,0 +1,311 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Client API for the HTTP interface on xend.
Callable as a script - see main().
"""
import sys
import httplib
import types
from StringIO import StringIO
import urlparse
from encode import *
import sxp
import PrettyPrint
DEBUG = 0
class Foo(httplib.HTTPResponse):
def begin(self):
fin = self.fp
while(1):
buf = fin.readline()
print "***", buf
if buf == '':
print
sys.exit()
def sxprio(sxpr):
io = StringIO()
sxp.show(sxpr, out=io)
print >> io
io.seek(0)
return io
def fileof(val):
"""Converter for passing configs.
Handles lists, files directly.
Assumes a string is a file name and passes its contents.
"""
if isinstance(val, types.ListType):
return sxprio(val)
if isinstance(val, types.StringType):
return file(val)
if hasattr(val, 'readlines'):
return val
# todo: need to sort of what urls/paths are using for objects.
# e.g. for domains at the moment return '0'.
# should probably return abs path w.r.t. server, e.g. /xend/domain/0.
# As an arg, assume abs path is obj uri, otherwise just id.
# Function to convert to full url: Xend.uri(path), e.g.
# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0
# And should accept urls for ids?
def urljoin(location, root, prefix='', rest=''):
prefix = str(prefix)
rest = str(rest)
base = 'http://' + location + root + prefix
url = urlparse.urljoin(base, rest)
return url
def nodeurl(location, root, id=''):
return urljoin(location, root, 'node/', id)
def domainurl(location, root, id=''):
return urljoin(location, root, 'domain/', id)
def consoleurl(location, root, id=''):
return urljoin(location, root, 'console/', id)
def deviceurl(location, root, id=''):
return urljoin(location, root, 'device/', id)
def vneturl(location, root, id=''):
return urljoin(location, root, 'vnet/', id)
def eventurl(location, root, id=''):
return urljoin(location, root, 'event/', id)
def xend_request(url, method, data=None):
urlinfo = urlparse.urlparse(url)
(uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
if DEBUG: print url, urlinfo
if uproto != 'http':
raise StandardError('Invalid protocol: ' + uproto)
if DEBUG: print '>xend_request', ulocation, upath, method, data
(hdr, args) = encode_data(data)
if data and method == 'GET':
upath += '?' + args
args = None
if method == "POST" and upath.endswith('/'):
upath = upath[:-1]
if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args
#hdr['User-Agent'] = 'Mozilla'
#hdr['Accept'] = 'text/html,text/plain'
conn = httplib.HTTPConnection(ulocation)
#conn.response_class = Foo
if DEBUG: conn.set_debuglevel(1)
conn.request(method, upath, args, hdr)
resp = conn.getresponse()
if DEBUG: print resp.status, resp.reason
if DEBUG: print resp.msg.headers
if resp.status in [204, 404]:
return None
if resp.status not in [200, 201, 202, 203]:
raise RuntimeError(resp.reason)
pin = sxp.Parser()
data = resp.read()
if DEBUG: print "***data" , data
if DEBUG: print "***"
pin.input(data);
pin.input_eof()
conn.close()
val = pin.get_val()
#if isinstance(val, types.ListType) and sxp.name(val) == 'val':
# val = val[1]
if isinstance(val, types.ListType) and sxp.name(val) == 'err':
raise RuntimeError(val[1])
if DEBUG: print '**val='; sxp.show(val); print
return val
def xend_get(url, args=None):
return xend_request(url, "GET", args)
def xend_call(url, data):
return xend_request(url, "POST", data)
class Xend:
SRV_DEFAULT = "localhost:8000"
ROOT_DEFAULT = "/xend/"
def __init__(self, srv=None, root=None):
self.bind(srv, root)
def bind(self, srv=None, root=None):
if srv is None: srv = self.SRV_DEFAULT
if root is None: root = self.ROOT_DEFAULT
if not root.endswith('/'): root += '/'
self.location = srv
self.root = root
def nodeurl(self, id=''):
return nodeurl(self.location, self.root, id)
def domainurl(self, id=''):
return domainurl(self.location, self.root, id)
def consoleurl(self, id=''):
return consoleurl(self.location, self.root, id)
def deviceurl(self, id=''):
return deviceurl(self.location, self.root, id)
def vneturl(self, id=''):
return vneturl(self.location, self.root, id)
def eventurl(self, id=''):
return eventurl(self.location, self.root, id)
def xend(self):
return xend_get(urljoin(self.location, self.root))
def xend_node(self):
return xend_get(self.nodeurl())
def xend_node_cpu_rrobin_slice_set(self, slice):
return xend_call(self.nodeurl(),
{'op' : 'cpu_rrobin_slice_set',
'slice' : slice })
def xend_node_cpu_bvt_slice_set(self, slice):
return xend_call(self.nodeurl(),
{'op' : 'cpu_bvt_slice_set',
'slice' : slice })
def xend_domains(self):
return xend_get(self.domainurl())
def xend_domain_create(self, conf):
return xend_call(self.domainurl(),
{'op' : 'create',
'config' : fileof(conf) })
def xend_domain(self, id):
return xend_get(self.domainurl(id))
def xend_domain_unpause(self, id):
return xend_call(self.domainurl(id),
{'op' : 'unpause'})
def xend_domain_pause(self, id):
return xend_call(self.domainurl(id),
{'op' : 'pause'})
def xend_domain_shutdown(self, id):
return xend_call(self.domainurl(id),
{'op' : 'shutdown'})
def xend_domain_destroy(self, id):
return xend_call(self.domainurl(id),
{'op' : 'destroy'})
def xend_domain_save(self, id, filename):
return xend_call(self.domainurl(id),
{'op' : 'save',
'file' : filename})
def xend_domain_restore(self, id, filename):
return xend_call(self.domainurl(id),
{'op' : 'restore',
'file' : filename })
def xend_domain_migrate(self, id, dst):
return xend_call(self.domainurl(id),
{'op' : 'migrate',
'destination': dst})
def xend_domain_pincpu(self, id, cpu):
return xend_call(self.domainurl(id),
{'op' : 'pincpu',
'cpu' : cpu})
def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu):
return xend_call(self.domainurl(id),
{'op' : 'cpu_bvt_set',
'mcuadv' : mvuadv,
'warp' : warp,
'warpl' : warpl,
'warpu' : warpu })
def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime):
return xend_call(self.domainurl(id),
{'op' : 'cpu_atropos_set',
'period' : period,
'slice' : slice,
'latency' : latency,
'xtratime': xtratime })
def xend_domain_vifs(self, id):
return xend_get(self.domainurl(id),
{ 'op' : 'vifs' })
def xend_domain_vif_ip_add(self, id, vif, ipaddr):
return xend_call(self.domainurl(id),
{'op' : 'vif_ip_add',
'vif' : vif,
'ip' : ipaddr })
def xend_domain_vbds(self, id):
return xend_get(self.domainurl(id),
{'op' : 'vbds'})
def xend_domain_vbd(self, id, vbd):
return xend_get(self.domainurl(id),
{'op' : 'vbd',
'vbd' : vbd})
def xend_consoles(self):
return xend_get(self.consoleurl())
def xend_console(self, id):
return xend_get(self.consoleurl(id))
def xend_vnets(self):
return xend_get(self.vneturl())
def xend_vnet_create(self, conf):
return xend_call(self.vneturl(),
{'op': 'create', 'config': fileof(conf) })
def xend_vnet(self, id):
return xend_get(self.vneturl(id))
def xend_vnet_delete(self, id):
return xend_call(self.vneturl(id),
{'op': 'delete'})
def xend_event_inject(self, sxpr):
val = xend_call(self.eventurl(),
{'op': 'inject', 'event': fileof(sxpr) })
def main(argv):
"""Call an API function:
python XendClient.py fn args...
The leading 'xend_' on the function can be omitted.
Example:
> python XendClient.py domains
(domain 0 8)
> python XendClient.py domain 0
(domain (id 0) (name Domain-0) (memory 128))
"""
server = Xend()
fn = argv[1]
if not fn.startswith('xend'):
fn = 'xend_' + fn
args = argv[2:]
val = getattr(server, fn)(*args)
PrettyPrint.prettyprint(val)
print
if __name__ == "__main__":
main(sys.argv)
else:
server = Xend()
+179
View File
@@ -0,0 +1,179 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import socket
import xen.ext.xc
xc = xen.ext.xc.new()
import sxp
import XendRoot
xroot = XendRoot.instance()
import XendDB
import EventServer
eserver = EventServer.instance()
from xen.xend.server import SrvDaemon
daemon = SrvDaemon.instance()
class XendConsoleInfo:
"""Console information record.
"""
def __init__(self, console, dom1, port1, dom2, port2, conn=None):
self.console = console
self.dom1 = int(dom1)
self.port1 = int(port1)
self.dom2 = int(dom2)
self.port2 = int(port2)
self.conn = conn
#self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2)
self.id = str(port1)
def __str__(self):
s = "console"
s += " id=%s" % self.id
s += " src=%d.%d" % (self.dom1, self.port1)
s += " dst=%d.%d" % (self.dom2, self.port2)
s += " port=%s" % self.console
if self.conn:
s += " conn=%s:%s" % (self.conn[0], self.conn[1])
return s
def sxpr(self):
sxpr = ['console',
['id', self.id],
['src', self.dom1, self.port1],
['dst', self.dom2, self.port2],
['port', self.console],
]
if self.conn:
sxpr.append(['connected', self.conn[0], self.conn[1]])
return sxpr
def connection(self):
return self.conn
def update(self, consinfo):
conn = sxp.child(consinfo, 'connected')
if conn:
self.conn = conn[1:]
else:
self.conn = None
def uri(self):
"""Get the uri to use to connect to the console.
This will be a telnet: uri.
return uri
"""
host = socket.gethostname()
return "telnet://%s:%s" % (host, self.console)
class XendConsole:
dbpath = "console"
def __init__(self):
self.db = XendDB.XendDB(self.dbpath)
self.console = {}
self.console_db = self.db.fetchall("")
if xroot.get_rebooted():
print 'XendConsole> rebooted: removing all console info'
self.rm_all()
eserver.subscribe('xend.domain.died', self.onDomainDied)
eserver.subscribe('xend.domain.destroy', self.onDomainDied)
def rm_all(self):
"""Remove all console info. Used after reboot.
"""
for (k, v) in self.console_db.items():
self._delete_console(k)
def refresh(self):
consoles = daemon.consoles()
cons = {}
for consinfo in consoles:
id = str(sxp.child_value(consinfo, 'id'))
cons[id] = consinfo
if id not in self.console:
self._new_console(consinfo)
for c in self.console.values():
consinfo = cons.get(c.id)
if consinfo:
c.update(consinfo)
else:
self._delete_console(c.id)
def onDomainDied(self, event, val):
dom = int(val)
#print 'XendConsole>onDomainDied', 'event', event, "dom=", dom
for c in self.consoles():
#print 'onDomainDied', "dom=", dom, "dom1=", c.dom1, "dom2=", c.dom2
if (c.dom1 == dom) or (c.dom2 == dom):
'XendConsole>onDomainDied', 'delete console dom=', dom
ctrl = daemon.get_domain_console(dom)
if ctrl:
ctrl.close()
self._delete_console(c.id)
def sync(self):
self.db.saveall("", self.console_db)
def sync_console(self, id):
self.db.save(id, self.console_db[id])
def _new_console(self, consinfo):
# todo: xen needs a call to get current domain id.
dom1 = 0
port1 = sxp.child_value(consinfo, 'local_port')
dom2 = sxp.child_value(consinfo, 'domain')
port2 = sxp.child_value(consinfo, 'remote_port')
console = sxp.child_value(consinfo, 'console_port')
info = XendConsoleInfo(console, dom1, int(port1), int(dom2), int(port2))
info.update(consinfo)
self._add_console(info.id, info)
return info
def _add_console(self, id, info):
self.console[id] = info
self.console_db[id] = info.sxpr()
self.sync_console(id)
def _delete_console(self, id):
if id in self.console:
del self.console[id]
if id in self.console_db:
del self.console_db[id]
self.db.delete(id)
def console_ls(self):
self.refresh()
return self.console.keys()
def consoles(self):
self.refresh()
return self.console.values()
def console_create(self, dom):
consinfo = daemon.console_create(dom)
info = self._new_console(consinfo)
return info
def console_get(self, id):
self.refresh()
return self.console.get(id)
def console_delete(self, id):
self._delete_console(id)
def console_disconnect(self, id):
id = int(id)
daemon.console_disconnect(id)
def instance():
global inst
try:
inst
except:
inst = XendConsole()
return inst
+91
View File
@@ -0,0 +1,91 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import os
import os.path
import errno
import dircache
import time
import sxp
import XendRoot
xroot = XendRoot.instance()
class XendDB:
"""Persistence for Xend. Stores data in files and directories.
"""
def __init__(self, path=None):
self.dbpath = xroot.get_dbroot()
if path:
self.dbpath = os.path.join(self.dbpath, path)
pass
def filepath(self, path):
return os.path.join(self.dbpath, path)
def fetch(self, path):
fpath = self.filepath(path)
return self.fetchfile(fpath)
def fetchfile(self, fpath):
pin = sxp.Parser()
fin = file(fpath, "rb")
try:
while 1:
try:
buf = fin.read(1024)
except IOError, ex:
if ex.errno == errno.EINTR:
continue
else:
raise
pin.input(buf)
if buf == '':
pin.input_eof()
break
finally:
fin.close()
return pin.get_val()
def save(self, path, sxpr):
fpath = self.filepath(path)
return self.savefile(fpath, sxpr)
def savefile(self, fpath, sxpr):
fdir = os.path.dirname(fpath)
if not os.path.isdir(fdir):
os.makedirs(fdir)
fout = file(fpath, "wb+")
try:
t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
fout.write("# %s %s\n" % (fpath, t))
sxp.show(sxpr, out=fout)
finally:
fout.close()
def fetchall(self, path):
dpath = self.filepath(path)
d = {}
for k in dircache.listdir(dpath):
try:
v = self.fetchfile(os.path.join(dpath, k))
d[k] = v
except:
pass
return d
def saveall(self, path, d):
for (k, v) in d.items():
self.save(os.path.join(path, k), v)
def delete(self, path):
dpath = self.filepath(path)
os.unlink(dpath)
def ls(self, path):
dpath = self.filepath(path)
return dircache.listdir(dpath)
+369
View File
@@ -0,0 +1,369 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Handler for domain operations.
Nothing here is persistent (across reboots).
Needs to be persistent for one uptime.
"""
import sys
from twisted.internet import defer
import xen.ext.xc; xc = xen.ext.xc.new()
import sxp
import XendRoot
xroot = XendRoot.instance()
import XendDB
import XendDomainInfo
import XendConsole
import EventServer
from xen.xend.server import SrvDaemon
xend = SrvDaemon.instance()
eserver = EventServer.instance()
__all__ = [ "XendDomain" ]
class XendDomain:
"""Index of all domains. Singleton.
"""
dbpath = "domain"
domain = {}
def __init__(self):
self.xconsole = XendConsole.instance()
# Table of domain info indexed by domain id.
self.db = XendDB.XendDB(self.dbpath)
#self.domain = {}
self.domain_db = self.db.fetchall("")
if xroot.get_rebooted():
print 'XendDomain> rebooted: removing all domain info'
self.rm_all()
eserver.subscribe('xend.virq', self.onVirq)
self.initial_refresh()
def onVirq(self, event, val):
print 'XendDomain> virq', val
self.reap()
def rm_all(self):
"""Remove all domain info. Used after reboot.
"""
for (k, v) in self.domain_db.items():
self._delete_domain(k, notify=0)
def initial_refresh(self):
"""Refresh initial domain info from domain_db.
"""
print "initial_refresh>"
for d in self.domain_db.values(): print 'db dom=', d
domlist = xc.domain_getinfo()
for d in domlist: print 'xc dom=', d
doms = {}
for d in domlist:
domid = str(d['dom'])
doms[domid] = d
dlist = []
for config in self.domain_db.values():
domid = str(sxp.child_value(config, 'id'))
print "dom=", domid, "config=", config
if domid in doms:
print "dom=", domid, "new"
deferred = self._new_domain(config, doms[domid])
dlist.append(deferred)
else:
print "dom=", domid, "del"
self._delete_domain(domid)
deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
def cbok(val):
#print "doms:"
#for d in self.domain.values(): print 'dom', d
self.refresh()
print "XendDomain>initial_refresh> doms:"
for d in self.domain.values(): print 'dom', d
deferred.addCallback(cbok)
def sync(self):
"""Sync domain db to disk.
"""
self.db.saveall("", self.domain_db)
def sync_domain(self, dom):
"""Sync info for a domain to disk.
dom domain id (string)
"""
self.db.save(dom, self.domain_db[dom])
def close(self):
pass
def _new_domain(self, savedinfo, info):
"""Create a domain entry from saved info.
"""
## console = None
## kernel = None
## id = sxp.child_value(info, 'id')
## dom = int(id)
## name = sxp.child_value(info, 'name')
## memory = int(sxp.child_value(info, 'memory'))
## consoleinfo = sxp.child(info, 'console')
## if consoleinfo:
## consoleid = sxp.child_value(consoleinfo, 'id')
## console = self.xconsole.console_get(consoleid)
## if dom and console is None:
## # Try to connect a console.
## console = self.xconsole.console_create(dom)
## config = sxp.child(info, 'config')
## if config:
## image = sxp.child(info, 'image')
## if image:
## image = sxp.child0(image)
## kernel = sxp.child_value(image, 'kernel')
## dominfo = XendDomainInfo.XendDomainInfo(
## config, dom, name, memory, kernel, console)
config = sxp.child_value(savedinfo, 'config')
deferred = XendDomainInfo.vm_recreate(config, info)
def fn(dominfo):
self.domain[dominfo.id] = dominfo
deferred.addCallback(fn)
return deferred
def _add_domain(self, id, info, notify=1):
self.domain[id] = info
self.domain_db[id] = info.sxpr()
self.sync_domain(id)
if notify: eserver.inject('xend.domain.created', id)
def _delete_domain(self, id, notify=1):
if id in self.domain:
if notify: eserver.inject('xend.domain.died', id)
del self.domain[id]
if id in self.domain_db:
del self.domain_db[id]
self.db.delete(id)
def reap(self):
"""Go through the domains looking for ones that have crashed or stopped.
Tidy them up.
"""
print 'XendDomain>reap>'
domlist = xc.domain_getinfo()
casualties = []
for d in domlist:
#print 'dom', d
dead = 0
dead = dead or (d['crashed'] or d['shutdown'])
dead = dead or (d['dying'] and
not(d['running'] or d['paused'] or d['blocked']))
if dead:
casualties.append(d)
for d in casualties:
id = str(d['dom'])
print 'XendDomain>reap> died id=', id, d
dominfo = self.domain.get(id)
if not dominfo: continue
dominfo.died()
self.domain_destroy(id, refresh=0)
print 'XendDomain>reap<'
def refresh(self):
"""Refresh domain list from Xen.
"""
domlist = xc.domain_getinfo()
# Index the domlist by id.
# Add entries for any domains we don't know about.
doms = {}
for d in domlist:
id = str(d['dom'])
doms[id] = d
if id not in self.domain:
config = None
#image = None
#newinfo = XendDomainInfo.XendDomainInfo(
# config, d['dom'], d['name'], d['mem_kb']/1024, image=image, info=d)
deferred = XendDomainInfo.vm_recreate(config, d)
def fn(dominfo):
self._add_domain(dominfo.id, dominfo)
deferred.addCallback(fn)
# Remove entries for domains that no longer exist.
for d in self.domain.values():
dominfo = doms.get(d.id)
if dominfo:
d.update(dominfo)
else:
self._delete_domain(d.id)
self.reap()
def refresh_domain(self, id):
dom = int(id)
dominfo = xc.domain_getinfo(dom, 1)
if dominfo == [] or dominfo[0]['dom'] != dom:
try:
self._delete_domain(id)
except:
print 'refresh_domain: error'
raise
pass
else:
d = self.domain.get(id)
if d:
d.update(dominfo[0])
def domain_ls(self):
# List domains.
# Update info from kernel first.
self.refresh()
return self.domain.keys()
def domains(self):
self.refresh()
return self.domain.values()
def domain_create(self, config):
# Create domain, log it.
deferred = XendDomainInfo.vm_create(config)
def fn(dominfo):
self._add_domain(dominfo.id, dominfo)
return dominfo
deferred.addCallback(fn)
return deferred
def domain_get(self, id):
id = str(id)
self.refresh_domain(id)
return self.domain.get(id)
def domain_unpause(self, id):
"""(Re)start domain running.
"""
dom = int(id)
eserver.inject('xend.domain.unpause', id)
return xc.domain_unpause(dom=dom)
def domain_pause(self, id):
"""Pause domain execution.
"""
dom = int(id)
eserver.inject('xend.domain.pause', id)
return xc.domain_pause(dom=dom)
def domain_shutdown(self, id, reason='poweroff'):
"""Shutdown domain (nicely).
"""
dom = int(id)
if dom <= 0:
return 0
eserver.inject('xend.domain.shutdown', [id, reason])
val = xend.domain_shutdown(dom, reason)
self.refresh()
return val
def domain_destroy(self, id, refresh=1):
"""Terminate domain immediately.
"""
dom = int(id)
if dom <= 0:
return 0
eserver.inject('xend.domain.destroy', id)
val = xc.domain_destroy(dom=dom)
if refresh: self.refresh()
return val
def domain_migrate(self, id, dst):
"""Start domain migration.
"""
# Need a cancel too?
pass
def domain_save(self, id, dst, progress=0):
"""Save domain state to file, destroy domain.
"""
dom = int(id)
dominfo = self.domain_get(id)
if not dominfo:
return -1
vmconfig = sxp.to_string(dominfo.sxpr())
self.domain_pause(id)
eserver.inject('xend.domain.save', id)
rc = xc.linux_save(dom=dom, state_file=dst, vmconfig=vmconfig, progress=progress)
if rc == 0:
self.domain_destroy(id)
return rc
def domain_restore(self, src, progress=0):
"""Restore domain from file.
"""
dominfo = XendDomainInfo.vm_restore(src, progress=progress)
self._add_domain(dominfo.id, dominfo)
return dominfo
#============================================================================
# Backward compatibility stuff from here on.
def domain_pincpu(self, dom, cpu):
dom = int(dom)
return xc.domain_pincpu(dom, cpu)
def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu):
dom = int(dom)
return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv,
warp=warp, warpl=warpl, warpu=warpu)
def domain_cpu_bvt_get(self, dom):
dom = int(dom)
return xc.bvtsched_domain_get(dom)
def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime):
dom = int(dom)
return xc.atropos_domain_set(dom, period, slice, latency, xtratime)
def domain_cpu_atropos_get(self, dom):
dom = int(dom)
return xc.atropos_domain_get(dom)
def domain_vif_ls(self, dom):
dominfo = self.domain_get(dom)
if not dominfo: return None
devs = dominfo.get_devices('vif')
return range(0, len(devs))
def domain_vif_get(self, dom, vif):
dominfo = self.domain_get(dom)
if not dominfo: return None
return dominfo.get_device_by_index(vif)
## def domain_vif_ip_add(self, dom, vif, ip):
## dom = int(dom)
## return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip)
def domain_vbd_ls(self, dom):
dominfo = self.domain_get(dom)
if not dominfo: return []
devs = dominfo.get_devices('vbd')
return [ sxp.child_value(v, 'dev') for v in devs ]
def domain_vbd_get(self, dom, vbd):
dominfo = self.domain_get(dom)
if not dominfo: return None
devs = dominfo.get_devices('vbd')
for v in devs:
if sxp.child_value(v, 'dev') == vbd:
return v
return None
def domain_shadow_control(self, dom, op):
dom = int(dom)
return xc.shadow_control(dom, op)
#============================================================================
def instance():
global inst
try:
inst
except:
inst = XendDomain()
return inst
+44
View File
@@ -0,0 +1,44 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Handler for persistent domain configs.
"""
import sxp
import XendDB
import XendDomain
__all__ = [ "XendDomainConfig" ]
class XendDomainConfig:
dbpath = 'config'
def __init__(self):
self.db = XendDB.XendDB(self.dbpath)
def domain_config_ls(self, path):
return self.db.ls(path)
def domain_config_create(self, path, sxpr):
self.db.save(path, sxpr)
pass
def domain_config_delete(self, path):
self.db.delete(path)
def domain_config_instance(self, path):
"""Create a domain from a config.
"""
config = self.db.fetch(path)
xd = XendDomain.instance()
newdom = xd.domain_create(config)
return newdom
def instance():
global inst
try:
inst
except:
inst = XendDomainConfig()
return inst
+908
View File
@@ -0,0 +1,908 @@
#!/usr/bin/python
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Representation of a single domain.
Includes support for domain construction, using
open-ended configurations.
Author: Mike Wray <mike.wray@hpl.hp.com>
"""
import string
import re
import sys
import os
from twisted.internet import defer
import xen.ext.xc; xc = xen.ext.xc.new()
import xen.util.ip
import sxp
import XendConsole
xendConsole = XendConsole.instance()
import server.SrvDaemon
xend = server.SrvDaemon.instance()
SIF_BLK_BE_DOMAIN = (1<<4)
SIF_NET_BE_DOMAIN = (1<<5)
def readlines(fd):
"""Version of readlines safe against EINTR.
"""
import errno
lines = []
while 1:
try:
line = fd.readline()
except IOError, ex:
if ex.errno == errno.EINTR:
continue
else:
raise
if line == '': break
lines.append(line)
return lines
class VmError(ValueError):
"""Vm construction error."""
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
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
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 = readline(fd)
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 = readlines(fd)
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 a physical device.
uname [string]: name of the device in the format \'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 )
else:
segments = None
return segments
def make_disk(dom, uname, dev, mode, recreate=0):
"""Create a virtual disk device for a domain.
@returns Deferred
"""
segments = lookup_disk_uname(uname)
if not segments:
raise VmError("vbd: Segments not found: uname=%s" % uname)
if len(segments) > 1:
raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
segment = segments[0]
vdev = blkdev_name_to_number(dev)
ctrl = xend.blkif_create(dom, recreate=recreate)
def fn(ctrl):
return xend.blkif_dev_create(dom, vdev, mode, segment, recreate=recreate)
ctrl.addCallback(fn)
return ctrl
def make_vif(dom, vif, vmac, recreate=0):
"""Create a virtual network device for a domain.
@returns Deferred
"""
xend.netif_create(dom, recreate=recreate)
d = xend.netif_dev_create(dom, vif, vmac, recreate=recreate)
return d
def vif_up(iplist):
"""send an unsolicited ARP reply for all non link-local IP addresses.
iplist IP addresses
"""
IP_NONLOCAL_BIND = '/proc/sys/net/ipv4/ip_nonlocal_bind'
def get_ip_nonlocal_bind():
return int(open(IP_NONLOCAL_BIND, 'r').read()[0])
def set_ip_nonlocal_bind(v):
print >> open(IP_NONLOCAL_BIND, 'w'), str(v)
def link_local(ip):
return xen.util.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0')
def arping(ip, gw):
cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw)
print cmd
os.system(cmd)
gateway = xen.util.ip.get_current_ipgw() or '255.255.255.255'
nlb = get_ip_nonlocal_bind()
if not nlb: set_ip_nonlocal_bind(1)
try:
for ip in iplist:
if not link_local(ip):
arping(ip, gateway)
finally:
if not nlb: set_ip_nonlocal_bind(0)
config_handlers = {}
def add_config_handler(name, h):
"""Add a handler for a config field.
name field name
h handler: fn(vm, config, field, index)
"""
config_handlers[name] = h
def get_config_handler(name):
"""Get a handler for a config field.
returns handler or None
"""
return config_handlers.get(name)
"""Table of handlers for virtual machine images.
Indexed by image type.
"""
image_handlers = {}
def add_image_handler(name, h):
"""Add a handler for an image type
name image type
h handler: fn(config, name, memory, image)
"""
image_handlers[name] = h
def get_image_handler(name):
"""Get the handler for an image type.
name image type
returns handler or None
"""
return image_handlers.get(name)
"""Table of handlers for devices.
Indexed by device type.
"""
device_handlers = {}
def add_device_handler(name, h):
"""Add a handler for a device type.
name device type
h handler: fn(vm, dev)
"""
device_handlers[name] = h
def get_device_handler(name):
"""Get the handler for a device type.
name device type
returns handler or None
"""
return device_handlers.get(name)
def vm_create(config):
"""Create a VM from a configuration.
If a vm has been partially created and there is an error it
is destroyed.
config configuration
returns Deferred
raises VmError for invalid configuration
"""
print 'vm_create>'
vm = XendDomainInfo()
return vm.construct(config)
def vm_recreate(config, info):
"""Create the VM object for an existing domain.
"""
vm = XendDomainInfo()
vm.recreate = 1
vm.setdom(info['dom'])
vm.name = info['name']
vm.memory = info['mem_kb']/1024
if config:
d = vm.construct(config)
else:
d = defer.Deferred()
d.callback(vm)
return d
def vm_restore(src, progress=0):
"""Restore a VM from a disk image.
src saved state to restore
progress progress reporting flag
returns deferred
raises VmError for invalid configuration
"""
vm = XendDomainInfo()
ostype = "linux" #todo Set from somewhere (store in the src?).
restorefn = getattr(xc, "%s_restore" % ostype)
d = restorefn(state_file=src, progress=progress)
dom = int(d['dom'])
if dom < 0:
raise VMError('restore failed')
vmconfig = sxp.from_string(d['vmconfig'])
vm.config = sxp.child_value(vmconfig, 'config')
deferred = vm.dom_configure(dom)
def vifs_cb(val, vm):
vif_up(vm.ipaddrs)
deferred.addCallback(vifs_cb, vm)
return deferred
def dom_get(dom):
domlist = xc.domain_getinfo(dom=dom)
if domlist and dom == domlist[0]['dom']:
return domlist[0]
return None
def append_deferred(dlist, v):
if isinstance(v, defer.Deferred):
dlist.append(v)
def _vm_configure1(val, vm):
d = vm.create_devices()
print '_vm_configure1> made devices...'
def cbok(x):
print '_vm_configure1> cbok', x
return x
d.addCallback(cbok)
d.addCallback(_vm_configure2, vm)
print '_vm_configure1<'
return d
def _vm_configure2(val, vm):
print '>callback _vm_configure2...'
d = vm.configure_fields()
def cbok(results):
print '_vm_configure2> cbok', results
return vm
def cberr(err):
print '_vm_configure2> cberr', err
vm.destroy()
return err
d.addCallback(cbok)
d.addErrback(cberr)
print '<_vm_configure2'
return d
class XendDomainInfo:
"""Virtual machine object."""
def __init__(self):
self.recreate = 0
self.config = None
self.id = None
self.dom = None
self.name = None
self.memory = None
self.image = None
self.ramdisk = None
self.cmdline = None
self.console = None
self.devices = {}
self.configs = []
self.info = None
self.ipaddrs = []
self.blkif_backend = 0
self.netif_backend = 0
#todo: state: running, suspended
self.state = 'running'
#todo: set to migrate info if migrating
self.migrate = None
def setdom(self, dom):
self.dom = int(dom)
self.id = str(dom)
def update(self, info):
"""Update with info from xc.domain_getinfo().
"""
self.info = info
self.memory = self.info['mem_kb'] / 1024
def __str__(self):
s = "domain"
s += " id=" + self.id
s += " name=" + self.name
s += " memory=" + str(self.memory)
if self.console:
s += " console=" + self.console.id
if self.image:
s += " image=" + self.image
s += ""
return s
__repr__ = __str__
def sxpr(self):
sxpr = ['domain',
['id', self.id],
['name', self.name],
['memory', self.memory] ]
if self.info:
run = (self.info['running'] and 'r') or '-'
block = (self.info['blocked'] and 'b') or '-'
stop = (self.info['paused'] and 'p') or '-'
susp = (self.info['shutdown'] and 's') or '-'
crash = (self.info['crashed'] and 'c') or '-'
state = run + block + stop + susp + crash
sxpr.append(['state', state])
if self.info['shutdown']:
reasons = ["poweroff", "reboot", "suspend"]
reason = reasons[self.info['shutdown_reason']]
sxpr.append(['shutdown_reason', reason])
sxpr.append(['cpu', self.info['cpu']])
sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
if self.console:
sxpr.append(self.console.sxpr())
if self.config:
sxpr.append(['config', self.config])
return sxpr
def construct(self, config):
# todo - add support for scheduling params?
self.config = config
try:
self.name = sxp.child_value(config, 'name')
self.memory = int(sxp.child_value(config, 'memory', '128'))
self.configure_backends()
image = sxp.child_value(config, 'image')
image_name = sxp.name(image)
image_handler = get_image_handler(image_name)
if image_handler is None:
raise VmError('unknown image type: ' + image_name)
image_handler(self, image)
deferred = self.configure()
except StandardError, ex:
# Catch errors, cleanup and re-raise.
self.destroy()
raise
def cbok(x):
print 'vm_create> cbok', x
return x
deferred.addCallback(cbok)
print 'vm_create<'
return deferred
def config_devices(self, name):
"""Get a list of the 'device' nodes of a given type from the config.
name device type
return list of device configs
"""
devices = []
for d in sxp.children(self.config, 'device'):
dev = sxp.child0(d)
if dev is None: continue
if name == sxp.name(dev):
devices.append(dev)
return devices
def add_device(self, type, dev):
"""Add a device to a virtual machine.
dev device to add
"""
dl = self.devices.get(type, [])
dl.append(dev)
self.devices[type] = dl
def get_devices(self, type):
val = self.devices.get(type, [])
return val
def get_device_by_id(self, type, id):
"""Get the device with the given id.
id device id
returns device or None
"""
dl = self.get_devices(type)
for d in dl:
if d.getprop('id') == id:
return d
return None
def get_device_by_index(self, type, idx):
"""Get the device with the given index.
idx device index
returns device or None
"""
dl = self.get_devices(type)
if 0 <= idx < len(dl):
return dl[idx]
else:
return None
def add_config(self, val):
"""Add configuration data to a virtual machine.
val data to add
"""
self.configs.append(val)
def destroy(self):
if self.dom <= 0:
return 0
return xc.domain_destroy(dom=self.dom)
def died(self):
print 'died>', self.dom
self.release_devices()
def release_devices(self):
print 'release_devices>', self.dom
self.release_vifs()
self.release_vbds()
self.devices = {}
def release_vifs(self):
print 'release_vifs>', self.dom
if self.dom is None: return
ctrl = xend.netif_get(self.dom)
if ctrl:
ctrl.destroy()
def release_vbds(self):
print 'release_vbds>', self.dom
if self.dom is None: return
ctrl = xend.blkif_get(self.dom)
if ctrl:
ctrl.destroy()
def show(self):
"""Print virtual machine info.
"""
print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
print "image:"
sxp.show(self.image)
print
for dl in self.devices:
for dev in dl:
print "device:"
sxp.show(dev)
print
for val in self.configs:
print "config:"
sxp.show(val)
print
print "]"
def init_domain(self):
"""Initialize the domain memory.
"""
if self.recreate: return
memory = self.memory
name = self.name
cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
print 'init_domain>', memory, name, cpu
dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
if dom <= 0:
raise VmError('Creating domain failed: name=%s memory=%d'
% (name, memory))
self.setdom(dom)
def build_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
"""Build the domain boot image.
"""
if self.recreate: return
if len(cmdline) >= 256:
print 'Warning: kernel cmdline too long'
dom = self.dom
buildfn = getattr(xc, '%s_build' % ostype)
print 'build_domain>', ostype, dom, kernel, cmdline, ramdisk
flags = 0
if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
err = buildfn(dom = dom,
image = kernel,
control_evtchn = self.console.port2,
cmdline = cmdline,
ramdisk = ramdisk,
flags = flags)
if err != 0:
raise VmError('Building domain failed: type=%s dom=%d err=%d'
% (ostype, dom, err))
def create_domain(self, ostype, kernel, ramdisk, cmdline, vifs_n):
"""Create a domain. Builds the image but does not configure it.
ostype OS type
kernel kernel image
ramdisk kernel ramdisk
cmdline kernel commandline
vifs_n number of network interfaces
"""
print 'create_domain>', ostype, kernel
if not self.recreate:
if not os.path.isfile(kernel):
raise VmError('Kernel image does not exist: %s' % kernel)
if ramdisk and not os.path.isfile(ramdisk):
raise VMError('Kernel ramdisk does not exist: %s' % ramdisk)
print 'create-domain> init_domain...'
self.init_domain()
print 'create_domain>', 'dom=', self.dom
self.console = xendConsole.console_create(self.dom)
self.build_domain(ostype, kernel, ramdisk, cmdline, vifs_n)
self.image = kernel
self.ramdisk = ramdisk
self.cmdline = cmdline
def create_devices(self):
"""Create the devices for a vm.
returns Deferred
raises VmError for invalid devices
"""
print '>create_devices'
dlist = []
devices = sxp.children(self.config, 'device')
index = {}
for d in devices:
dev = sxp.child0(d)
if dev is None:
raise VmError('invalid device')
dev_name = sxp.name(dev)
dev_index = index.get(dev_name, 0)
dev_handler = get_device_handler(dev_name)
if dev_handler is None:
raise VmError('unknown device type: ' + dev_name)
v = dev_handler(self, dev, dev_index)
append_deferred(dlist, v)
index[dev_name] = dev_index + 1
deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
print '<create_devices'
return deferred
def configure_backends(self):
"""Set configuration flags if the vm is a backend for netif of blkif.
"""
for c in sxp.children(self.config, 'backend'):
name = sxp.name(sxp.child0(c))
if name == 'blkif':
self.blkif_backend = 1
elif name == 'netif':
self.netif_backend = 1
else:
raise VmError('invalid backend type:' + str(name))
def create_backends(self):
"""Setup the netif and blkif backends.
"""
if self.blkif_backend:
xend.blkif_set_control_domain(self.dom, recreate=self.recreate)
if self.netif_backend:
xend.netif_set_control_domain(self.dom, recreate=self.recreate)
def configure(self):
"""Configure a vm.
vm virtual machine
config configuration
returns Deferred - calls callback with vm
"""
if self.blkif_backend:
d = defer.Deferred()
d.callback(1)
else:
d = xend.blkif_create(self.dom, recreate=self.recreate)
d.addCallback(_vm_configure1, self)
return d
def dom_configure(self, dom):
"""Configure a domain.
dom domain id
returns deferred
"""
d = dom_get(dom)
if not d:
raise VMError("Domain not found: %d" % dom)
try:
self.setdom(dom)
self.name = d['name']
self.memory = d['memory']/1024
deferred = self.configure()
except StandardError, ex:
self.destroy()
raise
return deferred
def configure_fields(self):
dlist = []
index = {}
for field in sxp.children(self.config):
field_name = sxp.name(field)
field_index = index.get(field_name, 0)
field_handler = get_config_handler(field_name)
# Ignore unknown fields. Warn?
if field_handler:
v = field_handler(self, self.config, field, field_index)
append_deferred(dlist, v)
index[field_name] = field_index + 1
d = defer.DeferredList(dlist, fireOnOneErrback=1)
return d
def vm_image_linux(vm, image):
"""Create a VM for a linux image.
name vm name
memory vm memory
image image config
returns vm
"""
kernel = sxp.child_value(image, "kernel")
cmdline = ""
ip = sxp.child_value(image, "ip", "dhcp")
if ip:
cmdline += " ip=" + ip
root = sxp.child_value(image, "root")
if root:
cmdline += " root=" + root
args = sxp.child_value(image, "args")
if args:
cmdline += " " + args
ramdisk = sxp.child_value(image, "ramdisk", '')
vifs = vm.config_devices("vif")
vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
return vm
def vm_image_netbsd(vm, image):
"""Create a VM for a bsd image.
name vm name
memory vm memory
image image config
returns vm
"""
#todo: Same as for linux. Is that right? If so can unify them.
kernel = sxp.child_value(image, "kernel")
cmdline = ""
ip = sxp.child_value(image, "ip", "dhcp")
if ip:
cmdline += "ip=" + ip
root = sxp.child_value(image, "root")
if root:
cmdline += "root=" + root
args = sxp.child_value(image, "args")
if args:
cmdline += " " + args
ramdisk = sxp.child_value(image, "ramdisk")
vifs = vm.config_devices("vif")
vm.create_domain("netbsd", kernel, ramdisk, cmdline, len(vifs))
return vm
def vm_dev_vif(vm, val, index):
"""Create a virtual network interface (vif).
vm virtual machine
val vif config
index vif index
"""
if vm.netif_backend:
raise VmError('vif: vif in netif backend domain')
vif = index #todo
vmac = sxp.child_value(val, "mac")
defer = make_vif(vm.dom, vif, vmac, vm.recreate)
def fn(id):
dev = xend.netif_dev(vm.dom, vif)
devid = sxp.attribute(val, 'id')
if devid:
dev.setprop('id', devid)
bridge = sxp.child_value(val, "bridge")
dev.up(bridge)
vm.add_device('vif', dev)
print 'vm_dev_vif> created', dev
return id
defer.addCallback(fn)
return defer
def vm_dev_vbd(vm, val, index):
"""Create a virtual block device (vbd).
vm virtual machine
val vbd config
index vbd index
"""
if vm.blkif_backend:
raise VmError('vbd: vbd in blkif backend domain')
vdev = index
uname = sxp.child_value(val, 'uname')
if not uname:
raise VMError('vbd: Missing uname')
dev = sxp.child_value(val, 'dev')
if not dev:
raise VMError('vbd: Missing dev')
mode = sxp.child_value(val, 'mode', 'r')
defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
def fn(vbd):
dev = xend.blkif_dev(vm.dom, vdev)
vm.add_device('vbd', dev)
return vbd
defer.addCallback(fn)
return defer
def parse_pci(val):
if isinstance(val, StringType):
radix = 10
if val.startswith('0x') or val.startswith('0X'):
radix = 16
v = int(val, radix)
else:
v = val
return v
def vm_dev_pci(vm, val, index):
bus = sxp.child_value(val, 'bus')
if not bus:
raise VMError('pci: Missing bus')
dev = sxp.child_value(val, 'dev')
if not dev:
raise VMError('pci: Missing dev')
func = sxp.child_value(val, 'func')
if not func:
raise VMError('pci: Missing func')
try:
bus = parse_pci(bus)
dev = parse_pci(dev)
func = parse_pci(func)
except:
raise VMError('pci: invalid parameter')
rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev,
func=func, enable=1)
if rc < 0:
#todo non-fatal
raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
(bus, dev, func))
return rc
def vm_field_vfr(vm, config, val, index):
"""Handle a vfr field in a config.
vm virtual machine
config vm config
val vfr field
"""
# Get the rules and add them.
# (vfr (vif (id foo) (ip x.x.x.x)) ... )
list = sxp.children(val, 'vif')
ipaddrs = []
for v in list:
id = sxp.child_value(v, 'id')
if id is None:
raise VmError('vfr: missing vif id')
id = int(id)
dev = vm.get_device_by_index('vif', id)
if not dev:
raise VmError('vfr: invalid vif id %d' % id)
vif = sxp.child_value(dev, 'vif')
ip = sxp.child_value(v, 'ip')
if not ip:
raise VmError('vfr: missing ip address')
ipaddrs.append(ip);
# todo: Configure the ipaddrs.
vm.ipaddrs = ipaddrs
def vnet_bridge(vnet, vmac, dom, idx):
"""Add the device for the vif to the bridge for its vnet.
"""
vif = "vif%d.%d" % (dom, idx)
try:
cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac)
print "*** vnet_bridge>", cmd
out = file("/proc/vnet/policy", "wb")
out.write(cmd)
err = out.close()
print "vnet_bridge>", "err=", err
except IOError, ex:
print "vnet_bridge>", ex
def vm_field_vnet(vm, config, val, index):
"""Handle a vnet field in a config.
vm virtual machine
config vm config
val vnet field
index index
"""
# Get the vif children. For each vif look up the vif device
# with the given id and configure its vnet.
# (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... )
vif_vnets = sxp.children(val, 'vif')
for v in vif_vnets:
id = sxp.child_value(v, 'id')
if id is None:
raise VmError('vnet: missing vif id')
dev = vm.get_device_by_id('vif', id)
#vnet = sxp.child_value(v, 'vnet', 1)
#mac = sxp.child_value(dev, 'mac')
#vif = sxp.child_value(dev, 'vif')
#vnet_bridge(vnet, mac, vm.dom, 0)
#vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
# Register image handlers for linux and bsd.
add_image_handler('linux', vm_image_linux)
add_image_handler('netbsd', vm_image_netbsd)
# Register device handlers for vifs and vbds.
add_device_handler('vif', vm_dev_vif)
add_device_handler('vbd', vm_dev_vbd)
add_device_handler('pci', vm_dev_pci)
# Register config handlers for vfr and vnet.
add_config_handler('vfr', vm_field_vfr)
add_config_handler('vnet', vm_field_vnet)
+103
View File
@@ -0,0 +1,103 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import sys
import socket
import sxp
import XendDB
import EventServer; eserver = EventServer.instance()
class XendMigrateInfo:
# states: begin, active, failed, succeeded?
def __init__(self, id, dom, dst):
self.id = id
self.state = 'begin'
self.src_host = socket.gethostname()
self.src_dom = dom
self.dst_host = dst
self.dst_dom = None
def set_state(self, state):
self.state = state
def get_state(self):
return self.state
def sxpr(self):
sxpr = ['migrate', ['id', self.id], ['state', self.state] ]
sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ]
sxpr.append(sxpr_src)
sxpr_dst = ['dst', ['host', self.dst] ]
if self.dst_dom:
sxpr_dst.append(['domain', self.dst_dom])
sxpr.append(sxpr_dst)
return sxpr
class XendMigrate:
# Represents migration in progress.
# Use log for indications of begin/end/errors?
# Need logging of: domain create/halt, migrate begin/end/fail
# Log via event server?
dbpath = "migrate"
def __init__(self):
self.db = XendDB.XendDB(self.dbpath)
self.migrate = {}
self.migrate_db = self.db.fetchall("")
self.id = 0
def nextid(self):
self.id += 1
return "%d" % self.id
def sync(self):
self.db.saveall("", self.migrate_db)
def sync_migrate(self, id):
self.db.save(id, self.migrate_db[id])
def close(self):
pass
def _add_migrate(self, id, info):
self.migrate[id] = info
self.migrate_db[id] = info.sxpr()
self.sync_migrate(id)
#eserver.inject('xend.migrate.begin', info.sxpr())
def _delete_migrate(self, id):
#eserver.inject('xend.migrate.end', id)
del self.migrate[id]
del self.migrate_db[id]
self.db.delete(id)
def migrate_ls(self):
return self.migrate.keys()
def migrates(self):
return self.migrate.values()
def migrate_get(self, id):
return self.migrate.get(id)
def migrate_begin(self, dom, dst):
# Check dom for existence, not migrating already.
# Create migrate info, tell xend to migrate it?
# - or fork migrate command ourselves?
# Subscribe to migrate notifications (for updating).
id = self.nextid()
info = XenMigrateInfo(id, dom, dst)
self._add_migrate(id, info)
return id
def instance():
global inst
try:
inst
except:
inst = XendMigrate()
return inst
+71
View File
@@ -0,0 +1,71 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Handler for node operations.
Has some persistent state:
- logs
- notification urls
"""
import os
import xen.ext.xc
class XendNode:
def __init__(self):
self.xc = xen.ext.xc.new()
def shutdown(self):
return 0
def reboot(self):
return 0
def notify(self, uri):
return 0
def cpu_bvt_slice_set(self, slice):
ret = 0
#ret = self.xc.bvtsched_global_set(ctx_allow=slice)
return ret
def cpu_bvt_slice_get(self, slice):
ret = 0
#ret = self.xc.bvtsched_global_get()
return ret
def cpu_rrobin_slice_set(self, slice):
ret = 0
#ret = self.xc.rrobin_global_set(slice)
return ret
def info(self):
return self.nodeinfo() + self.physinfo()
def nodeinfo(self):
(sys, host, rel, ver, mch) = os.uname()
return [['system', sys],
['host', host],
['release', rel],
['version', ver],
['machine', mch]]
def physinfo(self):
pinfo = self.xc.physinfo()
info = [['cores', pinfo['cores']],
['hyperthreads_per_core', pinfo['ht_per_core']],
['cpu_mhz', pinfo['cpu_khz']/1000],
['memory', pinfo['total_pages']/256],
['free_memory', pinfo['free_pages']/256]]
return info
def instance():
global inst
try:
inst
except:
inst = XendNode()
return inst
+156
View File
@@ -0,0 +1,156 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Xend root class.
Creates the event server and handles configuration.
"""
import os
import os.path
import sys
import EventServer
# Initial create of the event server.
eserver = EventServer.instance()
import sxp
def reboots():
"""Get a list of system reboots from wtmp.
"""
out = os.popen('/usr/bin/last reboot', 'r')
list = [ x.strip() for x in out if x.startswith('reboot') ]
return list
def last_reboot():
"""Get the last known system reboot.
"""
l = reboots()
return (l and l[-1]) or None
class XendRoot:
"""Root of the management classes."""
lastboot_default = "/var/xen/lastboot"
"""Default path to the root of the database."""
dbroot_default = "/var/xen/xend-db"
"""Default path to the config file."""
config_default = "/etc/xen/xend-config.sxp"
"""Environment variable used to override config_default."""
config_var = "XEND_CONFIG"
def __init__(self):
self.rebooted = 0
self.last_reboot = None
self.dbroot = None
self.config_path = None
self.config = None
self.configure()
self.check_lastboot()
eserver.subscribe('xend.*', self.event_handler)
#eserver.subscribe('xend.domain.created', self.event_handler)
#eserver.subscribe('xend.domain.died', self.event_handler)
def start(self):
eserver.inject('xend.start', self.rebooted)
def event_handler(self, event, val):
print >> sys.stderr, "EVENT>", event, val
def read_lastboot(self):
try:
val = file(self.lastboot, 'rb').readlines()[0]
except StandardError, ex:
print 'warning: Error reading', self.lastboot, ex
val = None
return val
def write_lastboot(self, val):
if not val: return
try:
fdir = os.path.dirname(self.lastboot)
if not os.path.isdir(fdir):
os.makedirs(fdir)
out = file(self.lastboot, 'wb+')
out.write(val)
out.close()
except IOError, ex:
print 'warning: Error writing', self.lastboot, ex
pass
def check_lastboot(self):
"""Check if there has been a system reboot since we saved lastboot.
"""
last_val = self.read_lastboot()
this_val = last_reboot()
if this_val == last_val:
self.rebooted = 0
else:
self.rebooted = 1
self.write_lastboot(this_val)
self.last_reboot = this_val
def get_last_reboot(self):
return self.last_reboot
def get_rebooted(self):
return self.rebooted
def configure(self):
self.set_config()
self.dbroot = self.get_config_value("dbroot", self.dbroot_default)
self.lastboot = self.get_config_value("lastboot", self.lastboot_default)
def get_dbroot(self):
"""Get the path to the database root.
"""
return self.dbroot
def set_config(self):
"""If the config file exists, read it. If not, ignore it.
The config file is a sequence of sxp forms.
"""
self.config_path = os.getenv(self.config_var, self.config_default)
if os.path.exists(self.config_path):
fin = file(self.config_path, 'rb')
try:
config = sxp.parse(fin)
config.insert(0, 'config')
self.config = config
finally:
fin.close()
else:
self.config = ['config']
def get_config(self, name=None):
"""Get the configuration element with the given name, or
the whole configuration if no name is given.
name element name (optional)
returns config or none
"""
if name is None:
val = self.config
else:
val = sxp.child(self.config, name)
return val
def get_config_value(self, name, val=None):
"""Get the value of an atomic configuration element.
name element name
val default value (optional, defaults to None)
returns value
"""
return sxp.child_value(self.config, name, val=val)
def instance():
global inst
try:
inst
except:
inst = XendRoot()
return inst
+69
View File
@@ -0,0 +1,69 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Handler for vnet operations.
"""
import sxp
import XendDB
class XendVnet:
"""Index of all vnets. Singleton.
"""
dbpath = "vnet"
def __init__(self):
# Table of vnet info indexed by vnet id.
self.vnet = {}
self.db = XendDB.XendDB(self.dbpath)
self.vnet = self.db.fetchall("")
def vnet_ls(self):
"""List all vnets.
"""
return self.vnet.keys()
def vnets(self):
return self.vnet.values()
def vnet_get(self, id):
"""Get a vnet.
id vnet id
"""
return self.vnet.get(id)
def vnet_create(self, info):
"""Create a vnet.
info config
"""
self.vnet_configure(info)
def vnet_configure(self, info):
"""Configure a vnet.
id vnet id
info config
"""
# Need to configure for real.
# Only sync if succeeded - otherwise need to back out.
self.vnet[info.id] = info
self.db.save(info.id, info)
def vnet_delete(self, id):
"""Delete a vnet.
id vnet id
"""
# Need to delete for real. What if fails?
if id in self.vnet:
del self.vnet[id]
self.db.delete(id)
def instance():
global inst
try:
inst
except:
inst = XendVnet()
return inst
+1
View File
@@ -0,0 +1 @@
+165
View File
@@ -0,0 +1,165 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Encoding for arguments to HTTP calls.
Uses the url-encoding with MIME type 'application/x-www-form-urlencoded'
if the data does not include files. Otherwise it uses the encoding with
MIME type 'multipart/form-data'. See the HTML4 spec for details.
"""
import sys
import types
from StringIO import StringIO
import urllib
import httplib
import random
import md5
# Extract from HTML4 spec.
## The following example illustrates "multipart/form-data"
## encoding. Suppose we have the following form:
## <FORM action="http://server.com/cgi/handle"
## enctype="multipart/form-data"
## method="post">
## <P>
## What is your name? <INPUT type="text" name="submit-name"><BR>
## What files are you sending? <INPUT type="file" name="files"><BR>
## <INPUT type="submit" value="Send"> <INPUT type="reset">
## </FORM>
## If the user enters "Larry" in the text input, and selects the text
## file "file1.txt", the user agent might send back the following data:
## Content-Type: multipart/form-data; boundary=AaB03x
## --AaB03x
## Content-Disposition: form-data; name="submit-name"
## Larry
## --AaB03x
## Content-Disposition: form-data; name="files"; filename="file1.txt"
## Content-Type: text/plain
## ... contents of file1.txt ...
## --AaB03x--
## If the user selected a second (image) file "file2.gif", the user agent
## might construct the parts as follows:
## Content-Type: multipart/form-data; boundary=AaB03x
## --AaB03x
## Content-Disposition: form-data; name="submit-name"
## Larry
## --AaB03x
## Content-Disposition: form-data; name="files"
## Content-Type: multipart/mixed; boundary=BbC04y
## --BbC04y
## Content-Disposition: file; filename="file1.txt"
## Content-Type: text/plain
## ... contents of file1.txt ...
## --BbC04y
## Content-Disposition: file; filename="file2.gif"
## Content-Type: image/gif
## Content-Transfer-Encoding: binary
## ...contents of file2.gif...
## --BbC04y--
## --AaB03x--
__all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ]
def data_values(d):
if isinstance(d, types.DictType):
return d.items()
else:
return d
def encode_data(d):
"""Encode some data for HTTP transport.
The encoding used is stored in 'Content-Type' in the headers.
d data - sequence of tuples or dictionary
returns a 2-tuple of the headers and the encoded data
"""
val = ({}, None)
if d is None: return val
multipart = 0
for (k, v) in data_values(d):
if encode_isfile(v):
multipart = 1
break
if multipart:
val = encode_multipart(d)
else:
val = encode_form(d)
return val
def encode_isfile(v):
if isinstance(v, types.FileType):
return 1
if hasattr(v, 'readlines'):
return 1
return 0
def encode_multipart(d):
boundary = mime_boundary()
hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary }
out = StringIO()
for (k,v) in data_values(d):
out.write('--')
out.write(boundary)
out.write('\r\n')
if encode_isfile(v):
out.write('Content-Disposition: form-data; name="')
out.write(k)
if hasattr(v, 'name'):
out.write('"; filename="')
out.write(v.name)
out.write('"\r\n')
out.write('Content-Type: application/octet-stream\r\n')
out.write('\r\n')
for l in v.readlines():
out.write(l)
else:
out.write('Content-Disposition: form-data; name="')
out.write(k)
out.write('"\r\n')
out.write('\r\n')
out.write(str(v))
out.write('\r\n')
out.write('--')
out.write(boundary)
out.write('--')
out.write('\r\n')
return (hdr, out.getvalue())
def mime_boundary():
random.seed()
m = md5.new()
for i in range(0, 10):
c = chr(random.randint(1, 255))
m.update(c)
b = m.hexdigest()
return b[0:16]
def encode_form(d):
hdr = { 'Content-Type': 'application/x-www-form-urlencoded' }
val = urllib.urlencode(d)
return (hdr, val)
def main():
#d = {'a': 1, 'b': 'x y', 'c': file('conf.sxp') }
#d = {'a': 1, 'b': 'x y' }
d = [ ('a', 1), ('b', 'x y'), ('c', file('conf.sxp')) ]
#d = [ ('a', 1), ('b', 'x y')]
v = encode_data(d)
print v[0]
sys.stdout.write(v[1])
print
if __name__ == "__main__":
main()
+137
View File
@@ -0,0 +1,137 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import cgi
import os
import sys
import types
import StringIO
from twisted.internet import defer
from twisted.internet import reactor
from twisted.web import error
from twisted.web import resource
from twisted.web import server
from xen.xend import sxp
from xen.xend import PrettyPrint
def uri_pathlist(p):
"""Split a path into a list.
p path
return list of path elements
"""
l = []
for x in p.split('/'):
if x == '': continue
l.append(x)
return l
class SrvBase(resource.Resource):
"""Base class for services.
"""
def parse_form(self, req, method):
"""Parse the data for a request, GET using the URL, POST using encoded data.
Posts should use enctype='multipart/form-data' in the <form> tag,
rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data'
handles file upload.
req request
returns a cgi.FieldStorage instance
"""
env = {}
env['REQUEST_METHOD'] = method
if self.query:
env['QUERY_STRING'] = self.query
val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env)
return val
def use_sxp(self, req):
"""Determine whether to send an SXP response to a request.
Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept.
req request
returns 1 for SXP, 0 otherwise
"""
ok = 0
user_agent = req.getHeader('User-Agent')
accept = req.getHeader('Accept')
if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0):
ok = 1
return ok
def get_op_method(self, op):
"""Get the method for an operation.
For operation 'foo' looks for 'op_foo'.
op operation name
returns method or None
"""
op_method_name = 'op_' + op
return getattr(self, op_method_name, None)
def perform(self, req):
"""General operation handler for posted operations.
For operation 'foo' looks for a method op_foo and calls
it with op_foo(op, req). Replies with code 500 if op_foo
is not found.
The method must return a list when req.use_sxp is true
and an HTML string otherwise (or list).
Methods may also return a Deferred (for incomplete processing).
req request
"""
op = req.args.get('op')
if op is None or len(op) != 1:
req.setResponseCode(404, "Invalid")
return ''
op = op[0]
op_method = self.get_op_method(op)
if op_method is None:
req.setResponseCode(501, "Not implemented")
req.setHeader("Content-Type", "text/plain")
req.write("Not implemented: " + op)
return ''
else:
val = op_method(op, req)
if isinstance(val, defer.Deferred):
val.addCallback(self._cb_perform, req, 1)
return server.NOT_DONE_YET
else:
self._cb_perform(val, req, 0)
return ''
def _cb_perform(self, val, req, dfr):
"""Callback to complete the request.
May be called from a Deferred.
"""
if isinstance(val, error.ErrorPage):
req.write(val.render(req))
elif self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
sxp.show(val, req)
else:
req.write('<html><head></head><body>')
self.print_path(req)
if isinstance(val, types.ListType):
req.write('<code><pre>')
PrettyPrint.prettyprint(val, out=req)
req.write('</pre></code>')
else:
req.write(str(val))
req.write('</body></html>')
if dfr:
req.finish()
def print_path(self, req):
"""Print the path with hyperlinks.
"""
pathlist = [x for x in req.prepath if x != '' ]
s = "/"
req.write('<h1><a href="/">/</a>')
for x in pathlist:
s += x + "/"
req.write(' <a href="%s">%s</a>/' % (s, x))
req.write("</h1>")
@@ -0,0 +1,42 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from xen.xend import sxp
from xen.xend import XendConsole
from SrvDir import SrvDir
class SrvConsole(SrvDir):
"""An individual console.
"""
def __init__(self, info):
SrvDir.__init__(self)
self.info = info
self.xc = XendConsole.instance()
def op_disconnect(self, op, req):
val = self.xc.console_disconnect(self.info.id)
return val
def render_POST(self, req):
return self.perform(req)
def render_GET(self, req):
if self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
sxp.show(self.info.sxpr(), out=req)
else:
req.write('<html><head></head><body>')
self.print_path(req)
#self.ls()
req.write('<p>%s</p>' % self.info)
req.write('<p><a href="%s">Connect to domain %d</a></p>'
% (self.info.uri(), self.info.dom2))
self.form(req)
req.write('</body></html>')
return ''
def form(self, req):
req.write('<form method="post" action="%s">' % req.prePathURL())
if self.info.connection():
req.write('<input type="submit" name="op" value="disconnect">')
req.write('</form>')
@@ -0,0 +1,59 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from SrvDir import SrvDir
from SrvConsole import SrvConsole
from xen.xend import XendConsole
from xen.xend import sxp
class SrvConsoleDir(SrvDir):
"""Console directory.
"""
def __init__(self):
SrvDir.__init__(self)
self.xconsole = XendConsole.instance()
def console(self, x):
val = None
try:
info = self.xconsole.console_get(x)
val = SrvConsole(info)
except KeyError, ex:
print 'SrvConsoleDir>', ex
pass
return val
def get(self, x):
v = SrvDir.get(self, x)
if v is not None:
return v
v = self.console(x)
return v
def render_GET(self, req):
if self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
self.ls_console(req, 1)
else:
req.write("<html><head></head><body>")
self.print_path(req)
self.ls(req)
self.ls_console(req)
#self.form(req.wfile)
req.write("</body></html>")
return ''
def ls_console(self, req, use_sxp=0):
url = req.prePathURL()
if not url.endswith('/'):
url += '/'
if use_sxp:
consoles = self.xconsole.console_ls()
sxp.show(consoles, out=req)
else:
consoles = self.xconsole.consoles()
consoles.sort(lambda x, y: cmp(x.id, y.id))
req.write('<ul>')
for c in consoles:
req.write('<li><a href="%s%s"> %s</a></li>' % (url, c.id, c))
req.write('</ul>')
+751
View File
@@ -0,0 +1,751 @@
###########################################################
## Xen controller daemon
## Copyright (c) 2004, K A Fraser (University of Cambridge)
## Copyright (C) 2004, Mike Wray <mike.wray@hp.com>
###########################################################
import os
import os.path
import signal
import sys
import threading
import linecache
import socket
import pwd
import re
import StringIO
from twisted.internet import pollreactor
pollreactor.install()
from twisted.internet import reactor
from twisted.internet import protocol
from twisted.internet import abstract
from twisted.internet import defer
from xen.ext import xu
from xen.xend import sxp
from xen.xend import PrettyPrint
from xen.xend import EventServer
eserver = EventServer.instance()
from xen.xend.server import SrvServer
import channel
import blkif
import netif
import console
import domain
from params import *
DEBUG = 1
class MgmtProtocol(protocol.DatagramProtocol):
"""Handler for the management socket (unix-domain).
"""
def __init__(self, daemon):
#protocol.DatagramProtocol.__init__(self)
self.daemon = daemon
def write(self, data, addr):
return self.transport.write(data, addr)
def datagramReceived(self, data, addr):
if DEBUG: print 'datagramReceived> addr=', addr, 'data=', data
io = StringIO.StringIO(data)
try:
vals = sxp.parse(io)
res = self.dispatch(vals[0])
self.send_result(addr, res)
except SystemExit:
raise
except:
if DEBUG:
raise
else:
self.send_error(addr)
def send_reply(self, addr, sxpr):
io = StringIO.StringIO()
sxp.show(sxpr, out=io)
io.seek(0)
self.write(io.getvalue(), addr)
def send_result(self, addr, res):
def fn(res, self=self, addr=addr):
self.send_reply(addr, ['ok', res])
if isinstance(res, defer.Deferred):
res.addCallback(fn)
else:
fn(res)
def send_error(self, addr):
(extype, exval) = sys.exc_info()[:2]
self.send_reply(addr, ['err',
['type', str(extype) ],
['value', str(exval) ] ] )
def opname(self, name):
"""Get the name of the method for an operation.
"""
return 'op_' + name.replace('.', '_')
def operror(self, name, v):
"""Default operation handler - signals an error.
"""
raise NotImplementedError('Invalid operation: ' +name)
def dispatch(self, req):
"""Dispatch a request to its handler.
"""
op_name = sxp.name(req)
op_method_name = self.opname(op_name)
op_method = getattr(self, op_method_name, self.operror)
return op_method(op_name, req)
def op_console_create(self, name, req):
"""Create a new control interface - console for a domain.
"""
print name, req
dom = sxp.child_value(req, 'domain')
if not dom: raise ValueError('Missing domain')
dom = int(dom)
console_port = sxp.child_value(req, 'console_port')
if console_port:
console_port = int(console_port)
resp = self.daemon.console_create(dom, console_port)
print name, resp
return resp
def op_consoles(self, name, req):
"""Get a list of the consoles.
"""
return self.daemon.consoles()
def op_console_disconnect(self, name, req):
id = sxp.child_value(req, 'id')
if not id:
raise ValueError('Missing console id')
id = int(id)
console = self.daemon.get_console(id)
if not console:
raise ValueError('Invalid console id')
if console.conn:
console.conn.loseConnection()
return ['ok']
def op_blkifs(self, name, req):
pass
def op_blkif_devs(self, name, req):
pass
def op_blkif_create(self, name, req):
pass
def op_blkif_dev_create(self, name, req):
pass
def op_netifs(self, name, req):
pass
def op_netif_devs(self, name, req):
pass
def op_netif_create(self, name, req):
pass
def op_netif_dev_create(self, name, req):
pass
class NotifierProtocol(protocol.Protocol):
"""Asynchronous handler for i/o on the notifier (event channel).
"""
def __init__(self, channelFactory):
self.channelFactory = channelFactory
def notificationReceived(self, idx, type):
#print 'NotifierProtocol>notificationReceived>', idx, type
channel = self.channelFactory.getChannel(idx)
if not channel:
return
#print 'NotifierProtocol>notificationReceived> channel', channel
channel.notificationReceived(type)
def connectionLost(self, reason=None):
pass
def doStart(self):
pass
def doStop(self):
pass
def startProtocol(self):
pass
def stopProtocol(self):
pass
class NotifierPort(abstract.FileDescriptor):
"""Transport class for the event channel.
"""
def __init__(self, daemon, notifier, proto, reactor=None):
assert isinstance(proto, NotifierProtocol)
abstract.FileDescriptor.__init__(self, reactor)
self.daemon = daemon
self.notifier = notifier
self.protocol = proto
def startListening(self):
self._bindNotifier()
self._connectToProtocol()
def stopListening(self):
if self.connected:
result = self.d = defer.Deferred()
else:
result = None
self.loseConnection()
return result
def fileno(self):
return self.notifier.fileno()
def _bindNotifier(self):
self.connected = 1
def _connectToProtocol(self):
self.protocol.makeConnection(self)
self.startReading()
def loseConnection(self):
if self.connected:
self.stopReading()
self.disconnecting = 1
reactor.callLater(0, self.connectionLost)
def connectionLost(self, reason=None):
abstract.FileDescriptor.connectionLost(self, reason)
if hasattr(self, 'protocol'):
self.protocol.doStop()
self.connected = 0
#self.notifier.close() # Not implemented.
os.close(self.fileno())
del self.notifier
if hasattr(self, 'd'):
self.d.callback(None)
del self.d
def doRead(self):
#print 'NotifierPort>doRead>', self
count = 0
while 1:
#print 'NotifierPort>doRead>', count
notification = self.notifier.read()
if not notification:
break
(idx, type) = notification
self.protocol.notificationReceived(idx, type)
self.notifier.unmask(idx)
count += 1
#print 'NotifierPort>doRead<'
class EventProtocol(protocol.Protocol):
"""Asynchronous handler for a connected event socket.
"""
def __init__(self, daemon):
#protocol.Protocol.__init__(self)
self.daemon = daemon
# Event queue.
self.queue = []
# Subscribed events.
self.events = []
self.parser = sxp.Parser()
self.pretty = 0
# For debugging subscribe to everything and make output pretty.
self.subscribe(['*'])
self.pretty = 1
def dataReceived(self, data):
try:
self.parser.input(data)
if self.parser.ready():
val = self.parser.get_val()
res = self.dispatch(val)
self.send_result(res)
if self.parser.at_eof():
self.loseConnection()
except SystemExit:
raise
except:
if DEBUG:
raise
else:
self.send_error()
def loseConnection(self):
if self.transport:
self.transport.loseConnection()
if self.connected:
reactor.callLater(0, self.connectionLost)
def connectionLost(self, reason=None):
self.unsubscribe()
def send_reply(self, sxpr):
io = StringIO.StringIO()
if self.pretty:
PrettyPrint.prettyprint(sxpr, out=io)
else:
sxp.show(sxpr, out=io)
print >> io
io.seek(0)
return self.transport.write(io.getvalue())
def send_result(self, res):
return self.send_reply(['ok', res])
def send_error(self):
(extype, exval) = sys.exc_info()[:2]
return self.send_reply(['err',
['type', str(extype)],
['value', str(exval)]])
def send_event(self, val):
return self.send_reply(['event', val[0], val[1]])
def unsubscribe(self):
for event in self.events:
eserver.unsubscribe(event, self.queue_event)
def subscribe(self, events):
self.unsubscribe()
for event in events:
eserver.subscribe(event, self.queue_event)
self.events = events
def queue_event(self, name, v):
# Despite the name we dont' queue the event here.
# We send it because the transport will queue it.
self.send_event([name, v])
def opname(self, name):
return 'op_' + name.replace('.', '_')
def operror(self, name, req):
raise NotImplementedError('Invalid operation: ' +name)
def dispatch(self, req):
op_name = sxp.name(req)
op_method_name = self.opname(op_name)
op_method = getattr(self, op_method_name, self.operror)
return op_method(op_name, req)
def op_help(self, name, req):
def nameop(x):
if x.startswith('op_'):
return x[3:].replace('_', '.')
else:
return x
l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
return l
def op_quit(self, name, req):
self.loseConnection()
def op_exit(self, name, req):
sys.exit(0)
def op_pretty(self, name, req):
self.pretty = 1
return ['ok']
def op_console_disconnect(self, name, req):
id = sxp.child_value(req, 'id')
if not id:
raise ValueError('Missing console id')
self.daemon.console_disconnect(id)
return ['ok']
def op_info(self, name, req):
val = ['info']
val += self.daemon.consoles()
val += self.daemon.blkifs()
val += self.daemon.netifs()
return val
def op_sys_subscribe(self, name, v):
# (sys.subscribe event*)
# Subscribe to the events:
self.subscribe(v[1:])
return ['ok']
def op_sys_inject(self, name, v):
# (sys.inject event)
event = v[1]
eserver.inject(sxp.name(event), event)
return ['ok']
class EventFactory(protocol.Factory):
"""Asynchronous handler for the event server socket.
"""
protocol = EventProtocol
service = None
def __init__(self, daemon):
#protocol.Factory.__init__(self)
self.daemon = daemon
def buildProtocol(self, addr):
proto = self.protocol(self.daemon)
proto.factory = self
return proto
class VirqClient:
def __init__(self, daemon):
self.daemon = daemon
def virqReceived(self, virq):
print 'VirqClient.virqReceived>', virq
eserver.inject('xend.virq', virq)
def lostChannel(self, channel):
print 'VirqClient.lostChannel>', channel
class Daemon:
"""The xend daemon.
"""
def __init__(self):
self.shutdown = 0
def daemon_pids(self):
pids = []
pidex = '(?P<pid>\d+)'
pythonex = '(?P<python>\S*python\S*)'
cmdex = '(?P<cmd>.*)'
procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$')
xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
procs = os.popen('ps -e -o pid,args 2>/dev/null')
for proc in procs:
pm = procre.match(proc)
if not pm: continue
xm = xendre.match(pm.group('cmd'))
if not xm: continue
#print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
pids.append(int(pm.group('pid')))
return pids
def new_cleanup(self, kill=0):
err = 0
pids = self.daemon_pids()
if kill:
for pid in pids:
print "Killing daemon pid=%d" % pid
os.kill(pid, signal.SIGHUP)
elif pids:
err = 1
print "Daemon already running: ", pids
return err
def cleanup(self, kill=False):
# No cleanup to do if PID_FILE is empty.
if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE):
return 0
# Read the pid of the previous invocation and search active process list.
pid = open(PID_FILE, 'r').read()
lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines()
for line in lines:
if re.search('^ *' + pid + '.+xend', line):
if not kill:
print "Daemon is already running (pid %d)" % int(pid)
return 1
# Old daemon is still active: terminate it.
os.kill(int(pid), 1)
# Delete the stale PID_FILE.
os.remove(PID_FILE)
return 0
def install_child_reaper(self):
#signal.signal(signal.SIGCHLD, self.onSIGCHLD)
# Ensure that zombie children are automatically reaped.
xu.autoreap()
def onSIGCHLD(self, signum, frame):
code = 1
while code > 0:
code = os.waitpid(-1, os.WNOHANG)
def start(self,trace=0):
if self.cleanup(kill=False):
return 1
# Detach from TTY.
if not DEBUG:
os.setsid()
if self.set_user():
return 1
self.install_child_reaper()
# Fork -- parent writes PID_FILE and exits.
pid = os.fork()
if pid:
# Parent
pidfile = open(PID_FILE, 'w')
pidfile.write(str(pid))
pidfile.close()
return 0
# Child
logfile = self.open_logfile()
self.redirect_output(logfile)
if trace:
self.tracefile = open('/var/log/xend.trace', 'w+', 1)
self.traceindent = 0
sys.settrace(self.trace)
try:
threading.settrace(self.trace) # Only in Python >= 2.3
except:
pass
self.run()
return 0
def print_trace(self,str):
for i in range(self.traceindent):
self.tracefile.write(" ")
self.tracefile.write(str)
def trace(self, frame, event, arg):
if event == 'call':
code = frame.f_code
filename = code.co_filename
m = re.search('.*xenmgr/(.*)', code.co_filename)
if not m:
return None
modulename = m.group(1)
if re.search('sxp.py', modulename):
return None
self.traceindent += 1
self.print_trace("++++ %s:%s\n"
% (modulename, code.co_name))
elif event == 'line':
filename = frame.f_code.co_filename
lineno = frame.f_lineno
self.print_trace("%4d %s" %
(lineno, linecache.getline(filename, lineno)))
elif event == 'return':
code = frame.f_code
filename = code.co_filename
m = re.search('.*xenmgr/(.*)', code.co_filename)
if not m:
return None
modulename = m.group(1)
self.print_trace("---- %s:%s\n"
% (modulename, code.co_name))
self.traceindent -= 1
elif event == 'exception':
pass
return self.trace
def open_logfile(self):
if not os.path.exists(CONTROL_DIR):
os.makedirs(CONTROL_DIR)
# Open log file. Truncate it if non-empty, and request line buffering.
if os.path.isfile(LOG_FILE):
os.rename(LOG_FILE, LOG_FILE+'.old')
logfile = open(LOG_FILE, 'w+', 1)
return logfile
def set_user(self):
# Set the UID.
try:
os.setuid(pwd.getpwnam(USER)[2])
return 0
except KeyError, error:
print "Error: no such user '%s'" % USER
return 1
def redirect_output(self, logfile):
if DEBUG: return
# Close down standard file handles
try:
os.close(0) # stdin
os.close(1) # stdout
os.close(2) # stderr
except:
pass
# Redirect output to log file.
sys.stdout = sys.stderr = logfile
def stop(self):
return self.cleanup(kill=True)
def run(self):
self.createFactories()
self.listenMgmt()
self.listenEvent()
self.listenNotifier()
self.listenVirq()
SrvServer.create(bridge=1)
reactor.run()
def createFactories(self):
self.channelF = channel.channelFactory()
self.domainCF = domain.DomainControllerFactory()
self.blkifCF = blkif.BlkifControllerFactory()
self.netifCF = netif.NetifControllerFactory()
self.consoleCF = console.ConsoleControllerFactory()
def listenMgmt(self):
protocol = MgmtProtocol(self)
s = os.path.join(CONTROL_DIR, MGMT_SOCK)
if os.path.exists(s):
os.unlink(s)
return reactor.listenUNIXDatagram(s, protocol)
def listenEvent(self):
protocol = EventFactory(self)
return reactor.listenTCP(EVENT_PORT, protocol)
def listenNotifier(self):
protocol = NotifierProtocol(self.channelF)
p = NotifierPort(self, self.channelF.notifier, protocol, reactor)
p.startListening()
return p
def listenVirq(self):
virqChan = self.channelF.virqChannel(channel.VIRQ_DOM_EXC)
virqChan.registerClient(VirqClient(self))
def exit(self):
reactor.diconnectAll()
sys.exit(0)
def blkif_set_control_domain(self, dom, recreate=0):
"""Set the block device backend control domain.
"""
return self.blkifCF.setControlDomain(dom, recreate=recreate)
def blkif_get_control_domain(self, dom):
"""Get the block device backend control domain.
"""
return self.blkifCF.getControlDomain()
def blkif_create(self, dom, recreate=0):
"""Create a block device interface controller.
Returns Deferred
"""
d = self.blkifCF.createInstance(dom, recreate=recreate)
return d
def blkifs(self):
return [ x.sxpr() for x in self.blkifCF.getInstances() ]
def blkif_get(self, dom):
return self.blkifCF.getInstanceByDom(dom)
def blkif_dev(self, dom, vdev):
return self.blkifCF.getDomainDevice(dom, vdev)
def blkif_dev_create(self, dom, vdev, mode, segment, recreate=0):
"""Create a block device.
Returns Deferred
"""
ctrl = self.blkifCF.getInstanceByDom(dom)
if not ctrl:
raise ValueError('No blkif controller: %d' % dom)
print 'blkif_dev_create>', dom, vdev, mode, segment
d = ctrl.attachDevice(vdev, mode, segment, recreate=recreate)
return d
def netif_set_control_domain(self, dom, recreate=0):
"""Set the network interface backend control domain.
"""
return self.netifCF.setControlDomain(dom, recreate=recreate)
def netif_get_control_domain(self, dom):
"""Get the network interface backend control domain.
"""
return self.netifCF.getControlDomain()
def netif_create(self, dom, recreate=0):
"""Create a network interface controller.
"""
return self.netifCF.createInstance(dom, recreate=recreate)
def netifs(self):
return [ x.sxpr() for x in self.netifCF.getInstances() ]
def netif_get(self, dom):
return self.netifCF.getInstanceByDom(dom)
def netif_dev_create(self, dom, vif, vmac, recreate=0):
"""Create a network device.
todo
"""
ctrl = self.netifCF.getInstanceByDom(dom)
if not ctrl:
raise ValueError('No netif controller: %d' % dom)
d = ctrl.attachDevice(vif, vmac, recreate=recreate)
return d
def netif_dev(self, dom, vif):
return self.netifCF.getDomainDevice(dom, vif)
def console_create(self, dom, console_port=None):
"""Create a console for a domain.
"""
console = self.consoleCF.getInstanceByDom(dom)
if console is None:
console = self.consoleCF.createInstance(dom, console_port)
return console.sxpr()
def consoles(self):
return [ c.sxpr() for c in self.consoleCF.getInstances() ]
def get_console(self, id):
return self.consoleCF.getInstance(id)
def get_domain_console(self, dom):
return self.consoleCF.getInstanceByDom(dom)
def console_disconnect(self, id):
"""Disconnect any connected console client.
"""
console = self.get_console(id)
if not console:
raise ValueError('Invalid console id')
console.disconnect()
def domain_shutdown(self, dom, reason):
"""Shutdown a domain.
"""
ctrl = self.domainCF.getInstanceByDom(dom)
if not ctrl:
raise ValueError('No domain controller: %d' % dom)
ctrl.shutdown(reason)
return 0
def instance():
global inst
try:
inst
except:
inst = Daemon()
return inst
@@ -0,0 +1,9 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from SrvDir import SrvDir
class SrvDeviceDir(SrvDir):
"""Device directory.
"""
pass
+91
View File
@@ -0,0 +1,91 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from twisted.web import error
from xen.xend import sxp
from SrvBase import SrvBase
class SrvConstructor:
"""Delayed constructor for sub-servers.
Does not import the sub-server class or create the object until needed.
"""
def __init__(self, klass):
"""Create a constructor. It is assumed that the class
should be imported as 'import klass from klass'.
klass name of its class
"""
self.klass = klass
self.obj = None
def getobj(self):
"""Get the sub-server object, importing its class and instantiating it if
necessary.
"""
if not self.obj:
exec 'from %s import %s' % (self.klass, self.klass)
klassobj = eval(self.klass)
self.obj = klassobj()
return self.obj
class SrvDir(SrvBase):
"""Base class for directory servlets.
"""
isLeaf = False
def __init__(self):
SrvBase.__init__(self)
self.table = {}
self.order = []
def getChild(self, x, req):
if x == '': return self
val = self.get(x)
if val is None:
return error.NoResource('Not found')
else:
return val
def get(self, x):
val = self.table.get(x)
if val is not None:
val = val.getobj()
return val
def add(self, x, xclass = None):
if xclass is None:
xclass = 'SrvDir'
self.table[x] = SrvConstructor(xclass)
self.order.append(x)
def render_GET(self, req):
if self.use_sxp(req):
req.setHeader("Content-type", sxp.mime_type)
self.ls(req, 1)
else:
req.write('<html><head></head><body>')
self.print_path(req)
self.ls(req)
self.form(req)
req.write('</body></html>')
return ''
def ls(self, req, use_sxp=0):
url = req.prePathURL()
if not url.endswith('/'):
url += '/'
if use_sxp:
req.write('(ls ')
for k in self.order:
req.write(' ' + k)
req.write(')')
else:
req.write('<ul>')
for k in self.order:
v = self.get(k)
req.write('<li><a href="%s%s">%s</a></li>'
% (url, k, k))
req.write('</ul>')
def form(self, req):
pass
+195
View File
@@ -0,0 +1,195 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from xen.xend import sxp
from xen.xend import XendDomain
from xen.xend import XendConsole
from xen.xend import PrettyPrint
from xen.xend.Args import FormFn
from SrvDir import SrvDir
class SrvDomain(SrvDir):
"""Service managing a single domain.
"""
def __init__(self, dom):
SrvDir.__init__(self)
self.dom = dom
self.xd = XendDomain.instance()
self.xconsole = XendConsole.instance()
def op_unpause(self, op, req):
val = self.xd.domain_unpause(self.dom.id)
return val
def op_pause(self, op, req):
val = self.xd.domain_pause(self.dom.id)
return val
def op_shutdown(self, op, req):
val = self.xd.domain_shutdown(self.dom.id)
req.setResponseCode(202)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
def op_destroy(self, op, req):
val = self.xd.domain_destroy(self.dom.id)
req.setHeader("Location", "%s/.." % req.prePathURL())
return val
def op_save(self, op, req):
fn = FormFn(self.xd.domain_save,
[['dom', 'int'],
['file', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_migrate(self, op, req):
fn = FormFn(self.xd.domain_migrate,
[['dom', 'int'],
['destination', 'str']])
val = fn(req.args, {'dom': self.dom.id})
val = 0 # Some migrate id.
req.setResponseCode(202)
#req.send_header("Location", "%s/.." % self.path) # Some migrate url.
return val
def op_pincpu(self, op, req):
fn = FormFn(self.xd.domain_pincpu,
[['dom', 'int'],
['cpu', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_cpu_bvt_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_bvt_set,
[['dom', 'int'],
['mcuadv', 'int'],
['warp', 'int'],
['warpl', 'int'],
['warpu', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_cpu_atropos_set(self, op, req):
fn = FormFn(self.xd.domain_cpu_atropos_set,
[['dom', 'int'],
['period', 'int'],
['slice', 'int'],
['latency', 'int'],
['xtratime', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vifs(self, op, req):
return self.xd.domain_vif_ls(self.dom.id)
def op_vif(self, op, req):
fn = FormFn(self.xd.domain_vif_get,
[['dom', 'int'],
['vif', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vif_stats(self, op, req):
#todo
fn = FormFn(self.xd.domain_vif_stats,
[['dom', 'int'],
['vif', 'int']])
#val = fn(req.args, {'dom': self.dom.id})
val = 999
#return val
return val
def op_vif_ip_add(self, op, req):
fn = FormFn(self.xd.domain_vif_ip_add,
[['dom', 'int'],
['vif', 'int'],
['ip', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vif_scheduler_set(self, op, req):
fn = FormFn(self.xd.domain_vif_scheduler_set,
[['dom', 'int'],
['vif', 'int'],
['bytes', 'int'],
['usecs', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vif_scheduler_get(self, op, req):
fn = FormFn(self.xd.domain_vif_scheduler_set,
[['dom', 'int'],
['vif', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vbds(self, op, req):
return self.xd.domain_vbd_ls(self.dom.id)
def op_vbd(self, op, req):
fn = FormFn(self.xd.domain_vbd_get,
[['dom', 'int'],
['vbd', 'int']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vbd_add(self, op, req):
fn = FormFn(self.xd.domain_vbd_add,
[['dom', 'int'],
['uname', 'str'],
['dev', 'str'],
['mode', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def op_vbd_remove(self, op, req):
fn = FormFn(self.xd.domain_vbd_remove,
[['dom', 'int'],
['dev', 'str']])
val = fn(req.args, {'dom': self.dom.id})
return val
def render_POST(self, req):
return self.perform(req)
def render_GET(self, req):
op = req.args.get('op')
if op and op[0] in ['vifs', 'vif', 'vif_stats', 'vbds', 'vbd']:
return self.perform(req)
if self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
sxp.show(self.dom.sxpr(), out=req)
else:
req.write('<html><head></head><body>')
self.print_path(req)
#self.ls()
req.write('<p>%s</p>' % self.dom)
if self.dom.console:
cinfo = self.dom.console
cid = cinfo.id
#todo: Local xref: need to know server prefix.
req.write('<p><a href="/xend/console/%s">Console %s</a></p>'
% (cid, cid))
req.write('<p><a href="%s">Connect to console</a></p>'
% cinfo.uri())
if self.dom.config:
req.write("<code><pre>")
PrettyPrint.prettyprint(self.dom.config, out=req)
req.write("</pre></code>")
req.write('<a href="%s?op=vif_stats&vif=0">vif 0 stats</a>'
% req.prePathURL())
self.form(req)
req.write('</body></html>')
return ''
def form(self, req):
req.write('<form method="post" action="%s">' % req.prePathURL())
req.write('<input type="submit" name="op" value="unpause">')
req.write('<input type="submit" name="op" value="pause">')
req.write('<input type="submit" name="op" value="shutdown">')
req.write('<input type="submit" name="op" value="destroy">')
req.write('<br><input type="submit" name="op" value="migrate">')
req.write('To: <input type="text" name="destination">')
req.write('</form>')
@@ -0,0 +1,144 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from StringIO import StringIO
from twisted.protocols import http
from twisted.web import error
from xen.xend import sxp
from xen.xend import XendDomain
from xen.xend.Args import FormFn
from SrvDir import SrvDir
from SrvDomain import SrvDomain
class SrvDomainDir(SrvDir):
"""Service that manages the domain directory.
"""
def __init__(self):
SrvDir.__init__(self)
self.xd = XendDomain.instance()
def domain(self, x):
val = None
try:
dom = self.xd.domain_get(x)
val = SrvDomain(dom)
except KeyError, ex:
print 'SrvDomainDir>', ex
pass
return val
def get(self, x):
v = SrvDir.get(self, x)
if v is not None:
return v
v = self.domain(x)
return v
def op_create(self, op, req):
ok = 0
try:
configstring = req.args.get('config')[0]
print 'config:', configstring
pin = sxp.Parser()
pin.input(configstring)
pin.input_eof()
config = pin.get_val()
ok = 1
except Exception, ex:
print 'op_create>', ex
if not ok:
req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
return "Invalid configuration"
return error.ErrorPage(http.BAD_REQUEST,
"Invalid",
"Invalid configuration")
try:
deferred = self.xd.domain_create(config)
deferred.addCallback(self._cb_op_create, configstring, req)
return deferred
except Exception, ex:
raise
#return ['err', str(ex) ]
#req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
#return str(ex)
#return error.ErrorPage(http.BAD_REQUEST,
# "Error creating domain",
# str(ex))
def _cb_op_create(self, dominfo, configstring, req):
"""Callback to handle deferred domain creation.
"""
dom = dominfo.id
domurl = "%s/%s" % (req.prePathURL(), dom)
req.setResponseCode(201, "created")
req.setHeader("Location", domurl)
if self.use_sxp(req):
return dominfo.sxpr()
else:
out = StringIO()
print >> out, ('<p> Created <a href="%s">Domain %s</a></p>'
% (domurl, dom))
print >> out, '<p><pre>'
print >> out, configstring
print >> out, '</pre></p>'
val = out.getvalue()
out.close()
return val
def op_restore(self, op, req):
fn = FormFn(self.xd.domain_restore,
[['file', 'str']])
val = fn(req.args)
return val
def render_POST(self, req):
return self.perform(req)
def render_GET(self, req):
if self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
self.ls_domain(req, 1)
else:
req.write("<html><head></head><body>")
self.print_path(req)
self.ls(req)
self.ls_domain(req)
self.form(req)
req.write("</body></html>")
return ''
def ls_domain(self, req, use_sxp=0):
url = req.prePathURL()
if not url.endswith('/'):
url += '/'
if use_sxp:
domains = self.xd.domain_ls()
sxp.show(domains, out=req)
else:
domains = self.xd.domains()
domains.sort(lambda x, y: cmp(x.id, y.id))
req.write('<ul>')
for d in domains:
req.write('<li><a href="%s%s"> Domain %s</a>'
% (url, d.id, d.id))
req.write('name=%s' % d.name)
req.write('memory=%d'% d.memory)
req.write('</li>')
req.write('</ul>')
def form(self, req):
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% req.prePathURL())
req.write('<button type="submit" name="op" value="create">Create Domain</button>')
req.write('Config <input type="file" name="config"><br>')
req.write('</form>')
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% req.prePathURL())
req.write('<button type="submit" name="op" value="create">Restore Domain</button>')
req.write('State <input type="string" name="state"><br>')
req.write('</form>')
@@ -0,0 +1,41 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from xen.xend import sxp
from xen.xend import EventServer
from SrvDir import SrvDir
class SrvEventDir(SrvDir):
"""Event directory.
"""
def __init__(self):
SrvDir.__init__(self)
self.eserver = EventServer.instance()
def op_inject(self, op, req):
eventstring = req.args.get('event')
pin = sxp.Parser()
pin.input(eventstring)
pin.input_eof()
sxpr = pin.get_val()
self.eserver.inject(sxp.name(sxpr), sxpr)
if req.use_sxp:
sxp.name(sxpr)
else:
return '<code>' + eventstring + '</code>'
def render_POST(self, req):
return self.perform(req)
def form(self, req):
action = req.prePathURL()
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% action)
req.write('<button type="submit" name="op" value="inject">Inject</button>')
req.write('Event <input type="text" name="event" size="40"><br>')
req.write('</form>')
req.write('<form method="post" action="%s" enctype="multipart/form-data">'
% action)
req.write('<button type="submit" name="op" value="inject">Inject</button>')
req.write('Event file<input type="file" name="event"><br>')
req.write('</form>')
+54
View File
@@ -0,0 +1,54 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
import os
from SrvDir import SrvDir
from xen.xend import sxp
from xen.xend import XendNode
class SrvNode(SrvDir):
"""Information about the node.
"""
def __init__(self):
SrvDir.__init__(self)
self.xn = XendNode.instance()
def op_shutdown(self, op, req):
val = self.xn.shutdown()
return val
def op_reboot(self, op, req):
val = self.xn.reboot()
return val
def op_cpu_rrobin_slice_set(self, op, req):
fn = FormFn(self.xn.cpu_rrobin_slice_set,
[['slice', 'int']])
val = fn(req.args, {})
return val
def op_cpu_bvt_slice_set(self, op, req):
fn = FormFn(self.xn.cpu_bvt_slice_set,
[['slice', 'int']])
val = fn(req.args, {})
return val
def render_POST(self, req):
return self.perform(req)
def render_GET(self, req):
if self.use_sxp(req):
req.setHeader("Content-Type", sxp.mime_type)
sxp.show(['node'] + self.info(), out=req)
else:
req.write('<html><head></head><body>')
self.print_path(req)
req.write('<ul>')
for d in self.info():
req.write('<li> %10s: %s' % (d[0], str(d[1])))
req.write('</ul>')
req.write('</body></html>')
return ''
def info(self):
return self.xn.info()
+30
View File
@@ -0,0 +1,30 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from xen.xend import XendRoot
xroot = XendRoot.instance()
from SrvDir import SrvDir
class SrvRoot(SrvDir):
"""The root of the xend server.
"""
"""Server sub-components. Each entry is (name, class), where
'name' is the entry name and 'class' is the name of its class.
"""
#todo Get this list from the XendRoot config.
subdirs = [
('node', 'SrvNode' ),
('domain', 'SrvDomainDir' ),
('console', 'SrvConsoleDir' ),
('event', 'SrvEventDir' ),
('device', 'SrvDeviceDir' ),
('vnet', 'SrvVnetDir' ),
]
def __init__(self):
SrvDir.__init__(self)
for (name, klass) in self.subdirs:
self.add(name, klass)
for (name, klass) in self.subdirs:
self.get(name)
xroot.start()
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/python2
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Example xend HTTP and console server.
Can be accessed from a browser or from a program.
Do 'python SrvServer.py' to run the server.
Then point a web browser at http://localhost:8000/xend and follow the links.
Most are stubs, except /domain which has a list of domains and a 'create domain'
button.
You can also access the server from a program.
Do 'python XendClient.py' to run a few test operations.
The data served differs depending on the client (as defined by User-Agent
and Accept in the HTTP headers). If the client is a browser, data
is returned in HTML, with interactive forms. If the client is a program,
data is returned in SXP format, with no forms.
The server serves to the world by default. To restrict it to the local host
change 'interface' in main().
Mike Wray <mike.wray@hp.com>
"""
# todo Support security settings etc. in the config file.
# todo Support command-line args.
from twisted.web import server
from twisted.web import resource
from twisted.internet import reactor
from xen.xend import XendRoot
xroot = XendRoot.instance()
from xen.xend import Vifctl
from SrvRoot import SrvRoot
def create(port=None, interface=None, bridge=0):
if port is None: port = 8000
if interface is None: interface = ''
if bridge or xroot.rebooted:
init_bridge()
root = resource.Resource()
xend = SrvRoot()
root.putChild('xend', xend)
site = server.Site(root)
reactor.listenTCP(port, site, interface=interface)
def init_bridge():
Vifctl.init()
def main(port=None, interface=None):
create(port, interface)
reactor.run()
if __name__ == '__main__':
main()
@@ -0,0 +1,9 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
from SrvDir import SrvDir
class SrvVnetDir(SrvDir):
"""Vnet directory.
"""
pass
+1
View File
@@ -0,0 +1 @@
+341
View File
@@ -0,0 +1,341 @@
from twisted.internet import defer
from xen.xend import sxp
from xen.xend import PrettyPrint
import channel
import controller
from messages import *
class BlkifControllerFactory(controller.ControllerFactory):
"""Factory for creating block device interface controllers.
Also handles the 'back-end' channel to the device driver domain.
"""
def __init__(self):
controller.ControllerFactory.__init__(self)
self.majorTypes = [ CMSG_BLKIF_BE ]
self.subTypes = {
CMSG_BLKIF_BE_CREATE : self.recv_be_create,
CMSG_BLKIF_BE_CONNECT : self.recv_be_connect,
CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create,
CMSG_BLKIF_BE_VBD_GROW : self.recv_be_vbd_grow,
CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
}
self.attached = 1
self.registerChannel()
def createInstance(self, dom, recreate=0):
d = self.addDeferred()
blkif = self.getInstanceByDom(dom)
if blkif:
self.callDeferred(blkif)
else:
blkif = BlkifController(self, dom)
self.addInstance(blkif)
if recreate:
self.callDeferred(blkif)
else:
blkif.send_be_create()
return d
def getDomainDevices(self, dom):
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevices()) or []
def getDomainDevice(self, dom, vdev):
blkif = self.getInstanceByDom(dom)
return (blkif and blkif.getDevice(vdev)) or None
def setControlDomain(self, dom, recreate=0):
if self.dom == dom: return
self.deregisterChannel()
if not recreate:
self.attached = 0
self.dom = dom
self.registerChannel()
#
#if xend.blkif.be_port:
# xend.blkif.recovery = True
#xend.blkif.be_port = xend.main.port_from_dom(dom)
def getControlDomain(self):
return self.dom
def reattachDevice(self, dom, vdev):
blkif = self.getInstanceByDom(dom)
if blkif:
blkif.reattachDevice(vdev)
self.attached = self.devicesAttached()
if self.attached:
self.reattached()
def devicesAttached(self):
"""Check if all devices are attached.
"""
attached = 1
for blkif in self.getInstances():
if not blkif.attached:
attached = 0
break
return attached
def reattached(self):
for blkif in self.getInstances():
blkif.reattached()
def recv_be_create(self, msg, req):
#print 'recv_be_create>'
val = unpackMsg('blkif_be_create_t', msg)
blkif = self.getInstanceByDom(val['domid'])
self.callDeferred(blkif)
def recv_be_connect(self, msg, req):
#print 'recv_be_create>'
val = unpackMsg('blkif_be_connect_t', msg)
blkif = self.getInstanceByDom(val['domid'])
if blkif:
blkif.send_fe_interface_status_changed()
else:
pass
def recv_be_vbd_create(self, msg, req):
#print 'recv_be_vbd_create>'
val = unpackMsg('blkif_be_vbd_create_t', msg)
blkif = self.getInstanceByDom(val['domid'])
if blkif:
blkif.send_be_vbd_grow(val['vdevice'])
else:
pass
def recv_be_vbd_grow(self, msg, req):
#print 'recv_be_vbd_grow>'
val = unpackMsg('blkif_be_vbd_grow_t', msg)
# Check status?
if self.attached:
self.callDeferred(0)
else:
self.reattachDevice(val['domid'], val['vdevice'])
def recv_be_driver_status_changed(self, msg, req):
val = unpackMsg('blkif_be_driver_status_changed_t', msg)
status = val['status']
if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
for blkif in self.getInstances():
blkif.detach()
class BlkDev(controller.Dev):
"""Info record for a block device.
"""
def __init__(self, ctrl, vdev, mode, segment):
controller.Dev.__init__(self, ctrl)
self.vdev = vdev
self.mode = mode
self.device = segment['device']
self.start_sector = segment['start_sector']
self.nr_sectors = segment['nr_sectors']
self.attached = 1
def readonly(self):
return 'w' not in self.mode
def sxpr(self):
val = ['blkdev', ['vdev', self.vdev], ['mode', self.mode] ]
return val
def destroy(self):
print 'BlkDev>destroy>', self.vdev
PrettyPrint.prettyprint(self.sxpr())
self.controller.send_be_vbd_destroy(self.vdev)
class BlkifController(controller.Controller):
"""Block device interface controller. Handles all block devices
for a domain.
"""
def __init__(self, factory, dom):
#print 'BlkifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
self.majorTypes = [ CMSG_BLKIF_FE ]
self.subTypes = {
CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
self.recv_fe_driver_status_changed,
CMSG_BLKIF_FE_INTERFACE_CONNECT :
self.recv_fe_interface_connect,
}
self.attached = 1
self.evtchn = None
self.registerChannel()
#print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['blkif', ['dom', self.dom]]
if self.evtchn:
val.append(['evtchn',
self.evtchn['port1'],
self.evtchn['port2']])
return val
def lostChannel(self):
print 'BlkifController>lostChannel>', 'dom=', self.dom
#self.destroyDevices()
controller.Controller.lostChannel(self)
def getDevices(self):
return self.devices.values()
def getDevice(self, vdev):
return self.devices.get(vdev)
def addDevice(self, vdev, mode, segment):
if vdev in self.devices: return None
dev = BlkDev(self, vdev, mode, segment)
self.devices[vdev] = dev
return dev
def attachDevice(self, vdev, mode, segment, recreate=0):
"""Attach a device to the specified interface.
"""
#print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
dev = self.addDevice(vdev, mode, segment)
if not dev: return -1
if recreate:
d = defer.Deferred()
d.callback(self)
else:
self.send_be_vbd_create(vdev)
d = self.factory.addDeferred()
return d
def destroy(self):
print 'BlkifController>destroy> dom=', self.dom
def cb_destroy(val):
self.send_be_destroy()
d = self.factory.addDeferred()
d.addCallback(cb_destroy)
self.send_be_disconnect()
#self.destroyDevices()
def destroyDevices(self):
for dev in self.getDevices():
dev.destroy()
def detach(self):
"""Detach all devices, when the back-end control domain has changed.
"""
self.attached = 0
for dev in self.devices.values():
dev.attached = 0
self.send_be_vbd_create(vdev)
def reattachDevice(self, vdev):
"""Reattach a device, when the back-end control domain has changed.
"""
dev = self.devices[vdev]
dev.attached = 1
attached = 1
for dev in self.devices.values():
if not dev.attached:
attached = 0
break
self.attached = attached
return self.attached
def reattached(self):
"""All devices have been reattached after the back-end control
domain has changed.
"""
msg = packMsg('blkif_fe_interface_status_changed_t',
{ 'handle' : 0,
'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED})
self.writeRequest(msg)
def recv_fe_driver_status_changed(self, msg, req):
msg = packMsg('blkif_fe_interface_status_changed_t',
{ 'handle' : 0,
'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED,
'evtchn' : 0 })
self.writeRequest(msg)
def recv_fe_interface_connect(self, msg, req):
val = unpackMsg('blkif_fe_interface_connect_t', msg)
self.evtchn = channel.eventChannel(0, self.dom)
print 'recv_fe_interface_connect>'
PrettyPrint.prettyprint(self.sxpr())
msg = packMsg('blkif_be_connect_t',
{ 'domid' : self.dom,
'blkif_handle' : val['handle'],
'evtchn' : self.evtchn['port1'],
'shmem_frame' : val['shmem_frame'] })
self.factory.writeRequest(msg)
pass
#def recv_fe_interface_status_changed(self, msg, req):
# (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
# print 'recv_fe_interface_status_changed>', hnd, status, chan
# pass
def send_fe_interface_status_changed(self):
msg = packMsg('blkif_fe_interface_status_changed_t',
{ 'handle' : 0,
'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
'evtchn' : self.evtchn['port2'] })
self.writeRequest(msg)
def send_be_create(self):
msg = packMsg('blkif_be_create_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
def send_be_disconnect(self):
print '>BlkifController>send_be_disconnect>', 'dom=', self.dom
msg = packMsg('blkif_be_disconnect_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
def send_be_destroy(self):
print '>BlkifController>send_be_destroy>', 'dom=', self.dom
msg = packMsg('blkif_be_destroy_t',
{ 'domid' : self.dom,
'blkif_handle' : 0 })
self.factory.writeRequest(msg)
def send_be_vbd_create(self, vdev):
dev = self.devices[vdev]
msg = packMsg('blkif_be_vbd_create_t',
{ 'domid' : self.dom,
'blkif_handle' : 0,
'vdevice' : dev.vdev,
'readonly' : dev.readonly() })
self.factory.writeRequest(msg)
def send_be_vbd_grow(self, vdev):
dev = self.devices[vdev]
msg = packMsg('blkif_be_vbd_grow_t',
{ 'domid' : self.dom,
'blkif_handle' : 0,
'vdevice' : dev.vdev,
'extent.device' : dev.device,
'extent.sector_start' : dev.start_sector,
'extent.sector_length' : dev.nr_sectors })
self.factory.writeRequest(msg)
def send_be_vbd_destroy(self, vdev):
print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev
PrettyPrint.prettyprint(self.sxpr())
dev = self.devices[vdev]
msg = packMsg('blkif_be_vbd_destroy_t',
{ 'domid' : self.dom,
'blkif_handle' : 0,
'vdevice' : dev.vdev })
del self.devices[vdev]
self.factory.writeRequest(msg)
+378
View File
@@ -0,0 +1,378 @@
import xen.ext.xc; xc = xen.ext.xc.new()
from xen.ext import xu
from messages import msgTypeName
VIRQ_MISDIRECT = 0 # Catch-all interrupt for unbound VIRQs.
VIRQ_TIMER = 1 # Timebase update, and/or requested timeout.
VIRQ_DEBUG = 2 # Request guest to dump debug info.
VIRQ_CONSOLE = 3 # (DOM0) bytes received on emergency console.
VIRQ_DOM_EXC = 4 # (DOM0) Exceptional event for some domain.
def eventChannel(dom1, dom2):
return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2)
class ChannelFactory:
"""Factory for creating channels.
Maintains a table of channels.
"""
""" Channels indexed by index. """
channels = {}
def __init__(self):
"""Constructor - do not use. Use the channelFactory function."""
self.notifier = xu.notifier()
def addChannel(self, channel):
"""Add a channel.
"""
idx = channel.idx
self.channels[idx] = channel
self.notifier.bind(idx)
# Try to wake it up
#self.notifier.unmask(idx)
#channel.notify()
def getChannel(self, idx):
"""Get the channel with the given index (if any).
"""
return self.channels.get(idx)
def delChannel(self, idx):
"""Remove the channel with the given index (if any).
"""
if idx in self.channels:
del self.channels[idx]
self.notifier.unbind(idx)
def domChannel(self, dom):
"""Get the channel for the given domain.
Construct if necessary.
"""
dom = int(dom)
for chan in self.channels.values():
if not isinstance(chan, Channel): continue
if chan.dom == dom:
return chan
chan = Channel(self, dom)
self.addChannel(chan)
return chan
def virqChannel(self, virq):
"""Get the channel for the given virq.
Construct if necessary.
"""
for chan in self.channels.values():
if not isinstance(chan, VirqChannel): continue
if chan.virq == virq:
return chan
chan = VirqChannel(self, virq)
self.addChannel(chan)
return chan
def channelClosed(self, channel):
"""The given channel has been closed - remove it.
"""
self.delChannel(channel.idx)
def createPort(self, dom):
"""Create a port for a channel to the given domain.
"""
return xu.port(dom)
def channelFactory():
"""Singleton constructor for the channel factory.
Use this instead of the class constructor.
"""
global inst
try:
inst
except:
inst = ChannelFactory()
return inst
class BaseChannel:
"""Abstract superclass for channels.
The subclass constructor must set idx to the port to use.
"""
def __init__(self, factory):
self.factory = factory
self.idx = -1
self.closed = 0
def getIndex(self):
"""Get the channel index.
"""
return self.idx
def notificationReceived(self, type):
"""Called when a notification is received.
Closes the channel on error, otherwise calls
handleNotification(type), which should be defined
in a subclass.
"""
#print 'notificationReceived> type=', type, self
if self.closed: return
if type == self.factory.notifier.EXCEPTION:
print 'notificationReceived> EXCEPTION'
info = xc.evtchn_status(self.idx)
if info['status'] == 'unbound':
print 'notificationReceived> EXCEPTION closing...'
self.close()
return
self.handleNotification(type)
def close(self):
"""Close the channel. Calls channelClosed() on the factory.
Override in subclass.
"""
self.factory.channelClosed(self)
def handleNotification(self, type):
"""Handle notification.
Define in subclass.
"""
pass
class VirqChannel(BaseChannel):
"""A channel for handling a virq.
"""
def __init__(self, factory, virq):
"""Create a channel for the given virq using the given factory.
Do not call directly, use virqChannel on the factory.
"""
BaseChannel.__init__(self, factory)
self.virq = virq
# Notification port (int).
self.port = xc.evtchn_bind_virq(virq)
self.idx = self.port
# Clients to call when a virq arrives.
self.clients = []
def __repr__(self):
return ('<VirqChannel virq=%d port=%d>'
% (self.virq, self.port))
def getVirq(self):
"""Get the channel's virq.
"""
return self.virq
def close(self):
"""Close the channel. Calls lostChannel(self) on all its clients and
channelClosed() on the factory.
"""
for c in self.clients:
c.lostChannel(self)
del self.clients
BaseChannel.close(self)
def registerClient(self, client):
"""Register a client. The client will be called with
client.virqReceived(virq) when a virq is received.
The client will be called with client.lostChannel(self) if the
channel is closed.
"""
self.clients.append(client)
def handleNotification(self, type):
for c in self.clients:
c.virqReceived(self.virq)
def notify(self):
xc.evtchn_send(self.port)
class Channel(BaseChannel):
"""A control channel to a domain. Messages for the domain device controllers
are multiplexed over the channel (console, block devs, net devs).
"""
def __init__(self, factory, dom):
"""Create a channel to the given domain using the given factory.
Do not call directly, use domChannel on the factory.
"""
BaseChannel.__init__(self, factory)
# Domain.
self.dom = int(dom)
# Domain port (object).
self.port = self.factory.createPort(dom)
# Channel port (int).
self.idx = self.port.local_port
# Registered devices.
self.devs = []
# Devices indexed by the message types they handle.
self.devs_by_type = {}
# Output queue.
self.queue = []
self.closed = 0
def getLocalPort(self):
"""Get the local port.
"""
return self.port.local_port
def getRemotePort(self):
"""Get the remote port.
"""
return self.port.remote_port
def close(self):
"""Close the channel. Calls lostChannel() on all its devices and
channelClosed() on the factory.
"""
self.closed = 1
for d in self.devs:
d.lostChannel()
self.factory.channelClosed(self)
self.devs = []
self.devs_by_type = {}
def registerDevice(self, types, dev):
"""Register a device controller.
@param types message types the controller handles
@param dev device controller
"""
if self.closed: return
self.devs.append(dev)
for ty in types:
self.devs_by_type[ty] = dev
def deregisterDevice(self, dev):
"""Remove the registration for a device controller.
@param dev device controller
"""
if dev in self.devs:
self.devs.remove(dev)
types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
for ty in types:
del self.devs_by_type[ty]
def getDevice(self, type):
"""Get the device controller handling a message type.
@param type message type
@returns controller or None
"""
return self.devs_by_type.get(type)
def getMessageType(self, msg):
"""Get a 2-tuple of the message type and subtype.
"""
hdr = msg.get_header()
return (hdr['type'], hdr.get('subtype'))
def __repr__(self):
return ('<Channel dom=%d ports=%d:%d>'
% (self.dom,
self.port.local_port,
self.port.remote_port))
def handleNotification(self, type):
work = 0
work += self.handleRequests()
work += self.handleResponses()
work += self.handleWrites()
if work:
self.notify()
def notify(self):
self.port.notify()
def handleRequests(self):
work = 0
while 1:
msg = self.readRequest()
if not msg: break
self.requestReceived(msg)
work += 1
return work
def requestReceived(self, msg):
(ty, subty) = self.getMessageType(msg)
#todo: Must respond before writing any more messages.
#todo: Should automate this (respond on write)
self.port.write_response(msg)
dev = self.getDevice(ty)
if dev:
dev.requestReceived(msg, ty, subty)
else:
print ("requestReceived> No device: Message type %s %d:%d"
% (msgTypeName(ty, subty), ty, subty)), self
def handleResponses(self):
work = 0
while 1:
msg = self.readResponse()
if not msg: break
self.responseReceived(msg)
work += 1
return work
def responseReceived(self, msg):
(ty, subty) = self.getMessageType(msg)
dev = self.getDevice(ty)
if dev:
dev.responseReceived(msg, ty, subty)
else:
print ("responseReceived> No device: Message type %d:%d"
% (msgTypeName(ty, subty), ty, subty)), self
def handleWrites(self):
work = 0
# Pull data from producers.
for dev in self.devs:
work += dev.produceRequests()
# Flush the queue.
while self.queue and self.port.space_to_write_request():
msg = self.queue.pop(0)
self.port.write_request(msg)
work += 1
return work
def writeRequest(self, msg, notify=1):
if self.closed:
val = -1
elif self.writeReady():
self.port.write_request(msg)
if notify: self.notify()
val = 1
else:
self.queue.append(msg)
val = 0
return val
def writeResponse(self, msg):
if self.closed: return -1
self.port.write_response(msg)
return 1
def writeReady(self):
if self.closed or self.queue: return 0
return self.port.space_to_write_request()
def readRequest(self):
if self.closed:
return None
if self.port.request_to_read():
val = self.port.read_request()
else:
val = None
return val
def readResponse(self):
if self.closed:
return None
if self.port.response_to_read():
val = self.port.read_response()
else:
val = None
return val
+232
View File
@@ -0,0 +1,232 @@
from twisted.internet import reactor
from twisted.internet import protocol
from twisted.protocols import telnet
from xen.ext import xu
from xen.xend import EventServer
eserver = EventServer.instance()
import controller
from messages import *
from params import *
"""Telnet binary option."""
TRANSMIT_BINARY = '0'
WILL = chr(251)
IAC = chr(255)
class ConsoleProtocol(protocol.Protocol):
"""Asynchronous handler for a console TCP socket.
"""
def __init__(self, controller, idx):
self.controller = controller
self.idx = idx
self.addr = None
self.binary = 0
def connectionMade(self):
peer = self.transport.getPeer()
self.addr = (peer.host, peer.port)
if self.controller.connect(self.addr, self):
self.transport.write("Cannot connect to console %d on domain %d\n"
% (self.idx, self.controller.dom))
self.loseConnection()
return
else:
# KAF: A nice quiet successful connect. Don't bother with telnet
# control sequence -- telnet is not the appropriate protocol here.
#self.transport.write("Connected to console %d on domain %d\n"
# % (self.idx, self.controller.dom))
#self.setTelnetTransmitBinary()
eserver.inject('xend.console.connect',
[self.idx, self.addr[0], self.addr[1]])
def setTelnetTransmitBinary(self):
"""Send the sequence to set the telnet TRANSMIT-BINARY option.
"""
self.write(IAC + WILL + TRANSMIT_BINARY)
def dataReceived(self, data):
if self.controller.handleInput(self, data):
self.loseConnection()
def write(self, data):
#if not self.connected: return -1
self.transport.write(data)
return len(data)
def connectionLost(self, reason=None):
eserver.inject('xend.console.disconnect',
[self.idx, self.addr[0], self.addr[1]])
self.controller.disconnect()
def loseConnection(self):
self.transport.loseConnection()
class ConsoleFactory(protocol.ServerFactory):
"""Asynchronous handler for a console server socket.
"""
protocol = ConsoleProtocol
def __init__(self, controller, idx):
#protocol.ServerFactory.__init__(self)
self.controller = controller
self.idx = idx
def buildProtocol(self, addr):
proto = self.protocol(self.controller, self.idx)
proto.factory = self
return proto
class ConsoleControllerFactory(controller.ControllerFactory):
"""Factory for creating console controllers.
"""
def createInstance(self, dom, console_port=None):
if console_port is None:
console_port = CONSOLE_PORT_BASE + dom
console = ConsoleController(self, dom, console_port)
self.addInstance(console)
eserver.inject('xend.console.create',
[console.idx, console.dom, console.console_port])
return console
def consoleClosed(self, console):
eserver.inject('xend.console.close', console.idx)
self.delInstance(console)
class ConsoleController(controller.Controller):
"""Console controller for a domain.
Does not poll for i/o itself, but relies on the notifier to post console
output and the connected TCP sockets to post console input.
"""
def __init__(self, factory, dom, console_port):
#print 'ConsoleController> dom=', dom, type(dom)
controller.Controller.__init__(self, factory, dom)
self.majorTypes = [ CMSG_CONSOLE ]
self.status = "new"
self.addr = None
self.conn = None
self.rbuf = xu.buffer()
self.wbuf = xu.buffer()
self.console_port = console_port
self.registerChannel()
self.listener = None
self.listen()
#print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val =['console',
['status', self.status ],
['id', self.idx ],
['domain', self.dom ],
['local_port', self.channel.getLocalPort() ],
['remote_port', self.channel.getRemotePort() ],
['console_port', self.console_port ] ]
if self.addr:
val.append(['connected', self.addr[0], self.addr[1]])
return val
def ready(self):
return not (self.closed() or self.rbuf.empty())
def closed(self):
return self.status == 'closed'
def connected(self):
return self.status == 'connected'
def close(self):
try:
#print 'ConsoleController> close dom=', self.dom
self.status = "closed"
if self.conn:
self.conn.loseConnection()
self.listener.stopListening()
self.deregisterChannel()
self.lostChannel()
except Exception, ex:
print 'ConsoleController>close>', ex
raise
def listen(self):
"""Listen for TCP connections to the console port..
"""
if self.closed(): return
self.status = "listening"
if self.listener:
#self.listener.startListening()
pass
else:
f = ConsoleFactory(self, self.idx)
self.listener = reactor.listenTCP(self.console_port, f)
def connect(self, addr, conn):
if self.closed(): return -1
if self.connected(): return -1
self.addr = addr
self.conn = conn
self.status = "connected"
self.handleOutput()
return 0
def disconnect(self):
if self.conn:
self.conn.loseConnection()
self.addr = None
self.conn = None
self.listen()
def requestReceived(self, msg, type, subtype):
#print '***Console', self.dom, msg.get_payload()
self.rbuf.write(msg.get_payload())
self.handleOutput()
def responseReceived(self, msg, type, subtype):
pass
def produceRequests(self):
# Send as much pending console data as there is room for.
work = 0
while not self.wbuf.empty() and self.channel.writeReady():
msg = xu.message(CMSG_CONSOLE, 0, 0)
msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
work += self.channel.writeRequest(msg, notify=0)
return work
def handleInput(self, conn, data):
"""Handle some external input aimed at the console.
Called from a TCP connection (conn).
"""
if self.closed(): return -1
if conn != self.conn: return 0
self.wbuf.write(data)
if self.produceRequests():
self.channel.notify()
return 0
def handleOutput(self):
"""Handle buffered output from the console.
Sends it to the connected console (if any).
"""
if self.closed():
#print 'Console>handleOutput> closed'
return -1
if not self.conn:
#print 'Console>handleOutput> not connected'
return 0
while not self.rbuf.empty():
try:
#print 'Console>handleOutput> writing...'
bytes = self.conn.write(self.rbuf.peek())
if bytes > 0:
self.rbuf.discard(bytes)
except socket.error, error:
pass
#print 'Console>handleOutput<'
return 0
+169
View File
@@ -0,0 +1,169 @@
from twisted.internet import defer
import channel
from messages import msgTypeName
class CtrlMsgRcvr:
"""Abstract class for things that deal with a control interface to a domain.
"""
def __init__(self):
self.channelFactory = channel.channelFactory()
self.majorTypes = [ ]
self.subTypes = {}
self.dom = None
self.channel = None
self.idx = None
def requestReceived(self, msg, type, subtype):
method = self.subTypes.get(subtype)
if method:
method(msg, 1)
else:
print ('requestReceived> No handler: Message type %s %d:%d'
% (msgTypeName(type, subtype), type, subtype)), self
def responseReceived(self, msg, type, subtype):
method = self.subTypes.get(subtype)
if method:
method(msg, 0)
else:
print ('responseReceived> No handler: Message type %s %d:%d'
% (msgTypeName(type, subtype), type, subtype)), self
def lostChannel(self):
pass
def registerChannel(self):
#print 'CtrlMsgRcvr>registerChannel>', self
self.channel = self.channelFactory.domChannel(self.dom)
self.idx = self.channel.getIndex()
if self.majorTypes:
self.channel.registerDevice(self.majorTypes, self)
def deregisterChannel(self):
#print 'CtrlMsgRcvr>deregisterChannel>', self
if self.channel:
self.channel.deregisterDevice(self)
del self.channel
def produceRequests(self):
return 0
def writeRequest(self, msg):
if self.channel:
self.channel.writeRequest(msg)
else:
print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
def writeResponse(self, msg):
if self.channel:
self.channel.writeResponse(msg)
else:
print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
class ControllerFactory(CtrlMsgRcvr):
"""Abstract class for factories creating controllers.
Maintains a table of instances.
"""
def __init__(self):
CtrlMsgRcvr.__init__(self)
self.instances = {}
self.dlist = []
self.dom = 0
# Timeout (in seconds) for deferreds.
self.timeout = 10
def addInstance(self, instance):
self.instances[instance.idx] = instance
def getInstance(self, idx):
return self.instances.get(idx)
def getInstances(self):
return self.instances.values()
def getInstanceByDom(self, dom):
for inst in self.instances.values():
if inst.dom == dom:
return inst
return None
def delInstance(self, instance):
#print 'ControllerFactory>delInstance>', instance.idx
if instance.idx in self.instances:
#print 'ControllerFactory>delInstance> remove', instance.idx
del self.instances[instance.idx]
def createInstance(self, dom, recreate=0):
raise NotImplementedError()
def instanceClosed(self, instance):
#print 'ControllerFactory>instanceClosed>', instance.idx, instance
self.delInstance(instance)
def addDeferred(self):
d = defer.Deferred()
if self.timeout > 0:
# The deferred will error if not called before timeout.
d.setTimeout(self.timeout)
self.dlist.append(d)
return d
def callDeferred(self, *args):
if self.dlist:
d = self.dlist.pop(0)
d.callback(*args)
def errDeferred(self, *args):
if self.dlist:
d = self.dlist.pop(0)
d.errback(*args)
class Controller(CtrlMsgRcvr):
"""Abstract class for a device controller attached to a domain.
"""
def __init__(self, factory, dom):
CtrlMsgRcvr.__init__(self)
self.factory = factory
self.dom = int(dom)
self.channel = None
self.idx = None
def close(self):
self.deregisterChannel()
self.lostChannel()
def lostChannel(self):
#print 'Controller>lostChannel>', self, self.factory
self.factory.instanceClosed(self)
class Dev:
def __init__(self, controller):
self.controller = controller
self.props = {}
def setprop(self, k, v):
self.props[k] = v
def getprop(self, k, v=None):
return self.props.get(k, v)
def hasprop(self, k):
return k in self.props
def delprop(self, k):
if k in self.props:
del self.props[k]
#def __repr__(self):
# return str(self.sxpr())
def sxpr(self):
raise NotImplementedError()
+269
View File
@@ -0,0 +1,269 @@
import struct
class Struct:
maxDepth = 10
base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
sizes = {'B': 1,
'H': 2,
'I': 4,
'L': 4,
'Q': 8,
'c': 1,
'h': 2,
'i': 4,
'l': 4,
'q': 8,
'x': 1,
}
formats = {
'int8' : 'B',
'int16' : 'H',
'int32' : 'I',
'int64' : 'Q',
'u8' : 'B',
'u16' : 'H',
'u32' : 'I',
'u64' : 'Q'
}
def typedef(self, name, val):
self.formats[name] = val
def struct(self, name, *f):
self.typedef(name, StructInfo(self, f))
def getType(self, name):
return self.formats[name]
def format(self, ty):
d = 0
f = ty
while d < self.maxDepth:
d += 1
f = self.formats[f]
if isinstance(f, StructInfo):
return f.format()
if f in self.base:
return f
return -1
def alignedformat(self, ty):
fmt = self.format(ty)
#print 'alignedformat> %s |%s|' %(ty, fmt)
afmt = self.align(fmt)
#print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
return afmt
def align(self, fmt):
n1 = 0
afmt = ''
for a in fmt:
n2 = self.getSize(a)
m = n1 % n2
if m:
d = (n2 - m)
afmt += 'x' * d
n1 += d
afmt += a
n1 += n2
return afmt
def fmtsize(self, fmt):
s = 0
for f in fmt:
s += self.getSize(f)
return s
def getSize(self, f):
return self.sizes[f]
def pack(self, ty, data):
return self.getType(ty).pack(data)
def unpack(self, ty, data):
return self.getType(ty).unpack(data)
def show(self):
l = self.formats.keys()
l.sort()
for v in l:
print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
class StructInfo:
def __init__(self, s, f):
self.fmt = None
self.structs = s
self.fields = f
def alignedformat(self):
if self.afmt: return self.afmt
self.afmt = self.structs.align(self.format())
return self.afmt
def format(self):
if self.fmt: return self.fmt
fmt = ""
for (ty, name) in self.fields:
fmt += self.formatString(ty)
self.fmt = fmt
return fmt
def formatString(self, ty):
if ty in self.fields:
ty = self.fields[ty]
return self.structs.format(ty)
def pack(self, *args):
return struct.pack(self.alignedformat(), *args)
def unpack(self, data):
return struct.unpack(self.alignedformat(), data)
types = Struct()
types.typedef('short' , 'h')
types.typedef('int' , 'i')
types.typedef('long' , 'l')
types.typedef('unsigned short', 'H')
types.typedef('unsigned int' , 'I')
types.typedef('unsigned long' , 'L')
types.typedef('domid_t' , 'u64')
types.typedef('blkif_vdev_t' , 'u16')
types.typedef('blkif_pdev_t' , 'u16')
types.typedef('blkif_sector_t', 'u64')
types.struct('u8[6]',
('u8', 'a1'),
('u8', 'a2'),
('u8', 'a3'),
('u8', 'a4'),
('u8', 'a5'),
('u8', 'a6'))
types.struct('blkif_fe_interface_status_changed_t',
('unsigned int', 'handle'),
('unsigned int', 'status'),
('unsigned int', 'evtchn'))
types.struct('blkif_fe_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('blkif_fe_interface_connect_t',
('unsigned int' , 'handle'),
('unsigned long', 'shmem_frame'))
types.struct('blkif_fe_interface_disconnect_t',
('unsigned int', 'handle'))
types.struct('blkif_extent_t',
('blkif_pdev_t' , 'device'),
('blkif_sector_t', 'sector_start'),
('blkif_sector_t', 'sector_length'))
types.struct('blkif_be_create_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_connect_t',
('domid_t' , 'domid'),
('unsigned int' , 'blkif_handle'),
('unsigned int' , 'evtchn'),
('unsigned long', 'shmem_frame'),
('unsigned int' , 'status'))
types.struct('blkif_be_disconnect_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('unsigned int', 'status'))
types.struct('blkif_be_vbd_create_t',
('domid_t' , 'domid'), #Q
('unsigned int', 'blkif_handle'), #I
('blkif_vdev_t', 'vdevice'), #H
('int' , 'readonly'), #i
('unsigned int', 'status')) #I
types.struct('blkif_be_vbd_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('blkif_vdev_t', 'vdevice'),
('unsigned int', 'status'))
types.struct('blkif_be_vbd_grow_t',
('domid_t' , 'domid'), #Q
('unsigned int' , 'blkif_handle'), #I
('blkif_vdev_t' , 'vdevice'), #H
('blkif_extent_t', 'extent'), #HQQ
('unsigned int' , 'status')) #I
types.struct('blkif_be_vbd_shrink_t',
('domid_t' , 'domid'),
('unsigned int', 'blkif_handle'),
('blkif_vdev_t', 'vdevice'),
('unsigned int', 'status'))
types.struct('blkif_be_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('netif_fe_interface_status_changed_t',
('unsigned int', 'handle'),
('unsigned int', 'status'),
('unsigned int', 'evtchn'),
('u8[6]', 'mac'))
types.struct('netif_fe_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
types.struct('netif_fe_interface_connect_t',
('unsigned int', 'handle'),
('unsigned long', 'tx_shmem_frame'),
('unsigned long', 'rx_shmem_frame'))
types.struct('netif_fe_interface_disconnect_t',
('unsigned int', 'handle'))
types.struct('netif_be_create_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('u8[6]' , 'mac'),
('unsigned int', 'status'))
types.struct('netif_be_destroy_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('unsigned int', 'status'))
types.struct('netif_be_connect_t',
('domid_t' , 'domid'),
('unsigned int' , 'netif_handle'),
('unsigned int' , 'evtchn'),
('unsigned long', 'tx_shmem_frame'),
('unsigned long', 'rx_shmem_frame'),
('unsigned int' , 'status'))
types.struct('netif_be_disconnect_t',
('domid_t' , 'domid'),
('unsigned int', 'netif_handle'),
('unsigned int', 'status'))
types.struct('netif_be_driver_status_changed_t',
('unsigned int', 'status'),
('unsigned int', 'nr_interfaces'))
if 1 or __name__ == "__main__":
types.show()
+41
View File
@@ -0,0 +1,41 @@
import channel
import controller
from messages import *
class DomainControllerFactory(controller.ControllerFactory):
"""Factory for creating domain controllers.
"""
def createInstance(self, dom):
d = DomainController(self, dom)
self.addInstance(d)
return d
def getInstanceByDom(self, dom):
for inst in self.instances.values():
if inst.dom == dom:
return inst
inst = self.createInstance(dom)
return inst
class DomainController(controller.Controller):
"""Generic controller for a domain.
"""
reasons = {'poweroff' : 'shutdown_poweroff_t',
'reboot' : 'shutdown_reboot_t',
'suspend' : 'shutdown_suspend_t' }
def __init__(self, factory, dom):
controller.Controller.__init__(self, factory, dom)
self.majorTypes = [ CMSG_SHUTDOWN ]
self.registerChannel()
print 'DomainController>', self, self.channel, self.idx
def shutdown(self, reason):
msgtype = self.reasons.get(reason)
if not msgtype:
raise ValueError('invalid reason:' + reason)
msg = packMsg(msgtype, {})
self.writeRequest(msg)
+219
View File
@@ -0,0 +1,219 @@
import struct
from xen.ext import xu
DEBUG = 0
""" All message formats.
Added to incrementally for the various message types.
See below.
"""
msg_formats = {}
#============================================================================
# Console message types.
#============================================================================
CMSG_CONSOLE = 0
console_formats = { 'console_data': (CMSG_CONSOLE, 0) }
msg_formats.update(console_formats)
#============================================================================
# Block interface message types.
#============================================================================
CMSG_BLKIF_BE = 1
CMSG_BLKIF_FE = 2
CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED = 0
CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED = 32
CMSG_BLKIF_FE_INTERFACE_CONNECT = 33
CMSG_BLKIF_FE_INTERFACE_DISCONNECT = 34
CMSG_BLKIF_BE_CREATE = 0
CMSG_BLKIF_BE_DESTROY = 1
CMSG_BLKIF_BE_CONNECT = 2
CMSG_BLKIF_BE_DISCONNECT = 3
CMSG_BLKIF_BE_VBD_CREATE = 4
CMSG_BLKIF_BE_VBD_DESTROY = 5
CMSG_BLKIF_BE_VBD_GROW = 6
CMSG_BLKIF_BE_VBD_SHRINK = 7
CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED = 32
BLKIF_DRIVER_STATUS_DOWN = 0
BLKIF_DRIVER_STATUS_UP = 1
BLKIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */
BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
BLKIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
BLKIF_BE_STATUS_OKAY = 0
BLKIF_BE_STATUS_ERROR = 1
BLKIF_BE_STATUS_INTERFACE_EXISTS = 2
BLKIF_BE_STATUS_INTERFACE_NOT_FOUND = 3
BLKIF_BE_STATUS_INTERFACE_CONNECTED = 4
BLKIF_BE_STATUS_VBD_EXISTS = 5
BLKIF_BE_STATUS_VBD_NOT_FOUND = 6
BLKIF_BE_STATUS_OUT_OF_MEMORY = 7
BLKIF_BE_STATUS_EXTENT_NOT_FOUND = 8
BLKIF_BE_STATUS_MAPPING_ERROR = 9
blkif_formats = {
'blkif_be_connect_t':
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT),
'blkif_be_create_t':
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE),
'blkif_be_disconnect_t':
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT),
'blkif_be_destroy_t':
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY),
'blkif_be_vbd_create_t':
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE),
'blkif_be_vbd_grow_t':
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW),
'blkif_be_vbd_destroy_t':
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY),
'blkif_fe_interface_status_changed_t':
(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED),
'blkif_fe_driver_status_changed_t':
(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED),
'blkif_fe_interface_connect_t':
(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT),
}
msg_formats.update(blkif_formats)
#============================================================================
# Network interface message types.
#============================================================================
CMSG_NETIF_BE = 3
CMSG_NETIF_FE = 4
CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED = 0
CMSG_NETIF_FE_DRIVER_STATUS_CHANGED = 32
CMSG_NETIF_FE_INTERFACE_CONNECT = 33
CMSG_NETIF_FE_INTERFACE_DISCONNECT = 34
CMSG_NETIF_BE_CREATE = 0
CMSG_NETIF_BE_DESTROY = 1
CMSG_NETIF_BE_CONNECT = 2
CMSG_NETIF_BE_DISCONNECT = 3
CMSG_NETIF_BE_DRIVER_STATUS_CHANGED = 32
NETIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */
NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
NETIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
NETIF_DRIVER_STATUS_DOWN = 0
NETIF_DRIVER_STATUS_UP = 1
netif_formats = {
'netif_be_connect_t':
(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT),
'netif_be_create_t':
(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE),
'netif_be_disconnect_t':
(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT),
'netif_be_destroy_t':
(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY),
'netif_be_driver_status_changed_t':
(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED),
'netif_fe_driver_status_changed_t':
(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED),
'netif_fe_interface_connect_t':
(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT),
'netif_fe_interface_status_changed_t':
(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED),
}
msg_formats.update(netif_formats)
#============================================================================
CMSG_SHUTDOWN = 6
CMSG_SHUTDOWN_POWEROFF = 0
CMSG_SHUTDOWN_REBOOT = 1
CMSG_SHUTDOWN_SUSPEND = 2
STOPCODE_shutdown = 0
STOPCODE_reboot = 1
STOPCODE_suspend = 2
shutdown_formats = {
'shutdown_poweroff_t':
(CMSG_SHUTDOWN, CMSG_SHUTDOWN_POWEROFF),
'shutdown_reboot_t':
(CMSG_SHUTDOWN, CMSG_SHUTDOWN_REBOOT),
'shutdown_suspend_t':
(CMSG_SHUTDOWN, CMSG_SHUTDOWN_SUSPEND),
}
msg_formats.update(shutdown_formats)
#============================================================================
class Msg:
pass
def packMsg(ty, params):
if DEBUG: print '>packMsg', ty, params
(major, minor) = msg_formats[ty]
args = {}
for (k, v) in params.items():
if k == 'mac':
for i in range(0, 6):
args['mac[%d]' % i] = v[i]
else:
args[k] = v
if DEBUG:
for (k, v) in args.items():
print 'packMsg>', k, v, type(v)
msgid = 0
msg = xu.message(major, minor, msgid, args)
return msg
def unpackMsg(ty, msg):
args = msg.get_payload()
mac = [0, 0, 0, 0, 0, 0]
macs = []
for (k, v) in args.items():
if k.startswith('mac['):
macs += k
i = int(k[4:5])
mac[i] = v
else:
pass
if macs:
args['mac'] = mac
for k in macs:
del args[k]
if DEBUG: print '<unpackMsg', ty, args
return args
def msgTypeName(ty, subty):
for (name, info) in msg_formats.items():
if info[0] == ty and info[1] == subty:
return name
return None
+316
View File
@@ -0,0 +1,316 @@
import random
from twisted.internet import defer
from xen.xend import sxp
from xen.xend import PrettyPrint
from xen.xend import Vifctl
import channel
import controller
from messages import *
class NetifControllerFactory(controller.ControllerFactory):
"""Factory for creating network interface controllers.
Also handles the 'back-end' channel to the device driver domain.
"""
def __init__(self):
controller.ControllerFactory.__init__(self)
self.majorTypes = [ CMSG_NETIF_BE ]
self.subTypes = {
CMSG_NETIF_BE_CREATE : self.recv_be_create,
CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
}
self.attached = 1
self.registerChannel()
def createInstance(self, dom, recreate=0):
"""Create or find the network interface controller for a domain.
"""
#print 'netif>createInstance> dom=', dom
netif = self.getInstanceByDom(dom)
if netif is None:
netif = NetifController(self, dom)
self.addInstance(netif)
return netif
def getDomainDevices(self, dom):
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevices()) or []
def getDomainDevice(self, dom, vif):
netif = self.getInstanceByDom(dom)
return (netif and netif.getDevice(vif)) or None
def setControlDomain(self, dom, recreate=0):
"""Set the 'back-end' device driver domain.
"""
if self.dom == dom: return
self.deregisterChannel()
if not recreate:
self.attached = 0
self.dom = dom
self.registerChannel()
#
#if xend.netif.be_port.remote_dom != 0:
# xend.netif.recovery = True
# xend.netif.be_port = xend.main.port_from_dom(dom)
#
def getControlDomain(self):
return self.dom
def recv_be_create(self, msg, req):
self.callDeferred(0)
def recv_be_connect(self, msg, req):
val = unpackMsg('netif_be_connect_t', msg)
dom = val['domid']
vif = val['netif_handle']
netif = self.getInstanceByDom(dom)
if netif:
netif.send_interface_connected(vif)
else:
print "recv_be_connect> unknown vif=", vif
pass
def recv_be_driver_status_changed(self, msg, req):
val = unpackMsg('netif_be_driver_status_changed_t', msg)
status = val['status']
if status == NETIF_DRIVER_STATUS_UP and not self.attached:
# If we are not attached the driver domain was changed, and
# this signals the new driver domain is ready.
for netif in self.getInstances():
netif.reattach_devices()
self.attached = 1
## pl = msg.get_payload()
## status = pl['status']
## if status == NETIF_DRIVER_STATUS_UP:
## if xend.netif.recovery:
## print "New netif backend now UP, notifying guests:"
## for netif_key in interface.list.keys():
## netif = interface.list[netif_key]
## netif.create()
## print " Notifying %d" % netif.dom
## msg = xu.message(
## CMSG_NETIF_FE,
## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
## { 'handle' : 0, 'status' : 1 })
## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
## print "Done notifying guests"
## recovery = False
class NetDev(controller.Dev):
"""Info record for a network device.
"""
def __init__(self, ctrl, vif, mac):
controller.Dev.__init__(self, ctrl)
self.vif = vif
self.mac = mac
self.evtchn = None
self.bridge = None
self.ipaddr = []
def sxpr(self):
vif = str(self.vif)
mac = self.get_mac()
val = ['netdev', ['vif', vif], ['mac', mac]]
if self.bridge:
val.append(['bridge', self.bridge])
if self.evtchn:
val.append(['evtchn',
self.evtchn['port1'],
self.evtchn['port2']])
return val
def get_vifname(self):
return "vif%d.%d" % (self.controller.dom, self.vif)
def get_mac(self):
return ':'.join(map(lambda x: "%x" % x, self.mac))
def vifctl_params(self):
return { 'mac' : self.get_mac(),
'bridge': self.bridge,
'ipaddr': self.ipaddr }
def up(self, bridge=None, ipaddr=[]):
self.bridge = bridge
self.ipaddr = ipaddr
Vifctl.up(self.get_vifname(), **self.vifctl_params())
def down(self):
Vifctl.down(self.get_vifname(), **self.vifctl_params())
def destroy(self):
def cb_destroy(val):
self.controller.send_be_destroy(self.vif)
print 'NetDev>destroy>', 'vif=', self.vif
PrettyPrint.prettyprint(self.sxpr())
self.down()
d = self.controller.factory.addDeferred()
d.addCallback(cb_destroy)
self.controller.send_be_disconnect(self.vif)
#self.controller.send_be_destroy(self.vif)
class NetifController(controller.Controller):
"""Network interface controller. Handles all network devices for a domain.
"""
def __init__(self, factory, dom):
#print 'NetifController> dom=', dom
controller.Controller.__init__(self, factory, dom)
self.devices = {}
self.majorTypes = [ CMSG_NETIF_FE ]
self.subTypes = {
CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
self.recv_fe_driver_status_changed,
CMSG_NETIF_FE_INTERFACE_CONNECT :
self.recv_fe_interface_connect,
}
self.registerChannel()
#print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
def sxpr(self):
val = ['netif', ['dom', self.dom]]
return val
def randomMAC(self):
# VIFs get a random MAC address with a "special" vendor id.
#
# NB. The vendor is currently an "obsolete" one that used to belong
# to DEC (AA-00-00). Using it is probably a bit rude :-)
#
# NB2. The first bit of the first random octet is set to zero for
# all dynamic MAC addresses. This may allow us to manually specify
# MAC addresses for some VIFs with no fear of clashes.
mac = [ 0xaa, 0x00, 0x00,
random.randint(0x00, 0x7f),
random.randint(0x00, 0xff),
random.randint(0x00, 0xff) ]
return mac
def lostChannel(self):
print 'NetifController>lostChannel>', 'dom=', self.dom
#self.destroyDevices()
controller.Controller.lostChannel(self)
def getDevices(self):
return self.devices.values()
def getDevice(self, vif):
return self.devices.get(vif)
def addDevice(self, vif, vmac):
if vmac is None:
mac = self.randomMAC()
else:
mac = [ int(x, 16) for x in vmac.split(':') ]
if len(mac) != 6: raise ValueError("invalid mac")
#print "attach_device>", "vif=", vif, "mac=", mac
dev = NetDev(self, vif, mac)
self.devices[vif] = dev
return dev
def destroy(self):
print 'NetifController>destroy>', 'dom=', self.dom
self.destroyDevices()
def destroyDevices(self):
for dev in self.getDevices():
dev.destroy()
def attachDevice(self, vif, vmac, recreate=0):
"""Attach a network device.
If vmac is None a random mac address is assigned.
@param vif interface index
@param vmac mac address (string)
"""
self.addDevice(vif, vmac)
if recreate:
d = defer.Deferred()
d.callback(self)
else:
d = self.factory.addDeferred()
self.send_be_create(vif)
return d
def reattach_devices(self):
"""Reattach all devices when the back-end control domain has changed.
"""
d = self.factory.addDeferred()
self.send_be_create(vif)
self.attach_fe_devices(0)
def attach_fe_devices(self):
for dev in self.devices.values():
msg = packMsg('netif_fe_interface_status_changed_t',
{ 'handle' : dev.vif,
'status' : NETIF_INTERFACE_STATUS_DISCONNECTED,
'evtchn' : 0,
'mac' : dev.mac })
self.writeRequest(msg)
def recv_fe_driver_status_changed(self, msg, req):
if not req: return
msg = packMsg('netif_fe_driver_status_changed_t',
{ 'status' : NETIF_DRIVER_STATUS_UP,
'nr_interfaces' : len(self.devices) })
self.writeRequest(msg)
self.attach_fe_devices()
def recv_fe_interface_connect(self, msg, req):
val = unpackMsg('netif_fe_interface_connect_t', msg)
dev = self.devices[val['handle']]
dev.evtchn = channel.eventChannel(0, self.dom)
msg = packMsg('netif_be_connect_t',
{ 'domid' : self.dom,
'netif_handle' : dev.vif,
'evtchn' : dev.evtchn['port1'],
'tx_shmem_frame' : val['tx_shmem_frame'],
'rx_shmem_frame' : val['rx_shmem_frame'] })
self.factory.writeRequest(msg)
def send_interface_connected(self, vif):
dev = self.devices[vif]
msg = packMsg('netif_fe_interface_status_changed_t',
{ 'handle' : dev.vif,
'status' : NETIF_INTERFACE_STATUS_CONNECTED,
'evtchn' : dev.evtchn['port2'],
'mac' : dev.mac })
self.writeRequest(msg)
def send_be_create(self, vif):
dev = self.devices[vif]
msg = packMsg('netif_be_create_t',
{ 'domid' : self.dom,
'netif_handle' : dev.vif,
'mac' : dev.mac })
self.factory.writeRequest(msg)
def send_be_disconnect(self, vif):
dev = self.devices[vif]
msg = packMsg('netif_be_disconnect_t',
{ 'domid' : self.dom,
'netif_handle' : dev.vif })
self.factory.writeRequest(msg)
def send_be_destroy(self, vif):
print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
PrettyPrint.prettyprint(self.sxpr())
dev = self.devices[vif]
del self.devices[vif]
msg = packMsg('netif_be_destroy_t',
{ 'domid' : self.dom,
'netif_handle' : vif })
self.factory.writeRequest(msg)
+10
View File
@@ -0,0 +1,10 @@
# The following parameters could be placed in a configuration file.
PID_FILE = '/var/run/xend.pid'
LOG_FILE = '/var/log/xend.log'
USER = 'root'
CONTROL_DIR = '/var/run/xend'
MGMT_SOCK = 'xendsock' # relative to CONTROL_DIR
EVENT_PORT = 8001
CONSOLE_PORT_BASE = 9600
+580
View File
@@ -0,0 +1,580 @@
#!/usr/bin/python2
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""
Input-driven parsing for s-expression (sxp) format.
Create a parser: pin = Parser();
Then call pin.input(buf) with your input.
Call pin.input_eof() when done.
Use pin.read() to see if a value has been parsed, pin.get_val()
to get a parsed value. You can call ready and get_val at any time -
you don't have to wait until after calling input_eof.
"""
from __future__ import generators
import sys
import types
import errno
import string
from StringIO import StringIO
__all__ = [
"mime_type",
"ParseError",
"Parser",
"atomp",
"show",
"show_xml",
"elementp",
"name",
"attributes",
"attribute",
"children",
"child",
"child_at",
"child0",
"child1",
"child2",
"child3",
"child4",
"child_value",
"has_id",
"with_id",
"child_with_id",
"elements",
"parse",
]
mime_type = "application/sxp"
escapes = {
'a': '\a',
'b': '\b',
't': '\t',
'n': '\n',
'v': '\v',
'f': '\f',
'r': '\r',
'\\': '\\',
'\'': '\'',
'\"': '\"'}
k_list_open = "("
k_list_close = ")"
k_attr_open = "@"
k_eval = "!"
escapes_rev = {}
for k in escapes:
escapes_rev[escapes[k]] = k
class ParseError(StandardError):
def __init__(self, parser, value):
self.parser = parser
self.value = value
def __str__(self):
return self.value
class ParserState:
def __init__(self, fn, parent=None):
self.parent = parent
self.buf = ''
self.val = []
self.delim = None
self.fn = fn
def push(self, fn):
return ParserState(fn, parent=self)
class Parser:
def __init__(self):
self.error = sys.stderr
self.reset()
def reset(self):
self.val = []
self.eof = 0
self.err = 0
self.line_no = 0
self.char_no = 0
self.state = None
def push_state(self, fn):
self.state = self.state.push(fn)
def pop_state(self):
val = self.state
self.state = self.state.parent
if self.state and self.state.fn == self.state_start:
# Return to start state - produce the value.
self.val += self.state.val
self.state.val = []
return val
def in_class(self, c, s):
return s.find(c) >= 0
def in_space_class(self, c):
return self.in_class(c, ' \t\n\v\f\r')
def is_separator(self, c):
return self.in_class(c, '{}()<>[]!;')
def in_comment_class(self, c):
return self.in_class(c, '#')
def in_string_quote_class(self, c):
return self.in_class(c, '"\'')
def in_printable_class(self, c):
return self.in_class(c, string.printable)
def set_error_stream(self, error):
self.error = error
def has_error(self):
return self.err > 0
def at_eof(self):
return self.eof
def input_eof(self):
self.eof = 1
self.input_char(-1)
def input(self, buf):
if not buf or len(buf) == 0:
self.input_eof()
else:
for c in buf:
self.input_char(c)
def input_char(self, c):
if self.at_eof():
pass
elif c == '\n':
self.line_no += 1
self.char_no = 0
else:
self.char_no += 1
if self.state is None:
self.begin_start(None)
self.state.fn(c)
def ready(self):
return len(self.val) > 0
def get_val(self):
v = self.val[0]
self.val = self.val[1:]
return v
def get_all(self):
return self.val
def begin_start(self, c):
self.state = ParserState(self.state_start)
def end_start(self):
self.val += self.state.val
self.pop_state()
def state_start(self, c):
if self.at_eof():
self.end_start()
elif self.in_space_class(c):
pass
elif self.in_comment_class(c):
self.begin_comment(c)
elif c == k_list_open:
self.begin_list(c)
elif c == k_list_close:
raise ParseError(self, "syntax error: "+c)
elif self.in_string_quote_class(c):
self.begin_string(c)
elif self.in_printable_class(c):
self.begin_atom(c)
elif c == chr(4):
# ctrl-D, EOT: end-of-text.
self.input_eof()
else:
raise ParseError(self, "invalid character: code %d" % ord(c))
def begin_comment(self, c):
self.push_state(self.state_comment)
self.state.buf += c
def end_comment(self):
self.pop_state()
def state_comment(self, c):
if c == '\n' or self.at_eof():
self.end_comment()
else:
self.state.buf += c
def begin_string(self, c):
self.push_state(self.state_string)
self.state.delim = c
def end_string(self):
val = self.state.buf
self.state.parent.val.append(val)
self.pop_state()
def state_string(self, c):
if self.at_eof():
raise ParseError(self, "unexpected EOF")
elif c == self.state.delim:
self.end_string()
elif c == '\\':
self.push_state(self.state_escape)
else:
self.state.buf += c
def state_escape(self, c):
if self.at_eof():
raise ParseError(self, "unexpected EOF")
d = escapes.get(c)
if d:
self.state.parent.buf += d
self.pop_state()
elif c == 'x':
self.state.fn = self.state_hex
self.state.val = 0
else:
self.state.fn = self.state_octal
self.state.val = 0
self.input_char(c)
def state_octal(self, c):
def octaldigit(c):
self.state.val *= 8
self.state.val += ord(c) - ord('0')
self.state.buf += c
if self.state.val < 0 or self.state.val > 0xff:
raise ParseError(self, "invalid octal escape: out of range " + self.state.buf)
if len(self.state.buf) == 3:
octaldone()
def octaldone():
d = chr(self.state.val)
self.state.parent.buf += d
self.pop_state()
if self.at_eof():
raise ParseError(self, "unexpected EOF")
elif '0' <= c <= '7':
octaldigit(c)
elif len(self.buf):
octaldone()
self.input_char(c)
def state_hex(self, c):
def hexdone():
d = chr(self.state.val)
self.state.parent.buf += d
self.pop_state()
def hexdigit(c, d):
self.state.val *= 16
self.state.val += ord(c) - ord(d)
self.state.buf += c
if self.state.val < 0 or self.state.val > 0xff:
raise ParseError(self, "invalid hex escape: out of range " + self.state.buf)
if len(self.state.buf) == 2:
hexdone()
if self.at_eof():
raise ParseError(self, "unexpected EOF")
elif '0' <= c <= '9':
hexdigit(c, '0')
elif 'A' <= c <= 'F':
hexdigit(c, 'A')
elif 'a' <= c <= 'f':
hexdigit(c, 'a')
elif len(buf):
hexdone()
self.input_char(c)
def begin_atom(self, c):
self.push_state(self.state_atom)
self.state.buf = c
def end_atom(self):
val = self.state.buf
self.state.parent.val.append(val)
self.pop_state()
def state_atom(self, c):
if self.at_eof():
self.end_atom()
elif (self.is_separator(c) or
self.in_space_class(c) or
self.in_comment_class(c)):
self.end_atom()
self.input_char(c)
else:
self.state.buf += c
def begin_list(self, c):
self.push_state(self.state_list)
def end_list(self):
val = self.state.val
self.state.parent.val.append(val)
self.pop_state()
def state_list(self, c):
if self.at_eof():
raise ParseError(self, "unexpected EOF")
elif c == k_list_close:
self.end_list()
else:
self.state_start(c)
def atomp(sxpr):
if sxpr.isalnum() or sxpr == '@':
return 1
for c in sxpr:
if c in string.whitespace: return 0
if c in '"\'\\(){}[]<>$#&%^': return 0
if c in string.ascii_letters: continue
if c in string.digits: continue
if c in '.-_:/~': continue
return 0
return 1
def show(sxpr, out=sys.stdout):
if isinstance(sxpr, types.ListType):
out.write(k_list_open)
i = 0
for x in sxpr:
if i: out.write(' ')
show(x, out)
i += 1
out.write(k_list_close)
elif isinstance(sxpr, types.StringType) and atomp(sxpr):
out.write(sxpr)
else:
#out.write("'" + str(sxpr) + "'")
out.write(repr(str(sxpr)))
def show_xml(sxpr, out=sys.stdout):
if isinstance(sxpr, types.ListType):
element = name(sxpr)
out.write('<%s' % element)
for attr in attributes(sxpr):
out.write(' %s=%s' % (attr[0], attr[1]))
out.write('>')
i = 0
for x in children(sxpr):
if i: out.write(' ')
show_xml(x, out)
i += 1
out.write('</%s>' % element)
elif isinstance(sxpr, types.StringType) and atomp(sxpr):
out.write(sxpr)
else:
out.write(str(sxpr))
def elementp(sxpr, elt=None):
return (isinstance(sxpr, types.ListType)
and len(sxpr)
and (None == elt or sxpr[0] == elt))
def name(sxpr):
val = None
if isinstance(sxpr, types.StringType):
val = sxpr
elif isinstance(sxpr, types.ListType) and len(sxpr):
val = sxpr[0]
return val
def attributes(sxpr):
val = []
if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
attr = sxpr[1]
if elementp(attr, k_attr_open):
val = attr[1:]
return val
def attribute(sxpr, key, val=None):
for x in attributes(sxpr):
if x[0] == key:
val = x[1]
break
return val
def children(sxpr, elt=None):
val = []
if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
i = 1
x = sxpr[i]
if elementp(x, k_attr_open):
i += 1
val = sxpr[i : ]
if elt:
def iselt(x):
return elementp(x, elt)
val = filter(iselt, val)
return val
def child(sxpr, elt, val=None):
for x in children(sxpr):
if elementp(x, elt):
val = x
break
return val
def child_at(sxpr, index, val=None):
kids = children(sxpr)
if len(kids) > index:
val = kids[index]
return val
def child0(sxpr, val=None):
return child_at(sxpr, 0, val)
def child1(sxpr, val=None):
return child_at(sxpr, 1, val)
def child2(sxpr, val=None):
return child_at(sxpr, 2, val)
def child3(sxpr, val=None):
return child_at(sxpr, 3, val)
def child4(sxpr, val=None):
return child_at(sxpr, 4, val)
def child_value(sxpr, elt, val=None):
kid = child(sxpr, elt)
if kid:
val = child_at(kid, 0, val)
return val
def has_id(sxpr, id):
"""Test if an s-expression has a given id.
"""
return attribute(sxpr, 'id') == id
def with_id(sxpr, id, val=None):
"""Find the first s-expression with a given id, at any depth.
sxpr s-exp or list
id id
val value if not found (default None)
return s-exp or val
"""
if isinstance(sxpr, types.ListType):
for n in sxpr:
if has_id(n, id):
val = n
break
v = with_id(n, id)
if v is None: continue
val = v
break
return val
def child_with_id(sxpr, id, val=None):
"""Find the first child with a given id.
sxpr s-exp or list
id id
val value if not found (default None)
return s-exp or val
"""
if isinstance(sxpr, types.ListType):
for n in sxpr:
if has_id(n, id):
val = n
break
return val
def elements(sxpr, ctxt=None):
"""Generate elements (at any depth).
Visit elements in pre-order.
Values generated are (node, context)
The context is None if there is no parent, otherwise
(index, parent, context) where index is the node's index w.r.t its parent,
and context is the parent's context.
sxpr s-exp
returns generator
"""
yield (sxpr, ctxt)
i = 0
for n in children(sxpr):
if isinstance(n, types.ListType):
# Calling elements() recursively does not generate recursively,
# it just returns a generator object. So we must iterate over it.
for v in elements(n, (i, sxpr, ctxt)):
yield v
i += 1
def to_string(sxpr):
"""Convert an sxpr to a string.
sxpr sxpr
returns string
"""
io = StringIO()
show(sxpr, io)
io.seek(0)
val = io.getvalue()
io.close()
return val
def from_string(str):
"""Create an sxpr by parsing a string.
str string
returns sxpr
"""
io = StringIO(str)
return parse(io)
def parse(io):
"""Completely parse all input from 'io'.
io input file object
returns list of values, None if incomplete
raises ParseError on parse error
"""
pin = Parser()
while 1:
buf = io.readline()
pin.input(buf)
if len(buf) == 0:
break
if pin.ready():
val = pin.get_all()
else:
val = None
return val
if __name__ == '__main__':
print ">main"
pin = Parser()
while 1:
buf = sys.stdin.read(1024)
#buf = sys.stdin.readline()
pin.input(buf)
while pin.ready():
val = pin.get_val()
print
print '****** val=', val
if len(buf) == 0:
break
View File
Whitespace-only changes.
+366
View File
@@ -0,0 +1,366 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Domain creation.
"""
import string
import sys
from xen.xend import sxp
from xen.xend import PrettyPrint
from xen.xend.XendClient import server
from xen.xm.opts import *
gopts = Opts(use="""[options]
Create a domain.
""")
gopts.opt('help', short='h',
fn=set_true, default=0,
use="Print this help.")
gopts.opt('quiet', short='q',
fn=set_true, default=0,
use="Quiet.")
gopts.opt('path', val='PATH',
fn=set_value, default='.:/etc/xen',
use="Search path for default scripts.")
gopts.opt('defaults', short='f', val='FILE',
fn=set_value, default='xmdefaults',
use="Use the given default script.")
gopts.opt('config', short='F', val='FILE',
fn=set_value, default=None,
use='Domain configuration to use (SXP).')
gopts.opt('load', short='L', val='FILE',
fn=set_value, default=None,
use='Domain saved state to load.')
gopts.opt('define', short='D', val='VAR=VAL',
fn=set_var, default=None,
use="""Set a variable before loading defaults, e.g. '-D vmid=3'
to set vmid. May be repeated to set more thanone variable.""")
gopts.opt('dryrun', short='n',
fn=set_true, default=0,
use="Dry run - print the config but don't create the domain.")
gopts.opt('name', short='N', val='NAME',
fn=set_value, default=None,
use="Domain name.")
gopts.opt('console', short='c',
fn=set_true, default=0,
use="Connect to console after domain is created.")
gopts.opt('kernel', short='k', val='FILE',
fn=set_value, default=None,
use="Path to kernel image.")
gopts.opt('ramdisk', short='r', val='FILE',
fn=set_value, default='',
use="Path to ramdisk.")
gopts.opt('builder', short='b', val='FUNCTION',
fn=set_value, default='linux',
use="Function to use to build the domain.")
gopts.opt('memory', short='m', val='MEMORY',
fn=set_value, default=128,
use="Domain memory in MB.")
gopts.opt('blkif',
fn=set_true, default=0,
use="Make the domain a block device backend.")
gopts.opt('netif',
fn=set_true, default=0,
use="Make the domain a network interface backend.")
gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
fn=append_value, default=[],
use="""Add a disk device to a domain. The physical device is DEV, which
is exported to the domain as VDEV. The disk is read-only if MODE
is 'r', read-write if MODE is 'w'.
The option may be repeated to add more than one disk.
""")
gopts.opt('pci', val='BUS,DEV,FUNC',
fn=append_value, default=[],
use="""Add a PCI device to a domain, using given params (in hex).
For example '-pci c0,02,1a'.
The option may be repeated to add more than one pci device.
""")
gopts.opt('ipaddr', short='i', val="IPADDR",
fn=append_value, default=[],
use="Add an IP address to the domain.")
gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
fn=append_value, default=[],
use="""Add a network interface with the given MAC address and bridge.
If mac is not specified a random MAC address is used.
If bridge is not specified the default bridge is used.
This option may be repeated to add more than one vif.
Specifying vifs will increase the number of interfaces as needed.
""")
gopts.opt('nics', val="NUM",
fn=set_int, default=1,
use="""Set the number of network interfaces.
Use the vif option to define interface parameters, otherwise
defaults are used. Specifying vifs will increase the
number of interfaces as needed.
""")
gopts.opt('root', short='R', val='DEVICE',
fn=set_value, default='',
use="""Set the root= parameter on the kernel command line.
Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
gopts.opt('extra', short='E', val="ARGS",
fn=set_value, default='',
use="Set extra arguments to append to the kernel command line.")
gopts.opt('ip', short='I', val='IPADDR',
fn=set_value, default='',
use="Set the kernel IP interface address.")
gopts.opt('gateway', val="IPADDR",
fn=set_value, default='',
use="Set the kernel IP gateway.")
gopts.opt('netmask', val="MASK",
fn=set_value, default = '',
use="Set the kernel IP netmask.")
gopts.opt('hostname', val="NAME",
fn=set_value, default='',
use="Set the kernel IP hostname.")
gopts.opt('interface', val="INTF",
fn=set_value, default="eth0",
use="Set the kernel IP interface name.")
gopts.opt('dhcp', val="off|dhcp",
fn=set_value, default='off',
use="Set the kernel dhcp option.")
gopts.opt('nfs_server', val="IPADDR",
fn=set_value, default=None,
use="Set the address of the NFS server for NFS root.")
gopts.opt('nfs_root', val="PATH",
fn=set_value, default=None,
use="Set the path of the root NFS directory.")
def strip(pre, s):
"""Strip prefix 'pre' if present.
"""
if s.startswith(pre):
return s[len(pre):]
else:
return s
def configure_image(config, opts):
"""Create the image config.
"""
config_image = [ opts.builder ]
config_image.append([ 'kernel', os.path.abspath(opts.kernel) ])
if opts.ramdisk:
config_image.append([ 'ramdisk', os.path.abspath(opts.ramdisk) ])
if opts.cmdline_ip:
cmdline_ip = strip('ip=', opts.cmdline_ip)
config_image.append(['ip', cmdline_ip])
if opts.root:
cmdline_root = strip('root=', opts.root)
config_image.append(['root', cmdline_root])
if opts.extra:
config_image.append(['args', opts.extra])
config.append(['image', config_image ])
def configure_disks(config_devs, opts):
"""Create the config for disks (virtual block devices).
"""
for (uname, dev, mode) in opts.disk:
config_vbd = ['vbd',
['uname', uname],
['dev', dev ],
['mode', mode ] ]
config_devs.append(['device', config_vbd])
def configure_pci(config_devs, opts):
"""Create the config for pci devices.
"""
for (bus, dev, func) in opts.pci:
config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
config_devs.append(['device', config_pci])
def configure_vifs(config_devs, opts):
"""Create the config for virtual network interfaces.
"""
vifs = opts.vif
vifs_n = max(opts.nics, len(vifs))
for idx in range(0, vifs_n):
if idx < len(vifs):
d = vifs[idx]
mac = d.get('mac')
bridge = d.get('bridge')
else:
mac = None
bridge = None
config_vif = ['vif']
if mac:
config_vif.append(['mac', mac])
if bridge:
config_vif.append(['bridge', bridge])
config_devs.append(['device', config_vif])
def configure_vfr(config, opts):
if not opts.ipaddr: return
config_vfr = ['vfr']
idx = 0 # No way of saying which IP is for which vif?
for ip in opts.ipaddr:
config_vfr.append(['vif', ['id', idx], ['ip', ip]])
config.append(config_vfr)
def make_config(opts):
"""Create the domain configuration.
"""
config = ['vm',
['name', opts.name ],
['memory', opts.memory ] ]
if opts.cpu:
config.append(['cpu', opts.cpu])
if opts.blkif:
config.append(['backend', ['blkif']])
if opts.netif:
config.append(['backend', ['netif']])
configure_image(config, opts)
config_devs = []
configure_disks(config_devs, opts)
configure_pci(config_devs, opts)
configure_vifs(config_devs, opts)
config += config_devs
return config
def preprocess_disk(opts):
if not opts.disk: return
disk = []
for v in opts.disk:
d = v.split(',')
if len(d) != 3:
opts.err('Invalid disk specifier: ' + v)
disk.append(d)
opts.disk = disk
def preprocess_pci(opts):
if not opts.pci: return
pci = []
for v in opts.pci:
d = v.split(',')
if len(d) != 3:
opts.err('Invalid pci specifier: ' + v)
# Components are in hex: add hex specifier.
hexd = map(lambda v: '0x'+v, d)
pci.append(hexd)
opts.pci = pci
def preprocess_vifs(opts):
if not opts.vif: return
vifs = []
for vif in opts.vif:
d = {}
a = vif.split(',')
for b in a:
(k, v) = b.strip().split('=')
k = k.strip()
v = v.strip()
if k not in ['mac', 'bridge']:
opts.err('Invalid vif specifier: ' + vif)
d[k] = v
vifs.append(d)
opts.vif = vifs
def preprocess_ip(opts):
setip = (opts.hostname or opts.netmask
or opts.gateway or opts.dhcp or opts.interface)
if not setip: return
#if not opts
ip = (opts.ip
+ ':'
+ ':' + opts.gateway
+ ':' + opts.netmask
+ ':' + opts.hostname
+ ':' + opts.interface
+ ':' + opts.dhcp)
opts.cmdline_ip = ip
def preprocess_nfs(opts):
if (opts.nfs_root or opts.nfs_server):
if (not opts.nfs_root) or (not opts.nfs_server):
opts.err('Must set nfs root and nfs server')
else:
return
nfs = 'nfsroot=' + opts.nfs_server + ':' + opts.nfs_root
opts.extra = nfs + ' ' + opts.extra
def preprocess(opts):
if not opts.kernel:
opts.err("No kernel specified")
preprocess_disk(opts)
preprocess_pci(opts)
preprocess_vifs(opts)
preprocess_ip(opts)
preprocess_nfs(opts)
def make_domain(opts, config):
"""Create, build and start a domain.
Returns: [int] the ID of the new domain.
"""
if opts.vals.load:
filename = os.path.abspath(opts.vals.load)
dominfo = server.xend_domain_restore(filename, config)
else:
dominfo = server.xend_domain_create(config)
dom = int(sxp.child_value(dominfo, 'id'))
console_info = sxp.child(dominfo, 'console')
if console_info:
console_port = int(sxp.child_value(console_info, 'port'))
else:
console_port = None
if server.xend_domain_unpause(dom) < 0:
server.xend_domain_destroy(dom)
opts.err("Failed to start domain %d" % dom)
opts.info("Started domain %d, console on port %d"
% (dom, console_port))
return (dom, console_port)
def main(argv):
opts = gopts
args = opts.parse(argv)
if opts.vals.help:
opts.usage()
return
if opts.vals.config:
pass
else:
opts.load_defaults()
preprocess(opts.vals)
config = make_config(opts.vals)
if opts.vals.dryrun:
PrettyPrint.prettyprint(config)
else:
make_domain(opts, config)
if __name__ == '__main__':
main(sys.argv)
+448
View File
@@ -0,0 +1,448 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Grand unified management application for Xen.
"""
import os
import os.path
import sys
from getopt import getopt
from xen.xend import PrettyPrint
from xen.xend import sxp
from xen.xend.XendClient import server
from xen.xm import create, shutdown
class Prog:
"""Base class for sub-programs.
"""
"""Program group it belongs to"""
group = 'all'
"""Program name."""
name = '??'
"""Short program info."""
info = ''
def __init__(self, xm):
self.xm = xm
def err(self, msg):
self.xm.err(msg)
def help(self, args):
self.shortHelp(args)
def shortHelp(self, args):
print "%-14s %s" % (self.name, self.info)
def main(self, args):
"""Program main entry point.
"""
pass
class ProgUnknown(Prog):
name = 'unknown'
info = ''
def help(self, args):
self.xm.err("Unknown command: %s\nTry '%s help' for more information."
% (args[0], self.xm.name))
main = help
class Xm:
"""Main application.
"""
def __init__(self):
self.name = 'xm'
self.unknown = ProgUnknown(self)
self.progs = {}
def err(self, msg):
print >>sys.stderr, "Error:", msg
sys.exit(1)
def main(self, args):
"""Main entry point. Dispatches to the progs.
"""
self.name = args[0]
if len(args) < 2:
self.err("Missing command\nTry '%s help' for more information."
% self.name)
help = self.helparg(args)
p = self.getprog(args[1], self.unknown)
if help:
p.help(args[1:])
else:
p.main(args[1:])
def helparg(self, args):
for a in args:
if a in ['-h', '--help']:
return 1
return 0
def prog(self, pklass):
"""Add a sub-program.
pklass program class (Prog subclass)
"""
p = pklass(self)
self.progs[p.name] = p
return p
def getprog(self, name, val=None):
"""Get a sub-program.
"""
return self.progs.get(name, val)
def proglist(self):
"""Get a list of sub-programs, ordered by group.
"""
groups = {}
for p in self.progs.values():
l = groups.get(p.group, [])
l.append(p)
groups[p.group] = l
kl = groups.keys()
kl.sort()
pl = []
for k in kl:
l = groups[k]
l.sort()
pl += l
return pl
# Create the application object, then add the sub-program classes.
xm = Xm()
class ProgHelp(Prog):
name = "help"
info = "Print help."
def help(self, args):
if len(args) == 2:
name = args[1]
p = self.xm.getprog(name)
if p:
p.help(args[1:])
else:
print '%s: Unknown command: %s' % (self.name, name)
else:
for p in self.xm.proglist():
p.shortHelp(args)
print "\nTry '%s help CMD' for help on CMD" % self.xm.name
main = help
xm.prog(ProgHelp)
class ProgCreate(Prog):
group = 'domain'
name = "create"
info = """Create a domain."""
def help(self, args):
create.main([args[0], '-h'])
def main(self, args):
create.main(args)
xm.prog(ProgCreate)
class ProgSave(Prog):
group = 'domain'
name = "save"
info = """Save domain state (and config) to file."""
def help(self, args):
print args[0], "DOM FILE"
print """\nSave domain with id DOM to FILE."""
def main(self, args):
if len(args) < 3: self.err("%s: Missing arguments" % args[0])
dom = args[1]
savefile = os.path.abspath(args[2])
server.xend_domain_save(dom, savefile)
xm.prog(ProgSave)
class ProgRestore(Prog):
group = 'domain'
name = "restore"
info = """Create a domain from a saved state."""
def help(self, args):
print args[0], "FILE [CONFIG]"
print "\nRestore a domain from FILE using configuration CONFIG."
def main(self, help, args):
if len(args) < 2: self.err("%s: Missing arguments" % args[0])
savefile = os.path.abspath(args[1])
if len(args) >= 3:
configfile = os.path.abspath(args[2])
else:
configfile = None
info = server.xend_domain_restore(savefile, configfile)
PrettyPrint.prettyprint(info)
xm.prog(ProgRestore)
class ProgList(Prog):
group = 'domain'
name = "list"
info = """List info about domains."""
short_options = 'l'
long_options = ['long']
def help(self, args):
if help:
print args[0], '[options] [DOM...]'
print """\nGet information about domains.
Either all domains or the domains given.
-l, --long Get more detailed information.
"""
return
def main(self, args):
use_long = 0
(options, params) = getopt(args[1:],
self.short_options,
self.long_options)
n = len(params)
for (k, v) in options:
if k in ['-l', '--long']:
use_long = 1
if n == 0:
doms = map(int, server.xend_domains())
doms.sort()
else:
doms = map(int, params)
if use_long:
self.long_list(doms)
else:
self.brief_list(doms)
def brief_list(self, doms):
print 'Dom Name Mem(MB) CPU State Time(s)'
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)7.1f" % d)
def long_list(self, doms):
for dom in doms:
info = server.xend_domain(dom)
print '\nDomain %d' % dom
PrettyPrint.prettyprint(info)
xm.prog(ProgList)
class ProgDestroy(Prog):
group = 'domain'
name = "destroy"
info = """Terminate a domain immediately."""
def help(self, args):
print args[0], 'DOM'
print '\nTerminate domain DOM immediately.'
def main(self, args):
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
server.xend_domain_destroy(dom)
xm.prog(ProgDestroy)
class ProgShutdown(Prog):
group = 'domain'
name = "shutdown"
info = """Shutdown a domain."""
def help(self, args):
shutdown.main([args[0], '-h'])
def main(self, args):
shutdown.main(args)
xm.prog(ProgShutdown)
class ProgPause(Prog):
group = 'domain'
name = "pause"
info = """Pause execution of a domain."""
def help(self, args):
print args[0], 'DOM'
print '\nPause execution of domain DOM.'
def main(self, args):
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
server.xend_domain_pause(dom)
xm.prog(ProgPause)
class ProgUnpause(Prog):
group = 'domain'
name = "unpause"
info = """Unpause a paused domain."""
def help(self, args):
print args[0], 'DOM'
print '\nUnpause execution of domain DOM.'
def main(self, args):
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
server.xend_domain_unpause(dom)
xm.prog(ProgUnpause)
class ProgPincpu(Prog):
group = 'domain'
name = "pincpu"
info = """Pin a domain to a cpu. """
def help(self, args):
print args[0],'DOM CPU'
print '\nPin domain DOM to cpu CPU.'
def main(self, args):
if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
v = map(int, args[1:3])
server.xend_domain_pincpu(*v)
xm.prog(ProgPincpu)
class ProgBvt(Prog):
group = 'scheduler'
name = "bvt"
info = """Set BVT scheduler parameters."""
def help(self, args):
print args[0], "DOM MCUADV WARP WARPL WARPU"
print '\nSet Borrowed Virtual Time scheduler parameters.'
def main(self, args):
if len(args) != 6: self.err("%s: Invalid argument(s)" % args[0])
v = map(int, args[1:6])
server.xend_domain_cpu_bvt_set(*v)
xm.prog(ProgBvt)
class ProgBvtslice(Prog):
group = 'scheduler'
name = "bvtslice"
info = """Set the BVT scheduler slice."""
def help(self, args):
print args[0], 'SLICE'
print '\nSet Borrowed Virtual Time scheduler slice.'
def main(self, args):
if len(args) < 2: self.err('%s: Missing slice' % args[0])
server.xend_node_cpu_bvt_slice_set(slice)
xm.prog(ProgBvtslice)
class ProgAtropos(Prog):
group = 'scheduler'
name= "atropos"
info = """Set atropos parameters."""
def help(self, args):
print args[0], "DOM PERIOD SLICE LATENCY XTRATIME"
print "\nSet atropos parameters."
def main(self, args):
if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
v = map(int, args[1:5])
server.xend_domain_cpu_atropos_set(*v)
xm.prog(ProgAtropos)
class ProgRrobin(Prog):
group = 'scheduler'
name = "rrobin"
info = """Set round robin slice."""
def help(self, args):
print args[0], "SLICE"
print "\nSet round robin scheduler slice."
def main(self, args):
if len(args) != 2: self.err("%s: Invalid argument(s)" % args[0])
rrslice = int(args[1])
server.xend_node_rrobin_set(rrslice)
xm.prog(ProgRrobin)
class ProgInfo(Prog):
group = 'host'
name = "info"
info = """Get information about the xen host."""
def main(self, args):
info = server.xend_node()
for x in info[1:]:
print "%-23s:" % x[0], x[1]
xm.prog(ProgInfo)
class ProgConsoles(Prog):
group = 'console'
name = "consoles"
info = """Get information about domain consoles."""
def main(self, args):
l = server.xend_consoles()
print "Dom Port Id"
for x in l:
info = server.xend_console(x)
d = {}
d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1]
d['port'] = sxp.child_value(info, 'port', '?')
d['id'] = sxp.child_value(info, 'id', '?')
print "%(dom)3s %(port)4s %(id)3s" % d
xm.prog(ProgConsoles)
class ProgConsole(Prog):
group = 'console'
name = "console"
info = """Open a console to a domain."""
def help(self, args):
print "console DOM"
print "\nOpen a console to domain DOM."
def main(self, args):
if len(args) < 2: self.err("%s: Missing domain" % args[0])
dom = args[1]
info = server.xend_domain(dom)
console = sxp.child(info, "console")
if not console:
self.err("No console information")
port = sxp.child_value(console, "port")
from xen.util import console_client
console_client.connect("localhost", int(port))
xm.prog(ProgConsole)
def main(args):
xm.main(args)
+340
View File
@@ -0,0 +1,340 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Object-oriented command-line option support.
"""
from getopt import getopt
import os
import os.path
import sys
import types
class Opt:
"""An individual option.
"""
def __init__(self, opts, name, short=None, long=None,
val=None, fn=None, use=None, default=None):
"""Create an option.
opts parent options object
name name of the field it controls
short short (1-char) command line switch (optional)
long long command-line switch. Defaults to option name.
val string used to print option args in help.
If val is not specified the option has no arg.
fn function to call when the option is specified.
use usage (help) string
default default value if not specified on command-line
"""
self.opts = opts
self.name = name
self.short = short
if long is None:
long = name
self.long = long
self.val = val
self.use = use
self.default = default
self.optkeys = []
if self.short:
self.optkeys.append('-' + self.short)
if self.long:
self.optkeys.append('--' + self.long)
self.fn = fn
self.specified_opt = None
self.specified_val = None
self.value = None
self.set(default)
def __repr__(self):
return self.name + '=' + str(self.specified_val)
__str__ = __repr__
def set(self, value):
"""Set the option value.
"""
self.opts.setopt(self.name, value)
def get(self):
"""Get the option value.
"""
return self.opts.getopt(self.name)
def append(self, value):
"""Append a value to the option value.
"""
v = self.get() or []
v.append(value)
self.set(v)
def short_opt(self):
"""Short option spec.
"""
if self.short:
if self.val:
return self.short + ':'
else:
return self.short
else:
return None
def long_opt(self):
"""Long option spec.
"""
if self.long:
if self.val:
return self.long + '='
else:
return self.long
else:
return None
def show(self):
sep = ''
for x in self.optkeys:
print sep, x,
sep = ','
if self.val:
print self.val,
print
if self.use:
print '\t',
print self.use
if self.val:
print '\tDefault', self.default or 'None'
def specify(self, k, v):
"""Specify the option. Called when the option is set
from the command line.
k option switch used
v optional value given (if any)
"""
if k in self.optkeys:
if self.val is None and v:
self.opts.err("Option '%s' does not take a value" % k)
self.specified_opt = k
self.specified_val = v
if self.fn:
self.fn(self, k, v)
return 1
else:
return 0
def specified(self):
"""Test whether the option has been specified: set
from the command line.
"""
return self.specified_opt
class OptVals:
"""Class to hold option values.
"""
pass
class Opts:
"""Container for options.
"""
def __init__(self, use=None):
"""Options constructor.
use usage string
"""
self.use = use
# List of options.
self.options = []
# Options indexed by name.
self.options_map = {}
# Command-line arguments.
self.argv = []
# Option values.
self.vals = OptVals()
self.vals.quiet = 0
# Variables for default scripts.
self.vars = {}
def __repr__(self):
return '\n'.join(map(str, self.options))
__str__ = __repr__
def opt(self, name, **args):
"""Add an option.
name option name
**args keyword params for option constructor
"""
x = Opt(self, name, **args)
self.options.append(x)
self.options_map[name] = x
return x
def setvar(self, var, val):
"""Set a default script variable.
"""
self.vars[var] = val
def getvar(self, var):
"""Get a default script variable.
"""
return self.vars.get(var)
def option(self, name):
"""Get an option (object).
"""
return self.options_map.get(name)
def setopt(self, name, val):
"""Set an option value.
An option can also be set using 'opts.vals.name = val'.
"""
setattr(self.vals, name, val)
def getopt(self, name):
"""Get an option value.
An option value can also be got using 'opts.vals.name'.
"""
getattr(self.vals, name)
def specified(self, name):
"""Test if an option has been specified.
"""
opt = self.option(name)
return opt and opt.specified()
def err(self, msg):
"""Print an error to stderr and exit.
"""
print >>sys.stderr, "Error:", msg
sys.exit(1)
def info(self, msg):
"""Print a message to stdout (unless quiet is set).
"""
if self.vals.quiet: return
print msg
def warn(self, msg):
"""Print a warning to stdout.
"""
print >>sys.stderr, "Warning:", msg
def parse(self, argv):
"""Parse arguments argv using the options.
return remaining arguments
"""
self.argv = argv
(vals, args) = getopt(argv[1:], self.short_opts(), self.long_opts())
self.args = args
for (k, v) in vals:
for opt in self.options:
if opt.specify(k, v): break
else:
print >>sys.stderr, "Error: Unknown option:", k
self.usage()
return args
def short_opts(self):
"""Get short options specifier for getopt.
"""
l = []
for x in self.options:
y = x.short_opt()
if not y: continue
l.append(y)
return ''.join(l)
def long_opts(self):
"""Get long options specifier for getopt.
"""
l = []
for x in self.options:
y = x.long_opt()
if not y: continue
l.append(y)
return l
def usage(self):
print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
for opt in self.options:
opt.show()
def load_defaults(self):
"""Load a defaults script. Assumes these options set:
'path' search path
'default' script name
"""
for x in [ '' ] + self.vals.path.split(':'):
if x:
p = os.path.join(x, self.vals.defaults)
else:
p = self.vals.defaults
if os.path.exists(p):
self.load(p)
break
else:
self.err("Cannot open defaults file %s" % self.vals.defaults)
def load(self, defaults, help=0):
"""Load a defaults file. Local variables in the file
are used to set options with the same names.
Variables are not used to set options that are already specified.
"""
# Create global and lobal dicts for the file.
# Initialize locals to the vars.
# Use exec to do the standard imports and
# define variables we are passing to the script.
globals = {}
locals = {}
locals.update(self.vars)
cmd = '\n'.join(["import sys",
"import os",
"import os.path",
"import xen.util.ip",
"xm_file = '%s'" % defaults,
"xm_help = %d" % help ])
exec cmd in globals, locals
execfile(defaults, globals, locals)
if help: return
# Extract the values set by the script and set the corresponding
# options, if not set on the command line.
vtypes = [ types.StringType,
types.ListType,
types.IntType,
types.FloatType
]
for (k, v) in locals.items():
if self.specified(k): continue
if not(type(v) in vtypes): continue
self.setopt(k, v)
def set_true(opt, k, v):
"""Set an option true."""
opt.set(1)
def set_false(opt, k, v):
"""Set an option false."""
opt.set(0)
def set_value(opt, k, v):
"""Set an option to a valoue."""
opt.set(v)
def set_int(opt, k, v):
"""Set an option to an integer value."""
try:
v = int(v)
except:
opt.opts.err('Invalid value: ' + str(v))
opt.set(v)
def append_value(opt, k, v):
"""Append a value to a list option."""
opt.append(v)
def set_var(opt, k, v):
"""Set a default script variable.
"""
(var, val) = v.strip().split('=')
opt.opts.setvar(var.strip(), val.strip())
+75
View File
@@ -0,0 +1,75 @@
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Domain shutdown.
"""
import string
import sys
import time
from xen.xend.XendClient import server
from xen.xm.opts import *
gopts = Opts(use="""[options] [DOM]
Shutdown one or more domains gracefully.""")
gopts.opt('help', short='h',
fn=set_true, default=0,
use="Print this help.")
gopts.opt('all', short='a',
fn=set_true, default=0,
use="Shutdown all domains.")
gopts.opt('wait', short='w',
fn=set_true, default=0,
use='Wait for shutdown to complete.')
gopts.opt('norestart', short='n',
fn=set_true, default=0,
use='Prevent domain restart.')
def shutdown(opts, doms, wait):
def domains():
return [ int(a) for a in server.xend_domains() ]
if doms == None: doms = domains()
if 0 in doms:
doms.remove(0)
for d in doms:
server.xend_domain_shutdown(d)
if wait:
while doms:
alive = domains()
dead = []
for d in doms:
if d in alive: continue
dead.append(d)
for d in dead:
opts.info("Domain %d terminated" % d)
doms.remove(d)
time.sleep(1)
opts.info("All domains terminated")
def main_all(opts, args):
shutdown(opts, None, opts.vals.wait)
def main_dom(opts, args):
if len(args) < 1: opts.err('Missing domain')
dom = args[0]
try:
domid = int(dom)
except:
opts.err('Invalid domain: ' + dom)
shutdown(opts, [ domid ], opts.vals.wait)
def main(argv):
opts = gopts
args = opts.parse(argv)
if opts.vals.help:
opts.usage()
return
print 'shutdown.main>', len(args), args
if opts.vals.all:
main_all(opts, args)
else:
main_dom(opts, args)
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.