ia64/xen-unstable

changeset 1465:2c6f86e0083e

bitkeeper revision 1.958 (40ca2c68fktLFIliN8Vr7Q8blSgj6w)

merge
author iap10@labyrinth.cl.cam.ac.uk
date Fri Jun 11 22:04:24 2004 +0000 (2004-06-11)
parents 0d4ff32c9df0 50df23f1e00d
children 225b184bd62d
files .rootkeys BitKeeper/etc/ignore BitKeeper/etc/logging_ok linux-2.4.26-xen-sparse/arch/xen/Makefile linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/Makefile linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c linux-2.4.26-xen-sparse/drivers/scsi/aic7xxx/Makefile tools/Makefile tools/examples/xm_dom_control.py tools/examples/xm_dom_create.py tools/examples/xm_vd_tool.py tools/xenctl/lib/ip.py tools/xenctl/lib/vdisk.py tools/xenctl/setup.py tools/xend/lib/main.py tools/xend/lib/utils.c tools/xenmgr/Makefile tools/xenmgr/lib/Args.py tools/xenmgr/lib/EventServer.py tools/xenmgr/lib/EventTypes.py tools/xenmgr/lib/PrettyPrint.py tools/xenmgr/lib/XendClient.py tools/xenmgr/lib/XendConsole.py tools/xenmgr/lib/XendDB.py tools/xenmgr/lib/XendDomain.py tools/xenmgr/lib/XendDomainConfig.py tools/xenmgr/lib/XendDomainInfo.py tools/xenmgr/lib/XendMigrate.py tools/xenmgr/lib/XendNode.py tools/xenmgr/lib/XendRoot.py tools/xenmgr/lib/XendVdisk.py tools/xenmgr/lib/XendVnet.py tools/xenmgr/lib/__init__.py tools/xenmgr/lib/encode.py tools/xenmgr/lib/server/SrvBase.py tools/xenmgr/lib/server/SrvConsole.py tools/xenmgr/lib/server/SrvConsoleDir.py tools/xenmgr/lib/server/SrvConsoleServer.py tools/xenmgr/lib/server/SrvDeviceDir.py tools/xenmgr/lib/server/SrvDir.py tools/xenmgr/lib/server/SrvDomain.py tools/xenmgr/lib/server/SrvDomainDir.py tools/xenmgr/lib/server/SrvEventDir.py tools/xenmgr/lib/server/SrvNode.py tools/xenmgr/lib/server/SrvRoot.py tools/xenmgr/lib/server/SrvServer.py tools/xenmgr/lib/server/SrvVdisk.py tools/xenmgr/lib/server/SrvVdiskDir.py tools/xenmgr/lib/server/SrvVnetDir.py tools/xenmgr/lib/server/__init__.py tools/xenmgr/lib/server/blkif.py tools/xenmgr/lib/server/channel.py tools/xenmgr/lib/server/console.py tools/xenmgr/lib/server/controller.py tools/xenmgr/lib/server/cstruct.py tools/xenmgr/lib/server/messages.py tools/xenmgr/lib/server/netif.py tools/xenmgr/lib/server/params.py tools/xenmgr/lib/sxp.py tools/xenmgr/netfix tools/xenmgr/setup.py tools/xenmgr/xend tools/xenmgr/xenmgrd xen/Makefile xen/arch/x86/Rules.mk xen/arch/x86/mm.c xen/common/domain.c xen/include/asm-x86/config.h xen/include/asm-x86/msr.h xen/include/asm-x86/pda.h xen/include/asm-x86/smp.h xen/include/asm-x86/string.h xen/include/asm-x86/system.h xen/include/asm-x86/types.h xen/include/asm-x86/x86_64/config.h xen/include/asm-x86/x86_64/pda.h xen/include/hypervisor-ifs/arch-x86/hypervisor-if.h xen/include/hypervisor-ifs/arch-x86_32.h xen/include/hypervisor-ifs/arch-x86_64.h xen/include/hypervisor-ifs/arch-x86_64/hypervisor-if.h xen/include/hypervisor-ifs/hypervisor-if.h
line diff
     1.1 --- a/.rootkeys	Fri Jun 11 21:59:47 2004 +0000
     1.2 +++ b/.rootkeys	Fri Jun 11 22:04:24 2004 +0000
     1.3 @@ -103,6 +103,7 @@ 3e5a4e66qRlSTcjafidMB6ulECADvg linux-2.4
     1.4  3e5a4e66mrtlmV75L1tjKDg8RaM5gA linux-2.4.26-xen-sparse/drivers/block/ll_rw_blk.c
     1.5  3f108aeaLcGDgQdFAANLTUEid0a05w linux-2.4.26-xen-sparse/drivers/char/mem.c
     1.6  3e5a4e66rw65CxyolW9PKz4GG42RcA linux-2.4.26-xen-sparse/drivers/char/tty_io.c
     1.7 +40c9c0c1pPwYE3-4i-oI3ubUu7UgvQ linux-2.4.26-xen-sparse/drivers/scsi/aic7xxx/Makefile
     1.8  3e5a4e669uzIE54VwucPYtGwXLAbzA linux-2.4.26-xen-sparse/fs/exec.c
     1.9  3e5a4e66wbeCpsJgVf_U8Jde-CNcsA linux-2.4.26-xen-sparse/include/asm-xen/bugs.h
    1.10  4048c0ddxnIa2GpBAVR-mY6mNSdeJg linux-2.4.26-xen-sparse/include/asm-xen/ctrl_if.h
    1.11 @@ -164,6 +165,9 @@ 401d7e16NpnVrFSsR7lKKKfTwCYvWA tools/exa
    1.12  401d7e16RJj-lbtsVEjua6HYAIiKiA tools/examples/xc_dom_create.py
    1.13  403b7cf7J7FsSSoEPGhx6gXR4pIdZg tools/examples/xc_physinfo.py
    1.14  401d7e16X4iojyKopo_j63AyzYZd2A tools/examples/xc_vd_tool.py
    1.15 +40c9c4684Wfg8VgMKtRFa_ULi2e_tQ tools/examples/xm_dom_control.py
    1.16 +40c9c468pXANclL7slGaoD0kSrIwoQ tools/examples/xm_dom_create.py
    1.17 +40c9c468QKoqBHjb5Qwrm60pNVcVng tools/examples/xm_vd_tool.py
    1.18  3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
    1.19  40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen
    1.20  3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
    1.21 @@ -206,8 +210,10 @@ 3fbd0a40yT6G3M9hMpaz5xTUdl0E4g tools/xc/
    1.22  4055ee41IfFazrwadCH2J72nz-A9YA tools/xenctl/Makefile
    1.23  4055ee4b_4Rvns_KzE12csI14EKK6Q tools/xenctl/lib/__init__.py
    1.24  4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/xenctl/lib/console_client.py
    1.25 +40c9c468IienauFHQ_xJIcqnPJ8giQ tools/xenctl/lib/ip.py
    1.26  4059c6a0pnxhG8hwSOivXybbGOwuXw tools/xenctl/lib/tempfile.py
    1.27  3fbd4bd6GtGwZGxYUJPOheYIR7bPaA tools/xenctl/lib/utils.py
    1.28 +40c9c468F36e06WH38kpYrD3JfXC0Q tools/xenctl/lib/vdisk.py
    1.29  4055ee44Bu6oP7U0WxxXypbUt4dNPQ tools/xenctl/setup.py
    1.30  40431ac64Hj4ixUnKmlugZKhXPFE_Q tools/xend/Makefile
    1.31  4055ad95Se-FqttgxollqOAAHB94zA tools/xend/lib/__init__.py
    1.32 @@ -220,6 +226,53 @@ 409ba2e729HhE7fEra4B5EqX-F8Xzw tools/xen
    1.33  40431ac8wrUEj-XM7B8smFtx_HA7lQ tools/xend/lib/utils.c
    1.34  4054a2fdkdATEnRw-U7AUlgu-6JiUA tools/xend/setup.py
    1.35  4056cd26Qyp09iNoOjrvzg8KYzSqOw tools/xend/xend
    1.36 +40c9c468icGyC5RAF1bRKsCXPDCvsA tools/xenmgr/Makefile
    1.37 +40c9c468SNuObE_YWARyS0hzTPSzKg tools/xenmgr/lib/Args.py
    1.38 +40c9c468Um_qc66OQeLEceIz1pgD5g tools/xenmgr/lib/EventServer.py
    1.39 +40c9c468U8EVl0d3G--8YXVg6VJD3g tools/xenmgr/lib/EventTypes.py
    1.40 +40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/xenmgr/lib/PrettyPrint.py
    1.41 +40c9c4688m3eqnC8fhLu1APm36VOVA tools/xenmgr/lib/XendClient.py
    1.42 +40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/xenmgr/lib/XendConsole.py
    1.43 +40c9c468WnXs6eOUSff23IIGI4kMfQ tools/xenmgr/lib/XendDB.py
    1.44 +40c9c468fSl3H3IypyT0ppkbb0ZT9A tools/xenmgr/lib/XendDomain.py
    1.45 +40c9c468bbKq3uC7_fuNUkiMMjArdw tools/xenmgr/lib/XendDomainConfig.py
    1.46 +40c9c4685ykq87_n1kVUbMr9flx9fg tools/xenmgr/lib/XendDomainInfo.py
    1.47 +40c9c46854nsHmuxHQHncKk5rAs5NA tools/xenmgr/lib/XendMigrate.py
    1.48 +40c9c468M96gA1EYDvNa5w5kQNYLFA tools/xenmgr/lib/XendNode.py
    1.49 +40c9c4686jruMyZIqiaZRMiMoqMJtg tools/xenmgr/lib/XendRoot.py
    1.50 +40c9c468P75aHqyIE156JXwc-5W92A tools/xenmgr/lib/XendVdisk.py
    1.51 +40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/xenmgr/lib/XendVnet.py
    1.52 +40c9c468x191zetrVlMnExfsQWHxIQ tools/xenmgr/lib/__init__.py
    1.53 +40c9c468S2YnCEKmk4ey8XQIST7INg tools/xenmgr/lib/encode.py
    1.54 +40c9c468DCpMe542varOolW1Xc68ew tools/xenmgr/lib/server/SrvBase.py
    1.55 +40c9c468IxQabrKJSWs0aEjl-27mRQ tools/xenmgr/lib/server/SrvConsole.py
    1.56 +40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/xenmgr/lib/server/SrvConsoleDir.py
    1.57 +40c9c468woSmBByfeXA4o_jGf2gCgA tools/xenmgr/lib/server/SrvConsoleServer.py
    1.58 +40c9c468kACsmkqjxBWKHRo071L26w tools/xenmgr/lib/server/SrvDeviceDir.py
    1.59 +40c9c468EQZJVkCLds-OhesJVVyZbQ tools/xenmgr/lib/server/SrvDir.py
    1.60 +40c9c468TyHZUq8sk0FF_vxM6Sozrg tools/xenmgr/lib/server/SrvDomain.py
    1.61 +40c9c469WzajDjutou3X7FmL9hMf3g tools/xenmgr/lib/server/SrvDomainDir.py
    1.62 +40c9c469-8mYEJJTAR6w_ClrJRAfwQ tools/xenmgr/lib/server/SrvEventDir.py
    1.63 +40c9c4694eu5759Dehr4Uhakei0EMg tools/xenmgr/lib/server/SrvNode.py
    1.64 +40c9c469TaZ83ypsrktmPSHLEZiP5w tools/xenmgr/lib/server/SrvRoot.py
    1.65 +40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/xenmgr/lib/server/SrvServer.py
    1.66 +40c9c469JlUVPkwGWZyVnqIsU8U6Bw tools/xenmgr/lib/server/SrvVdisk.py
    1.67 +40c9c469sG8iuyxjVH3zKw8XOAyxtQ tools/xenmgr/lib/server/SrvVdiskDir.py
    1.68 +40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/xenmgr/lib/server/SrvVnetDir.py
    1.69 +40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/xenmgr/lib/server/__init__.py
    1.70 +40c9c4692hckPol_EK0EGB16ZyDsyQ tools/xenmgr/lib/server/blkif.py
    1.71 +40c9c469N2-b3GqpLHHHPZykJPLVvA tools/xenmgr/lib/server/channel.py
    1.72 +40c9c469hJ_IlatRne-9QEa0-wlquw tools/xenmgr/lib/server/console.py
    1.73 +40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/xenmgr/lib/server/controller.py
    1.74 +40c9c469vHh-qLiiubdbKEQbJf18Zw tools/xenmgr/lib/server/cstruct.py
    1.75 +40c9c469yrm31i60pGKslTi2Zgpotg tools/xenmgr/lib/server/messages.py
    1.76 +40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/xenmgr/lib/server/netif.py
    1.77 +40c9c469ZqILEQ8x6yWy0_51jopiCg tools/xenmgr/lib/server/params.py
    1.78 +40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/xenmgr/lib/sxp.py
    1.79 +40c9c469kT0H9COWzA4XzPBjWK0WsA tools/xenmgr/netfix
    1.80 +40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/xenmgr/setup.py
    1.81 +40c9c4697z76HDfkCLdMhmaEwzFoNQ tools/xenmgr/xend
    1.82 +40c9c469JkN47d1oXi-e0RjAP-C6uQ tools/xenmgr/xenmgrd
    1.83  403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile
    1.84  40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats
    1.85  4050c413PhhLNAYk3TEwP37i_iLw9Q tools/xentrace/xentrace.8
    1.86 @@ -373,6 +426,7 @@ 3ddb79c2wa0dA_LGigxOelSGbJ284Q xen/inclu
    1.87  3ddb79c3xjYnrv5t3VqYlR4tNEOl4Q xen/include/asm-x86/page.h
    1.88  3e450943kzme29HPCtq5HNOVQkddfw xen/include/asm-x86/param.h
    1.89  3ddb79c3ysKUbxZuwKBRK3WXU2TlEg xen/include/asm-x86/pci.h
    1.90 +404f1bb41Yl-5ZjIWnG66HDCj6OIWA xen/include/asm-x86/pda.h
    1.91  4022a73diKn2Ax4-R4gzk59lm1YdDg xen/include/asm-x86/pdb.h
    1.92  3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-x86/processor.h
    1.93  3ddb79c3mbqEM7QQr3zVq7NiBNhouA xen/include/asm-x86/ptrace.h
    1.94 @@ -388,18 +442,16 @@ 3e450943TfE-iovQIY_tMO_VdGsPhA xen/inclu
    1.95  3ddb79c4HugMq7IYGxcQKFBpKwKhzA xen/include/asm-x86/types.h
    1.96  3ddb79c3M2n1ROZH6xk3HbyN4CPDqg xen/include/asm-x86/uaccess.h
    1.97  3ddb79c3uPGcP_l_2xyGgBSWd5aC-Q xen/include/asm-x86/unaligned.h
    1.98 -404f1b9b_phpQlRnyiWqP6RodfZDpg xen/include/asm-x86/x86_64/config.h
    1.99  404f1b9ceJeGVaPNIENm2FkK0AgEOQ xen/include/asm-x86/x86_64/current.h
   1.100  404f1b9fl6AQ_a-T1TDK3fuwTPXmHw xen/include/asm-x86/x86_64/desc.h
   1.101  404f1badfXZJZ2sU8sh9PS2EZvd19Q xen/include/asm-x86/x86_64/ldt.h
   1.102  404f1bb1LSCqrMDSfRAti5NdMQPJBQ xen/include/asm-x86/x86_64/page.h
   1.103 -404f1bb41Yl-5ZjIWnG66HDCj6OIWA xen/include/asm-x86/x86_64/pda.h
   1.104  404f1bb756fZfxk5HDx7J7BW3R-1jQ xen/include/asm-x86/x86_64/processor.h
   1.105  404f1bb86rAXB3aLS1vYdcqpJiEcyg xen/include/asm-x86/x86_64/ptrace.h
   1.106  404f1bc4tWkB9Qr8RkKtZGW5eMQzhw xen/include/asm-x86/x86_64/uaccess.h
   1.107  400304fcmRQmDdFYEzDh0wcBba9alg xen/include/hypervisor-ifs/COPYING
   1.108 -404f1bc68SXxmv0zQpXBWGrCzSyp8w xen/include/hypervisor-ifs/arch-x86/hypervisor-if.h
   1.109 -404f1bc7IwU-qnH8mJeVu0YsNGMrcw xen/include/hypervisor-ifs/arch-x86_64/hypervisor-if.h
   1.110 +404f1bc68SXxmv0zQpXBWGrCzSyp8w xen/include/hypervisor-ifs/arch-x86_32.h
   1.111 +404f1bc7IwU-qnH8mJeVu0YsNGMrcw xen/include/hypervisor-ifs/arch-x86_64.h
   1.112  3ddb79c2PMeWTK86y4C3F4MzHw4A1g xen/include/hypervisor-ifs/dom0_ops.h
   1.113  403cd194j2pyLqXD8FJ-ukvZzkPenw xen/include/hypervisor-ifs/event_channel.h
   1.114  3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/hypervisor-ifs/hypervisor-if.h
     2.1 --- a/BitKeeper/etc/ignore	Fri Jun 11 21:59:47 2004 +0000
     2.2 +++ b/BitKeeper/etc/ignore	Fri Jun 11 22:04:24 2004 +0000
     2.3 @@ -1,21 +1,24 @@
     2.4 +*.a
     2.5 +*.o
     2.6 +*.pyc
     2.7 +*.so
     2.8 +*.so.*
     2.9  BitKeeper/*/*
    2.10  PENDING/*
    2.11 -*.o
    2.12 -*.so
    2.13 -*.so.*
    2.14 -*.a
    2.15 -*.pyc
    2.16 +TAGS
    2.17  extras/mini-os/h/hypervisor-ifs
    2.18 +install/*
    2.19 +linux-*-xen/*
    2.20 +linux-*.tar.gz
    2.21 +linux-2.4.26-xen/*
    2.22  linux-xen-sparse
    2.23  tools/*/build/lib*/*.py
    2.24  tools/balloon/balloon
    2.25  tools/misc/miniterm/miniterm
    2.26 -tools/misc/xen_read_console
    2.27  tools/misc/xen_cpuperf
    2.28  tools/misc/xen_log
    2.29 +tools/misc/xen_read_console
    2.30  tools/xentrace/xentrace
    2.31 -xen/xen
    2.32 -xen/xen.*
    2.33  xen/drivers/pci/classlist.h
    2.34  xen/drivers/pci/devlist.h
    2.35  xen/drivers/pci/gen-devlist
    2.36 @@ -24,7 +27,5 @@ xen/include/hypervisor-ifs/arch
    2.37  xen/include/xen/compile.h
    2.38  xen/tools/elf-reloc
    2.39  xen/tools/figlet/figlet
    2.40 -TAGS
    2.41 -install/*
    2.42 -linux-*.tar.gz
    2.43 -linux-*-xen/*
    2.44 +xen/xen
    2.45 +xen/xen.*
     3.1 --- a/BitKeeper/etc/logging_ok	Fri Jun 11 21:59:47 2004 +0000
     3.2 +++ b/BitKeeper/etc/logging_ok	Fri Jun 11 22:04:24 2004 +0000
     3.3 @@ -23,6 +23,7 @@ kaf24@striker.cl.cam.ac.uk
     3.4  laudney@eclipse.(none)
     3.5  lynx@idefix.cl.cam.ac.uk
     3.6  maw48@labyrinth.cl.cam.ac.uk
     3.7 +mjw@wray-m-3.hpl.hp.com
     3.8  mwilli2@equilibrium.research.intel-research.net
     3.9  rac61@labyrinth.cl.cam.ac.uk
    3.10  rgr22@boulderdash.cl.cam.ac.uk
     4.1 --- a/linux-2.4.26-xen-sparse/arch/xen/Makefile	Fri Jun 11 21:59:47 2004 +0000
     4.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/Makefile	Fri Jun 11 22:04:24 2004 +0000
     4.3 @@ -124,10 +124,6 @@ archclean:
     4.4  
     4.5  archmrproper:
     4.6  	rm -f include/asm-xen/hypervisor-ifs/arch
     4.7 -	rm -f $(prefix)/boot/vmlinux-syms-$(KERNELRELEASE)
     4.8 -	rm -f $(prefix)/boot/vmlinuz-$(KERNELRELEASE)
     4.9  
    4.10  archdep:
    4.11 -	rm -f include/asm-xen/hypervisor-ifs/arch
    4.12 -	( cd include/asm-xen/hypervisor-ifs ; rm -rf arch ; ln -sf arch-x86 arch)
    4.13  	@$(MAKEBOOT) dep
     5.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/Makefile	Fri Jun 11 21:59:47 2004 +0000
     5.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/Makefile	Fri Jun 11 22:04:24 2004 +0000
     5.3 @@ -1,3 +1,4 @@
     5.4  O_TARGET := drv.o
     5.5 +export-objs := interface.o
     5.6  obj-y := main.o control.o interface.o
     5.7  include $(TOPDIR)/Rules.make
     6.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c	Fri Jun 11 21:59:47 2004 +0000
     6.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c	Fri Jun 11 22:04:24 2004 +0000
     6.3 @@ -71,13 +71,14 @@ void __netif_disconnect_complete(netif_t
     6.4  
     6.5  void netif_create(netif_be_create_t *create)
     6.6  {
     6.7 +    int                err = 0;
     6.8      domid_t            domid  = create->domid;
     6.9      unsigned int       handle = create->netif_handle;
    6.10      struct net_device *dev;
    6.11      netif_t          **pnetif, *netif;
    6.12 -    char               name[IFNAMSIZ];
    6.13 +    char               name[IFNAMSIZ] = {};
    6.14  
    6.15 -    snprintf(name, IFNAMSIZ, "vif%u.%u", domid, handle);
    6.16 +    snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
    6.17      dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
    6.18      if ( dev == NULL )
    6.19      {
    6.20 @@ -123,9 +124,9 @@ void netif_create(netif_be_create_t *cre
    6.21      /* XXX In bridge mode we should force a different MAC from remote end. */
    6.22      dev->dev_addr[2] ^= 1;
    6.23  
    6.24 -    if ( register_netdev(dev) != 0 )
    6.25 -    {
    6.26 -        DPRINTK("Could not register new net device\n");
    6.27 +    err = register_netdev(dev);
    6.28 +    if (err) {
    6.29 +        DPRINTK("Could not register new net device %s: err=%d\n", dev->name, err);
    6.30          create->status = NETIF_BE_STATUS_OUT_OF_MEMORY;
    6.31          kfree(dev);
    6.32          return;
    6.33 @@ -302,3 +303,13 @@ void netif_interface_init(void)
    6.34      bridge_br->bridge_forward_delay = bridge_br->forward_delay = 0;
    6.35      bridge_br->stp_enabled = 0;
    6.36  }
    6.37 +
    6.38 +#ifndef CONFIG_BRIDGE
    6.39 +#error Must configure Ethernet bridging in Network Options
    6.40 +#endif
    6.41 +EXPORT_SYMBOL(br_add_bridge);
    6.42 +EXPORT_SYMBOL(br_del_bridge);
    6.43 +EXPORT_SYMBOL(br_add_if);
    6.44 +EXPORT_SYMBOL(br_del_if);
    6.45 +EXPORT_SYMBOL(br_get_bridge_ifindices);
    6.46 +EXPORT_SYMBOL(br_get_port_ifindices);
     7.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c	Fri Jun 11 21:59:47 2004 +0000
     7.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/frontend/main.c	Fri Jun 11 22:04:24 2004 +0000
     7.3 @@ -99,6 +99,72 @@ static struct net_device *find_dev_by_ha
     7.4      return NULL;
     7.5  }
     7.6  
     7.7 +#define MULTIVIF
     7.8 +//#ifdef MULTIVIF
     7.9 +
    7.10 +/** Network interface info. */
    7.11 +struct netif_ctrl {
    7.12 +    /** Number of interfaces. */
    7.13 +    int interface_n;
    7.14 +    /** Number of connected interfaces. */
    7.15 +    int connected_n;
    7.16 +    /** Error code. */
    7.17 +    int err;
    7.18 +};
    7.19 +
    7.20 +static struct netif_ctrl netctrl = {};
    7.21 +
    7.22 +static void netctrl_init(void){
    7.23 +    netctrl = (struct netif_ctrl){};
    7.24 +    netctrl.interface_n = -1;
    7.25 +}
    7.26 +
    7.27 +/** Get or set a network interface error.
    7.28 + */
    7.29 +static int netctrl_err(int err)
    7.30 +{
    7.31 +    if(err < 0 && !netctrl.err){
    7.32 +        netctrl.err = err;
    7.33 +        printk(KERN_WARNING "%s> err=%d\n", __FUNCTION__, err);
    7.34 +    }
    7.35 +    return netctrl.err;
    7.36 +}
    7.37 +
    7.38 +/** Test if all network interfaces are connected.
    7.39 + *
    7.40 + * @return 1 if all connected, 0 if not, negative error code otherwise
    7.41 + */
    7.42 +static int netctrl_connected(void)
    7.43 +{
    7.44 +    int ok = 0;
    7.45 +    ok = (netctrl.err ? netctrl.err : (netctrl.connected_n == netctrl.interface_n));
    7.46 +    return ok;
    7.47 +}
    7.48 +
    7.49 +/** Count the connected network interfaces.
    7.50 + *
    7.51 + * @return connected count
    7.52 + */
    7.53 +static int netctrl_connected_count(void)
    7.54 +{
    7.55 +    
    7.56 +    struct list_head *ent;
    7.57 +    struct net_private *np;
    7.58 +    unsigned int connected;
    7.59 +
    7.60 +    connected = 0;
    7.61 +    
    7.62 +    list_for_each(ent, &dev_list) {
    7.63 +        np = list_entry(ent, struct net_private, list);
    7.64 +        if ( np->state == NETIF_STATE_CONNECTED){
    7.65 +            connected++;
    7.66 +        }
    7.67 +    }
    7.68 +    netctrl.connected_n = connected;
    7.69 +    return connected;
    7.70 +}
    7.71 +
    7.72 +//#endif
    7.73  
    7.74  static int network_open(struct net_device *dev)
    7.75  {
    7.76 @@ -488,21 +554,100 @@ static struct net_device_stats *network_
    7.77  }
    7.78  
    7.79  
    7.80 +static void network_reconnect(struct net_device *dev, netif_fe_interface_status_changed_t *status)
    7.81 +{
    7.82 +    struct net_private *np;
    7.83 +    int i, requeue_idx;
    7.84 +    netif_tx_request_t *tx;
    7.85 +
    7.86 +    np = dev->priv;
    7.87 +    spin_lock_irq(&np->rx_lock);
    7.88 +    spin_lock(&np->tx_lock);
    7.89 +
    7.90 +    /* Recovery procedure: */
    7.91 +
    7.92 +    /* Step 1: Reinitialise variables. */
    7.93 +    np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
    7.94 +    np->rx->event = 1;
    7.95 +
    7.96 +    /* Step 2: Rebuild the RX and TX ring contents.
    7.97 +     * NB. We could just free the queued TX packets now but we hope
    7.98 +     * that sending them out might do some good.  We have to rebuild
    7.99 +     * the RX ring because some of our pages are currently flipped out
   7.100 +     * so we can't just free the RX skbs.
   7.101 +     * NB2. Freelist index entries are always going to be less than
   7.102 +     *  __PAGE_OFFSET, whereas pointers to skbs will always be equal or
   7.103 +     * greater than __PAGE_OFFSET: we use this property to distinguish
   7.104 +     * them.
   7.105 +     */
   7.106 +
   7.107 +    /* Rebuild the TX buffer freelist and the TX ring itself.
   7.108 +     * NB. This reorders packets.  We could keep more private state
   7.109 +     * to avoid this but maybe it doesn't matter so much given the
   7.110 +     * interface has been down.
   7.111 +     */
   7.112 +    for( requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++ ){
   7.113 +            if( (unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET ) {
   7.114 +                struct sk_buff *skb = np->tx_skbs[i];
   7.115 +                
   7.116 +                tx = &np->tx->ring[requeue_idx++].req;
   7.117 +                
   7.118 +                tx->id   = i;
   7.119 +                tx->addr = virt_to_machine(skb->data);
   7.120 +                tx->size = skb->len;
   7.121 +                
   7.122 +                np->stats.tx_bytes += skb->len;
   7.123 +                np->stats.tx_packets++;
   7.124 +            }
   7.125 +    }
   7.126 +    wmb();
   7.127 +    np->tx->req_prod = requeue_idx;
   7.128 +
   7.129 +    /* Rebuild the RX buffer freelist and the RX ring itself. */
   7.130 +    for ( requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++ )
   7.131 +        if ( (unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET )
   7.132 +            np->rx->ring[requeue_idx++].req.id = i;
   7.133 +    wmb();                
   7.134 +    np->rx->req_prod = requeue_idx;
   7.135 +
   7.136 +    /* Step 3: All public and private state should now be sane.  Get
   7.137 +     * ready to start sending and receiving packets and give the driver
   7.138 +     * domain a kick because we've probably just requeued some
   7.139 +     * packets.
   7.140 +     */
   7.141 +    netif_carrier_on(dev);
   7.142 +    netif_start_queue(dev);
   7.143 +    np->state = NETIF_STATE_ACTIVE;
   7.144 +
   7.145 +    notify_via_evtchn(status->evtchn);  
   7.146 +
   7.147 +    network_tx_buf_gc(dev);
   7.148 +
   7.149 +    printk(KERN_INFO "Recovery completed\n");
   7.150 +
   7.151 +    spin_unlock(&np->tx_lock);
   7.152 +    spin_unlock_irq(&np->rx_lock);
   7.153 +}
   7.154 +
   7.155  static void netif_status_change(netif_fe_interface_status_changed_t *status)
   7.156  {
   7.157      ctrl_msg_t                   cmsg;
   7.158      netif_fe_interface_connect_t up;
   7.159      struct net_device *dev;
   7.160      struct net_private *np;
   7.161 -
   7.162 -    if ( status->handle != 0 )
   7.163 -    {
   7.164 -        printk(KERN_WARNING "Status change on unsupported netif %d\n",
   7.165 -               status->handle);
   7.166 +    
   7.167 +//#ifdef MULTIVIF
   7.168 +    if(netctrl.interface_n <= 0){
   7.169 +        printk(KERN_WARNING "Status change: no interfaces\n");
   7.170          return;
   7.171      }
   7.172 -
   7.173 -    dev = find_dev_by_handle(0);
   7.174 +//#endif
   7.175 +    dev = find_dev_by_handle(status->handle);
   7.176 +    if(!dev){
   7.177 +        printk(KERN_WARNING "Status change: invalid netif handle %u\n",
   7.178 +               status->handle);
   7.179 +         return;
   7.180 +    }
   7.181      np  = dev->priv;
   7.182      
   7.183      switch ( status->status )
   7.184 @@ -560,7 +705,7 @@ static void netif_status_change(netif_fe
   7.185          cmsg.type      = CMSG_NETIF_FE;
   7.186          cmsg.subtype   = CMSG_NETIF_FE_INTERFACE_CONNECT;
   7.187          cmsg.length    = sizeof(netif_fe_interface_connect_t);
   7.188 -        up.handle      = 0;
   7.189 +        up.handle      = status->handle;
   7.190          up.tx_shmem_frame = virt_to_machine(np->tx) >> PAGE_SHIFT;
   7.191          up.rx_shmem_frame = virt_to_machine(np->rx) >> PAGE_SHIFT;
   7.192          memcpy(cmsg.msg, &up, sizeof(up));
   7.193 @@ -570,8 +715,7 @@ static void netif_status_change(netif_fe
   7.194          break;
   7.195  
   7.196      case NETIF_INTERFACE_STATUS_CONNECTED:
   7.197 -        if ( np->state == NETIF_STATE_CLOSED )
   7.198 -        {
   7.199 +        if ( np->state == NETIF_STATE_CLOSED ){
   7.200              printk(KERN_WARNING "Unexpected netif-CONNECTED message"
   7.201                     " in state %d\n", np->state);
   7.202              break;
   7.203 @@ -579,87 +723,20 @@ static void netif_status_change(netif_fe
   7.204  
   7.205          memcpy(dev->dev_addr, status->mac, ETH_ALEN);
   7.206  
   7.207 -        if(netif_carrier_ok(dev))
   7.208 +        if(netif_carrier_ok(dev)){
   7.209              np->state = NETIF_STATE_CONNECTED;
   7.210 -        else
   7.211 -        {
   7.212 -            int i, requeue_idx;
   7.213 -            netif_tx_request_t *tx;
   7.214 -
   7.215 -            spin_lock_irq(&np->rx_lock);
   7.216 -            spin_lock(&np->tx_lock);
   7.217 -
   7.218 -            /* Recovery procedure: */
   7.219 -
   7.220 -            /* Step 1: Reinitialise variables. */
   7.221 -            np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0;
   7.222 -            np->rx->event = 1;
   7.223 -
   7.224 -            /* Step 2: Rebuild the RX and TX ring contents.
   7.225 -             * NB. We could just free the queued TX packets now but we hope
   7.226 -             * that sending them out might do some good.  We have to rebuild
   7.227 -             * the RX ring because some of our pages are currently flipped out
   7.228 -             * so we can't just free the RX skbs.
   7.229 -	     * NB2. Freelist index entries are always going to be less than
   7.230 -	     *  __PAGE_OFFSET, whereas pointers to skbs will always be equal or
   7.231 -	     * greater than __PAGE_OFFSET: we use this property to distinguish
   7.232 -             * them.
   7.233 -             */
   7.234 -
   7.235 -            /* Rebuild the TX buffer freelist and the TX ring itself.
   7.236 -             * NB. This reorders packets.  We could keep more private state
   7.237 -             * to avoid this but maybe it doesn't matter so much given the
   7.238 -             * interface has been down.
   7.239 -             */
   7.240 -            for ( requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++ )
   7.241 -            {
   7.242 -                if ( (unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET )
   7.243 -                {
   7.244 -                    struct sk_buff *skb = np->tx_skbs[i];
   7.245 -                    
   7.246 -                    tx = &np->tx->ring[requeue_idx++].req;
   7.247 -                    
   7.248 -                    tx->id   = i;
   7.249 -                    tx->addr = virt_to_machine(skb->data);
   7.250 -                    tx->size = skb->len;
   7.251 -                    
   7.252 -                    np->stats.tx_bytes += skb->len;
   7.253 -                    np->stats.tx_packets++;
   7.254 -                }
   7.255 -            }
   7.256 -            wmb();
   7.257 -            np->tx->req_prod = requeue_idx;
   7.258 -
   7.259 -            /* Rebuild the RX buffer freelist and the RX ring itself. */
   7.260 -            for ( requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++ )
   7.261 -                if ( (unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET )
   7.262 -                    np->rx->ring[requeue_idx++].req.id = i;
   7.263 -            wmb();                
   7.264 -            np->rx->req_prod = requeue_idx;
   7.265 -
   7.266 -            /* Step 3: All public and private state should now be sane.  Get
   7.267 -             * ready to start sending and receiving packets and give the driver
   7.268 -             * domain a kick because we've probably just requeued some
   7.269 -             * packets.
   7.270 -             */
   7.271 -            netif_carrier_on(dev);
   7.272 -            netif_start_queue(dev);
   7.273 -            np->state = NETIF_STATE_ACTIVE;
   7.274 -
   7.275 -            notify_via_evtchn(status->evtchn);  
   7.276 -
   7.277 -	    network_tx_buf_gc(dev);
   7.278 -
   7.279 -            printk(KERN_INFO "Recovery completed\n");
   7.280 -
   7.281 -            spin_unlock(&np->tx_lock);
   7.282 -            spin_unlock_irq(&np->rx_lock);
   7.283 +        } else {
   7.284 +            network_reconnect(dev, status);
   7.285          }
   7.286  
   7.287          np->evtchn = status->evtchn;
   7.288          np->irq = bind_evtchn_to_irq(np->evtchn);
   7.289          (void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM, 
   7.290                            dev->name, dev);
   7.291 +        
   7.292 +#ifdef MULTIVIF
   7.293 +        netctrl_connected_count();
   7.294 +#endif
   7.295          break;
   7.296  
   7.297      default:
   7.298 @@ -669,27 +746,102 @@ static void netif_status_change(netif_fe
   7.299      }
   7.300  }
   7.301  
   7.302 +/** Create a network devices.
   7.303 + *
   7.304 + * @param handle device handle
   7.305 + * @param val return parameter for created device
   7.306 + * @return 0 on success, error code otherwise
   7.307 + */
   7.308 +static int create_netdev(int handle, struct net_device **val){
   7.309 +    int err = 0;
   7.310 +    struct net_device *dev = NULL;
   7.311 +    struct net_private *np = NULL;
   7.312 +
   7.313 +    dev = alloc_etherdev(sizeof(struct net_private));
   7.314 +    if (!dev){
   7.315 +        printk(KERN_WARNING "%s> alloc_etherdev failed.\n", __FUNCTION__);
   7.316 +        err = -ENOMEM;
   7.317 +        goto exit;
   7.318 +    }
   7.319 +    np         = dev->priv;
   7.320 +    np->state  = NETIF_STATE_CLOSED;
   7.321 +    np->handle = handle;
   7.322 +    
   7.323 +    dev->open            = network_open;
   7.324 +    dev->hard_start_xmit = network_start_xmit;
   7.325 +    dev->stop            = network_close;
   7.326 +    dev->get_stats       = network_get_stats;
   7.327 +    dev->poll            = netif_poll;
   7.328 +    dev->weight          = 64;
   7.329 +    
   7.330 +    err = register_netdev(dev);
   7.331 +    if (err){
   7.332 +        printk(KERN_WARNING "%s> register_netdev err=%d\n", __FUNCTION__, err);
   7.333 +        goto exit;
   7.334 +    }
   7.335 +    np->dev = dev;
   7.336 +    list_add(&np->list, &dev_list);
   7.337 +  exit:
   7.338 +    if(err){
   7.339 +        if(dev) kfree(dev);
   7.340 +        dev = NULL;
   7.341 +    }
   7.342 +    if(val) *val = dev;
   7.343 +    return err;
   7.344 +}
   7.345 +
   7.346 +//#ifdef MULTIVIF
   7.347 +/** Initialize the network control interface. Set the number of network devices
   7.348 + * and create them.
   7.349 + */
   7.350 +static void netif_driver_status_change(netif_fe_driver_status_changed_t *status)
   7.351 +{
   7.352 +    int err = 0;
   7.353 +    int i;
   7.354 +    
   7.355 +    netctrl.interface_n = status->nr_interfaces;
   7.356 +    netctrl.connected_n = 0;
   7.357 +
   7.358 +    for(i = 0; i < netctrl.interface_n; i++){
   7.359 +        err = create_netdev(i, NULL);
   7.360 +        if(err){
   7.361 +            netctrl_err(err);
   7.362 +            break;
   7.363 +        }
   7.364 +    }
   7.365 +}
   7.366 +//#endif
   7.367 +
   7.368  
   7.369  static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
   7.370  {
   7.371 +    int respond = 1;
   7.372      switch ( msg->subtype )
   7.373      {
   7.374      case CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED:
   7.375          if ( msg->length != sizeof(netif_fe_interface_status_changed_t) )
   7.376 -            goto parse_error;
   7.377 +            goto error;
   7.378          netif_status_change((netif_fe_interface_status_changed_t *)
   7.379                              &msg->msg[0]);
   7.380          break;
   7.381 +//#ifdef MULTIVIF
   7.382 +    case CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
   7.383 +        if ( msg->length != sizeof(netif_fe_driver_status_changed_t) )
   7.384 +            goto error;
   7.385 +        netif_driver_status_change((netif_fe_driver_status_changed_t *)
   7.386 +                                   &msg->msg[0]);
   7.387 +        // Message is a response, so do not respond.
   7.388 +        respond = 0;
   7.389 +        break;
   7.390 +//#endif
   7.391 +      error:
   7.392      default:
   7.393 -        goto parse_error;
   7.394 +        msg->length = 0;
   7.395 +        break;
   7.396      }
   7.397 -
   7.398 -    ctrl_if_send_response(msg);
   7.399 -    return;
   7.400 -
   7.401 - parse_error:
   7.402 -    msg->length = 0;
   7.403 -    ctrl_if_send_response(msg);
   7.404 +    if(respond){
   7.405 +        ctrl_if_send_response(msg);
   7.406 +    }
   7.407  }
   7.408  
   7.409  
   7.410 @@ -697,9 +849,11 @@ static int __init init_module(void)
   7.411  {
   7.412      ctrl_msg_t                       cmsg;
   7.413      netif_fe_driver_status_changed_t st;
   7.414 -    int err;
   7.415 -    struct net_device *dev;
   7.416 -    struct net_private *np;
   7.417 +    int err = 0;
   7.418 +#ifdef MULTIVIF
   7.419 +    int wait_n = 20;
   7.420 +    int wait_i;
   7.421 +#endif
   7.422  
   7.423      if ( (start_info.flags & SIF_INITDOMAIN) ||
   7.424           (start_info.flags & SIF_NET_BE_DOMAIN) )
   7.425 @@ -708,32 +862,9 @@ static int __init init_module(void)
   7.426      printk("Initialising Xen virtual ethernet frontend driver");
   7.427  
   7.428      INIT_LIST_HEAD(&dev_list);
   7.429 -
   7.430 -    if ( (dev = alloc_etherdev(sizeof(struct net_private))) == NULL )
   7.431 -    {
   7.432 -        err = -ENOMEM;
   7.433 -        goto fail;
   7.434 -    }
   7.435 -
   7.436 -    np = dev->priv;
   7.437 -    np->state  = NETIF_STATE_CLOSED;
   7.438 -    np->handle = 0;
   7.439 -
   7.440 -    dev->open            = network_open;
   7.441 -    dev->hard_start_xmit = network_start_xmit;
   7.442 -    dev->stop            = network_close;
   7.443 -    dev->get_stats       = network_get_stats;
   7.444 -    dev->poll            = netif_poll;
   7.445 -    dev->weight          = 64;
   7.446 -    
   7.447 -    if ( (err = register_netdev(dev)) != 0 )
   7.448 -    {
   7.449 -        kfree(dev);
   7.450 -        goto fail;
   7.451 -    }
   7.452 -    
   7.453 -    np->dev = dev;
   7.454 -    list_add(&np->list, &dev_list);
   7.455 +#ifdef MULTIVIF
   7.456 +    netctrl_init();
   7.457 +#endif
   7.458  
   7.459      (void)ctrl_if_register_receiver(CMSG_NETIF_FE, netif_ctrlif_rx,
   7.460                                      CALLBACK_IN_BLOCKING_CONTEXT);
   7.461 @@ -743,25 +874,30 @@ static int __init init_module(void)
   7.462      cmsg.subtype   = CMSG_NETIF_FE_DRIVER_STATUS_CHANGED;
   7.463      cmsg.length    = sizeof(netif_fe_driver_status_changed_t);
   7.464      st.status      = NETIF_DRIVER_STATUS_UP;
   7.465 +    st.nr_interfaces = 0;
   7.466      memcpy(cmsg.msg, &st, sizeof(st));
   7.467 -
   7.468      ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
   7.469 -    
   7.470 -    /*
   7.471 -     * We should read 'nr_interfaces' from response message and wait
   7.472 -     * for notifications before proceeding. For now we assume that we
   7.473 -     * will be notified of exactly one interface.
   7.474 -     */
   7.475 -    while ( np->state != NETIF_STATE_CONNECTED )
   7.476 -    {
   7.477 +
   7.478 +#ifdef MULTIVIF
   7.479 +    /* Wait for all interfaces to be connected. */
   7.480 +    for(wait_i = 0; 1; wait_i++) {
   7.481 +        if(wait_i < wait_n){
   7.482 +            err = netctrl_connected();
   7.483 +        } else {
   7.484 +            err = -ENETDOWN;
   7.485 +        }
   7.486 +        if(err < 0) goto exit;
   7.487 +        if(err > 0){
   7.488 +            err = 0;
   7.489 +            break;
   7.490 +        }
   7.491          set_current_state(TASK_INTERRUPTIBLE);
   7.492          schedule_timeout(1);
   7.493 -    }
   7.494 +     }
   7.495 +#endif
   7.496  
   7.497 -    return 0;
   7.498 -
   7.499 - fail:
   7.500 -    cleanup_module();
   7.501 + exit:
   7.502 +    if(err) cleanup_module();
   7.503      return err;
   7.504  }
   7.505  
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/linux-2.4.26-xen-sparse/drivers/scsi/aic7xxx/Makefile	Fri Jun 11 22:04:24 2004 +0000
     8.3 @@ -0,0 +1,97 @@
     8.4 +#
     8.5 +# drivers/scsi/aic7xxx/Makefile
     8.6 +#
     8.7 +# Makefile for the Linux aic7xxx SCSI driver.
     8.8 +#
     8.9 +
    8.10 +O_TARGET := aic7xxx_drv.o
    8.11 +
    8.12 +list-multi	:= aic7xxx.o aic79xx.o
    8.13 +
    8.14 +obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx.o
    8.15 +ifeq ($(CONFIG_PCI),y)
    8.16 +obj-$(CONFIG_SCSI_AIC79XX)	+= aic79xx.o
    8.17 +endif
    8.18 +
    8.19 +EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi -Werror
    8.20 +#EXTRA_CFLAGS += -g
    8.21 +
    8.22 +# Platform Specific Files
    8.23 +obj-aic7xxx = aic7xxx_osm.o aic7xxx_proc.o
    8.24 +
    8.25 +# Core Files
    8.26 +obj-aic7xxx += aic7xxx_core.o aic7xxx_93cx6.o
    8.27 +ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y)
    8.28 +obj-aic7xxx += aic7xxx_reg_print.o
    8.29 +endif
    8.30 +
    8.31 +#EISA Specific Files
    8.32 +AIC7XXX_EISA_ARCH = $(filter i386 alpha xen,$(ARCH))
    8.33 +ifneq ($(AIC7XXX_EISA_ARCH),)
    8.34 +obj-aic7xxx += aic7770.o
    8.35 +# Platform Specific EISA Files
    8.36 +obj-aic7xxx += aic7770_osm.o
    8.37 +endif
    8.38 +
    8.39 +#PCI Specific Files
    8.40 +ifeq ($(CONFIG_PCI),y)
    8.41 +obj-aic7xxx += aic7xxx_pci.o
    8.42 +# Platform Specific PCI Files
    8.43 +obj-aic7xxx += aic7xxx_osm_pci.o
    8.44 +endif
    8.45 +
    8.46 +# Platform Specific U320 Files
    8.47 +obj-aic79xx = aic79xx_osm.o aic79xx_proc.o aic79xx_osm_pci.o
    8.48 +# Core Files
    8.49 +obj-aic79xx += aic79xx_core.o aic79xx_pci.o
    8.50 +ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y)
    8.51 +obj-aic79xx += aic79xx_reg_print.o
    8.52 +endif
    8.53 +
    8.54 +# Override our module desitnation
    8.55 +MOD_DESTDIR = $(shell cd .. && $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh)
    8.56 +
    8.57 +include $(TOPDIR)/Rules.make
    8.58 +
    8.59 +aic7xxx_core.o: aic7xxx_seq.h
    8.60 +$(obj-aic7xxx): aic7xxx_reg.h
    8.61 +aic7xxx.o: aic7xxx_seq.h aic7xxx_reg.h $(obj-aic7xxx)
    8.62 +	$(LD) $(LD_RFLAG) -r -o $@ $(obj-aic7xxx)
    8.63 +
    8.64 +aic79xx_core.o: aic79xx_seq.h
    8.65 +$(obj-aic79xx): aic79xx_reg.h
    8.66 +aic79xx.o: aic79xx_seq.h aic79xx_reg.h $(obj-aic79xx)
    8.67 +	$(LD) $(LD_RFLAG) -r -o $@ $(obj-aic79xx)
    8.68 +
    8.69 +ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
    8.70 +aic7xxx_gen = aic7xxx_seq.h aic7xxx_reg.h
    8.71 +ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y)
    8.72 +aic7xxx_gen += aic7xxx_reg_print.c
    8.73 +aic7xxx_asm_cmd = aicasm/aicasm -I. -r aic7xxx_reg.h		\
    8.74 +		 -p aic7xxx_reg_print.c -i aic7xxx_osm.h	\
    8.75 +		 -o aic7xxx_seq.h aic7xxx.seq
    8.76 +else
    8.77 +aic7xxx_asm_cmd = aicasm/aicasm -I. -r aic7xxx_reg.h		\
    8.78 +		 -o aic7xxx_seq.h aic7xxx.seq
    8.79 +endif
    8.80 +$(aic7xxx_gen): aic7xxx.seq aic7xxx.reg aicasm/aicasm
    8.81 +	$(aic7xxx_asm_cmd)
    8.82 +endif
    8.83 +
    8.84 +ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y)
    8.85 +aic79xx_gen = aic79xx_seq.h aic79xx_reg.h
    8.86 +ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y)
    8.87 +aic79xx_gen += aic79xx_reg_print.c
    8.88 +aic79xx_asm_cmd = aicasm/aicasm -I. -r aic79xx_reg.h		\
    8.89 +		 -p aic79xx_reg_print.c -i aic79xx_osm.h	\
    8.90 +		 -o aic79xx_seq.h aic79xx.seq
    8.91 +else
    8.92 +aic79xx_asm_cmd = aicasm/aicasm -I. -r aic79xx_reg.h \
    8.93 +		 -o aic79xx_seq.h aic79xx.seq
    8.94 +endif
    8.95 +$(aic79xx_gen): aic79xx.seq aic79xx.reg aicasm/aicasm
    8.96 +	$(aic79xx_asm_cmd)
    8.97 +endif
    8.98 +
    8.99 +aicasm/aicasm: aicasm/*.[chyl]
   8.100 +	$(MAKE) -C aicasm
     9.1 --- a/tools/Makefile	Fri Jun 11 21:59:47 2004 +0000
     9.2 +++ b/tools/Makefile	Fri Jun 11 22:04:24 2004 +0000
     9.3 @@ -7,6 +7,7 @@ all:
     9.4  	$(MAKE) -C xentrace
     9.5  	$(MAKE) -C xenctl
     9.6  	$(MAKE) -C xend
     9.7 +	$(MAKE) -C xenmgr
     9.8  
     9.9  install: all
    9.10  	$(MAKE) -C balloon install
    9.11 @@ -16,6 +17,7 @@ install: all
    9.12  	$(MAKE) -C xentrace install
    9.13  	$(MAKE) -C xenctl install
    9.14  	$(MAKE) -C xend install
    9.15 +	$(MAKE) -C xenmgr install
    9.16  
    9.17  dist: $(TARGET)
    9.18  	$(MAKE) prefix=`pwd`/../../install dist=yes install
    9.19 @@ -30,4 +32,5 @@ clean:
    9.20  	$(MAKE) -C xentrace clean
    9.21  	$(MAKE) -C xenctl clean
    9.22  	$(MAKE) -C xend clean
    9.23 +	$(MAKE) -C xenmgr install
    9.24  
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tools/examples/xm_dom_control.py	Fri Jun 11 22:04:24 2004 +0000
    10.3 @@ -0,0 +1,233 @@
    10.4 +#!/usr/bin/env python
    10.5 +
    10.6 +import sys
    10.7 +import re
    10.8 +import string
    10.9 +import time
   10.10 +import os
   10.11 +import os.path
   10.12 +import signal
   10.13 +
   10.14 +from xenmgr.XendClient import server
   10.15 +
   10.16 +# usage: xc_dom_control [command] <params>
   10.17 +#
   10.18 +# this script isn't very smart, but it'll do for now.
   10.19 +#
   10.20 +
   10.21 +def usage (rc=0):
   10.22 +    if rc:
   10.23 +        out = sys.stderr
   10.24 +    else:
   10.25 +        out = sys.stdout
   10.26 +    print >> out, """
   10.27 +Usage: %s [command] <params>
   10.28 +
   10.29 +  help                   -- print usage
   10.30 +  stop      [dom]        -- pause a domain
   10.31 +  start     [dom]        -- un-pause a domain
   10.32 +  shutdown  [dom] [[-w]] -- request a domain to shutdown (can specify 'all')
   10.33 +                            (optionally wait for complete shutdown)
   10.34 +  destroy   [dom]        -- immediately terminate a domain
   10.35 +  pincpu    [dom] [cpu]  -- pin a domain to the specified CPU
   10.36 +  suspend   [dom] [file] -- write domain's memory to a file and terminate
   10.37 +			    (resume by re-running xc_dom_create with -L option)
   10.38 +  unwatch   [dom]        -- kill the auto-restart daemon for a domain
   10.39 +  list                   -- print info about all domains
   10.40 +  listvbds               -- print info about all virtual block devs
   10.41 +  cpu_bvtset [dom] [mcuadv] [warp] [warpl] [warpu]
   10.42 +                         -- set BVT scheduling parameters for domain
   10.43 +  cpu_bvtslice [slice]   -- set default BVT scheduler slice
   10.44 +  cpu_atropos_set [dom] [period] [slice] [latency] [xtratime]
   10.45 +                         -- set Atropos scheduling parameters for domain
   10.46 +  cpu_rrobin_slice [slice] -- set Round Robin scheduler slice
   10.47 +  vif_stats [dom] [vif]  -- get stats for a given network vif
   10.48 +  vif_addip [dom] [vif] [ip]  -- add an IP address to a given vif
   10.49 +  vif_setsched [dom] [vif] [bytes] [usecs] -- rate limit vif bandwidth
   10.50 +  vif_getsched [dom] [vif] -- print vif's scheduling parameters
   10.51 +  vbd_add [dom] [uname] [dev] [mode] -- make disk/partition uname available to 
   10.52 +                            domain as dev e.g. 'vbd_add 2 phy:sda3 hda1 w'
   10.53 +  vbd_remove [dom] [dev] -- remove disk or partition attached as 'dev' 
   10.54 +""" % sys.argv[0]
   10.55 +    if rc: sys.exit(rc)
   10.56 +
   10.57 +if len(sys.argv) < 2: usage(1)
   10.58 +cmd = sys.argv[1]
   10.59 +
   10.60 +#todo: replace all uses of xc with the new api.
   10.61 +import Xc; xc = Xc.new()
   10.62 +
   10.63 +rc = ''
   10.64 +dom = None
   10.65 +
   10.66 +
   10.67 +def auto_restart_pid_file(dom):
   10.68 +    # The auto-restart daemon's pid file.
   10.69 +    return '/var/run/xendomains/%d.pid' % dom
   10.70 +
   10.71 +def auto_restart_pid(dom):
   10.72 +    watcher = auto_restart_pid_file(dom)
   10.73 +    if os.path.isfile(watcher):
   10.74 +        fd = open(watcher,'r')
   10.75 +        pid = int(fd.readline())
   10.76 +    else:
   10.77 +        pid = None
   10.78 +    return pid
   10.79 + 
   10.80 +def auto_restart_kill(dom):
   10.81 +    #todo: replace this - tell xend not to restart any more.
   10.82 +    # Kill a domain's auto restart daemon.
   10.83 +    pid = auto_restart_pid(dom)
   10.84 +    if pid:
   10.85 +        os.kill(pid, signal.SIGTERM)
   10.86 +
   10.87 +
   10.88 +if len( sys.argv ) > 2 and re.match('\d+$', sys.argv[2]):
   10.89 +    dom = long(sys.argv[2])
   10.90 +
   10.91 +if cmd == "help":
   10.92 +    usage()
   10.93 +    
   10.94 +elif cmd == 'stop':
   10.95 +    rc = server.xend_domain_stop(dom)
   10.96 +
   10.97 +elif cmd == 'start':
   10.98 +    rc = server.xend_domain_start(dom)    
   10.99 +
  10.100 +elif cmd == 'shutdown':
  10.101 +    doms = []
  10.102 +    shutdown = []
  10.103 +    if dom != None:
  10.104 +        doms = [ dom ]
  10.105 +    elif sys.argv[2] == 'all':
  10.106 +        doms = server.xend_domains()
  10.107 +        doms.remove('0')
  10.108 +    for d in doms:
  10.109 +        ret = server.xend_domain_shutdown(d)
  10.110 +        if ret == 0:
  10.111 +            shutdown.append(d)
  10.112 +        else:
  10.113 +            rc = ret
  10.114 +
  10.115 +    wait = (len(sys.argv) == 4 and sys.argv[3] == "-w")
  10.116 +    if wait:
  10.117 +        # wait for all domains we shut down to terminate
  10.118 +        for dom in shutdown:
  10.119 +            while True:
  10.120 +                info = server.xend_domain(dom)
  10.121 +                if not info: break
  10.122 +                time.sleep(1)
  10.123 +
  10.124 +elif cmd == 'destroy':
  10.125 +    rc = server.xend_domain_halt(dom)    
  10.126 +
  10.127 +elif cmd == 'pincpu':
  10.128 +    if len(sys.argv) < 4: usage(1)
  10.129 +    cpu = int(sys.argv[3])
  10.130 +    rc = server.xend_domain_pincpu(dom, cpu)
  10.131 +
  10.132 +elif cmd == 'list':
  10.133 +    print 'Dom  Name             Mem(MB)  CPU  State  Time(s)'
  10.134 +    for dom in server.xend_domains():
  10.135 +        info = server.xend_domain(dom)
  10.136 +        d = {}
  10.137 +        d['dom'] = dom
  10.138 +        d['name'] = sxp.get_child_value(info, 'name', '??')
  10.139 +        d['mem'] = int(sxp.get_child_value(info, 'memory', '0'))
  10.140 +        d['cpu'] = int(sxp.get_child_value(info, 'cpu', '0'))
  10.141 +        d['state'] = sxp.get_child_value(info, 'state', '??')
  10.142 +        d['cpu_time'] = sxp.get_child_value(info, 'cpu_time', '0')
  10.143 +        print ("%(dom)-4d %(name)-16s %(mem)7d %(cpu)3d %(state)5s %(cpu_time)8d"
  10.144 +               % d)
  10.145 +
  10.146 +elif cmd == 'unwatch':
  10.147 +    auto_restart_kill(dom)
  10.148 +
  10.149 +elif cmd == 'listvbds':
  10.150 +    print 'Dom   Dev   Mode   Size(MB)'
  10.151 +    for dom in server.xend_domains():
  10.152 +        for vbd in server.xend_domain_vbds(dom):
  10.153 +            info = server.xend_domain_vbd(vbd)
  10.154 +            v['vbd'] = vbd
  10.155 +            v['size'] = int(sxp.get_child_value(info, 'size', '0'))
  10.156 +            v['mode'] = sxp.get_child_value(info, 'mode', '??')
  10.157 +            vbd['size_mb'] = vbd['nr_sectors'] / 2048
  10.158 +            print ('%(dom)-4d  %(vbd)04x  %(mode)-2s      %(size)d' % v)
  10.159 +
  10.160 +elif cmd == 'suspend':
  10.161 +    if len(sys.argv) < 4: usage(1)
  10.162 +    file = os.path.abspath(sys.argv[3])
  10.163 +    auto_restart_kill(dom)
  10.164 +    rc = server.xend_domain_save(dom, file, progress=1)
  10.165 +
  10.166 +elif cmd == 'cpu_bvtslice':
  10.167 +    if len(sys.argv) < 3: usage(1)
  10.168 +    slice = sys.argv[2]
  10.169 +    rc = server.xend_node_cpu_bvt_slice_set(slice)
  10.170 +
  10.171 +elif cmd == 'cpu_bvtset':
  10.172 +    if len(sys.argv) < 7: usage(1)
  10.173 +    (mcuadv, warp, warpl, warpu) = map(int, sys.argv[3:7])
  10.174 +    
  10.175 +    rc = server.xend_domain_cpu_bvt_set(dom, mcuadv, warp, warpl, warpu)
  10.176 +    
  10.177 +elif cmd == 'vif_stats':
  10.178 +    if len(sys.argv) < 4: usage(1)
  10.179 +    vif = int(sys.argv[3])
  10.180 +
  10.181 +    print server.xend_domain_vif_stats(dom, vif)
  10.182 +
  10.183 +elif cmd == 'vif_addip':
  10.184 +    if len(sys.argv) < 5: usage(1)
  10.185 +    vif = int(sys.argv[3])
  10.186 +    ip  = sys.argv[4]
  10.187 +    rc = server.xend_domain_vif_addip(dom, vif, ip)
  10.188 +
  10.189 +elif cmd == 'vif_setsched':
  10.190 +    if len(sys.argv) < 6: usage(1)
  10.191 +    (vif, bytes, usecs) = map(int, sys.argv[3:6])
  10.192 +    rc = server.xend_domain_vif_scheduler_set(dom, vif, bytes, usecs)
  10.193 +
  10.194 +elif cmd == 'vif_getsched':
  10.195 +    if len(sys.argv) < 4: usage(1)
  10.196 +    vif = int(sys.argv[3])
  10.197 +    print server.xend_domain_vif_scheduler_get(dom, vif)
  10.198 +
  10.199 +elif cmd == 'vbd_add':
  10.200 +    if len(sys.argv) < 6: usage(1)
  10.201 +    uname = sys.argv[3]
  10.202 +    dev = sys.argv[4]
  10.203 +    mode = sys.argv[5]
  10.204 +    try:
  10.205 +        vbd = server.xend_domain_vbd_add(dom, uname, dev, mode)
  10.206 +    except StandardError, ex:
  10.207 +        print "Error:", ex
  10.208 +        sys.exit(1)
  10.209 +    print "Added disk/partition %s to domain %d as device %s (%x)" % (uname, dom, dev, vbd)
  10.210 +
  10.211 +elif cmd == 'vbd_remove':
  10.212 +    if len(sys.argv) < 4: usage(1)
  10.213 +    dev = sys.argv[3]
  10.214 +    vbd = server.xend_domain_vbd_remove(dom, dev)
  10.215 +    if vbd < 0:
  10.216 +	print "Failed"
  10.217 +	sys.exit(1)
  10.218 +    else:
  10.219 +	print "Removed disk/partition attached as device %s (%x) in domain %d" % (dev, vbd, dom)
  10.220 +
  10.221 +elif cmd == 'cpu_atropos_set': # args: dom period slice latency xtratime
  10.222 +    if len(sys.argv) < 6: usage(1)
  10.223 +    (period, slice, latency, xtratime) = map(int, sys.argv[3:7])
  10.224 +    rc = server.xend_domain_cpu_atropos_set(
  10.225 +        dom, period, slice, latency, xtratime)
  10.226 +
  10.227 +elif cmd == 'cpu_rrobin_slice':
  10.228 +    if len(sys.argv) < 3: usage(1)
  10.229 +    slice = int(sys.argv[2])
  10.230 +    rc = server.xend_node_rrobin_set(slice=slice)
  10.231 +
  10.232 +else:
  10.233 +    usage(1)
  10.234 +
  10.235 +if rc != '':
  10.236 +    print "return code %d" % rc
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tools/examples/xm_dom_create.py	Fri Jun 11 22:04:24 2004 +0000
    11.3 @@ -0,0 +1,402 @@
    11.4 +#!/usr/bin/env python
    11.5 +
    11.6 +import string
    11.7 +import sys
    11.8 +import os
    11.9 +import os.path
   11.10 +import time
   11.11 +import socket
   11.12 +import getopt
   11.13 +import signal
   11.14 +import syslog
   11.15 +
   11.16 +import xenctl.console_client
   11.17 +
   11.18 +from xenmgr import sxp
   11.19 +from xenmgr import PrettyPrint
   11.20 +from xenmgr.XendClient import server
   11.21 +
   11.22 +config_dir  = '/etc/xc/'
   11.23 +config_file = xc_config_file = config_dir + 'defaults'
   11.24 +
   11.25 +def main_usage ():
   11.26 +    print >>sys.stderr,"""
   11.27 +Usage: %s <args>
   11.28 +
   11.29 +This tool is used to create and start new domains. It reads defaults
   11.30 +from a file written in Python, having allowed variables to be set and
   11.31 +passed into the file. Further command line arguments allow the
   11.32 +defaults to be overridden. The defaults for each parameter are listed
   11.33 +in [] brackets. Arguments are as follows:
   11.34 +
   11.35 +Arguments to control the parsing of the defaults file:
   11.36 + -f config_file   -- Use the specified defaults script. 
   11.37 +                     Default: ['%s']
   11.38 + -L state_file    -- Load virtual machine memory state from state_file
   11.39 + -D foo=bar       -- Set variable foo=bar before parsing config
   11.40 +                     E.g. '-D vmid=3;ip=1.2.3.4'
   11.41 + -h               -- Print extended help message, including all arguments
   11.42 + -n               -- Dry run only, don't actually create domain
   11.43 +                     Prints the config, suitable for -F.
   11.44 + -q               -- Quiet - write output only to the system log
   11.45 + -F domain_config -- Build domain using the config in the file.
   11.46 +                     Suitable files can be made using '-n' to output a config.
   11.47 +""" % (sys.argv[0], xc_config_file)
   11.48 +
   11.49 +def extra_usage ():
   11.50 +    print >>sys.stderr,"""
   11.51 +Arguments to override current config read from '%s':
   11.52 + -c               -- Turn into console terminal after domain is created
   11.53 + -k image         -- Path to kernel image ['%s']
   11.54 + -r ramdisk       -- Path to ramdisk (or empty) ['%s']
   11.55 + -b builder_fn    -- Function to use to build domain ['%s']
   11.56 + -m mem_size      -- Initial memory allocation in MB [%dMB]
   11.57 + -N domain_name   -- Set textual name of domain ['%s']
   11.58 + -a auto_restart  -- Restart domain on exit, yes/no ['%d']
   11.59 + -e vbd_expert    -- Safety catch to avoid some disk accidents ['%s'] 
   11.60 + -d udisk,dev,rw  -- Add disk, partition, or virtual disk to domain. E.g. to 
   11.61 +                     make partion sda4 available to the domain as hda1 with 
   11.62 +                     read-write access: '-d phy:sda4,hda1,rw' To add 
   11.63 +                     multiple disks use multiple -d flags or seperate with ';'
   11.64 +                     Default: ['%s']
   11.65 + -i vfr_ipaddr    -- Add IP address to the list which Xen will route to
   11.66 +                     the domain. Use multiple times to add more IP addrs.
   11.67 +		     Default: ['%s']
   11.68 +
   11.69 +Args to override the kernel command line, which is concatenated from these:
   11.70 + -I cmdline_ip    -- Override 'ip=ipaddr:nfsserv:gateway:netmask::eth0:off'
   11.71 +                     Default: ['%s']
   11.72 + -R cmdline_root  -- Override root device parameters.
   11.73 +                     Default: ['%s']
   11.74 + -E cmdline_extra -- Override extra kernel args and rc script env vars.
   11.75 +                     Default: ['%s']
   11.76 +
   11.77 +""" % (config_file,
   11.78 +       image, ramdisk, builder_fn, mem_size, domain_name, auto_restart,
   11.79 +       vbd_expert, 
   11.80 +       printvbds( vbd_list ), 
   11.81 +       reduce ( (lambda a,b: a+':'+b), vfr_ipaddr,'' )[1:],
   11.82 +       cmdline_ip, cmdline_root, cmdline_extra)
   11.83 +
   11.84 +def config_usage (): pass
   11.85 +
   11.86 +def answer ( s ):
   11.87 +    s = string.lower(s)
   11.88 +    if s == 'yes' or s == 'true' or s == '1': return 1
   11.89 +    return 0
   11.90 +
   11.91 +def printvbds ( v ):
   11.92 +    s=''
   11.93 +    for (a,b,c) in v:
   11.94 +	s = s + '; %s,%s,%s' % (a,b,c)
   11.95 +    return s[2:]
   11.96 +
   11.97 +def output(string):
   11.98 +    global quiet
   11.99 +    syslog.syslog(string)
  11.100 +    if not quiet:
  11.101 +        print string
  11.102 +    return
  11.103 +
  11.104 +bail=False; dryrun=False; extrahelp=False; quiet = False
  11.105 +image=''; ramdisk=''; builder_fn='linux'; restore=0; state_file=''
  11.106 +mem_size=0; domain_name=''; vfr_ipaddr=[];
  11.107 +vbd_expert='rr'; auto_restart=False;
  11.108 +vbd_list = []; cmdline_ip = ''; cmdline_root=''; cmdline_extra=''
  11.109 +pci_device_list = []; console_port = -1
  11.110 +auto_console = False
  11.111 +config_from_file = False
  11.112 +
  11.113 +##### Determine location of defaults file
  11.114 +#####
  11.115 +
  11.116 +try:
  11.117 +    opts, args = getopt.getopt(sys.argv[1:], "h?nqcf:F:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" )
  11.118 +
  11.119 +    for opt in opts:
  11.120 +	if opt[0] == '-f': config_file= opt[1]
  11.121 +	if opt[0] == '-h' or opt[0] == '-?' : bail=True; extrahelp=True
  11.122 +	if opt[0] == '-n': dryrun=True
  11.123 +	if opt[0] == '-D': 
  11.124 +	    for o in string.split( opt[1], ';' ):
  11.125 +		(l,r) = string.split( o, '=' )
  11.126 +		exec "%s='%s'" % (l,r)
  11.127 +        if opt[0] == '-q': quiet = True
  11.128 +        if opt[0] == '-L': restore = True; state_file = opt[1]
  11.129 +        if opt[0] == '-F': config_from_file = True; domain_config = opt[1]
  11.130 +
  11.131 +
  11.132 +except getopt.GetoptError:
  11.133 +    bail=True
  11.134 +
  11.135 +if not config_from_file:
  11.136 +    try:
  11.137 +        os.stat( config_file )
  11.138 +    except:
  11.139 +        try:
  11.140 +            d = config_dir + config_file
  11.141 +            os.stat( d )
  11.142 +            config_file = d
  11.143 +        except:
  11.144 +            print >> sys.stderr, "Unable to open config file '%s'" % config_file
  11.145 +            bail = True
  11.146 +
  11.147 +
  11.148 +##### Parse the config file
  11.149 +#####
  11.150 +
  11.151 +if not config_from_file:
  11.152 +    if not quiet:
  11.153 +        print "Parsing config file '%s'" % config_file
  11.154 +
  11.155 +    try:
  11.156 +        execfile ( config_file )
  11.157 +    except (AssertionError,IOError):
  11.158 +        print >>sys.stderr,"Exiting %s" % sys.argv[0]
  11.159 +        bail = True
  11.160 +
  11.161 +##### Print out config if necessary 
  11.162 +##### 
  11.163 +
  11.164 +def bailout():
  11.165 +    global extrahelp
  11.166 +    main_usage()
  11.167 +    config_usage()
  11.168 +    if extrahelp: extra_usage()
  11.169 +    sys.exit(1)
  11.170 +
  11.171 +if bail:
  11.172 +    bailout()
  11.173 +
  11.174 +##### Parse any command line overrides 
  11.175 +##### 
  11.176 +
  11.177 +x_vbd_list = []
  11.178 +x_vfr_ipaddr  = []
  11.179 +
  11.180 +for opt in opts:
  11.181 +    if opt[0] == '-k': image = opt[1]
  11.182 +    if opt[0] == '-r': ramdisk = opt[1]
  11.183 +    if opt[0] == '-b': builder_fn = opt[1]  
  11.184 +    if opt[0] == '-m': mem_size = int(opt[1])
  11.185 +    if opt[0] == '-C': cpu = int(opt[1])
  11.186 +    if opt[0] == '-N': domain_name = opt[1]
  11.187 +    if opt[0] == '-a': auto_restart = answer(opt[1])
  11.188 +    if opt[0] == '-e': vbd_expert = opt[1]
  11.189 +    if opt[0] == '-I': cmdline_ip = opt[1]
  11.190 +    if opt[0] == '-R': cmdline_root = opt[1]
  11.191 +    if opt[0] == '-E': cmdline_extra = opt[1]
  11.192 +    if opt[0] == '-i': x_vfr_ipaddr.append(opt[1])
  11.193 +    if opt[0] == '-c': auto_console = True
  11.194 +    if opt[0] == '-d':
  11.195 +	try:
  11.196 +	    vv = string.split(opt[1],';')	    
  11.197 +	    for v in vv:
  11.198 +		(udisk,dev,mode) = string.split(v,',')
  11.199 +		x_vbd_list.append( (udisk,dev,mode) )
  11.200 +	except:
  11.201 +	    print >>sys.stderr, "Invalid block device specification : %s" % opt[1]
  11.202 +	    sys.exit(1)
  11.203 +
  11.204 +if x_vbd_list: vbd_list = x_vbd_list
  11.205 +if x_vfr_ipaddr: vfr_ipaddr = x_vfr_ipaddr
  11.206 +
  11.207 +syslog.openlog('xc_dom_create.py %s' % config_file, 0, syslog.LOG_DAEMON)
  11.208 +
  11.209 +def strip(pre, s):
  11.210 +    if s.startswith(pre):
  11.211 +        return s[len(pre):]
  11.212 +    else:
  11.213 +        return s
  11.214 +
  11.215 +def make_domain_config():
  11.216 +    global builder_fn, image, ramdisk, mem_size, domain_name
  11.217 +    global cpu
  11.218 +    global cmdline, cmdline_ip, cmdline_root
  11.219 +    global vfr_ipaddr, vbd_list, vbd_expert
  11.220 +    
  11.221 +    config = ['config',
  11.222 +              ['name', domain_name ],
  11.223 +              ['memory', mem_size ],
  11.224 +              ]
  11.225 +    if cpu:
  11.226 +        config.append(['cpu', cpu])
  11.227 +    
  11.228 +    config_image = [ builder_fn ]
  11.229 +    config_image.append([ 'kernel', os.path.abspath(image) ])
  11.230 +    if ramdisk:
  11.231 +        config_image.append([ 'ramdisk', os.path.abspath(ramdisk) ])
  11.232 +    if cmdline_ip:
  11.233 +        cmdline_ip = strip("ip=", cmdline_ip)
  11.234 +        config_image.append(['ip', cmdline_ip])
  11.235 +    if cmdline_root:
  11.236 +        cmdline_root = strip("root=", cmdline_root)
  11.237 +        config_image.append(['root', cmdline_root])
  11.238 +    if cmdline_extra:
  11.239 +        config_image.append(['args', cmdline_extra])
  11.240 +    config.append(['image', config_image ])
  11.241 +    	
  11.242 +    config_devs = []
  11.243 +    for (uname, dev, mode) in vbd_list:
  11.244 +        config_vbd = ['vbd',
  11.245 +                      ['uname', uname],
  11.246 +                      ['dev', dev ],
  11.247 +                      ['mode', mode ] ]
  11.248 +        if vbd_expert != 'rr':
  11.249 +            config_vbd.append(['sharing', vbd_expert])
  11.250 +        config_devs.append(['device', config_vbd])
  11.251 +
  11.252 +    for (bus, dev, func) in pci_device_list:
  11.253 +        config_pci = ['pci',
  11.254 +                      ['bus', bus ],
  11.255 +                      ['dev', dev ],
  11.256 +                      ['func', func] ]
  11.257 +        config_devs.append(['device', config_pci])
  11.258 +
  11.259 +    config += config_devs
  11.260 +    
  11.261 +    config_vfr = ['vfr']
  11.262 +    idx = 0 # No way of saying which IP is for which vif?
  11.263 +    for ip in vfr_ipaddr:
  11.264 +        config_vfr.append(['vif', ['id', idx], ['ip', ip]])
  11.265 +
  11.266 +    config.append(config_vfr)
  11.267 +    return config
  11.268 +
  11.269 +def parse_config_file(domain_file):
  11.270 +    config = None
  11.271 +    fin = None
  11.272 +    try:
  11.273 +        fin = file(domain_file, "rb")
  11.274 +        config = sxp.parse(fin)
  11.275 +        if len(config) >= 1:
  11.276 +            config = config[0]
  11.277 +        else:
  11.278 +            raise StandardError("Invalid configuration")
  11.279 +    except StandardError, ex:
  11.280 +        print >> sys.stderr, "Error :", ex
  11.281 +        sys.exit(1)
  11.282 +    #finally:
  11.283 +    if fin: fin.close()
  11.284 +    return config
  11.285 +
  11.286 +# This function creates, builds and starts a domain, using the values
  11.287 +# in the global variables, set above.  It is used in the subsequent
  11.288 +# code for starting the new domain and rebooting it if appropriate.
  11.289 +def make_domain(config):
  11.290 +    """Create, build and start a domain.
  11.291 +    Returns: [int] the ID of the new domain.
  11.292 +    """
  11.293 +    global restore
  11.294 +
  11.295 +    if restore:
  11.296 +        dominfo = server.xend_domain_restore(state_file, config)
  11.297 +    else:
  11.298 +        dominfo = server.xend_domain_create(config)
  11.299 +
  11.300 +    dom = int(sxp.child_value(dominfo, 'id'))
  11.301 +    console_info = sxp.child(dominfo, 'console')
  11.302 +    if console_info:
  11.303 +        console_port = int(sxp.child_value(console_info, 'port'))
  11.304 +    else:
  11.305 +        console_port = None
  11.306 +    
  11.307 +    if server.xend_domain_start(dom) < 0:
  11.308 +        print "Error starting domain"
  11.309 +        server.xend_domain_halt(dom)
  11.310 +        sys.exit()
  11.311 +
  11.312 +    return (dom, console_port)
  11.313 +
  11.314 +PID_DIR = '/var/run/xendomains/'
  11.315 +
  11.316 +def pidfile(dom):
  11.317 +    return PID_DIR + '%d.pid' % dom
  11.318 +
  11.319 +def mkpidfile():
  11.320 +    global current_id
  11.321 +    if not os.path.isdir(PID_DIR):
  11.322 +        os.mkdir(PID_DIR)
  11.323 +
  11.324 +    fd = open(pidfile(current_id), 'w')
  11.325 +    print >> fd, str(os.getpid())
  11.326 +    fd.close()
  11.327 +    return
  11.328 +
  11.329 +def rmpidfile():
  11.330 +    global current_id
  11.331 +    os.unlink(pidfile(current_id))
  11.332 +
  11.333 +def death_handler(dummy1,dummy2):
  11.334 +    global current_id
  11.335 +    os.unlink(pidfile(current_id))
  11.336 +    output('Auto-restart daemon: daemon PID = %d for domain %d is now exiting'
  11.337 +              % (os.getpid(), current_id))
  11.338 +    sys.exit(0)
  11.339 +    return
  11.340 +
  11.341 +#============================================================================
  11.342 +# The starting / monitoring of the domain actually happens here...
  11.343 +
  11.344 +if config_from_file:
  11.345 +    config = parse_config_file(domain_config)
  11.346 +else:
  11.347 +    config = make_domain_config()
  11.348 +
  11.349 +if dryrun:
  11.350 +    print "# %s" % ' '.join(sys.argv)
  11.351 +    PrettyPrint.prettyprint(config)
  11.352 +    sys.exit(0)
  11.353 +elif quiet:
  11.354 +    pass
  11.355 +else:
  11.356 +    PrettyPrint.prettyprint(config)
  11.357 +
  11.358 +# start the domain and record its ID number
  11.359 +(current_id, current_port) = make_domain(config)
  11.360 +
  11.361 +def start_msg(prefix, dom, port):
  11.362 +    output(prefix + "VM started in domain %d" % dom)
  11.363 +    if port:
  11.364 +        output(prefix + "Console I/O available on TCP port %d." % port)
  11.365 +
  11.366 +start_msg('', current_id, current_port)
  11.367 +
  11.368 +if current_port and auto_console:
  11.369 +    xenctl.console_client.connect('127.0.0.1', current_port)
  11.370 +
  11.371 +# if the auto_restart flag is set then keep polling to see if the domain is
  11.372 +# alive - restart if it is not by calling make_domain() again (it's necessary
  11.373 +# to update the id variable, since the new domain may have a new ID)
  11.374 +
  11.375 +#todo: Replace this - get xend to watch them.
  11.376 +if auto_restart:
  11.377 +    ARD = "Auto-restart daemon: "
  11.378 +    # turn ourselves into a background daemon
  11.379 +    try:
  11.380 +	pid = os.fork()
  11.381 +	if pid > 0:
  11.382 +	    sys.exit(0)
  11.383 +	os.setsid()
  11.384 +	pid = os.fork()
  11.385 +	if pid > 0:
  11.386 +            output(ARD + 'PID = %d' % pid)
  11.387 +	    sys.exit(0)
  11.388 +        signal.signal(signal.SIGTERM,death_handler)
  11.389 +    except OSError:
  11.390 +	print >> sys.stderr, ARD+'Startup failed'
  11.391 +	sys.exit(1)
  11.392 +
  11.393 +    mkpidfile()
  11.394 +
  11.395 +    while True:
  11.396 +	time.sleep(1)
  11.397 +        # todo: use new interface
  11.398 +        info = xc.domain_getinfo(current_id, 1)
  11.399 +	if info == [] or info[0]['dom'] != current_id:
  11.400 +	    output(ARD + "Domain %d terminated, restarting VM in new domain"
  11.401 +                                     % current_id)
  11.402 +            rmpidfile()
  11.403 +	    (current_id, current_port) = make_domain()
  11.404 +            mkpidfile()
  11.405 +            start_msg(ARD, current_id, current_port)
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tools/examples/xm_vd_tool.py	Fri Jun 11 22:04:24 2004 +0000
    12.3 @@ -0,0 +1,157 @@
    12.4 +#!/usr/bin/env python
    12.5 +
    12.6 +import sys
    12.7 +import re
    12.8 +import string
    12.9 +
   12.10 +from xenctl import vdisk
   12.11 +
   12.12 +def usage():
   12.13 +
   12.14 +    print >>sys.stderr,"""
   12.15 +Usage: %s command <params>
   12.16 +
   12.17 +  initialise [dev] [[ext_size]] - init. a physcial partition to store vd's
   12.18 +  create [size] [[expiry]]      - allocate a vd of specified size (and expiry)
   12.19 +  enlarge [vdid] [extra_size]   - enlarge a specified vd by some amount
   12.20 +  delete [vdid]                 - delete a vd
   12.21 +  import [filename] [[expiry]]  - create a vd and populate w/ image from file
   12.22 +  export [vdid] [filename]      - copy vd's contents to a file
   12.23 +  setexpiry [vdid] [[expiry]]   - update the expiry time for a vd
   12.24 +  list                          - list all the unexpired virtual disks  
   12.25 +  undelete [vdid] [[expiry]]    - attempts to recover an expired vd
   12.26 +  freespace                     - print out the amount of space in free pool
   12.27 +
   12.28 +notes:
   12.29 +  vdid      - the virtual disk's identity string
   12.30 +  size      - measured in MB
   12.31 +  expiry    - is the expiry time of the virtual disk in seconds from now
   12.32 +               (0 = don't expire) 
   12.33 +  device    - physical partition to 'format' to hold vd's. e.g. hda4
   12.34 +  ext_size  - extent size (default 64MB)
   12.35 +""" % sys.argv[0]  
   12.36 +
   12.37 +if len(sys.argv) < 2: 
   12.38 +    usage()
   12.39 +    sys.exit(-1)
   12.40 +
   12.41 +rc=''
   12.42 +src=''
   12.43 +expiry_time = 0
   12.44 +cmd = sys.argv[1]
   12.45 +
   12.46 +if cmd == 'initialise':
   12.47 +
   12.48 +    dev = sys.argv[2]
   12.49 +
   12.50 +    if len(sys.argv) > 3:
   12.51 +	extent_size = int(sys.argv[3])
   12.52 +    else:
   12.53 +	print """No extent size specified - using default size of 64MB"""
   12.54 +	extent_size = 64
   12.55 +
   12.56 +    print "Formatting for virtual disks"
   12.57 +    print "Device: " + dev
   12.58 +    print "Extent size: " + str(extent_size) + "MB"
   12.59 +
   12.60 +    rc = vdisk.vd_format(dev, extent_size)
   12.61 +
   12.62 +elif cmd == 'create':
   12.63 + 
   12.64 +    size = int(sys.argv[2])
   12.65 +    
   12.66 +    if len(sys.argv) > 3:
   12.67 +	expiry_time = int(sys.argv[3])
   12.68 +
   12.69 +    print "Creating a virtual disk"
   12.70 +    print "Size: %d" % size
   12.71 +    print "Expiry time (seconds from now): %d" % expiry_time
   12.72 +
   12.73 +    src = vdisk.vd_create(size, expiry_time)
   12.74 +
   12.75 +elif cmd == 'enlarge':
   12.76 +
   12.77 +    id = sys.argv[2]
   12.78 +
   12.79 +    extra_size = int(sys.argv[3])
   12.80 +
   12.81 +    rc = vdisk.vd_enlarge(id, extra_size)
   12.82 +
   12.83 +elif cmd == 'delete':
   12.84 +
   12.85 +    id = sys.argv[2]
   12.86 +
   12.87 +    print "Deleting a virtual disk with ID: " + id
   12.88 +
   12.89 +    rc = vdisk.vd_delete(id)
   12.90 +
   12.91 +elif cmd == 'import':
   12.92 +
   12.93 +    file = sys.argv[2]
   12.94 +    
   12.95 +    if len(sys.argv) > 3:
   12.96 +	expiry_time = int(sys.argv[3])
   12.97 +
   12.98 +    print "Allocate new virtual disk and populate from file : %s" % file
   12.99 +
  12.100 +    print vdisk.vd_read_from_file(file, expiry_time)
  12.101 +
  12.102 +elif cmd == 'export':
  12.103 +
  12.104 +    id = sys.argv[2]
  12.105 +    file = sys.argv[3]
  12.106 +
  12.107 +    print "Dump contents of virtual disk to file : %s" % file
  12.108 +
  12.109 +    rc = vdisk.vd_cp_to_file(id, file )
  12.110 +
  12.111 +elif cmd == 'setexpiry':
  12.112 +
  12.113 +    id = sys.argv[2]
  12.114 +
  12.115 +    if len(sys.argv) > 3:
  12.116 +	expiry_time = int(sys.argv[3])
  12.117 +
  12.118 +    print "Refreshing a virtual disk"
  12.119 +    print "Id: " + id
  12.120 +    print "Expiry time (seconds from now [or 0]): " + str(expiry_time)
  12.121 +
  12.122 +    rc = vdisk.vd_refresh(id, expiry_time)
  12.123 +
  12.124 +elif cmd == 'list':
  12.125 +    print 'ID    Size(MB)      Expiry'
  12.126 +
  12.127 +    for vbd in vdisk.vd_list():
  12.128 +        vbd['size_mb'] = vbd['size'] / vdisk.VBD_SECTORS_PER_MB
  12.129 +        vbd['expiry'] = (vbd['expires'] and vbd['expiry_time']) or 'never'
  12.130 +        print '%(vdisk_id)-4s  %(size_mb)-12d  %(expiry)s' % vbd
  12.131 +
  12.132 +elif cmd == 'freespace':
  12.133 +
  12.134 +    print vdisk.vd_freespace()
  12.135 +
  12.136 +elif cmd == 'undelete':
  12.137 +
  12.138 +    id = sys.argv[2]
  12.139 +
  12.140 +    if len(sys.argv) > 3:
  12.141 +	expiry_time = int(sys.argv[3])
  12.142 +   
  12.143 +    if vdisk.vd_undelete(id, expiry_time):
  12.144 +	print "Undelete operation failed for virtual disk: " + id
  12.145 +    else:
  12.146 +	print "Undelete operation succeeded for virtual disk: " + id
  12.147 +
  12.148 +else:
  12.149 +    usage()
  12.150 +    sys.exit(-1)
  12.151 +
  12.152 +
  12.153 +if src != '':  
  12.154 +    print "Returned virtual disk id is : %s" % src
  12.155 +
  12.156 +if rc != '':
  12.157 +    print "return code %d" % rc
  12.158 +
  12.159 +
  12.160 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/tools/xenctl/lib/ip.py	Fri Jun 11 22:04:24 2004 +0000
    13.3 @@ -0,0 +1,95 @@
    13.4 +import os
    13.5 +import re
    13.6 +import socket
    13.7 +import struct
    13.8 +
    13.9 +##### Networking-related functions
   13.10 +
   13.11 +def get_current_ipaddr(dev='eth0'):
   13.12 +    """Return a string containing the primary IP address for the given
   13.13 +    network interface (default 'eth0').
   13.14 +    """
   13.15 +    fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
   13.16 +    lines = readlines(fd)
   13.17 +    for line in lines:
   13.18 +        m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
   13.19 +                       line )
   13.20 +        if m:
   13.21 +            return m.group(1)
   13.22 +    return None
   13.23 +
   13.24 +def get_current_ipmask(dev='eth0'):
   13.25 +    """Return a string containing the primary IP netmask for the given
   13.26 +    network interface (default 'eth0').
   13.27 +    """
   13.28 +    fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
   13.29 +    lines = readlines(fd)
   13.30 +    for line in lines:
   13.31 +        m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
   13.32 +                       line )
   13.33 +        if m:
   13.34 +            return m.group(1)
   13.35 +    return None
   13.36 +
   13.37 +def get_current_ipgw(dev='eth0'):
   13.38 +    """Return a string containing the IP gateway for the given
   13.39 +    network interface (default 'eth0').
   13.40 +    """
   13.41 +    fd = os.popen( '/sbin/route -n' )
   13.42 +    lines = readlines(fd)
   13.43 +    for line in lines:
   13.44 +        m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
   13.45 +                       '\s+\S+\s+\S*G.*' + dev + '.*', line )
   13.46 +        if m:
   13.47 +            return m.group(1)
   13.48 +    return None
   13.49 +
   13.50 +def setup_vfr_rules_for_vif(dom,vif,addr):
   13.51 +    """Takes a tuple ( domain-id, vif-id, ip-addr ), where the ip-addr
   13.52 +    is expressed as a textual dotted quad, and set up appropriate routing
   13.53 +    rules in Xen. No return value.
   13.54 +    """
   13.55 +    fd = os.open( '/proc/xen/vfr', os.O_WRONLY )
   13.56 +    if ( re.search( '169\.254', addr) ):
   13.57 +        os.write( fd, 'ADD ACCEPT srcaddr=' + addr +
   13.58 +                  ' srcaddrmask=255.255.255.255' +
   13.59 +                  ' srcdom=' + str(dom) + ' srcidx=' + str(vif) +
   13.60 +                  ' dstdom=0 dstidx=0 proto=any\n' )
   13.61 +    else:
   13.62 +        os.write( fd, 'ADD ACCEPT srcaddr=' + addr +
   13.63 +                  ' srcaddrmask=255.255.255.255' +
   13.64 +                  ' srcdom=' + str(dom) + ' srcidx=' + str(vif) +
   13.65 +                  ' dst=PHYS proto=any\n' )
   13.66 +    os.write( fd, 'ADD ACCEPT dstaddr=' + addr +
   13.67 +              ' dstaddrmask=255.255.255.255' +
   13.68 +              ' src=ANY' +
   13.69 +              ' dstdom=' + str(dom) + ' dstidx=' + str(vif) +
   13.70 +              ' proto=any\n' )
   13.71 +    os.close( fd )
   13.72 +    return None
   13.73 +
   13.74 +def inet_aton(addr):
   13.75 +    """Convert an IP addr in IPv4 dot notation into an int.
   13.76 +    """
   13.77 +    b = socket.inet_aton(addr)
   13.78 +    return struct.unpack('!I', b)[0]
   13.79 +
   13.80 +def inet_ntoa(n):
   13.81 +    """Convert an int into an IP addr in IPv4 dot notation.
   13.82 +    """
   13.83 +    b = struct.pack('!I', n)
   13.84 +    return socket.inet_ntoa(b)
   13.85 +
   13.86 +def add_offset_to_ip(addr, offset):
   13.87 +    """Add a numerical offset to an IP addr in IPv4 dot notation.
   13.88 +    """
   13.89 +    n = inet_aton(addr)
   13.90 +    n += offset
   13.91 +    return inet_ntoa(n)
   13.92 +
   13.93 +def check_subnet( ip, network, netmask ):
   13.94 +    n_ip = inet_aton(ip)
   13.95 +    n_net = inet_aton(network)
   13.96 +    n_mask = inet_aton(netmask)
   13.97 +    return (n_ip & n_mask) == (n_net & n_mask)
   13.98 +
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/tools/xenctl/lib/vdisk.py	Fri Jun 11 22:04:24 2004 +0000
    14.3 @@ -0,0 +1,944 @@
    14.4 +import os
    14.5 +import re
    14.6 +import socket
    14.7 +import string
    14.8 +import sys
    14.9 +import tempfile
   14.10 +import struct
   14.11 +
   14.12 +##### Module variables
   14.13 +
   14.14 +"""Location of the Virtual Disk management database.
   14.15 +   defaults to /var/db/xen_vdisks.sqlite
   14.16 +"""
   14.17 +VD_DB_FILE = "/var/db/xen_vdisks.sqlite"
   14.18 +
   14.19 +"""VBD expertise level - determines the strictness of the sanity checking.
   14.20 +  This mode determines the level of complaints when disk sharing occurs
   14.21 +  through the current VBD mappings.
   14.22 +   0 - only allow shared mappings if both domains have r/o access (always OK)
   14.23 +   1 - also allow sharing with one dom r/w and the other r/o
   14.24 +   2 - allow sharing with both doms r/w
   14.25 +"""
   14.26 +VBD_SAFETY_RR = 0
   14.27 +VBD_SAFETY_RW = 1
   14.28 +VBD_SAFETY_WW = 2
   14.29 +
   14.30 +VBD_SECTORS_PER_MB = 2048
   14.31 +
   14.32 +##### Module initialisation
   14.33 +
   14.34 +try:
   14.35 +    # try to import sqlite (not everyone will have it installed)
   14.36 +    import sqlite
   14.37 +except ImportError:
   14.38 +    # on failure, just catch the error, don't do anything
   14.39 +    pass
   14.40 +
   14.41 +
   14.42 +
   14.43 +##### VBD-related Functions
   14.44 +
   14.45 +def blkdev_name_to_number(name):
   14.46 +    """Take the given textual block-device name (e.g., '/dev/sda1',
   14.47 +    'hda') and return the device number used by the OS. """
   14.48 +
   14.49 +    if not re.match( '/dev/', name ):
   14.50 +        name = '/dev/' + name
   14.51 +        
   14.52 +    return os.stat(name).st_rdev
   14.53 +
   14.54 +# lookup_blkdev_partn_info( '/dev/sda3' )
   14.55 +def lookup_raw_partn(partition):
   14.56 +    """Take the given block-device name (e.g., '/dev/sda1', 'hda')
   14.57 +    and return a dictionary { device, start_sector,
   14.58 +    nr_sectors, type }
   14.59 +        device:       Device number of the given partition
   14.60 +        start_sector: Index of first sector of the partition
   14.61 +        nr_sectors:   Number of sectors comprising this partition
   14.62 +        type:         'Disk' or identifying name for partition type
   14.63 +    """
   14.64 +
   14.65 +    if not re.match( '/dev/', partition ):
   14.66 +        partition = '/dev/' + partition
   14.67 +
   14.68 +    drive = re.split( '[0-9]', partition )[0]
   14.69 +
   14.70 +    if drive == partition:
   14.71 +        fd = os.popen( '/sbin/sfdisk -s ' + drive + ' 2>/dev/null' )
   14.72 +        line = readline(fd)
   14.73 +        if line:
   14.74 +            return [ { 'device' : blkdev_name_to_number(drive),
   14.75 +                       'start_sector' : long(0),
   14.76 +                       'nr_sectors' : long(line) * 2,
   14.77 +                       'type' : 'Disk' } ]
   14.78 +        return None
   14.79 +
   14.80 +    # determine position on disk
   14.81 +    fd = os.popen( '/sbin/sfdisk -d ' + drive + ' 2>/dev/null' )
   14.82 +
   14.83 +    #['/dev/sda3 : start= 16948575, size=16836120, Id=83, bootable\012']
   14.84 +    lines = readlines(fd)
   14.85 +    for line in lines:
   14.86 +        m = re.search( '^' + partition + '\s*: start=\s*([0-9]+), ' +
   14.87 +                       'size=\s*([0-9]+), Id=\s*(\S+).*$', line)
   14.88 +        if m:
   14.89 +            return [ { 'device' : blkdev_name_to_number(drive),
   14.90 +                       'start_sector' : long(m.group(1)),
   14.91 +                       'nr_sectors' : long(m.group(2)),
   14.92 +                       'type' : m.group(3) } ]
   14.93 +    
   14.94 +    return None
   14.95 +
   14.96 +def lookup_disk_uname( uname ):
   14.97 +    """Lookup a list of segments for either a physical or a virtual device.
   14.98 +    uname [string]:  name of the device in the format \'vd:id\' for a virtual
   14.99 +                     disk, or \'phy:dev\' for a physical device
  14.100 +    returns [list of dicts]: list of extents that make up the named device
  14.101 +    """
  14.102 +    ( type, d_name ) = string.split( uname, ':' )
  14.103 +
  14.104 +    if type == "phy":
  14.105 +        segments = lookup_raw_partn( d_name )
  14.106 +    elif type == "vd":
  14.107 +	segments = vd_lookup( d_name )
  14.108 +
  14.109 +    return segments
  14.110 +
  14.111 +
  14.112 +##### VD Management-related functions
  14.113 +
  14.114 +##### By Mark Williamson, <mark.a.williamson@intel.com>
  14.115 +##### (C) Intel Research Cambridge
  14.116 +
  14.117 +# TODO:
  14.118 +#
  14.119 +# Plenty of room for enhancement to this functionality (contributions
  14.120 +# welcome - and then you get to have your name in the source ;-)...
  14.121 +#
  14.122 +# vd_unformat() : want facilities to unallocate virtual disk
  14.123 +# partitions, possibly migrating virtual disks of them, with checks to see if
  14.124 +# it's safe and options to force it anyway
  14.125 +#
  14.126 +# vd_create() : should have an optional argument specifying a physical
  14.127 +# disk preference - useful to allocate for guest doms to do RAID
  14.128 +#
  14.129 +# vd_undelete() : add ability to "best effort" undelete as much of a
  14.130 +# vdisk as is left in the case that some of it has already been
  14.131 +# reallocated.  Some people might still be able to recover some of
  14.132 +# their data this way, even if some of the disk has disappeared.
  14.133 +#
  14.134 +# It'd be nice if we could wipe virtual disks for security purposes -
  14.135 +# should be easy to do this using dev if=/dev/{zero,random} on each
  14.136 +# extent in turn.  There could be another optional flag to vd_create
  14.137 +# in order to allow this.
  14.138 +#
  14.139 +# Error codes could be more expressive - i.e. actually tell why the
  14.140 +# error occurred rather than "it broke".  Currently the code avoids
  14.141 +# using exceptions to make control scripting simpler and more
  14.142 +# accessible to beginners - therefore probably should just use more
  14.143 +# return codes.
  14.144 +#
  14.145 +# Enhancements / additions to the example scripts are also welcome:
  14.146 +# some people will interact with this code mostly through those
  14.147 +# scripts.
  14.148 +#
  14.149 +# More documentation of how this stuff should be used is always nice -
  14.150 +# if you have a novel configuration that you feel isn't discussed
  14.151 +# enough in the HOWTO (which is currently a work in progress), feel
  14.152 +# free to contribute a walkthrough, or something more substantial.
  14.153 +#
  14.154 +
  14.155 +
  14.156 +def __vd_no_database():
  14.157 +    """Called when no database found - exits with an error
  14.158 +    """
  14.159 +    print >> sys.stderr, "ERROR: Could not locate the database file at " + VD_DB_FILE
  14.160 +    sys.exit(1)
  14.161 +
  14.162 +def readlines(fd):
  14.163 +    """Version of readlines safe against EINTR.
  14.164 +    """
  14.165 +    import errno
  14.166 +    
  14.167 +    lines = []
  14.168 +    while 1:
  14.169 +        try:
  14.170 +            line = fd.readline()
  14.171 +        except IOError, ex:
  14.172 +            if ex.errno == errno.EINTR:
  14.173 +                continue
  14.174 +            else:
  14.175 +                raise
  14.176 +        if line == '': break
  14.177 +        lines.append(line)
  14.178 +    return lines
  14.179 +
  14.180 +def readline(fd):
  14.181 +    """Version of readline safe against EINTR.
  14.182 +    """
  14.183 +    while 1:
  14.184 +        try:
  14.185 +            return fd.readline()
  14.186 +        except IOError, ex:
  14.187 +            if ex.errno == errno.EINTR:
  14.188 +                continue
  14.189 +            else:
  14.190 +                raise
  14.191 +        
  14.192 +
  14.193 +def vd_format(partition, extent_size_mb):
  14.194 +    """Format a partition or drive for use a virtual disk storage.
  14.195 +    partition [string]: device file representing the partition
  14.196 +    extent_size_mb [string]: extent size in megabytes to use on this disk
  14.197 +    """
  14.198 +
  14.199 +    if not os.path.isfile(VD_DB_FILE):
  14.200 +        vd_init_db(VD_DB_FILE)
  14.201 +    
  14.202 +    if not re.match( '/dev/', partition ):
  14.203 +        partition = '/dev/' + partition
  14.204 +
  14.205 +    cx = sqlite.connect(VD_DB_FILE)
  14.206 +    cu = cx.cursor()
  14.207 +
  14.208 +    cu.execute("select * from vdisk_part where partition = \'"
  14.209 +               + partition + "\'")
  14.210 +    row = cu.fetchone()
  14.211 +
  14.212 +    extent_size = extent_size_mb * VBD_SECTORS_PER_MB # convert megabytes to sectors
  14.213 +    
  14.214 +    if not row:
  14.215 +        part_info = lookup_raw_partn(partition)[0]
  14.216 +        
  14.217 +        cu.execute("INSERT INTO vdisk_part(partition, part_id, extent_size) " +
  14.218 +                   "VALUES ( \'" + partition + "\', "
  14.219 +                   + str(blkdev_name_to_number(partition))
  14.220 +                   + ", " + str(extent_size) + ")")
  14.221 +
  14.222 +
  14.223 +        cu.execute("SELECT max(vdisk_extent_no) FROM vdisk_extents "
  14.224 +                   + "WHERE vdisk_id = 0")
  14.225 +        
  14.226 +        max_id, = cu.fetchone()
  14.227 +
  14.228 +        if max_id != None:
  14.229 +            new_id = max_id + 1
  14.230 +        else:
  14.231 +            new_id = 0
  14.232 +
  14.233 +        num_extents = part_info['nr_sectors'] / extent_size
  14.234 +
  14.235 +        for i in range(num_extents):
  14.236 +            sql ="""INSERT INTO vdisk_extents(vdisk_extent_no, vdisk_id,
  14.237 +                                              part_id, part_extent_no)
  14.238 +                    VALUES ("""+ str(new_id + i) + ", 0, "\
  14.239 +                               + str(blkdev_name_to_number(partition))\
  14.240 +                               + ", " + str(num_extents - (i + 1)) + ")"
  14.241 +            cu.execute(sql)
  14.242 +
  14.243 +    cx.commit()
  14.244 +    cx.close()
  14.245 +    return 0
  14.246 +
  14.247 +
  14.248 +def vd_create(size_mb, expiry):
  14.249 +    """Create a new virtual disk.
  14.250 +    size_mb [int]: size in megabytes for the new virtual disk
  14.251 +    expiry [int]: expiry time in seconds from now
  14.252 +    """
  14.253 +
  14.254 +    if not os.path.isfile(VD_DB_FILE):
  14.255 +        __vd_no_database()
  14.256 +
  14.257 +    cx = sqlite.connect(VD_DB_FILE)
  14.258 +    cu = cx.cursor()
  14.259 +
  14.260 +    size = size_mb * VBD_SECTORS_PER_MB
  14.261 +
  14.262 +    cu.execute("SELECT max(vdisk_id) FROM vdisks")
  14.263 +    max_id, = cu.fetchone()
  14.264 +    new_id = int(max_id) + 1
  14.265 +
  14.266 +    # fetch a list of extents from the expired disks, along with information
  14.267 +    # about their size
  14.268 +    cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
  14.269 +                         vdisk_extents.part_id, extent_size
  14.270 +                  FROM vdisks NATURAL JOIN vdisk_extents
  14.271 +                                                  NATURAL JOIN vdisk_part
  14.272 +                  WHERE expires AND expiry_time <= datetime('now')
  14.273 +                  ORDER BY expiry_time ASC, vdisk_extent_no DESC
  14.274 +               """)  # aims to reuse the last extents
  14.275 +                     # from the longest-expired disks first
  14.276 +
  14.277 +    allocated = 0
  14.278 +
  14.279 +    if expiry:
  14.280 +        expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
  14.281 +        expires = 1
  14.282 +    else:
  14.283 +        expiry_ts = "NULL"
  14.284 +        expires = 0
  14.285 +
  14.286 +    # we'll use this to build the SQL statement we want
  14.287 +    building_sql = "INSERT INTO vdisks(vdisk_id, size, expires, expiry_time)" \
  14.288 +                   +" VALUES ("+str(new_id)+", "+str(size)+ ", "              \
  14.289 +                   + str(expires) + ", " + expiry_ts + "); "
  14.290 +
  14.291 +    counter = 0
  14.292 +
  14.293 +    while allocated < size:
  14.294 +        row = cu.fetchone()
  14.295 +        if not row:
  14.296 +            print "ran out of space, having allocated %d meg of %d" % (allocated, size)
  14.297 +            cx.close()
  14.298 +            return -1
  14.299 +        
  14.300 +
  14.301 +        (vdisk_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
  14.302 +        allocated += extent_size
  14.303 +        building_sql += "UPDATE vdisk_extents SET vdisk_id = " + str(new_id) \
  14.304 +                        + ", " + "vdisk_extent_no = " + str(counter)         \
  14.305 +                        + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
  14.306 +                        + " AND vdisk_id = " + str(vdisk_id) + "; "
  14.307 +
  14.308 +        counter += 1
  14.309 +        
  14.310 +
  14.311 +    # this will execute the SQL query we build to store details of the new
  14.312 +    # virtual disk and allocate space to it print building_sql
  14.313 +    cu.execute(building_sql)
  14.314 +    
  14.315 +    cx.commit()
  14.316 +    cx.close()
  14.317 +    return str(new_id)
  14.318 +
  14.319 +
  14.320 +def vd_lookup(id):
  14.321 +    """Lookup a Virtual Disk by ID.
  14.322 +    id [string]: a virtual disk identifier
  14.323 +    Returns [list of dicts]: a list of extents as dicts, containing fields:
  14.324 +                             device : Linux device number of host disk
  14.325 +                             start_sector : within the device
  14.326 +                             nr_sectors : size of this extent
  14.327 +                             type : set to \'VD Extent\'
  14.328 +                             
  14.329 +                             part_device : Linux device no of host partition
  14.330 +                             part_start_sector : within the partition
  14.331 +    """
  14.332 +
  14.333 +    if not os.path.isfile(VD_DB_FILE):
  14.334 +        __vd_no_database()
  14.335 +
  14.336 +    cx = sqlite.connect(VD_DB_FILE)
  14.337 +    cu = cx.cursor()
  14.338 +
  14.339 +    cu.execute("-- types int")
  14.340 +    cu.execute("""SELECT COUNT(*)
  14.341 +                  FROM vdisks
  14.342 +                  WHERE (expiry_time > datetime('now') OR NOT expires)
  14.343 +                              AND vdisk_id = """ + id)
  14.344 +    count, = cu.fetchone()
  14.345 +
  14.346 +    if not count:
  14.347 +        cx.close()
  14.348 +        return None
  14.349 +
  14.350 +    cu.execute("SELECT size from vdisks WHERE vdisk_id = " + id)
  14.351 +    real_size, = cu.fetchone()
  14.352 +  
  14.353 +    # This query tells PySQLite how to convert the data returned from the
  14.354 +    # following query - the use of the multiplication confuses it otherwise ;-)
  14.355 +    # This row is significant to PySQLite but is syntactically an SQL comment.
  14.356 +
  14.357 +    cu.execute("-- types str, int, int, int")
  14.358 +
  14.359 +    # This SQL statement is designed so that when the results are fetched they
  14.360 +    # will be in the right format to return immediately.
  14.361 +    cu.execute("""SELECT partition, vdisk_part.part_id,
  14.362 +                         round(part_extent_no * extent_size) as start,
  14.363 +                         extent_size
  14.364 +                         
  14.365 +                  FROM vdisks NATURAL JOIN vdisk_extents
  14.366 +                                             NATURAL JOIN vdisk_part
  14.367 +                                                
  14.368 +                  WHERE vdisk_extents.vdisk_id = """ + id
  14.369 +               + " ORDER BY vdisk_extents.vdisk_extent_no ASC"
  14.370 +               )
  14.371 +
  14.372 +    extent_tuples = cu.fetchall()
  14.373 +
  14.374 +    # use this function to map the results from the database into a dict
  14.375 +    # list of extents, for consistency with the rest of the code
  14.376 +    def transform ((partition, part_device, part_offset, nr_sectors)):
  14.377 +        return {
  14.378 +                 # the disk device this extent is on - for passing to Xen
  14.379 +                 'device' : lookup_raw_partn(partition)[0]['device'],
  14.380 +                 # the offset of this extent within the disk - for passing to Xen
  14.381 +                 'start_sector' : long(part_offset + lookup_raw_partn(partition)[0]['start_sector']),
  14.382 +                 # extent size, in sectors
  14.383 +                 'nr_sectors' : nr_sectors,
  14.384 +                 # partition device this extent is on (useful to know for xenctl.utils fns)
  14.385 +                 'part_device' : part_device,
  14.386 +                 # start sector within this partition (useful to know for xenctl.utils fns)
  14.387 +                 'part_start_sector' : part_offset,
  14.388 +                 # type of this extent - handy to know
  14.389 +                 'type' : 'VD Extent' }
  14.390 +
  14.391 +    cx.commit()
  14.392 +    cx.close()
  14.393 +
  14.394 +    extent_dicts = map(transform, extent_tuples)
  14.395 +
  14.396 +    # calculate the over-allocation in sectors (happens because
  14.397 +    # we allocate whole extents)
  14.398 +    allocated_size = 0
  14.399 +    for i in extent_dicts:
  14.400 +        allocated_size += i['nr_sectors']
  14.401 +
  14.402 +    over_allocation = allocated_size - real_size
  14.403 +
  14.404 +    # trim down the last extent's length so the resulting VBD will be the
  14.405 +    # size requested, rather than being rounded up to the nearest extent
  14.406 +    extent_dicts[len(extent_dicts) - 1]['nr_sectors'] -= over_allocation
  14.407 +
  14.408 +    return extent_dicts
  14.409 +
  14.410 +
  14.411 +def vd_enlarge(vdisk_id, extra_size_mb):
  14.412 +    """Create a new virtual disk.
  14.413 +    vdisk_id [string]   :    ID of the virtual disk to enlarge
  14.414 +    extra_size_mb  [int]:    size in megabytes to increase the allocation by
  14.415 +    returns  [int]      :    0 on success, otherwise non-zero
  14.416 +    """
  14.417 +
  14.418 +    if not os.path.isfile(VD_DB_FILE):
  14.419 +        __vd_no_database()
  14.420 +
  14.421 +    cx = sqlite.connect(VD_DB_FILE)
  14.422 +    cu = cx.cursor()
  14.423 +
  14.424 +    extra_size = extra_size_mb * VBD_SECTORS_PER_MB
  14.425 +
  14.426 +    cu.execute("-- types int")
  14.427 +    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id
  14.428 +               + " AND (expiry_time > datetime('now') OR NOT expires)")
  14.429 +    count, = cu.fetchone()
  14.430 +
  14.431 +    if not count: # no such vdisk
  14.432 +        cx.close()
  14.433 +        return -1
  14.434 +
  14.435 +    cu.execute("-- types int")
  14.436 +    cu.execute("""SELECT SUM(extent_size)
  14.437 +                  FROM vdisks NATURAL JOIN vdisk_extents
  14.438 +                                         NATURAL JOIN vdisk_part
  14.439 +                  WHERE vdisks.vdisk_id = """ + vdisk_id)
  14.440 +
  14.441 +    real_size, = cu.fetchone() # get the true allocated size
  14.442 +
  14.443 +    cu.execute("-- types int")
  14.444 +    cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id)
  14.445 +
  14.446 +    old_size, = cu.fetchone()
  14.447 +
  14.448 +
  14.449 +    cu.execute("--- types int")
  14.450 +    cu.execute("""SELECT MAX(vdisk_extent_no)
  14.451 +                  FROM vdisk_extents
  14.452 +                  WHERE vdisk_id = """ + vdisk_id)
  14.453 +
  14.454 +    counter = cu.fetchone()[0] + 1 # this stores the extent numbers
  14.455 +
  14.456 +
  14.457 +    # because of the extent-based allocation, the VD may already have more
  14.458 +    # allocated space than they asked for.  Find out how much we really
  14.459 +    # need to add.
  14.460 +    add_size = extra_size + old_size - real_size
  14.461 +
  14.462 +    # fetch a list of extents from the expired disks, along with information
  14.463 +    # about their size
  14.464 +    cu.execute("""SELECT vdisks.vdisk_id, vdisk_extent_no, part_extent_no,
  14.465 +                         vdisk_extents.part_id, extent_size
  14.466 +                  FROM vdisks NATURAL JOIN vdisk_extents
  14.467 +                                                  NATURAL JOIN vdisk_part
  14.468 +                  WHERE expires AND expiry_time <= datetime('now')
  14.469 +                  ORDER BY expiry_time ASC, vdisk_extent_no DESC
  14.470 +               """)  # aims to reuse the last extents
  14.471 +                     # from the longest-expired disks first
  14.472 +
  14.473 +    allocated = 0
  14.474 +
  14.475 +    building_sql = "UPDATE vdisks SET size = " + str(old_size + extra_size)\
  14.476 +                   + " WHERE vdisk_id = " + vdisk_id + "; "
  14.477 +
  14.478 +    while allocated < add_size:
  14.479 +        row = cu.fetchone()
  14.480 +        if not row:
  14.481 +            cx.close()
  14.482 +            return -1
  14.483 +
  14.484 +        (dead_vd_id, vdisk_extent_no, part_extent_no, part_id, extent_size) = row
  14.485 +        allocated += extent_size
  14.486 +        building_sql += "UPDATE vdisk_extents SET vdisk_id = " + vdisk_id    \
  14.487 +                        + ", " + "vdisk_extent_no = " + str(counter)         \
  14.488 +                        + " WHERE vdisk_extent_no = " + str(vdisk_extent_no) \
  14.489 +                        + " AND vdisk_id = " + str(dead_vd_id) + "; "
  14.490 +
  14.491 +        counter += 1
  14.492 +        
  14.493 +
  14.494 +    # this will execute the SQL query we build to store details of the new
  14.495 +    # virtual disk and allocate space to it print building_sql
  14.496 +    cu.execute(building_sql)
  14.497 +    
  14.498 +    cx.commit()
  14.499 +    cx.close()
  14.500 +    return 0
  14.501 +
  14.502 +
  14.503 +def vd_undelete(vdisk_id, expiry_time):
  14.504 +    """Create a new virtual disk.
  14.505 +    vdisk_id      [int]: size in megabytes for the new virtual disk
  14.506 +    expiry_time   [int]: expiry time, in seconds from now
  14.507 +    returns       [int]: zero on success, non-zero on failure
  14.508 +    """
  14.509 +
  14.510 +    if not os.path.isfile(VD_DB_FILE):
  14.511 +        __vd_no_database()
  14.512 +
  14.513 +    if vdisk_id == '0': #  undeleting vdisk 0 isn't sane!
  14.514 +        return -1
  14.515 +
  14.516 +    cx = sqlite.connect(VD_DB_FILE)
  14.517 +    cu = cx.cursor()
  14.518 +
  14.519 +    cu.execute("-- types int")
  14.520 +    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + vdisk_id)
  14.521 +    count, = cu.fetchone()
  14.522 +
  14.523 +    if not count:
  14.524 +        cx.close()
  14.525 +        return -1
  14.526 +
  14.527 +    cu.execute("-- types int")
  14.528 +    cu.execute("""SELECT SUM(extent_size)
  14.529 +                  FROM vdisks NATURAL JOIN vdisk_extents
  14.530 +                                         NATURAL JOIN vdisk_part
  14.531 +                  WHERE vdisks.vdisk_id = """ + vdisk_id)
  14.532 +
  14.533 +    real_size, = cu.fetchone() # get the true allocated size
  14.534 +
  14.535 +
  14.536 +    cu.execute("-- types int")
  14.537 +    cu.execute("SELECT size FROM vdisks WHERE vdisk_id = " + vdisk_id)
  14.538 +
  14.539 +    old_size, = cu.fetchone()
  14.540 +
  14.541 +    if real_size < old_size:
  14.542 +        cx.close()
  14.543 +        return -1
  14.544 +
  14.545 +    if expiry_time == 0:
  14.546 +        expires = '0'
  14.547 +    else:
  14.548 +        expires = '1'
  14.549 +
  14.550 +    # this will execute the SQL query we build to store details of the new
  14.551 +    # virtual disk and allocate space to it print building_sql
  14.552 +    cu.execute("UPDATE vdisks SET expiry_time = datetime('now','"
  14.553 +               + str(expiry_time) + " seconds'), expires = " + expires
  14.554 +               + " WHERE vdisk_id = " + vdisk_id)
  14.555 +    
  14.556 +    cx.commit()
  14.557 +    cx.close()
  14.558 +    return 0
  14.559 +
  14.560 +
  14.561 +
  14.562 +
  14.563 +def vd_list():
  14.564 +    """Lists all the virtual disks registered in the system.
  14.565 +    returns [list of dicts]
  14.566 +    """
  14.567 +    
  14.568 +    if not os.path.isfile(VD_DB_FILE):
  14.569 +        __vd_no_database()
  14.570 +
  14.571 +    cx = sqlite.connect(VD_DB_FILE)
  14.572 +    cu = cx.cursor()
  14.573 +
  14.574 +    cu.execute("""SELECT vdisk_id, size, expires, expiry_time
  14.575 +                  FROM vdisks
  14.576 +                  WHERE (NOT expires) OR expiry_time > datetime('now')
  14.577 +               """)
  14.578 +
  14.579 +    ret = cu.fetchall()
  14.580 +
  14.581 +    cx.close()
  14.582 +
  14.583 +    def makedicts((vdisk_id, size, expires, expiry_time)):
  14.584 +        return { 'vdisk_id' : str(vdisk_id), 'size': size,
  14.585 +                 'expires' : expires, 'expiry_time' : expiry_time }
  14.586 +
  14.587 +    return map(makedicts, ret)
  14.588 +
  14.589 +
  14.590 +def vd_refresh(id, expiry):
  14.591 +    """Change the expiry time of a virtual disk.
  14.592 +    id [string]  : a virtual disk identifier
  14.593 +    expiry [int] : expiry time in seconds from now (0 = never expire)
  14.594 +    returns [int]: zero on success, non-zero on failure
  14.595 +    """
  14.596 +
  14.597 +    if not os.path.isfile(VD_DB_FILE):
  14.598 +        __vd_no_database()
  14.599 +    
  14.600 +    cx = sqlite.connect(VD_DB_FILE)
  14.601 +    cu = cx.cursor()
  14.602 +
  14.603 +    cu.execute("-- types int")
  14.604 +    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id
  14.605 +               + " AND (expiry_time > datetime('now') OR NOT expires)")
  14.606 +    count, = cu.fetchone()
  14.607 +
  14.608 +    if not count:
  14.609 +        cx.close()
  14.610 +        return -1
  14.611 +
  14.612 +    if expiry:
  14.613 +        expires = 1
  14.614 +        expiry_ts = "datetime('now', '" + str(expiry) + " seconds')"
  14.615 +    else:
  14.616 +        expires = 0
  14.617 +        expiry_ts = "NULL"
  14.618 +
  14.619 +    cu.execute("UPDATE vdisks SET expires = " + str(expires)
  14.620 +               + ", expiry_time = " + expiry_ts
  14.621 +               + " WHERE (expiry_time > datetime('now') OR NOT expires)"
  14.622 +               + " AND vdisk_id = " + id)
  14.623 +
  14.624 +    cx.commit()
  14.625 +    cx.close()
  14.626 +    
  14.627 +    return 0
  14.628 +
  14.629 +
  14.630 +def vd_delete(id):
  14.631 +    """Deletes a Virtual Disk, making its extents available for future VDs.
  14.632 +       id [string]   : identifier for the virtual disk to delete
  14.633 +       returns [int] : 0 on success, -1 on failure (VD not found
  14.634 +                       or already deleted)
  14.635 +    """
  14.636 +
  14.637 +    if not os.path.isfile(VD_DB_FILE):
  14.638 +        __vd_no_database()
  14.639 +    
  14.640 +    cx = sqlite.connect(VD_DB_FILE)
  14.641 +    cu = cx.cursor()
  14.642 +
  14.643 +    cu.execute("-- types int")
  14.644 +    cu.execute("SELECT COUNT(*) FROM vdisks WHERE vdisk_id = " + id
  14.645 +               + " AND (expiry_time > datetime('now') OR NOT expires)")
  14.646 +    count, = cu.fetchone()
  14.647 +
  14.648 +    if not count:
  14.649 +        cx.close()
  14.650 +        return -1
  14.651 +
  14.652 +    cu.execute("UPDATE vdisks SET expires = 1, expiry_time = datetime('now')"
  14.653 +               + " WHERE vdisk_id = " + id)
  14.654 +
  14.655 +    cx.commit()
  14.656 +    cx.close()
  14.657 +    
  14.658 +    return 0
  14.659 +
  14.660 +
  14.661 +def vd_freespace():
  14.662 +    """Returns the amount of free space available for new virtual disks, in MB
  14.663 +    returns [int] : free space for VDs in MB
  14.664 +    """
  14.665 +
  14.666 +    if not os.path.isfile(VD_DB_FILE):
  14.667 +        __vd_no_database()
  14.668 + 
  14.669 +    cx = sqlite.connect(VD_DB_FILE)
  14.670 +    cu = cx.cursor()
  14.671 +
  14.672 +    cu.execute("-- types int")
  14.673 +
  14.674 +    cu.execute("""SELECT SUM(extent_size)
  14.675 +                  FROM vdisks NATURAL JOIN vdisk_extents
  14.676 +                                           NATURAL JOIN vdisk_part
  14.677 +                  WHERE expiry_time <= datetime('now') AND expires""")
  14.678 +
  14.679 +    sum, = cu.fetchone()
  14.680 +
  14.681 +    cx.close()
  14.682 +
  14.683 +    return sum / VBD_SECTORS_PER_MB
  14.684 +
  14.685 +
  14.686 +def vd_init_db(path):
  14.687 +    """Initialise the VD SQLite database
  14.688 +    path [string]: path to the SQLite database file
  14.689 +    """
  14.690 +
  14.691 +    cx = sqlite.connect(path)
  14.692 +    cu = cx.cursor()
  14.693 +
  14.694 +    cu.execute(
  14.695 +        """CREATE TABLE vdisk_extents
  14.696 +                           ( vdisk_extent_no INT,
  14.697 +                             vdisk_id INT,
  14.698 +                             part_id INT,
  14.699 +                             part_extent_no INT )
  14.700 +        """)
  14.701 +
  14.702 +    cu.execute(
  14.703 +        """CREATE TABLE vdisk_part
  14.704 +                           ( part_id INT,
  14.705 +                             partition VARCHAR,
  14.706 +                             extent_size INT )
  14.707 +        """)
  14.708 +
  14.709 +    cu.execute(
  14.710 +        """CREATE TABLE vdisks
  14.711 +                           ( vdisk_id INT,
  14.712 +                             size INT,
  14.713 +                             expires BOOLEAN,
  14.714 +                             expiry_time TIMESTAMP )
  14.715 +        """)
  14.716 +
  14.717 +
  14.718 +    cu.execute(
  14.719 +        """INSERT INTO vdisks ( vdisk_id, size, expires, expiry_time )
  14.720 +                       VALUES ( 0,        0,    1,       datetime('now') )
  14.721 +        """)
  14.722 +
  14.723 +    cx.commit()
  14.724 +    cx.close()
  14.725 +
  14.726 +    VD_DB_FILE = path
  14.727 +
  14.728 +
  14.729 +
  14.730 +def vd_cp_to_file(vdisk_id,filename):
  14.731 +    """Writes the contents of a specified vdisk out into a disk file, leaving
  14.732 +    the original copy in the virtual disk pool."""
  14.733 +
  14.734 +    cx = sqlite.connect(VD_DB_FILE)
  14.735 +    cu = cx.cursor()
  14.736 +
  14.737 +    extents = vd_lookup(vdisk_id)
  14.738 +
  14.739 +    if not extents:
  14.740 +        return -1
  14.741 +    
  14.742 +    file_idx = 0 # index into source file, in sectors
  14.743 +
  14.744 +    for i in extents:
  14.745 +        cu.execute("""SELECT partition, extent_size FROM vdisk_part
  14.746 +                      WHERE part_id =  """ + str(i['part_device']))
  14.747 +
  14.748 +        (partition, extent_size) = cu.fetchone()
  14.749 +
  14.750 +        os.system("dd bs=1b if=" + partition + " of=" + filename
  14.751 +                  + " skip=" + str(i['part_start_sector'])
  14.752 +                  + " seek=" + str(file_idx)
  14.753 +                  + " count=" + str(i['nr_sectors'])
  14.754 +                  + " > /dev/null")
  14.755 +
  14.756 +        file_idx += i['nr_sectors']
  14.757 +
  14.758 +    cx.close()
  14.759 +
  14.760 +    return 0 # should return -1 if something breaks
  14.761 +    
  14.762 +
  14.763 +def vd_mv_to_file(vdisk_id,filename):
  14.764 +    """Writes a vdisk out into a disk file and frees the space originally
  14.765 +    taken within the virtual disk pool.
  14.766 +    vdisk_id [string]: ID of the vdisk to write out
  14.767 +    filename [string]: file to write vdisk contents out to
  14.768 +    returns [int]: zero on success, nonzero on failure
  14.769 +    """
  14.770 +
  14.771 +    if vd_cp_to_file(vdisk_id,filename):
  14.772 +        return -1
  14.773 +
  14.774 +    if vd_delete(vdisk_id):
  14.775 +        return -1
  14.776 +
  14.777 +    return 0
  14.778 +
  14.779 +
  14.780 +def vd_read_from_file(filename,expiry):
  14.781 +    """Reads the contents of a file directly into a vdisk, which is
  14.782 +    automatically allocated to fit.
  14.783 +    filename [string]: file to read disk contents from
  14.784 +    returns [string] : vdisk ID for the destination vdisk
  14.785 +    """
  14.786 +
  14.787 +    size_bytes = os.stat(filename).st_size
  14.788 +
  14.789 +    (size_mb,leftover) =  divmod(size_bytes,1048580) # size in megabytes
  14.790 +    if leftover > 0: size_mb += 1 # round up if not an exact number of MB
  14.791 +
  14.792 +    vdisk_id = vd_create(size_mb, expiry)
  14.793 +
  14.794 +    if vdisk_id < 0:
  14.795 +        return -1
  14.796 +
  14.797 +    cx = sqlite.connect(VD_DB_FILE)
  14.798 +    cu = cx.cursor()
  14.799 +
  14.800 +    cu.execute("""SELECT partition, extent_size, part_extent_no
  14.801 +                  FROM vdisk_part NATURAL JOIN vdisk_extents
  14.802 +                  WHERE vdisk_id =  """ + vdisk_id + """
  14.803 +                  ORDER BY vdisk_extent_no ASC""")
  14.804 +
  14.805 +    extents = cu.fetchall()
  14.806 +
  14.807 +    size_sectors = size_mb * VBD_SECTORS_PER_MB # for feeding to dd
  14.808 +
  14.809 +    file_idx = 0 # index into source file, in sectors
  14.810 +
  14.811 +    def write_extent_to_vd((partition, extent_size, part_extent_no),
  14.812 +                           file_idx, filename):
  14.813 +        """Write an extent out to disk and update file_idx"""
  14.814 +
  14.815 +        os.system("dd bs=512 if=" + filename + " of=" + partition
  14.816 +                  + " skip=" + str(file_idx)
  14.817 +                  + " seek=" + str(part_extent_no * extent_size)
  14.818 +                  + " count=" + str(min(extent_size, size_sectors - file_idx))
  14.819 +                  + " > /dev/null")
  14.820 +
  14.821 +        return extent_size
  14.822 +
  14.823 +    for i in extents:
  14.824 +        file_idx += write_extent_to_vd(i, file_idx, filename)
  14.825 +
  14.826 +    cx.close()
  14.827 +
  14.828 +    return vdisk_id
  14.829 +    
  14.830 +
  14.831 +
  14.832 +
  14.833 +def vd_extents_validate(new_extents, new_writeable, safety=VBD_SAFETY_RR):
  14.834 +    """Validate the extents against the existing extents.
  14.835 +    Complains if the list supplied clashes against the extents that
  14.836 +    are already in use in the system.
  14.837 +    new_extents [list of dicts]: list of new extents, as dicts
  14.838 +    new_writeable [int]: 1 if they are to be writeable, 0 otherwise
  14.839 +    returns [int]: either the expertise level of the mapping if it doesn't
  14.840 +                   exceed VBD_EXPERT_MODE or -1 if it does (error)
  14.841 +    """
  14.842 +
  14.843 +    import Xc # this is only needed in this function
  14.844 +
  14.845 +    xc = Xc.new()
  14.846 +
  14.847 +    ##### Probe for explicitly created virtual disks and build a list
  14.848 +    ##### of extents for comparison with the ones that are being added
  14.849 +
  14.850 +    probe = xc.vbd_probe()
  14.851 +
  14.852 +    old_extents = [] # this will hold a list of all existing extents and
  14.853 +                     # their writeable status, as a list of (device,
  14.854 +                     # start, size, writeable?) tuples
  14.855 +
  14.856 +    for vbd in probe:
  14.857 +        this_vbd_extents = xc.vbd_getextents(vbd['dom'],vbd['vbd'])
  14.858 +        for vbd_ext in this_vbd_extents:
  14.859 +            vbd_ext['writeable'] = vbd['writeable']
  14.860 +            old_extents.append(vbd_ext)
  14.861 +            
  14.862 +    ##### Now scan /proc/mounts for compile a list of extents corresponding to
  14.863 +    ##### any devices mounted in DOM0.  This list is added on to old_extents
  14.864 +
  14.865 +    regexp = re.compile("/dev/(\S*) \S* \S* (..).*")
  14.866 +    fd = open('/proc/mounts', "r")
  14.867 +
  14.868 +    while True:
  14.869 +        line = readline(fd)
  14.870 +        if not line: # if we've run out of lines then stop reading
  14.871 +            break
  14.872 +        
  14.873 +        m = regexp.match(line)
  14.874 +
  14.875 +        # if the regexp didn't match then it's probably a line we don't
  14.876 +        # care about - skip to next line
  14.877 +        if not m:
  14.878 +            continue
  14.879 +
  14.880 +        # lookup the device
  14.881 +        ext_list = lookup_raw_partn(m.group(1))
  14.882 +
  14.883 +        # if lookup failed, skip to next mounted device
  14.884 +        if not ext_list:
  14.885 +            continue
  14.886 +
  14.887 +        # set a writeable flag as appropriate
  14.888 +        for ext in ext_list:
  14.889 +            ext['writeable'] = m.group(2) == 'rw'
  14.890 +
  14.891 +        # now we've got here, the contents of ext_list are in a
  14.892 +        # suitable format to be added onto the old_extents list, ready
  14.893 +        # for checking against the new extents
  14.894 +
  14.895 +        old_extents.extend(ext_list)
  14.896 +
  14.897 +    fd.close() # close /proc/mounts
  14.898 +
  14.899 +    ##### By this point, old_extents contains a list of extents, in
  14.900 +    ##### dictionary format corresponding to every extent of physical
  14.901 +    ##### disk that's either part of an explicitly created VBD, or is
  14.902 +    ##### mounted under DOM0.  We now check these extents against the
  14.903 +    ##### proposed additions in new_extents, to see if a conflict will
  14.904 +    ##### happen if they are added with write status new_writeable
  14.905 +
  14.906 +    level = 0 # this'll accumulate the max warning level
  14.907 +
  14.908 +    # Search for clashes between the new extents and the old ones
  14.909 +    # Takes time O(len(new_extents) * len(old_extents))
  14.910 +    for new_ext in new_extents:
  14.911 +        for old_ext in old_extents:
  14.912 +            if(new_ext['device'] == old_ext['device']):
  14.913 +
  14.914 +                new_ext_start = new_ext['start_sector']
  14.915 +                new_ext_end = new_ext_start + new_ext['nr_sectors'] - 1
  14.916 +                
  14.917 +                old_ext_start = old_ext['start_sector']
  14.918 +                old_ext_end = old_ext_start + old_ext['nr_sectors'] - 1
  14.919 +                
  14.920 +                if((old_ext_start <= new_ext_start <= old_ext_end) or
  14.921 +                   (old_ext_start <= new_ext_end <= old_ext_end)):
  14.922 +                    if (not old_ext['writeable']) and new_writeable:
  14.923 +                        level = max(1,level)
  14.924 +                    elif old_ext['writeable'] and (not new_writeable):
  14.925 +                        level = max(1,level)
  14.926 +                    elif old_ext['writeable'] and new_writeable:
  14.927 +                        level = max(2,level)
  14.928 +
  14.929 +
  14.930 +    ##### level now holds the warning level incurred by the current
  14.931 +    ##### VBD setup and we complain appropriately to the user
  14.932 +
  14.933 +
  14.934 +    if level == 1:
  14.935 +        print >> sys.stderr, """Warning: one or more hard disk extents
  14.936 +         writeable by one domain are also readable by another."""
  14.937 +    elif level == 2:
  14.938 +        print >> sys.stderr, """Warning: one or more hard disk extents are
  14.939 +         writeable by two or more domains simultaneously."""
  14.940 +
  14.941 +    if level > safety:
  14.942 +        print >> sys.stderr, """ERROR: This kind of disk sharing is not allowed
  14.943 +        at the current safety level (%d).""" % safety
  14.944 +        level = -1
  14.945 +
  14.946 +    return level
  14.947 +
    15.1 --- a/tools/xenctl/setup.py	Fri Jun 11 21:59:47 2004 +0000
    15.2 +++ b/tools/xenctl/setup.py	Fri Jun 11 22:04:24 2004 +0000
    15.3 @@ -2,7 +2,7 @@
    15.4  from distutils.core import setup, Extension
    15.5  import sys
    15.6  
    15.7 -modules = [ 'xenctl.console_client', 'xenctl.utils' ]
    15.8 +modules = [ 'xenctl.console_client', 'xenctl.utils', 'xenctl.ip' , 'xenctl.vdisk' ]
    15.9  
   15.10  # We need the 'tempfile' module from Python 2.3. We install this ourselves
   15.11  # if the installed Python is older than 2.3.
    16.1 --- a/tools/xend/lib/main.py	Fri Jun 11 21:59:47 2004 +0000
    16.2 +++ b/tools/xend/lib/main.py	Fri Jun 11 22:04:24 2004 +0000
    16.3 @@ -73,12 +73,10 @@ def daemon_loop():
    16.4      # back-ends should use the DOM0 control interface).
    16.5      dom0_port = xend.utils.port(0)
    16.6      xend.netif.be_port = dom0_port
    16.7 -    xend.blkif_be_port = dom0_port
    16.8 +    xend.blkif.be_port = dom0_port
    16.9      notifier.bind(dom0_port.local_port)
   16.10      port_list[dom0_port.local_port] = dom0_port
   16.11  
   16.12 -    xend.netif.be_port = dom0_port
   16.13 -
   16.14      ##
   16.15      ## MAIN LOOP
   16.16      ## 
    17.1 --- a/tools/xend/lib/utils.c	Fri Jun 11 21:59:47 2004 +0000
    17.2 +++ b/tools/xend/lib/utils.c	Fri Jun 11 22:04:24 2004 +0000
    17.3 @@ -412,7 +412,8 @@ static PyObject *xu_message_get_payload(
    17.4          C2P(netif_fe_interface_status_changed_t, evtchn, Int, Long);
    17.5          return dict;
    17.6      case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
    17.7 -        C2P(netif_fe_driver_status_changed_t, status, Int, Long);
    17.8 +        C2P(netif_fe_driver_status_changed_t, status,        Int, Long);
    17.9 +        C2P(netif_fe_driver_status_changed_t, nr_interfaces, Int, Long);
   17.10          return dict;
   17.11      case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT):
   17.12          C2P(netif_fe_interface_connect_t, handle,         Int, Long);
   17.13 @@ -603,6 +604,9 @@ static PyObject *xu_message_new(PyObject
   17.14          P2C(netif_be_disconnect_t, domid,        u32);
   17.15          P2C(netif_be_disconnect_t, netif_handle, u32);
   17.16          break;
   17.17 +    case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
   17.18 +        P2C(netif_fe_driver_status_changed_t, status,        u32);
   17.19 +        P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
   17.20      }
   17.21  
   17.22      if ( dict_items_parsed != PyDict_Size(payload) )
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tools/xenmgr/Makefile	Fri Jun 11 22:04:24 2004 +0000
    18.3 @@ -0,0 +1,19 @@
    18.4 +
    18.5 +all:
    18.6 +	python setup.py build
    18.7 +
    18.8 +install: all
    18.9 +	if [ "$(prefix)" = "" ]; then                   \
   18.10 +	    python setup.py install;                    \
   18.11 +	elif [ "$(dist)" = "yes" ]; then                \
   18.12 +	    python setup.py install --home="$(prefix)"; \
   18.13 +	else                                            \
   18.14 +	    python setup.py install --root="$(prefix)"; \
   18.15 +	fi
   18.16 +	mkdir -p $(prefix)/usr/sbin
   18.17 +	install -m0755 xenmgrd $(prefix)/usr/sbin
   18.18 +	install -m0755 xend $(prefix)/usr/sbin
   18.19 +	install -m0755 netfix $(prefix)/usr/sbin
   18.20 +
   18.21 +clean:
   18.22 +	rm -rf build *.pyc *.pyo *.o *.a *~
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tools/xenmgr/lib/Args.py	Fri Jun 11 22:04:24 2004 +0000
    19.3 @@ -0,0 +1,126 @@
    19.4 +import sxp
    19.5 +
    19.6 +class ArgError(StandardError):
    19.7 +    pass
    19.8 +
    19.9 +class Args:
   19.10 +    """Argument encoding support for HTTP.
   19.11 +    """
   19.12 +    
   19.13 +    def __init__(self, paramspec, keyspec):
   19.14 +        self.arg_ord = []
   19.15 +        self.arg_dict = {}
   19.16 +        self.key_ord = []
   19.17 +        self.key_dict = {}
   19.18 +        for (name, type) in paramspec:
   19.19 +                self.arg_ord.append(name)
   19.20 +                self.arg_dict[name] = type
   19.21 +        for (name, type) in keyspec:
   19.22 +                self.key_ord.append(name)
   19.23 +                self.key_dict[name] = type
   19.24 +
   19.25 +    def get_args(self, d, xargs=None):
   19.26 +        args = {}
   19.27 +        keys = {}
   19.28 +        params = []
   19.29 +        if xargs:
   19.30 +            self.split_args(xargs, args, keys)
   19.31 +        self.split_args(d, args, keys)
   19.32 +        for a in self.arg_ord:
   19.33 +            if a in args:
   19.34 +                params.append(args[a])
   19.35 +            else:
   19.36 +                raise ArgError('Missing parameter: %s' % a)
   19.37 +        return (params, keys)
   19.38 +
   19.39 +    def split_args(self, d, args, keys):
   19.40 +        for (k, v) in d.items():
   19.41 +            if k in self.arg_dict:
   19.42 +                type = self.arg_dict[k]
   19.43 +                val = self.coerce(type, v)
   19.44 +                args[k] = val
   19.45 +            elif k in self.key_dict:
   19.46 +                type = self.key_dict[k]
   19.47 +                val = self.coerce(type, v)
   19.48 +                keys[k] = val
   19.49 +            else:
   19.50 +                raise ArgError('Invalid parameter: %s' % k)
   19.51 +
   19.52 +    def get_form_args(self, f, xargs=None):
   19.53 +        d = {}
   19.54 +        for (k, v) in f.items():
   19.55 +            n = len(v)
   19.56 +            if ((k not in self.arg_dict) and
   19.57 +                (k not in self.key_dict)):
   19.58 +                continue
   19.59 +            if n == 0:
   19.60 +                continue
   19.61 +            elif n == 1:
   19.62 +                d[k] = v[0]
   19.63 +            else:
   19.64 +                raise ArgError('Too many values for %s' % k)
   19.65 +        return self.get_args(d, xargs=xargs)
   19.66 +
   19.67 +    def coerce(self, type, v):
   19.68 +        try:
   19.69 +            if type == 'int':
   19.70 +                return int(v)
   19.71 +            if type == 'str':
   19.72 +                return str(v)
   19.73 +            if type == 'sxpr':
   19.74 +                return self.sxpr(v)
   19.75 +        except ArgError:
   19.76 +            raise
   19.77 +        except StandardError, ex:
   19.78 +            raise ArgError(str(ex))
   19.79 +
   19.80 +    def sxpr(self, v):
   19.81 +        if instanceof(v, types.ListType):
   19.82 +            return v
   19.83 +        if instanceof(v, types.File) or hasattr(v, 'readline'):
   19.84 +            return sxpr_file(v)
   19.85 +        if instanceof(v, types.StringType):
   19.86 +            return sxpr_file(StringIO(v))
   19.87 +        return str(v)
   19.88 +
   19.89 +    def sxpr_file(self, fin):
   19.90 +        try:
   19.91 +            vals = sxp.parse(fin)
   19.92 +        except:
   19.93 +            raise ArgError('Coercion to sxpr failed')
   19.94 +        if len(vals) == 1:
   19.95 +            return vals[0]
   19.96 +        else:
   19.97 +            raise ArgError('Too many sxprs')
   19.98 +
   19.99 +    def call_with_args(self, fn, args, xargs=None):
  19.100 +        (params, keys) = self.get_args(args, xargs=xargs)
  19.101 +        fn(*params, **keys)
  19.102 +
  19.103 +    def call_with_form_args(self, fn, fargs, xargs=None):
  19.104 +        (params, keys) = self.get_form_args(fargs, xargs=xargs)
  19.105 +        fn(*params, **keys)
  19.106 +
  19.107 +class ArgFn(Args):
  19.108 +    """Represent a remote HTTP operation as a function.
  19.109 +    Used on the client.
  19.110 +    """
  19.111 +
  19.112 +    def __init__(self, fn, paramspec, keyspec={}):
  19.113 +        Args.__init__(self, paramspec, keyspec)
  19.114 +        self.fn = fn
  19.115 +
  19.116 +    def __call__(self, fargs, xargs=None):
  19.117 +        return self.call_with_args(self.fn, fargs, xargs=xargs)
  19.118 +    
  19.119 +class FormFn(Args):
  19.120 +    """Represent an operation as a function over a form.
  19.121 +    Used in the HTTP server.
  19.122 +    """
  19.123 +
  19.124 +    def __init__(self, fn, paramspec, keyspec={}):
  19.125 +        Args.__init__(self, paramspec, keyspec)
  19.126 +        self.fn = fn
  19.127 +
  19.128 +    def __call__(self, fargs, xargs=None):
  19.129 +        return self.call_with_form_args(self.fn, fargs, xargs=xargs)
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tools/xenmgr/lib/EventServer.py	Fri Jun 11 22:04:24 2004 +0000
    20.3 @@ -0,0 +1,204 @@
    20.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    20.5 +"""Simple publish/subscribe event server.
    20.6 +
    20.7 +"""
    20.8 +import string
    20.9 +
   20.10 +# subscribe a.b.c h: map a.b.c -> h
   20.11 +# subscribe a.b.* h: map a.b.* -> h
   20.12 +# subscribe a.b.? h: map a.b.? -> h
   20.13 +#
   20.14 +# for event a.b.c.d:
   20.15 +#
   20.16 +# lookup a.b.c.d, call handlers
   20.17 +#
   20.18 +# lookup a.b.c.?, call handlers
   20.19 +#
   20.20 +# lookup a.b.c.d.*, call handlers
   20.21 +# lookup a.b.c.*, call handlers
   20.22 +# lookup a.b.*, call handlers
   20.23 +# lookup a.*, call handlers
   20.24 +# lookup *, call handlers
   20.25 +
   20.26 +# a.b.c.d = (a b c d)
   20.27 +# a.b.c.? = (a b c _)
   20.28 +# a.b.c.* = (a b c . _)
   20.29 +
   20.30 +class EventServer:
   20.31 +
   20.32 +    DOT = '.'
   20.33 +    QUERY = '?'
   20.34 +    DOT_QUERY = DOT + QUERY
   20.35 +    STAR = '*'
   20.36 +    DOT_STAR = DOT + STAR
   20.37 +
   20.38 +    def __init__(self, run=0):
   20.39 +        self.handlers = {}
   20.40 +        self.run = run
   20.41 +        self.queue = []
   20.42 +
   20.43 +    def start(self):
   20.44 +        """Enable event handling. Sends any queued events.
   20.45 +        """
   20.46 +        self.run = 1
   20.47 +        for (e,v) in self.queue:
   20.48 +            self.inject(e, v)
   20.49 +        self.queue = []
   20.50 +
   20.51 +    def stop(self):
   20.52 +        """Suspend event handling. Events injected while suspended
   20.53 +        are queued until we are started again.
   20.54 +        """
   20.55 +        self.run = 0
   20.56 +
   20.57 +    def subscribe(self, event, handler):
   20.58 +        """Subscribe to an event. For example 'a.b.c.d'.
   20.59 +        A subcription like 'a.b.c.?' ending in '?' matches any value
   20.60 +        for the '?'. A subscription like 'a.b.c.*' ending in '*' matches
   20.61 +        any event type with the same prefix, 'a.b.c' in this case.
   20.62 +
   20.63 +        event	event name
   20.64 +        handler event handler fn(event, val)
   20.65 +        """
   20.66 +        hl = self.handlers.get(event)
   20.67 +        if hl is None:
   20.68 +            self.handlers[event] = [handler]
   20.69 +        else:
   20.70 +            hl.append(handler)
   20.71 +
   20.72 +    def unsubscribe_all(self, event=None):
   20.73 +        """Unsubscribe all handlers for a given event, or all handlers.
   20.74 +
   20.75 +        event	event (optional)
   20.76 +        """
   20.77 +        if event == None:
   20.78 +            self.handlers.clear()
   20.79 +        else:
   20.80 +            del self.handlers[event]
   20.81 +        
   20.82 +    def unsubscribe(self, event, handler):
   20.83 +        """Unsubscribe a given event and handler.
   20.84 +
   20.85 +        event	event
   20.86 +        handler handler
   20.87 +        """
   20.88 +        hl = self.handlers.get(event)
   20.89 +        if hl is None:
   20.90 +            return
   20.91 +        hl.remove(handler)
   20.92 +
   20.93 +    def inject(self, event, val):
   20.94 +        """Inject an event. Handlers for it are called if runing, otherwise
   20.95 +        it is queued.
   20.96 +
   20.97 +        event	event type
   20.98 +        val	event value
   20.99 +        """
  20.100 +        if self.run:
  20.101 +            #print ">event", event, val
  20.102 +            self.call_event_handlers(event, event, val)
  20.103 +            self.call_query_handlers(event, val)
  20.104 +            self.call_star_handlers(event, val)
  20.105 +        else:
  20.106 +            self.queue.append( (event, val) )
  20.107 +
  20.108 +    def call_event_handlers(self, key, event, val):
  20.109 +        """Call the handlers for an event.
  20.110 +        It is safe for handlers to subscribe or unsubscribe.
  20.111 +
  20.112 +        key	key for handler list
  20.113 +        event	event type
  20.114 +        val	event value
  20.115 +        """
  20.116 +        hl = self.handlers.get(key)
  20.117 +        if hl is None:
  20.118 +            return
  20.119 +        # Copy the handler list so that handlers can call
  20.120 +        # subscribe/unsubscribe safely - python list iteration
  20.121 +        # is not safe against list modification.
  20.122 +        for h in hl[:]:
  20.123 +            try:
  20.124 +                h(event, val)
  20.125 +            except:
  20.126 +                pass
  20.127 +        
  20.128 +    def call_query_handlers(self, event, val):
  20.129 +        """Call regex handlers for events matching 'event' that end in '?'.
  20.130 +
  20.131 +        event	event type
  20.132 +        val	event value
  20.133 +        """
  20.134 +        dot_idx = event.rfind(self.DOT)
  20.135 +        if dot_idx == -1:
  20.136 +            self.call_event_handlers(self.QUERY, event, val)
  20.137 +        else:
  20.138 +            event_query = event[0:dot_idx] + self.DOT_QUERY
  20.139 +            self.call_event_handlers(event_query, event, val)
  20.140 +
  20.141 +    def call_star_handlers(self, event, val):
  20.142 +        """Call regex handlers for events matching 'event' that end in '*'.
  20.143 +
  20.144 +        event	event type
  20.145 +        val	event value
  20.146 +        """
  20.147 +        etype = string.split(event, self.DOT)
  20.148 +        for i in range(len(etype), 0, -1):
  20.149 +            event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR
  20.150 +            self.call_event_handlers(event_star, event, val)
  20.151 +        self.call_event_handlers(self.STAR, event, val)       
  20.152 +
  20.153 +def instance():
  20.154 +    global inst
  20.155 +    try:
  20.156 +        inst
  20.157 +    except:
  20.158 +        inst = EventServer()
  20.159 +        inst.start()
  20.160 +    return inst
  20.161 +
  20.162 +def main():
  20.163 +    def sys_star(event, val):
  20.164 +        print 'sys_star', event, val
  20.165 +
  20.166 +    def sys_foo(event, val):
  20.167 +        print 'sys_foo', event, val
  20.168 +        s.unsubscribe('sys.foo', sys_foo)
  20.169 +
  20.170 +    def sys_foo2(event, val):
  20.171 +        print 'sys_foo2', event, val
  20.172 +
  20.173 +    def sys_bar(event, val):
  20.174 +        print 'sys_bar', event, val
  20.175 +
  20.176 +    def sys_foo_bar(event, val):
  20.177 +        print 'sys_foo_bar', event, val
  20.178 +
  20.179 +    def foo_bar(event, val):
  20.180 +        print 'foo_bar', event, val
  20.181 +
  20.182 +    s = EventServer()
  20.183 +    s.start()
  20.184 +    s.subscribe('sys.*', sys_star)
  20.185 +    s.subscribe('sys.foo', sys_foo)
  20.186 +    s.subscribe('sys.foo', sys_foo2)
  20.187 +    s.subscribe('sys.bar', sys_bar)
  20.188 +    s.subscribe('sys.foo.bar', sys_foo_bar)
  20.189 +    s.subscribe('foo.bar', foo_bar)
  20.190 +    s.inject('sys.foo', 'hello')
  20.191 +    print
  20.192 +    s.inject('sys.bar', 'hello again')
  20.193 +    print
  20.194 +    s.inject('sys.foo.bar', 'hello again')
  20.195 +    print
  20.196 +    s.inject('foo.bar', 'hello again')
  20.197 +    print
  20.198 +    s.inject('foo', 'hello again')
  20.199 +    print
  20.200 +    s.start()
  20.201 +    s.unsubscribe('sys.*', sys_star)
  20.202 +    s.unsubscribe_all('sys.*')
  20.203 +    s.inject('sys.foo', 'hello')
  20.204 +
  20.205 +if __name__ == "__main__":
  20.206 +    main()
  20.207 +
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tools/xenmgr/lib/EventTypes.py	Fri Jun 11 22:04:24 2004 +0000
    21.3 @@ -0,0 +1,34 @@
    21.4 +#   Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    21.5 +
    21.6 +## XEND_DOMAIN_CREATE = "xend.domain.create": dom
    21.7 +## create: 
    21.8 +## xend.domain.destroy: dom, reason:died/crashed
    21.9 +## xend.domain.up ?
   21.10 +
   21.11 +## xend.domain.start: dom
   21.12 +## xend.domain.stop: dom
   21.13 +## xend.domain.shutdown: dom
   21.14 +## xend.domain.halt: dom
   21.15 +
   21.16 +## xend.domain.migrate.begin: dom, to
   21.17 +## Begin tells: src host, src domain uri, dst host. Dst id known?
   21.18 +## err: src host, src domain uri, dst host, dst id if known, status (of domain: ok, dead,...), reason
   21.19 +## end: src host, src domain uri, dst host, dst uri
   21.20 +
   21.21 +## Events for both ends of migrate: for exporter and importer?
   21.22 +## Include migrate id so can tie together.
   21.23 +## Have uri /xend/migrate/<id> for migrate info (migrations in progress).
   21.24 +
   21.25 +## (xend.domain.migrate.begin (src <host>) (src.domain <id>)
   21.26 +##                            (dst <host>) (id <migrate id>))
   21.27 + 
   21.28 +## xend.domain.migrate.end:
   21.29 +## (xend.domain.migrate.end (domain <id>) (to <host>)
   21.30 +
   21.31 +## xend.node.up:  xend uri
   21.32 +## xend.node.down: xend uri
   21.33 +
   21.34 +## xend.error ?
   21.35 +
   21.36 +## format:
   21.37 +
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tools/xenmgr/lib/PrettyPrint.py	Fri Jun 11 22:04:24 2004 +0000
    22.3 @@ -0,0 +1,299 @@
    22.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    22.5 +
    22.6 +"""General pretty-printer, including support for SXP.
    22.7 +
    22.8 +"""
    22.9 +import sys
   22.10 +import types
   22.11 +import StringIO
   22.12 +import sxp
   22.13 +
   22.14 +class PrettyItem:
   22.15 +
   22.16 +    def __init__(self, width):
   22.17 +        self.width = width
   22.18 +
   22.19 +    def insert(self, block):
   22.20 +        block.addtoline(self)
   22.21 +
   22.22 +    def get_width(self):
   22.23 +        return self.width
   22.24 +
   22.25 +    def output(self, out):
   22.26 +        print '***PrettyItem>output>', self
   22.27 +        pass
   22.28 +
   22.29 +    def prettyprint(self, out, width):
   22.30 +        print '***PrettyItem>prettyprint>', self
   22.31 +        return width
   22.32 +
   22.33 +class PrettyString(PrettyItem):
   22.34 +
   22.35 +    def __init__(self, x):
   22.36 +        PrettyItem.__init__(self, len(x))
   22.37 +        self.value = x
   22.38 +
   22.39 +    def output(self, out):
   22.40 +        out.write(self.value)
   22.41 +
   22.42 +    def prettyprint(self, line):
   22.43 +        line.output(self)
   22.44 +
   22.45 +    def show(self, out):
   22.46 +        print >> out, ("(string (width %d) '%s')" % (self.width, self.value))
   22.47 +
   22.48 +class PrettySpace(PrettyItem):
   22.49 +
   22.50 +    def output(self, out):
   22.51 +        out.write(' ' * self.width)
   22.52 +
   22.53 +    def prettyprint(self, line):
   22.54 +        line.output(self)
   22.55 +
   22.56 +    def show(self, out):
   22.57 +        print >> out, ("(space (width %d))" % self.width)
   22.58 +        
   22.59 +class PrettyBreak(PrettyItem):
   22.60 +
   22.61 +    def __init__(self, width, indent):
   22.62 +        PrettyItem.__init__(self, width)
   22.63 +        self.indent = indent
   22.64 +        self.space = 0
   22.65 +        self.active = 0
   22.66 +
   22.67 +    def output(self, out):
   22.68 +        out.write(' ' * self.width)
   22.69 +
   22.70 +    def prettyprint(self, line):
   22.71 +        if line.breaks(self.space):
   22.72 +            self.active = 1
   22.73 +            line.newline(self.indent)
   22.74 +        else:
   22.75 +            line.output(self)
   22.76 +
   22.77 +    def show(self, out):
   22.78 +        print >> out, ("(break (width %d) (indent %d) (space %d) (active %d))"
   22.79 +                       % (self.width, self.indent, self.space, self.lspace, self.active))
   22.80 +
   22.81 +class PrettyNewline(PrettySpace):
   22.82 +
   22.83 +    def __init__(self, indent):
   22.84 +        PrettySpace.__init__(self, indent)
   22.85 +
   22.86 +    def insert(self, block):
   22.87 +        block.newline()
   22.88 +        block.addtoline(self)
   22.89 +
   22.90 +    def output(self, out):
   22.91 +        out.write(' ' * self.width)
   22.92 +
   22.93 +    def prettyprint(self, line):
   22.94 +        line.newline(0)
   22.95 +        line.output(self)
   22.96 +
   22.97 +    def show(self, out):
   22.98 +        print >> out, ("(nl (indent %d))" % self.indent)
   22.99 +
  22.100 +class PrettyLine(PrettyItem):
  22.101 +    def __init__(self):
  22.102 +        PrettyItem.__init__(self, 0)
  22.103 +        self.content = []
  22.104 +
  22.105 +    def write(self, x):
  22.106 +        self.content.append(x)
  22.107 +
  22.108 +    def end(self):
  22.109 +        width = 0
  22.110 +        lastwidth = 0
  22.111 +        lastbreak = None
  22.112 +        for x in self.content:
  22.113 +            if isinstance(x, PrettyBreak):
  22.114 +                if lastbreak:
  22.115 +                    lastbreak.space = (width - lastwidth)
  22.116 +                lastbreak = x
  22.117 +                lastwidth = width
  22.118 +            width += x.get_width()
  22.119 +        if lastbreak:
  22.120 +            lastbreak.space = (width - lastwidth)
  22.121 +        self.width = width
  22.122 + 
  22.123 +    def prettyprint(self, line):
  22.124 +        for x in self.content:
  22.125 +            x.prettyprint(line)
  22.126 +
  22.127 +    def show(self, out):
  22.128 +        print >> out, '(LINE (width %d)' % self.width
  22.129 +        for x in self.content:
  22.130 +            x.show(out)
  22.131 +        print >> out, ')'
  22.132 +
  22.133 +class PrettyBlock(PrettyItem):
  22.134 +
  22.135 +    def __init__(self, all=0, parent=None):
  22.136 +        self.width = 0
  22.137 +        self.lines = []
  22.138 +        self.parent = parent
  22.139 +        self.indent = 0
  22.140 +        self.all = all
  22.141 +        self.broken = 0
  22.142 +        self.newline()
  22.143 +
  22.144 +    def add(self, item):
  22.145 +        item.insert(self)
  22.146 +
  22.147 +    def end(self):
  22.148 +        self.width = 0
  22.149 +        for l in self.lines:
  22.150 +            l.end()
  22.151 +            if self.width < l.width:
  22.152 +                self.width = l.width
  22.153 +
  22.154 +    def breaks(self, n):
  22.155 +        return self.all and self.broken
  22.156 +
  22.157 +    def newline(self):
  22.158 +        self.lines.append(PrettyLine())
  22.159 +
  22.160 +    def addtoline(self, x):
  22.161 +        self.lines[-1].write(x)
  22.162 +
  22.163 +    def prettyprint(self, line):
  22.164 +        self.indent = line.used
  22.165 +        line.block = self
  22.166 +        if not line.fits(self.width):
  22.167 +            self.broken = 1
  22.168 +        for l in self.lines:
  22.169 +            l.prettyprint(line)
  22.170 +        line.block = self.parent
  22.171 +
  22.172 +    def show(self, out):
  22.173 +        print >> out, ('(BLOCK (width %d) (indent %d) (all %d) (broken %d)' %
  22.174 +                       (self.width, self.indent, self.all, self.broken))
  22.175 +        for l in self.lines:
  22.176 +            l.show(out)
  22.177 +        print >> out, ')'
  22.178 +
  22.179 +class Line:
  22.180 +
  22.181 +    def __init__(self, out, width):
  22.182 +        self.out = out
  22.183 +        self.width = width
  22.184 +        self.used = 0
  22.185 +        self.space = self.width
  22.186 +
  22.187 +    def newline(self, indent):
  22.188 +        indent += self.block.indent
  22.189 +        self.out.write('\n')
  22.190 +        self.out.write(' ' * indent)
  22.191 +        self.used = indent
  22.192 +        self.space = self.width - self.used
  22.193 +
  22.194 +    def fits(self, n):
  22.195 +        return self.space - n >= 0
  22.196 +
  22.197 +    def breaks(self, n):
  22.198 +        return self.block.breaks(n) or not self.fits(n)
  22.199 +
  22.200 +    def output(self, x):
  22.201 +        n = x.get_width()
  22.202 +        self.space -= n
  22.203 +        self.used += n
  22.204 +        if self.space < 0:
  22.205 +            self.space = 0
  22.206 +        x.output(self.out)
  22.207 +
  22.208 +class PrettyPrinter:
  22.209 +    """A prettyprinter based on what I remember of Derek Oppen's
  22.210 +    prettyprint algorithm from TOPLAS way back.
  22.211 +    """
  22.212 +
  22.213 +    def __init__(self, width=40):
  22.214 +        self.width = width
  22.215 +        self.block = None
  22.216 +        self.top = None
  22.217 +
  22.218 +    def write(self, x):
  22.219 +        self.block.add(PrettyString(x))
  22.220 +
  22.221 +    def add(self, item):
  22.222 +        self.block.add(item)
  22.223 +
  22.224 +    def addbreak(self, width=1, indent=4):
  22.225 +        self.add(PrettyBreak(width, indent))
  22.226 +
  22.227 +    def addspace(self, width=1):
  22.228 +        self.add(PrettySpace(width))
  22.229 +
  22.230 +    def addnl(self, indent=0):
  22.231 +        self.add(PrettyNewline(indent))
  22.232 +
  22.233 +    def begin(self, all=0):
  22.234 +        block = PrettyBlock(all=all, parent=self.block)
  22.235 +        self.block = block
  22.236 +
  22.237 +    def end(self):
  22.238 +        self.block.end()
  22.239 +        if self.block.parent:
  22.240 +            self.block.parent.add(self.block)
  22.241 +        else:
  22.242 +            self.top = self.block
  22.243 +        self.block = self.block.parent
  22.244 +
  22.245 +    def prettyprint(self, out=sys.stdout):
  22.246 +        line = Line(out, self.width)
  22.247 +        self.top.prettyprint(line)
  22.248 +
  22.249 +class SXPPrettyPrinter(PrettyPrinter):
  22.250 +    """An SXP prettyprinter.
  22.251 +    """
  22.252 +    
  22.253 +    def pstring(self, x):
  22.254 +        io = StringIO.StringIO()
  22.255 +        sxp.show(x, out=io)
  22.256 +        io.seek(0)
  22.257 +        val = io.getvalue()
  22.258 +        io.close()
  22.259 +        return val
  22.260 +
  22.261 +    def pprint(self, l):
  22.262 +        if isinstance(l, types.ListType):
  22.263 +            self.begin(all=1)
  22.264 +            self.write('(')
  22.265 +            i = 0
  22.266 +            for x in l:
  22.267 +                if(i): self.addbreak()
  22.268 +                self.pprint(x)
  22.269 +                i += 1
  22.270 +            self.addbreak(width=0, indent=0)
  22.271 +            self.write(')')
  22.272 +            self.end()
  22.273 +        else:
  22.274 +            self.write(self.pstring(l))
  22.275 +
  22.276 +def prettyprint(sxpr, out=sys.stdout, width=80):
  22.277 +    """Prettyprint an SXP form.
  22.278 +
  22.279 +    sxpr	s-expression
  22.280 +    out		destination
  22.281 +    width	maximum output width
  22.282 +    """
  22.283 +    if isinstance(sxpr, types.ListType):
  22.284 +        pp = SXPPrettyPrinter(width=width)
  22.285 +        pp.pprint(sxpr)
  22.286 +        pp.prettyprint(out=out)
  22.287 +    else:
  22.288 +        sxp.show(sxpr, out=out)
  22.289 +    print >> out
  22.290 +
  22.291 +def main():
  22.292 +    pin = sxp.Parser()
  22.293 +    while 1:
  22.294 +        buf = sys.stdin.read(100)
  22.295 +        pin.input(buf)
  22.296 +        if buf == '': break
  22.297 +    l = pin.get_val()
  22.298 +    prettyprint(l, width=80)
  22.299 +
  22.300 +if __name__ == "__main__":
  22.301 +    main()
  22.302 +    
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tools/xenmgr/lib/XendClient.py	Fri Jun 11 22:04:24 2004 +0000
    23.3 @@ -0,0 +1,368 @@
    23.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    23.5 +"""Client API for the HTTP interface on xend.
    23.6 +Callable as a script - see main().
    23.7 +"""
    23.8 +import sys
    23.9 +import httplib
   23.10 +import types
   23.11 +from StringIO import StringIO
   23.12 +import urlparse
   23.13 +
   23.14 +from encode import *
   23.15 +import sxp
   23.16 +import PrettyPrint
   23.17 +
   23.18 +DEBUG = 1
   23.19 +
   23.20 +class Foo(httplib.HTTPResponse):
   23.21 +
   23.22 +    def begin(self):
   23.23 +        fin = self.fp
   23.24 +        while(1):
   23.25 +            buf = fin.readline()
   23.26 +            print "***", buf
   23.27 +            if buf == '':
   23.28 +                print
   23.29 +                sys.exit()
   23.30 +
   23.31 +
   23.32 +def sxprio(sxpr):
   23.33 +    io = StringIO()
   23.34 +    sxp.show(sxpr, out=io)
   23.35 +    print >> io
   23.36 +    io.seek(0)
   23.37 +    return io
   23.38 +
   23.39 +def fileof(val):
   23.40 +    """Converter for passing configs.
   23.41 +    Handles lists, files directly.
   23.42 +    Assumes a string is a file name and passes its contents.
   23.43 +    """
   23.44 +    if isinstance(val, types.ListType):
   23.45 +        return sxprio(val)
   23.46 +    if isinstance(val, types.StringType):
   23.47 +        return file(val)
   23.48 +    if hasattr(val, 'readlines'):
   23.49 +        return val
   23.50 +
   23.51 +# todo: need to sort of what urls/paths are using for objects.
   23.52 +# e.g. for domains at the moment return '0'.
   23.53 +# should probably return abs path w.r.t. server, e.g. /xend/domain/0.
   23.54 +# As an arg, assume abs path is obj uri, otherwise just id.
   23.55 +
   23.56 +# Function to convert to full url: Xend.uri(path), e.g.
   23.57 +# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0
   23.58 +# And should accept urls for ids?
   23.59 +
   23.60 +def urljoin(location, root, prefix='', rest=''):
   23.61 +    base = 'http://' + location + root + prefix
   23.62 +    url = urlparse.urljoin(base, rest)
   23.63 +    return url
   23.64 +
   23.65 +def nodeurl(location, root, id=''):
   23.66 +    return urljoin(location, root, 'node/', id)
   23.67 +
   23.68 +def domainurl(location, root, id=''):
   23.69 +    return urljoin(location, root, 'domain/', id)
   23.70 +
   23.71 +def consoleurl(location, root, id=''):
   23.72 +    return urljoin(location, root, 'console/', id)
   23.73 +
   23.74 +def vbdurl(location, root, id=''):
   23.75 +    return urljoin(location, root, 'vbd/', id)
   23.76 +
   23.77 +def deviceurl(location, root, id=''):
   23.78 +    return urljoin(location, root, 'device/', id)
   23.79 +
   23.80 +def vneturl(location, root, id=''):
   23.81 +    return urljoin(location, root, 'vnet/', id)
   23.82 +
   23.83 +def eventurl(location, root, id=''):
   23.84 +    return urljoin(location, root, 'event/', id)
   23.85 +
   23.86 +def xend_request(url, method, data=None):
   23.87 +    urlinfo = urlparse.urlparse(url)
   23.88 +    (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
   23.89 +    if DEBUG: print url, urlinfo
   23.90 +    if uproto != 'http':
   23.91 +        raise StandardError('Invalid protocol: ' + uproto)
   23.92 +    if DEBUG: print '>xend_request', ulocation, upath, method, data
   23.93 +    (hdr, args) = encode_data(data)
   23.94 +    if data and method == 'GET':
   23.95 +        upath += '?' + args
   23.96 +        args = None
   23.97 +    if method == "POST" and upath.endswith('/'):
   23.98 +        upath = upath[:-1]
   23.99 +    if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args
  23.100 +    #hdr['User-Agent'] = 'Mozilla'
  23.101 +    #hdr['Accept'] = 'text/html,text/plain'
  23.102 +    conn = httplib.HTTPConnection(ulocation)
  23.103 +    #conn.response_class = Foo
  23.104 +    conn.set_debuglevel(1)
  23.105 +    conn.request(method, upath, args, hdr)
  23.106 +    resp = conn.getresponse()
  23.107 +    if DEBUG: print resp.status, resp.reason
  23.108 +    if DEBUG: print resp.msg.headers
  23.109 +    if resp.status in [204, 404]:
  23.110 +        return None
  23.111 +    if resp.status not in [200, 201, 202, 203]:
  23.112 +        raise RuntimeError(resp.reason)
  23.113 +    pin = sxp.Parser()
  23.114 +    data = resp.read()
  23.115 +    if DEBUG: print "***data" , data
  23.116 +    if DEBUG: print "***"
  23.117 +    pin.input(data);
  23.118 +    pin.input_eof()
  23.119 +    conn.close()
  23.120 +    val = pin.get_val()
  23.121 +    #if isinstance(val, types.ListType) and sxp.name(val) == 'val':
  23.122 +    #    val = val[1]
  23.123 +    if isinstance(val, types.ListType) and sxp.name(val) == 'err':
  23.124 +        raise RuntimeError(val[1])
  23.125 +    if DEBUG: print '**val='
  23.126 +    #sxp.show(val); print
  23.127 +    PrettyPrint.prettyprint(val)
  23.128 +    if DEBUG: print '**'
  23.129 +    return val
  23.130 +
  23.131 +def xend_get(url, args=None):
  23.132 +    return xend_request(url, "GET", args)
  23.133 +
  23.134 +def xend_call(url, data):
  23.135 +    return xend_request(url, "POST", data)
  23.136 +
  23.137 +class Xend:
  23.138 +
  23.139 +    SRV_DEFAULT = "localhost:8000"
  23.140 +    ROOT_DEFAULT = "/xend/"
  23.141 +
  23.142 +    def __init__(self, srv=None, root=None):
  23.143 +        self.bind(srv, root)
  23.144 +
  23.145 +    def bind(self, srv=None, root=None):
  23.146 +        if srv is None: srv = self.SRV_DEFAULT
  23.147 +        if root is None: root = self.ROOT_DEFAULT
  23.148 +        if not root.endswith('/'): root += '/'
  23.149 +        self.location = srv
  23.150 +        self.root = root
  23.151 +
  23.152 +    def nodeurl(self, id=''):
  23.153 +        return nodeurl(self.location, self.root, id)
  23.154 +
  23.155 +    def domainurl(self, id=''):
  23.156 +        return domainurl(self.location, self.root, id)
  23.157 +
  23.158 +    def consoleurl(self, id=''):
  23.159 +        return consoleurl(self.location, self.root, id)
  23.160 +
  23.161 +    def vbdurl(self, id=''):
  23.162 +        return vbdurl(self.location, self.root, id)
  23.163 +
  23.164 +    def deviceurl(self, id=''):
  23.165 +        return deviceurl(self.location, self.root, id)
  23.166 +
  23.167 +    def vneturl(self, id=''):
  23.168 +        return vneturl(self.location, self.root, id)
  23.169 +
  23.170 +    def eventurl(self, id=''):
  23.171 +        return eventurl(self.location, self.root, id)
  23.172 +
  23.173 +    def xend(self):
  23.174 +        return xend_get(urljoin(self.location, self.root))
  23.175 +
  23.176 +    def xend_node(self):
  23.177 +        return xend_get(self.nodeurl())
  23.178 +
  23.179 +    def xend_node_cpu_rrobin_slice_set(self, slice):
  23.180 +        return xend_call(self.nodeurl(),
  23.181 +                         {'op'      : 'cpu_rrobin_slice_set',
  23.182 +                          'slice'   : slice })
  23.183 +    
  23.184 +    def xend_node_cpu_bvt_slice_set(self, slice):
  23.185 +        return xend_call(self.nodeurl(),
  23.186 +                         {'op'      : 'cpu_bvt_slice_set',
  23.187 +                          'slice'   : slice })
  23.188 +
  23.189 +    def xend_domains(self):
  23.190 +        return xend_get(self.domainurl())
  23.191 +
  23.192 +    def xend_domain_create(self, conf):
  23.193 +        return xend_call(self.domainurl(),
  23.194 +                         {'op'      : 'create',
  23.195 +                          'config'  : fileof(conf) })
  23.196 +
  23.197 +    def xend_domain(self, id):
  23.198 +        return xend_get(self.domainurl(id))
  23.199 +
  23.200 +    def xend_domain_start(self, id):
  23.201 +        return xend_call(self.domainurl(id),
  23.202 +                         {'op'      : 'start'})
  23.203 +
  23.204 +    def xend_domain_stop(self, id):
  23.205 +        return xend_call(self.domainurl(id),
  23.206 +                         {'op'      : 'stop'})
  23.207 +
  23.208 +    def xend_domain_shutdown(self, id):
  23.209 +        return xend_call(self.domainurl(id),
  23.210 +                         {'op'      : 'shutdown'})
  23.211 +
  23.212 +    def xend_domain_halt(self, id):
  23.213 +        return xend_call(self.domainurl(id),
  23.214 +                         {'op'      : 'halt'})
  23.215 +
  23.216 +    def xend_domain_save(self, id, filename):
  23.217 +        return xend_call(self.domainurl(id),
  23.218 +                         {'op'      : 'save',
  23.219 +                          'file'    : filename})
  23.220 +
  23.221 +    def xend_domain_restore(self, id, filename, conf):
  23.222 +        return xend_call(self.domainurl(id),
  23.223 +                         {'op'      : 'restore',
  23.224 +                          'file'    : filename,
  23.225 +                          'config'  : fileof(conf) })
  23.226 +
  23.227 +    def xend_domain_migrate(self, id, dst):
  23.228 +        return xend_call(self.domainurl(id),
  23.229 +                         {'op'      : 'migrate',
  23.230 +                          'dst'     : dst})
  23.231 +
  23.232 +    def xend_domain_pincpu(self, id, cpu):
  23.233 +        return xend_call(self.domainurl(id),
  23.234 +                         {'op'      : 'pincpu',
  23.235 +                          'cpu'     : cpu})
  23.236 +
  23.237 +    def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu):
  23.238 +        return xend_call(self.domainurl(id),
  23.239 +                         {'op'      : 'cpu_bvt_set',
  23.240 +                          'mcuadv'  : mvuadv,
  23.241 +                          'warp'    : warp,
  23.242 +                          'warpl'   : warpl,
  23.243 +                          'warpu'   : warpu })
  23.244 +
  23.245 +    def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime):
  23.246 +        return xend_call(self.domainurl(id),
  23.247 +                         {'op'      : 'cpu_atropos_set',
  23.248 +                          'period'  : period,
  23.249 +                          'slice'   : slice,
  23.250 +                          'latency' : latency,
  23.251 +                          'xtratime': xtratime })
  23.252 +
  23.253 +    def xend_domain_vifs(self, id):
  23.254 +        return xend_get(self.domainurl(id),
  23.255 +                        { 'op'      : 'vifs' })
  23.256 +    
  23.257 +    def xend_domain_vif_stats(self, id, vif):
  23.258 +        return xend_get(self.domainurl(id),
  23.259 +                        { 'op'      : 'vif_stats',
  23.260 +                          'vif'     : vif})
  23.261 +
  23.262 +    def xend_domain_vif_ip_add(self, id, vif, ipaddr):
  23.263 +        return xend_call(self.domainurl(id),
  23.264 +                         {'op'      : 'vif_ip_add',
  23.265 +                          'vif'     : vif,
  23.266 +                          'ip'      : ipaddr })
  23.267 +        
  23.268 +    def xend_domain_vif_scheduler_set(id, vif, bytes, usecs):
  23.269 +        return xend_call(self.domainurl(id),
  23.270 +                         {'op'      : 'vif_scheduler_set',
  23.271 +                          'vif'     : vif,
  23.272 +                          'bytes'   : bytes,
  23.273 +                          'usecs'   : usecs })
  23.274 +
  23.275 +    def xend_domain_vif_scheduler_get(id, vif):
  23.276 +        return xend_get(self.domainurl(id),
  23.277 +                         {'op'      : 'vif_scheduler_get',
  23.278 +                          'vif'     : vif})
  23.279 +
  23.280 +    def xend_domain_vbds(self, id):
  23.281 +        return xend_get(self.domainurl(id),
  23.282 +                        {'op'       : 'vbds'})
  23.283 +
  23.284 +    def xend_domain_vbd(self, id, vbd):
  23.285 +        return xend_get(self.domainurl(id),
  23.286 +                        {'op'       : 'vbd',
  23.287 +                         'vbd'      : vbd})
  23.288 +
  23.289 +    def xend_domain_vbd_add(self, id, uname, dev, mode):
  23.290 +        return xend_call(self.domainurl(id),
  23.291 +                         {'op'      : 'vbd_add',
  23.292 +                          'uname'   : uname,
  23.293 +                          'dev'     : dev,
  23.294 +                          'mode'    : mode})
  23.295 +
  23.296 +    def xend_domain_vbd_remove(self, id, dev):
  23.297 +        return xend_call(self.domainurl(id),
  23.298 +                         {'op'      : 'vbd_remove',
  23.299 +                          'dev'     : dev})
  23.300 +
  23.301 +    def xend_consoles(self):
  23.302 +        return xend_get(self.consoleurl())
  23.303 +
  23.304 +    def xend_console(self, id):
  23.305 +        return xend_get(self.consoleurl(id))
  23.306 +
  23.307 +    def xend_vbds(self):
  23.308 +        return xend_get(self.vbdurl())
  23.309 +
  23.310 +    def xend_vbd_create(self, conf):
  23.311 +        return xend_call(self.vbdurl(),
  23.312 +                         {'op': 'create', 'config': fileof(conf) })
  23.313 +
  23.314 +    def xend_vbd(self, id):
  23.315 +        return xend_get(self.vbdurl(id))
  23.316 +
  23.317 +    def xend_vbd_delete(self, id):
  23.318 +        return xend_call(self.vbdurl(id),
  23.319 +                         {'op': 'delete'})
  23.320 +
  23.321 +    def xend_vbd_refresh(self, id, expiry):
  23.322 +        return xend_call(self.vbdurl(id),
  23.323 +                         {'op': 'refresh', 'expiry': expiry })
  23.324 +
  23.325 +    def xend_vbd_expand(self, id, size):
  23.326 +        return xend_call(self.vbdurl(id),
  23.327 +                         {'op': 'expand', 'size': size})
  23.328 +
  23.329 +    def xend_vnets(self):
  23.330 +        return xend_get(self.vneturl())
  23.331 +
  23.332 +    def xend_vnet_create(self, conf):
  23.333 +        return xend_call(self.vneturl(),
  23.334 +                         {'op': 'create', 'config': fileof(conf) })
  23.335 +
  23.336 +    def xend_vnet(self, id):
  23.337 +        return xend_get(self.vneturl(id))
  23.338 +
  23.339 +    def xend_vnet_delete(self, id):
  23.340 +        return xend_call(self.vneturl(id),
  23.341 +                         {'op': 'delete'})
  23.342 +
  23.343 +    def xend_event_inject(self, sxpr):
  23.344 +        val = xend_call(self.eventurl(),
  23.345 +                        {'op': 'inject', 'event': fileof(sxpr) })
  23.346 +    
  23.347 +
  23.348 +def main(argv):
  23.349 +    """Call an API function:
  23.350 +    
  23.351 +    python XendClient.py fn args...
  23.352 +
  23.353 +    The leading 'xend_' on the function can be omitted.
  23.354 +    Example:
  23.355 +
  23.356 +    > python XendClient.py domains
  23.357 +    (domain 0 8)
  23.358 +    > python XendClient.py domain 0
  23.359 +    (domain (id 0) (name Domain-0) (memory 128))
  23.360 +    """
  23.361 +    server = Xend()
  23.362 +    fn = argv[1]
  23.363 +    if not fn.startswith('xend'):
  23.364 +        fn = 'xend_' + fn
  23.365 +    args = argv[2:]
  23.366 +    getattr(server, fn)(*args)
  23.367 +
  23.368 +if __name__ == "__main__":
  23.369 +    main(sys.argv)
  23.370 +else:    
  23.371 +    server = Xend()
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/tools/xenmgr/lib/XendConsole.py	Fri Jun 11 22:04:24 2004 +0000
    24.3 @@ -0,0 +1,172 @@
    24.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    24.5 +
    24.6 +import socket
    24.7 +import Xc
    24.8 +xc = Xc.new()
    24.9 +
   24.10 +import sxp
   24.11 +import XendRoot
   24.12 +xroot = XendRoot.instance()
   24.13 +import XendDB
   24.14 +
   24.15 +import EventServer
   24.16 +eserver = EventServer.instance()
   24.17 +
   24.18 +from xenmgr.server import SrvConsoleServer
   24.19 +xcd = SrvConsoleServer.instance()
   24.20 +
   24.21 +class XendConsoleInfo:
   24.22 +    """Console information record.
   24.23 +    """
   24.24 +
   24.25 +    def __init__(self, console, dom1, port1, dom2, port2, conn=None):
   24.26 +        self.console = console
   24.27 +        self.dom1  = dom1
   24.28 +        self.port1 = port1
   24.29 +        self.dom2  = dom2
   24.30 +        self.port2 = port2
   24.31 +        self.conn  = conn
   24.32 +        #self.id = "%d.%d-%d.%d" % (self.dom1, self.port1, self.dom2, self.port2)
   24.33 +        self.id = str(port1)
   24.34 +
   24.35 +    def __str__(self):
   24.36 +        s = "console"
   24.37 +        s += " id=%s" % self.id
   24.38 +        s += " src=%d.%d" % (self.dom1, self.port1)
   24.39 +        s += " dst=%d.%d" % (self.dom2, self.port2)
   24.40 +        s += " port=%s" % self.console
   24.41 +        if self.conn:
   24.42 +            s += " conn=%s:%s" % (self.conn[0], self.conn[1])
   24.43 +        return s
   24.44 +
   24.45 +    def sxpr(self):
   24.46 +        sxpr = ['console',
   24.47 +                ['id', self.id],
   24.48 +                ['src', self.dom1, self.port1],
   24.49 +                ['dst', self.dom2, self.port2],
   24.50 +                ['port', self.console],
   24.51 +                ]
   24.52 +        if self.conn:
   24.53 +            sxpr.append(['connected', self.conn[0], self.conn[1]])
   24.54 +        return sxpr
   24.55 +
   24.56 +    def connection(self):
   24.57 +        return self.conn
   24.58 +
   24.59 +    def update(self, consinfo):
   24.60 +        conn = sxp.child(consinfo, 'connected')
   24.61 +        if conn:
   24.62 +            self.conn = conn[1:]
   24.63 +        else:
   24.64 +            self.conn = None
   24.65 +
   24.66 +    def uri(self):
   24.67 +        """Get the uri to use to connect to the console.
   24.68 +        This will be a telnet: uri.
   24.69 +
   24.70 +        return uri
   24.71 +        """
   24.72 +        host = socket.gethostname()
   24.73 +        return "telnet://%s:%s" % (host, self.console)
   24.74 +
   24.75 +class XendConsole:
   24.76 +
   24.77 +    dbpath = "console"
   24.78 +
   24.79 +    def  __init__(self):
   24.80 +        self.db = XendDB.XendDB(self.dbpath)
   24.81 +        self.console = {}
   24.82 +        self.console_db = self.db.fetchall("")
   24.83 +        if xroot.get_rebooted():
   24.84 +            print 'XendConsole> rebooted: removing all console info'
   24.85 +            self.rm_all()
   24.86 +        eserver.subscribe('xend.domain.died', self.onDomainDied)
   24.87 +
   24.88 +    def rm_all(self):
   24.89 +        """Remove all console info. Used after reboot.
   24.90 +        """
   24.91 +        for (k, v) in self.console_db.items():
   24.92 +            self._delete_console(k)
   24.93 +
   24.94 +    def refresh(self):
   24.95 +        consoles = xcd.consoles()
   24.96 +        cons = {}
   24.97 +        for consinfo in consoles:
   24.98 +            id = str(sxp.child_value(consinfo, 'id'))
   24.99 +            cons[id] = consinfo
  24.100 +            if id not in self.console:
  24.101 +                self._new_console(consinfo)
  24.102 +        for c in self.console.values():
  24.103 +            consinfo = cons.get(c.id)
  24.104 +            if consinfo:
  24.105 +                c.update(consinfo)
  24.106 +            else:
  24.107 +                self._delete_console(c.id)
  24.108 +
  24.109 +    def onDomainDied(self, event, val):
  24.110 +        dom = int(val)
  24.111 +        for c in self.consoles():
  24.112 +            if (c.dom1 == dom) or (c.dom2 == dom):
  24.113 +                self._delete_console(c.id)
  24.114 +
  24.115 +    def sync(self):
  24.116 +        self.db.saveall("", self.console_db)
  24.117 +
  24.118 +    def sync_console(self, id):
  24.119 +        self.db.save(id, self.console_db[id])
  24.120 +
  24.121 +    def _new_console(self, consinfo):
  24.122 +        # todo: xen needs a call to get current domain id.
  24.123 +        dom1 = 0
  24.124 +        port1 = sxp.child_value(consinfo, 'local_port')
  24.125 +        dom2 = sxp.child_value(consinfo, 'domain')
  24.126 +        port2 = sxp.child_value(consinfo, 'remote_port')
  24.127 +        console = sxp.child_value(consinfo, 'console_port')
  24.128 +        info = XendConsoleInfo(console, dom1, int(port1), int(dom2), int(port2))
  24.129 +        info.update(consinfo)
  24.130 +        self._add_console(info.id, info)
  24.131 +        return info
  24.132 +
  24.133 +    def _add_console(self, id, info):
  24.134 +        self.console[id] = info
  24.135 +        self.console_db[id] = info.sxpr()
  24.136 +        self.sync_console(id)
  24.137 +
  24.138 +    def _delete_console(self, id):
  24.139 +        if id in self.console:
  24.140 +            del self.console[id]
  24.141 +        if id in self.console_db:
  24.142 +            del self.console_db[id]
  24.143 +            self.db.delete(id)
  24.144 +
  24.145 +    def console_ls(self):
  24.146 +        self.refresh()
  24.147 +        return self.console.keys()
  24.148 +
  24.149 +    def consoles(self):
  24.150 +        self.refresh()
  24.151 +        return self.console.values()
  24.152 +    
  24.153 +    def console_create(self, dom):
  24.154 +        consinfo = xcd.console_create(dom)
  24.155 +        info = self._new_console(consinfo)
  24.156 +        return info
  24.157 +    
  24.158 +    def console_get(self, id):
  24.159 +        self.refresh()
  24.160 +        return self.console.get(id)
  24.161 +
  24.162 +    def console_delete(self, id):
  24.163 +        self._delete_console(id)
  24.164 +
  24.165 +    def console_disconnect(self, id):
  24.166 +        id = int(id)
  24.167 +        xcd.console_disconnect(id)
  24.168 +
  24.169 +def instance():
  24.170 +    global inst
  24.171 +    try:
  24.172 +        inst
  24.173 +    except:
  24.174 +        inst = XendConsole()
  24.175 +    return inst
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/tools/xenmgr/lib/XendDB.py	Fri Jun 11 22:04:24 2004 +0000
    25.3 @@ -0,0 +1,91 @@
    25.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    25.5 +
    25.6 +import os
    25.7 +import os.path
    25.8 +import errno
    25.9 +import dircache
   25.10 +import time
   25.11 +
   25.12 +import sxp
   25.13 +import XendRoot
   25.14 +xroot = XendRoot.instance()
   25.15 +
   25.16 +class XendDB:
   25.17 +    """Persistence for Xend. Stores data in files and directories.
   25.18 +    """
   25.19 +
   25.20 +    def __init__(self, path=None):
   25.21 +        self.dbpath = xroot.get_dbroot()
   25.22 +        if path:
   25.23 +            self.dbpath = os.path.join(self.dbpath, path)
   25.24 +        pass
   25.25 +
   25.26 +    def filepath(self, path):
   25.27 +        return os.path.join(self.dbpath, path)
   25.28 +        
   25.29 +    def fetch(self, path):
   25.30 +        fpath = self.filepath(path)
   25.31 +        return self.fetchfile(fpath)
   25.32 +
   25.33 +    def fetchfile(self, fpath):
   25.34 +        pin = sxp.Parser()
   25.35 +        fin = file(fpath, "rb")
   25.36 +        try:
   25.37 +            while 1:
   25.38 +                try:
   25.39 +                    buf = fin.read(1024)
   25.40 +                except IOError, ex:
   25.41 +                    if ex.errno == errno.EINTR:
   25.42 +                        continue
   25.43 +                    else:
   25.44 +                        raise
   25.45 +                pin.input(buf)
   25.46 +                if buf == '':
   25.47 +                    pin.input_eof()
   25.48 +                    break
   25.49 +        finally:
   25.50 +            fin.close()
   25.51 +        return pin.get_val()
   25.52 +
   25.53 +    def save(self, path, sxpr):
   25.54 +        fpath = self.filepath(path)
   25.55 +        return self.savefile(fpath, sxpr)
   25.56 +    
   25.57 +    def savefile(self, fpath, sxpr):
   25.58 +        fdir = os.path.dirname(fpath)
   25.59 +        if not os.path.isdir(fdir):
   25.60 +            os.makedirs(fdir)
   25.61 +        fout = file(fpath, "wb+")
   25.62 +        try:
   25.63 +            t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
   25.64 +            fout.write("# %s %s\n" % (fpath, t))
   25.65 +            sxp.show(sxpr, out=fout)
   25.66 +        finally:
   25.67 +            fout.close()
   25.68 +
   25.69 +    def fetchall(self, path):
   25.70 +        dpath = self.filepath(path)
   25.71 +        d = {}
   25.72 +        for k in dircache.listdir(dpath):
   25.73 +            try:
   25.74 +                v = self.fetchfile(os.path.join(dpath, k))
   25.75 +                d[k] = v
   25.76 +            except:
   25.77 +                pass
   25.78 +        return d
   25.79 +
   25.80 +    def saveall(self, path, d):
   25.81 +        for (k, v) in d.items():
   25.82 +            self.save(os.path.join(path, k), v)
   25.83 +
   25.84 +    def delete(self, path):
   25.85 +        dpath = self.filepath(path)
   25.86 +        os.unlink(dpath)
   25.87 +
   25.88 +    def ls(self, path):
   25.89 +        dpath = self.filepath(path)
   25.90 +        return dircache.listdir(dpath)
   25.91 +            
   25.92 +        
   25.93 +
   25.94 +        
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/tools/xenmgr/lib/XendDomain.py	Fri Jun 11 22:04:24 2004 +0000
    26.3 @@ -0,0 +1,347 @@
    26.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    26.5 +
    26.6 +"""Handler for domain operations.
    26.7 + Nothing here is persistent (across reboots).
    26.8 + Needs to be persistent for one uptime.
    26.9 +"""
   26.10 +import sys
   26.11 +
   26.12 +import Xc; xc = Xc.new()
   26.13 +import xenctl.ip
   26.14 +import xenctl.vdisk
   26.15 +
   26.16 +import sxp
   26.17 +import XendRoot
   26.18 +xroot = XendRoot.instance()
   26.19 +import XendDB
   26.20 +import XendDomainInfo
   26.21 +import XendConsole
   26.22 +import EventServer
   26.23 +
   26.24 +eserver = EventServer.instance()
   26.25 +
   26.26 +__all__ = [ "XendDomain" ]
   26.27 +        
   26.28 +class XendDomain:
   26.29 +    """Index of all domains. Singleton.
   26.30 +    """
   26.31 +    
   26.32 +    dbpath = "domain"
   26.33 +    domain = {}
   26.34 +    
   26.35 +    def __init__(self):
   26.36 +        self.xconsole = XendConsole.instance()
   26.37 +        # Table of domain info indexed by domain id.
   26.38 +        self.db = XendDB.XendDB(self.dbpath)
   26.39 +        #self.domain = {}
   26.40 +        self.domain_db = self.db.fetchall("")
   26.41 +        if xroot.get_rebooted():
   26.42 +            print 'XendDomain> rebooted: removing all domain info'
   26.43 +            self.rm_all()
   26.44 +        self.initial_refresh()
   26.45 +
   26.46 +    def rm_all(self):
   26.47 +        """Remove all domain info. Used after reboot.
   26.48 +        """
   26.49 +        for (k, v) in self.domain_db.items():
   26.50 +            self._delete_domain(k, notify=0)
   26.51 +            
   26.52 +    def initial_refresh(self):
   26.53 +        """Refresh initial domain info from domain_db.
   26.54 +        """
   26.55 +        domlist = xc.domain_getinfo()
   26.56 +        doms = {}
   26.57 +        for d in domlist:
   26.58 +            domid = str(d['dom'])
   26.59 +            doms[domid] = d
   26.60 +        for config in self.domain_db.values():
   26.61 +            domid = int(sxp.child_value(config, 'id'))
   26.62 +            if domid in doms:
   26.63 +                self._new_domain(config)
   26.64 +            else:
   26.65 +                self._delete_domain(domid)
   26.66 +        self.refresh()
   26.67 +
   26.68 +    def sync(self):
   26.69 +        """Sync domain db to disk.
   26.70 +        """
   26.71 +        self.db.saveall("", self.domain_db)
   26.72 +
   26.73 +    def sync_domain(self, dom):
   26.74 +        """Sync info for a domain to disk.
   26.75 +
   26.76 +        dom	domain id (string)
   26.77 +        """
   26.78 +        self.db.save(dom, self.domain_db[dom])
   26.79 +
   26.80 +    def close(self):
   26.81 +        pass
   26.82 +
   26.83 +    def _new_domain(self, info):
   26.84 +        """Create a domain entry from saved info.
   26.85 +        """
   26.86 +        console = None
   26.87 +        kernel = None
   26.88 +        id = sxp.child_value(info, 'id')
   26.89 +        dom = int(id)
   26.90 +        name = sxp.child_value(info, 'name')
   26.91 +        memory = int(sxp.child_value(info, 'memory'))
   26.92 +        consoleinfo = sxp.child(info, 'console')
   26.93 +        if consoleinfo:
   26.94 +            consoleid = sxp.child_value(consoleinfo, 'id')
   26.95 +            console = self.xconsole.console_get(consoleid)
   26.96 +        if dom and console is None:
   26.97 +            # Try to connect a console.
   26.98 +            console = self.xconsole.console_create(dom)
   26.99 +        config = sxp.child(info, 'config')
  26.100 +        if config:
  26.101 +            image = sxp.child(info, 'image')
  26.102 +            if image:
  26.103 +                image = sxp.child0(image)
  26.104 +                kernel = sxp.child_value(image, 'kernel')
  26.105 +        dominfo = XendDomainInfo.XendDomainInfo(
  26.106 +            config, dom, name, memory, kernel, console)
  26.107 +        self.domain[id] = dominfo
  26.108 +
  26.109 +    def _add_domain(self, id, info, notify=1):
  26.110 +        self.domain[id] = info
  26.111 +        self.domain_db[id] = info.sxpr()
  26.112 +        self.sync_domain(id)
  26.113 +        if notify: eserver.inject('xend.domain.created', id)
  26.114 +
  26.115 +    def _delete_domain(self, id, notify=1):
  26.116 +        if id in self.domain:
  26.117 +            if notify: eserver.inject('xend.domain.died', id)
  26.118 +            del self.domain[id]
  26.119 +        if id in self.domain_db:
  26.120 +            del self.domain_db[id]
  26.121 +            self.db.delete(id)
  26.122 +
  26.123 +    def refresh(self):
  26.124 +        """Refresh domain list from Xen.
  26.125 +        """
  26.126 +        domlist = xc.domain_getinfo()
  26.127 +        # Index the domlist by id.
  26.128 +        # Add entries for any domains we don't know about.
  26.129 +        doms = {}
  26.130 +        for d in domlist:
  26.131 +            id = str(d['dom'])
  26.132 +            doms[id] = d
  26.133 +            if id not in self.domain:
  26.134 +                config = None
  26.135 +                image = None
  26.136 +                newinfo = XendDomainInfo.XendDomainInfo(
  26.137 +                    config, d['dom'], d['name'], d['mem_kb']/1024, image)
  26.138 +                self._add_domain(id, newinfo)
  26.139 +        # Remove entries for domains that no longer exist.
  26.140 +        for d in self.domain.values():
  26.141 +            dominfo = doms.get(d.id)
  26.142 +            if dominfo:
  26.143 +                d.update(dominfo)
  26.144 +            else:
  26.145 +                self._delete_domain(d.id)
  26.146 +
  26.147 +    def refresh_domain(self, id):
  26.148 +        dom = int(id)
  26.149 +        dominfo = xc.domain_getinfo(dom, 1)
  26.150 +        if dominfo == [] or dominfo[0]['dom'] != dom:
  26.151 +            try:
  26.152 +                self._delete_domain(id)
  26.153 +            except:
  26.154 +                pass
  26.155 +        else:
  26.156 +            d = self.domain.get(id)
  26.157 +            if d:
  26.158 +                d.update(dominfo)
  26.159 +
  26.160 +    def domain_ls(self):
  26.161 +        # List domains.
  26.162 +        # Update info from kernel first.
  26.163 +        self.refresh()
  26.164 +        return self.domain.keys()
  26.165 +
  26.166 +    def domains(self):
  26.167 +        self.refresh()
  26.168 +        return self.domain.values()
  26.169 +    
  26.170 +    def domain_create(self, config):
  26.171 +        # Create domain, log it.
  26.172 +        deferred = XendDomainInfo.vm_create(config)
  26.173 +        def fn(dominfo):
  26.174 +            self._add_domain(dominfo.id, dominfo)
  26.175 +            return dominfo
  26.176 +        deferred.addCallback(fn)
  26.177 +        return deferred
  26.178 +    
  26.179 +    def domain_get(self, id):
  26.180 +        id = str(id)
  26.181 +        self.refresh_domain(id)
  26.182 +        return self.domain[id]
  26.183 +    
  26.184 +    def domain_start(self, id):
  26.185 +        """Start domain running.
  26.186 +        """
  26.187 +        dom = int(id)
  26.188 +        eserver.inject('xend.domain.start', id)
  26.189 +        return xc.domain_start(dom=dom)
  26.190 +    
  26.191 +    def domain_stop(self, id):
  26.192 +        """Stop domain running.
  26.193 +        """
  26.194 +        dom = int(id)
  26.195 +        return xc.domain_stop(dom=dom)
  26.196 +    
  26.197 +    def domain_shutdown(self, id):
  26.198 +        """Shutdown domain (nicely).
  26.199 +        """
  26.200 +        dom = int(id)
  26.201 +        if dom <= 0:
  26.202 +            return 0
  26.203 +        eserver.inject('xend.domain.shutdown', id)
  26.204 +        val = xc.domain_destroy(dom=dom, force=0)
  26.205 +        self.refresh()
  26.206 +        return val
  26.207 +    
  26.208 +    def domain_halt(self, id):
  26.209 +        """Shutdown domain immediately.
  26.210 +        """
  26.211 +        dom = int(id)
  26.212 +        if dom <= 0:
  26.213 +            return 0
  26.214 +        eserver.inject('xend.domain.halt', id)
  26.215 +        val = xc.domain_destroy(dom=dom, force=1)
  26.216 +        self.refresh()
  26.217 +        return val       
  26.218 +
  26.219 +    def domain_migrate(self, id, dst):
  26.220 +        """Start domain migration.
  26.221 +        """
  26.222 +        # Need a cancel too?
  26.223 +        pass
  26.224 +    
  26.225 +    def domain_save(self, id, dst, progress=0):
  26.226 +        """Save domain state to file, halt domain.
  26.227 +        """
  26.228 +        dom = int(id)
  26.229 +        self.domain_stop(id)
  26.230 +        eserver.inject('xend.domain.save', id)
  26.231 +        rc = xc.linux_save(dom=dom, state_file=dst, progress=progress)
  26.232 +        if rc == 0:
  26.233 +            self.domain_halt(id)
  26.234 +        return rc
  26.235 +    
  26.236 +    def domain_restore(self, src, config, progress=0):
  26.237 +        """Restore domain from file.
  26.238 +        """
  26.239 +        dominfo = XendDomainInfo.dom_restore(dom, config)
  26.240 +        self._add_domain(dominfo.id, dominfo)
  26.241 +        return dominfo
  26.242 +    
  26.243 +    def domain_device_add(self, id, info):
  26.244 +        """Add a device to a domain.
  26.245 +        """
  26.246 +        pass
  26.247 +    
  26.248 +    def domain_device_remove(self, id, dev):
  26.249 +        """Delete a device from a domain.
  26.250 +        """
  26.251 +        pass
  26.252 +    
  26.253 +    def domain_device_configure(self, id, dev, info):
  26.254 +        """Configure a domain device.
  26.255 +        """
  26.256 +        pass
  26.257 +
  26.258 +    #============================================================================
  26.259 +    # Backward compatibility stuff from here on.
  26.260 +
  26.261 +    def domain_pincpu(self, dom, cpu):
  26.262 +        dom = int(dom)
  26.263 +        return xc.domain_pincpu(dom, cpu)
  26.264 +
  26.265 +    def domain_cpu_bvt_set(self, dom, mcuadv, warp, warpl, warpu):
  26.266 +        dom = int(dom)
  26.267 +        return xc.bvtsched_domain_set(dom=dom, mcuadv=mcuadv,
  26.268 +                                      warp=warp, warpl=warpl, warpu=warpu)
  26.269 +
  26.270 +    def domain_cpu_bvt_get(self, dom):
  26.271 +        dom = int(dom)
  26.272 +        return xc.bvtsched_domain_get(dom)
  26.273 +    
  26.274 +    def domain_cpu_atropos_set(self, dom, period, slice, latency, xtratime):
  26.275 +        dom = int(dom)
  26.276 +        return xc.atropos_domain_set(dom, period, slice, latency, xtratime)
  26.277 +
  26.278 +    def domain_cpu_atropos_get(self, dom):
  26.279 +        dom = int(dom)
  26.280 +        return xc.atropos_domain_get(dom)
  26.281 +
  26.282 +    def domain_vif_ls(self, dom):
  26.283 +        dominfo = self.domain_get(dom)
  26.284 +        if not dominfo: return None
  26.285 +        devs = dominfo.get_devices('vif')
  26.286 +        return range(0, len(devs))
  26.287 +
  26.288 +    def domain_vif_get(self, dom, vif):
  26.289 +        dominfo = self.domain_get(dom)
  26.290 +        if not dominfo: return None
  26.291 +        return dominfo.get_device_by_index(vif)
  26.292 +
  26.293 +    def domain_vif_stats(self, dom, vif):
  26.294 +        dom = int(dom)
  26.295 +        return xc.vif_stats_get(dom=dom, vif=vif)
  26.296 +
  26.297 +    def domain_vif_ip_add(self, dom, vif, ip):
  26.298 +        dom = int(dom)
  26.299 +        return xenctl.ip.setup_vfr_rules_for_vif(dom, vif, ip)
  26.300 +
  26.301 +    def domain_vif_scheduler_set(self, dom, vif, bytes, usecs):
  26.302 +        dom = int(dom)
  26.303 +        return xc.xc_vif_scheduler_set(dom=dom, vif=vif,
  26.304 +                                       credit_bytes=bytes, credit_usecs=usecs)
  26.305 +
  26.306 +    def domain_vif_scheduler_get(self, dom, vif):
  26.307 +        dom = int(dom)
  26.308 +        return xc.vif_scheduler_get(dom=dom, vif=vif)
  26.309 +
  26.310 +    def domain_vbd_ls(self, dom):
  26.311 +        dominfo = self.domain_get(dom)
  26.312 +        if not dominfo: return []
  26.313 +        devs = dominfo.get_devices('vbd')
  26.314 +        return [ sxp.child_value(v, 'dev') for v in devs ]
  26.315 +
  26.316 +    def domain_vbd_get(self, dom, vbd):
  26.317 +        dominfo = self.domain_get(dom)
  26.318 +        if not dominfo: return None
  26.319 +        devs = dominfo.get_devices('vbd')
  26.320 +        for v in devs:
  26.321 +            if sxp.child_value(v, 'dev') == vbd:
  26.322 +                return v
  26.323 +        return None
  26.324 +
  26.325 +    def domain_vbd_add(self, dom, uname, dev, mode):
  26.326 +        dom = int(dom)
  26.327 +        vbd = vm.make_disk(dom, uname, dev, mode)
  26.328 +        return vbd
  26.329 +
  26.330 +    def domain_vbd_remove(self, dom, dev):
  26.331 +        dom = int(dom)
  26.332 +        vbd = xenctl.vdisk.blkdev_name_to_number(dev)
  26.333 +        if vbd < 0: return vbd
  26.334 +        err = xc.vbd_destroy(dom, vbd)
  26.335 +        if err < 0: return err
  26.336 +        return vbd
  26.337 +
  26.338 +    def domain_shadow_control(self, dom, op):
  26.339 +        dom = int(dom)
  26.340 +        return xc.shadow_control(dom, op)
  26.341 +
  26.342 +    #============================================================================
  26.343 +
  26.344 +def instance():
  26.345 +    global inst
  26.346 +    try:
  26.347 +        inst
  26.348 +    except:
  26.349 +        inst = XendDomain()
  26.350 +    return inst
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/tools/xenmgr/lib/XendDomainConfig.py	Fri Jun 11 22:04:24 2004 +0000
    27.3 @@ -0,0 +1,44 @@
    27.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    27.5 +
    27.6 +"""Handler for persistent domain configs.
    27.7 +
    27.8 +"""
    27.9 +
   27.10 +import sxp
   27.11 +import XendDB
   27.12 +import XendDomain
   27.13 +
   27.14 +__all__ = [ "XendDomainConfig" ]
   27.15 +
   27.16 +class XendDomainConfig:
   27.17 +
   27.18 +    dbpath = 'config'
   27.19 +
   27.20 +    def __init__(self):
   27.21 +        self.db = XendDB.XendDB(self.dbpath)
   27.22 +
   27.23 +    def domain_config_ls(self, path):
   27.24 +        return self.db.ls(path)
   27.25 +
   27.26 +    def domain_config_create(self, path, sxpr):
   27.27 +        self.db.save(path, sxpr)
   27.28 +        pass
   27.29 +
   27.30 +    def domain_config_delete(self, path):
   27.31 +        self.db.delete(path)
   27.32 +
   27.33 +    def domain_config_instance(self, path):
   27.34 +        """Create a domain from a config.
   27.35 +        """
   27.36 +        config = self.db.fetch(path)
   27.37 +        xd = XendDomain.instance()
   27.38 +        newdom = xd.domain_create(config)
   27.39 +        return newdom
   27.40 +
   27.41 +def instance():
   27.42 +    global inst
   27.43 +    try:
   27.44 +        inst
   27.45 +    except:
   27.46 +        inst = XendDomainConfig()
   27.47 +    return inst
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/tools/xenmgr/lib/XendDomainInfo.py	Fri Jun 11 22:04:24 2004 +0000
    28.3 @@ -0,0 +1,697 @@
    28.4 +#!/usr/bin/python
    28.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    28.6 +
    28.7 +"""Representation of a single domain.
    28.8 +Includes support for domain construction, using
    28.9 +open-ended configurations.
   28.10 +
   28.11 +Author: Mike Wray <mike.wray@hpl.hp.com>
   28.12 +
   28.13 +"""
   28.14 +
   28.15 +import sys
   28.16 +import os
   28.17 +
   28.18 +from twisted.internet import defer
   28.19 +
   28.20 +import Xc; xc = Xc.new()
   28.21 +
   28.22 +import xenctl.ip
   28.23 +import xenctl.vdisk
   28.24 +
   28.25 +import sxp
   28.26 +
   28.27 +import XendConsole
   28.28 +xendConsole = XendConsole.instance()
   28.29 +
   28.30 +import server.SrvConsoleServer
   28.31 +xend = server.SrvConsoleServer.instance()
   28.32 +
   28.33 +class VmError(ValueError):
   28.34 +    """Vm construction error."""
   28.35 +
   28.36 +    def __init__(self, value):
   28.37 +        self.value = value
   28.38 +
   28.39 +    def __str__(self):
   28.40 +        return self.value
   28.41 +
   28.42 +
   28.43 +class XendDomainInfo:
   28.44 +    """Virtual machine object."""
   28.45 +
   28.46 +    def __init__(self, config, dom, name, memory, image=None, console=None):
   28.47 +        """Construct a virtual machine object.
   28.48 +
   28.49 +        config   configuration
   28.50 +        dom      domain id
   28.51 +        name     name
   28.52 +        memory   memory size (in MB)
   28.53 +        image    image object
   28.54 +        """
   28.55 +        #todo: add info: runtime, state, ...
   28.56 +        self.config = config
   28.57 +        self.id = str(dom)
   28.58 +        self.dom = dom
   28.59 +        self.name = name
   28.60 +        self.memory = memory
   28.61 +        self.image = image
   28.62 +        self.console = console
   28.63 +        self.devices = {}
   28.64 +        self.configs = []
   28.65 +        self.info = None
   28.66 +
   28.67 +        #todo: state: running, suspended
   28.68 +        self.state = 'running'
   28.69 +        #todo: set to migrate info if migrating
   28.70 +        self.migrate = None
   28.71 +
   28.72 +    def update(self, info):
   28.73 +        """Update with  info from xc.domain_getinfo().
   28.74 +        """
   28.75 +        self.info = info
   28.76 +
   28.77 +    def __str__(self):
   28.78 +        s = "domain"
   28.79 +        s += " id=" + self.id
   28.80 +        s += " name=" + self.name
   28.81 +        s += " memory=" + str(self.memory)
   28.82 +        if self.console:
   28.83 +            s += " console=" + self.console.id
   28.84 +        if self.image:
   28.85 +            s += " image=" + self.image
   28.86 +        s += ""
   28.87 +        return s
   28.88 +
   28.89 +    __repr__ = __str__
   28.90 +
   28.91 +    def sxpr(self):
   28.92 +        sxpr = ['domain',
   28.93 +                ['id', self.id],
   28.94 +                ['name', self.name],
   28.95 +                ['memory', self.memory] ]
   28.96 +        if self.info:
   28.97 +            run = (self.info['running'] and 'r') or '-'
   28.98 +            stop = (self.info['stopped'] and 's') or '-'
   28.99 +            state = run + state
  28.100 +            sxpr.append(['cpu', self.info['cpu']])
  28.101 +            sxpr.append(['state', state])
  28.102 +            sxpr.append(['cpu_time', self.info['cpu_time']/1e8])
  28.103 +        if self.console:
  28.104 +            sxpr.append(self.console.sxpr())
  28.105 +        if self.config:
  28.106 +            sxpr.append(['config', self.config])
  28.107 +        return sxpr
  28.108 +
  28.109 +    def add_device(self, type, dev):
  28.110 +        """Add a device to a virtual machine.
  28.111 +
  28.112 +        dev      device to add
  28.113 +        """
  28.114 +        dl = self.devices.get(type, [])
  28.115 +        dl.append(dev)
  28.116 +        self.devices[type] = dl
  28.117 +
  28.118 +    def get_devices(self, type):
  28.119 +        val = self.devices.get(type, [])
  28.120 +        print 'get_devices', type; sxp.show(val); print
  28.121 +        return val
  28.122 +
  28.123 +    def get_device_by_id(self, type, id):
  28.124 +        """Get the device with the given id.
  28.125 +
  28.126 +        id       device id
  28.127 +
  28.128 +        returns  device or None
  28.129 +        """
  28.130 +        return sxp.child_with_id(self.get_devices(type), id)
  28.131 +
  28.132 +    def get_device_by_index(self, type, idx):
  28.133 +        dl = self.get_devices(type)
  28.134 +        if 0 <= idx < len(dl):
  28.135 +            return dl[idx]
  28.136 +        else:
  28.137 +            return None
  28.138 +
  28.139 +    def add_config(self, val):
  28.140 +        """Add configuration data to a virtual machine.
  28.141 +
  28.142 +        val      data to add
  28.143 +        """
  28.144 +        self.configs.append(val)
  28.145 +
  28.146 +    def destroy(self):
  28.147 +        if self.dom <= 0:
  28.148 +            return 0
  28.149 +        return xc.domain_destroy(dom=self.dom, force=1)
  28.150 +
  28.151 +    def show(self):
  28.152 +        """Print virtual machine info.
  28.153 +        """
  28.154 +        print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory)
  28.155 +        print "image:"
  28.156 +        sxp.show(self.image)
  28.157 +        print
  28.158 +        for dl in self.devices:
  28.159 +            for dev in dl:
  28.160 +                print "device:"
  28.161 +                sxp.show(dev)
  28.162 +                print
  28.163 +        for val in self.configs:
  28.164 +            print "config:"
  28.165 +            sxp.show(val)
  28.166 +            print
  28.167 +        print "]"
  28.168 +
  28.169 +def safety_level(sharing):
  28.170 +    if sharing == 'rw':
  28.171 +        return xenctl.vdisk.VBD_SAFETY_RW
  28.172 +    if sharing == 'ww':
  28.173 +        return xenctl.vdisk.VBD_SAFETY_WW
  28.174 +    return xenctl.vdisk.VBD_SAFETY_RR
  28.175 +
  28.176 +
  28.177 +def make_disk_old(dom, uname, dev, mode, sharing):
  28.178 +    writeable = ('w' in mode)
  28.179 +    safety = safety_level(sharing)
  28.180 +    vbd = xenctl.vdisk.blkdev_name_to_number(dev)
  28.181 +    extents = xenctl.vdisk.lookup_disk_uname(uname)
  28.182 +    if not extents:
  28.183 +        raise VmError("vbd: Extents not found: uname=%s" % uname)
  28.184 +
  28.185 +    # check that setting up this VBD won't violate the sharing
  28.186 +    # allowed by the current VBD expertise level
  28.187 +    if xenctl.vdisk.vd_extents_validate(extents, writeable, safety=safety) < 0:
  28.188 +        raise VmError("vbd: Extents invalid: uname=%s" % uname)
  28.189 +            
  28.190 +    if xc.vbd_create(dom=dom, vbd=vbd, writeable=writeable):
  28.191 +        raise VmError("vbd: Creating device failed: dom=%d uname=%s vbd=%d mode=%s"
  28.192 +                      % (dom, uname, vbdmode))
  28.193 +
  28.194 +    if xc.vbd_setextents(dom=dom, vbd=vbd, extents=extents):
  28.195 +        raise VMError("vbd: Setting extents failed: dom=%d uname=%s vbd=%d"
  28.196 +                      % (dom, uname, vbd))
  28.197 +    return vbd
  28.198 +
  28.199 +def make_disk(dom, uname, dev, mode, sharing):
  28.200 +    """Create a virtual disk device for a domain.
  28.201 +
  28.202 +    @returns Deferred
  28.203 +    """
  28.204 +    segments = xenctl.vdisk.lookup_disk_uname(uname)
  28.205 +    if not segments:
  28.206 +        raise VmError("vbd: Segments not found: uname=%s" % uname)
  28.207 +    if len(segments) > 1:
  28.208 +        raise VmError("vbd: Multi-segment vdisk: uname=%s" % uname)
  28.209 +    segment = segments[0]
  28.210 +    vdev = xenctl.vdisk.blkdev_name_to_number(dev)
  28.211 +    ctrl = xend.blkif_create(dom)
  28.212 +    
  28.213 +    def fn(ctrl):
  28.214 +        return xend.blkif_dev_create(dom, vdev, mode, segment)
  28.215 +    ctrl.addCallback(fn)
  28.216 +    return ctrl
  28.217 +        
  28.218 +def make_vif_old(dom, vif, vmac, vnet):
  28.219 +    return # todo: Not supported yet.
  28.220 +    err = xc.vif_setinfo(dom=dom, vif=vif, vmac=vmac, vnet=vnet)
  28.221 +    if err < 0:
  28.222 +        raise VmError('vnet: Error %d setting vif mac dom=%d vif=%d vmac=%s vnet=%d' %
  28.223 +                        (err, dom, vif, vmac, vnet))
  28.224 +
  28.225 +def make_vif(dom, vif, vmac):
  28.226 +    """Create a virtual network device for a domain.
  28.227 +
  28.228 +    
  28.229 +    @returns Deferred
  28.230 +    """
  28.231 +    xend.netif_create(dom)
  28.232 +    d = xend.netif_dev_create(dom, vif, vmac)
  28.233 +    return d
  28.234 +
  28.235 +def vif_up(iplist):
  28.236 +    #todo: Need a better way.
  28.237 +    # send an unsolicited ARP reply for all non link-local IPs
  28.238 +
  28.239 +    IP_NONLOCAL_BIND = '/proc/sys/net/ipv4/ip_nonlocal_bind'
  28.240 +    
  28.241 +    def get_ip_nonlocal_bind():
  28.242 +        return int(open(IP_NONLOCAL_BIND, 'r').read()[0])
  28.243 +
  28.244 +    def set_ip_nonlocal_bind(v):
  28.245 +        print >> open(IP_NONLOCAL_BIND, 'w'), str(v)
  28.246 +
  28.247 +    def link_local(ip):
  28.248 +        return xenctl.ip.check_subnet(ip, '169.254.0.0', '255.255.0.0')
  28.249 +
  28.250 +    def arping(ip, gw):
  28.251 +        cmd = '/usr/sbin/arping -A -b -I eth0 -c 1 -s %s %s' % (ip, gw)
  28.252 +        print cmd
  28.253 +        os.system(cmd)
  28.254 +        
  28.255 +    gateway = xenctl.ip.get_current_ipgw() or '255.255.255.255'
  28.256 +    nlb = get_ip_nonlocal_bind()
  28.257 +    if not nlb: set_ip_nonlocal_bind(1)
  28.258 +    try:
  28.259 +        for ip in iplist:
  28.260 +            if not link_local(ip):
  28.261 +                arping(ip, gateway)
  28.262 +    finally:
  28.263 +        if not nlb: set_ip_nonlocal_bind(0)
  28.264 +
  28.265 +def xen_domain_create(config, ostype, name, memory, kernel, ramdisk, cmdline, vifs_n):
  28.266 +    if not os.path.isfile(kernel):
  28.267 +        raise VmError('Kernel image does not exist: %s' % kernel)
  28.268 +    if ramdisk and not os.path.isfile(ramdisk):
  28.269 +        raise VMError('Kernel ramdisk does not exist: %s' % ramdisk)
  28.270 +
  28.271 +    cpu = int(sxp.child_value(config, 'cpu', '-1'))
  28.272 +    dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
  28.273 +    if dom <= 0:
  28.274 +        raise VmError('Creating domain failed: name=%s memory=%d kernel=%s'
  28.275 +                      % (name, memory, kernel))
  28.276 +    console = xendConsole.console_create(dom)
  28.277 +    buildfn = getattr(xc, '%s_build' % ostype)
  28.278 +    err = buildfn(dom            = dom,
  28.279 +                  image          = kernel,
  28.280 +                  control_evtchn = console.port2,
  28.281 +                  cmdline        = cmdline,
  28.282 +                  ramdisk        = ramdisk)
  28.283 +    if err != 0:
  28.284 +        raise VmError('Building domain failed: type=%s dom=%d err=%d'
  28.285 +                      % (ostype, dom, err))
  28.286 +    vm = XendDomainInfo(config, dom, name, memory, kernel, console)
  28.287 +    return vm
  28.288 +
  28.289 +config_handlers = {}
  28.290 +
  28.291 +def add_config_handler(name, h):
  28.292 +    """Add a handler for a config field.
  28.293 +
  28.294 +    name     field name
  28.295 +    h        handler: fn(vm, config, field, index)
  28.296 +    """
  28.297 +    config_handlers[name] = h
  28.298 +
  28.299 +def get_config_handler(name):
  28.300 +    """Get a handler for a config field.
  28.301 +
  28.302 +    returns handler or None
  28.303 +    """
  28.304 +    return config_handlers.get(name)
  28.305 +
  28.306 +"""Table of handlers for virtual machine images.
  28.307 +Indexed by image type.
  28.308 +"""
  28.309 +image_handlers = {}
  28.310 +
  28.311 +def add_image_handler(name, h):
  28.312 +    """Add a handler for an image type
  28.313 +    name     image type
  28.314 +    h        handler: fn(config, name, memory, image)
  28.315 +    """
  28.316 +    image_handlers[name] = h
  28.317 +
  28.318 +def get_image_handler(name):
  28.319 +    """Get the handler for an image type.
  28.320 +    name     image type
  28.321 +
  28.322 +    returns handler or None
  28.323 +    """
  28.324 +    return image_handlers.get(name)
  28.325 +
  28.326 +"""Table of handlers for devices.
  28.327 +Indexed by device type.
  28.328 +"""
  28.329 +device_handlers = {}
  28.330 +
  28.331 +def add_device_handler(name, h):
  28.332 +    """Add a handler for a device type.
  28.333 +
  28.334 +    name      device type
  28.335 +    h         handler: fn(vm, dev)
  28.336 +    """
  28.337 +    device_handlers[name] = h
  28.338 +
  28.339 +def get_device_handler(name):
  28.340 +    """Get the handler for a device type.
  28.341 +
  28.342 +    name      device type
  28.343 +
  28.344 +    returns handler or None
  28.345 +    """
  28.346 +    return device_handlers.get(name)
  28.347 +
  28.348 +def vm_create(config):
  28.349 +    """Create a VM from a configuration.
  28.350 +    If a vm has been partially created and there is an error it
  28.351 +    is destroyed.
  28.352 +
  28.353 +    config    configuration
  28.354 +
  28.355 +    returns Deferred
  28.356 +    raises VmError for invalid configuration
  28.357 +    """
  28.358 +    # todo - add support for scheduling params?
  28.359 +    print 'vm_create>'
  28.360 +    xenctl.vdisk.VBD_EXPERT_MODE = 0
  28.361 +    vm = None
  28.362 +    try:
  28.363 +        name = sxp.child_value(config, 'name')
  28.364 +        memory = int(sxp.child_value(config, 'memory', '128'))
  28.365 +        image = sxp.child_value(config, 'image')
  28.366 +        
  28.367 +        image_name = sxp.name(image)
  28.368 +        image_handler = get_image_handler(image_name)
  28.369 +        if image_handler is None:
  28.370 +            raise VmError('unknown image type: ' + image_name)
  28.371 +        vm = image_handler(config, name, memory, image)
  28.372 +        deferred = vm_configure(vm, config)
  28.373 +    except StandardError, ex:
  28.374 +        # Catch errors, cleanup and re-raise.
  28.375 +        if vm:
  28.376 +            vm.destroy()
  28.377 +        raise
  28.378 +    def cbok(x):
  28.379 +        print 'vm_create> cbok', x
  28.380 +        return x
  28.381 +    deferred.addCallback(cbok)
  28.382 +    print 'vm_create<'
  28.383 +    return deferred
  28.384 +
  28.385 +def vm_restore(src, config, progress=0):
  28.386 +    ostype = "linux" #todo set from config
  28.387 +    restorefn = getattr(xc, "%s_restore" % ostype)
  28.388 +    dom = restorefn(state_file=src, progress=progress)
  28.389 +    if dom < 0: return dom
  28.390 +    deferred = dom_configure(dom, config)
  28.391 +    return deferred
  28.392 +    
  28.393 +def dom_get(dom):
  28.394 +    domlist = xc.domain_getinfo(dom=dom)
  28.395 +    if domlist and dom == domlist[0]['dom']:
  28.396 +        return domlist[0]
  28.397 +    return None
  28.398 +    
  28.399 +def dom_configure(dom, config):
  28.400 +    d = dom_get(dom)
  28.401 +    if not d:
  28.402 +        raise VMError("Domain not found: %d" % dom)
  28.403 +    try:
  28.404 +        name = d['name']
  28.405 +        memory = d['memory']/1024
  28.406 +        image = None
  28.407 +        vm = VM(config, dom, name, memory, image)
  28.408 +        deferred = vm_configure(vm, config)
  28.409 +    except StandardError, ex:
  28.410 +        if vm:
  28.411 +            vm.destroy()
  28.412 +        raise
  28.413 +    return deferred
  28.414 +
  28.415 +def append_deferred(dlist, v):
  28.416 +    if isinstance(v, defer.Deferred):
  28.417 +        dlist.append(v)
  28.418 +
  28.419 +def vm_create_devices(vm, config):
  28.420 +    """Create the devices for a vm.
  28.421 +
  28.422 +    vm         virtual machine
  28.423 +    config     configuration
  28.424 +
  28.425 +    returns Deferred
  28.426 +    raises VmError for invalid devices
  28.427 +    """
  28.428 +    print '>vm_create_devices'
  28.429 +    dlist = []
  28.430 +    devices = sxp.children(config, 'device')
  28.431 +    index = {}
  28.432 +    for d in devices:
  28.433 +        dev = sxp.child0(d)
  28.434 +        if dev is None:
  28.435 +            raise VmError('invalid device')
  28.436 +        dev_name = sxp.name(dev)
  28.437 +        dev_index = index.get(dev_name, 0)
  28.438 +        dev_handler = get_device_handler(dev_name)
  28.439 +        if dev_handler is None:
  28.440 +            raise VmError('unknown device type: ' + dev_name)
  28.441 +        v = dev_handler(vm, dev, dev_index)
  28.442 +        append_deferred(dlist, v)
  28.443 +        index[dev_name] = dev_index + 1
  28.444 +    deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
  28.445 +    print '<vm_create_devices'
  28.446 +    return deferred
  28.447 +
  28.448 +def vm_configure(vm, config):
  28.449 +    """Configure a vm.
  28.450 +
  28.451 +    vm         virtual machine
  28.452 +    config     configuration
  28.453 +
  28.454 +    returns Deferred - calls callback with vm
  28.455 +    """
  28.456 +    d = xend.blkif_create(vm.dom)
  28.457 +    d.addCallback(_vm_configure1, vm, config)
  28.458 +    return d
  28.459 +
  28.460 +def _vm_configure1(val, vm, config):
  28.461 +    d = vm_create_devices(vm, config)
  28.462 +    print '_vm_configure1> made devices...'
  28.463 +    def cbok(x):
  28.464 +        print '_vm_configure1> cbok', x
  28.465 +        return x
  28.466 +    d.addCallback(cbok)
  28.467 +    d.addCallback(_vm_configure2, vm, config)
  28.468 +    print '_vm_configure1<'
  28.469 +    return d
  28.470 +
  28.471 +def _vm_configure2(val, vm, config):
  28.472 +    print '>callback _vm_configure2...'
  28.473 +    dlist = []
  28.474 +    index = {}
  28.475 +    for field in sxp.children(config):
  28.476 +        field_name = sxp.name(field)
  28.477 +        field_index = index.get(field_name, 0)
  28.478 +        field_handler = get_config_handler(field_name)
  28.479 +        # Ignore unknown fields. Warn?
  28.480 +        if field_handler:
  28.481 +            v = field_handler(vm, config, field, field_index)
  28.482 +            append_deferred(dlist, v)
  28.483 +        index[field_name] = field_index + 1
  28.484 +    d = defer.DeferredList(dlist, fireOnOneErrback=1)
  28.485 +    def cbok(results):
  28.486 +        print '_vm_configure2> cbok', results
  28.487 +        return vm
  28.488 +    def cberr(err):
  28.489 +        print '_vm_configure2> cberr', err
  28.490 +        vm.destroy()
  28.491 +        return err
  28.492 +    d.addCallback(cbok)
  28.493 +    d.addErrback(cberr)
  28.494 +    print '<_vm_configure2'
  28.495 +    return d
  28.496 +
  28.497 +def config_devices(config, name):
  28.498 +    """Get a list of the 'device' nodes of a given type from a config.
  28.499 +
  28.500 +    config	configuration
  28.501 +    name	device type
  28.502 +    return list of device configs
  28.503 +    """
  28.504 +    devices = []
  28.505 +    for d in sxp.children(config, 'device'):
  28.506 +        dev = sxp.child0(d)
  28.507 +        if dev is None: continue
  28.508 +        if name == sxp.name(dev):
  28.509 +            devices.append(dev)
  28.510 +    return devices
  28.511 +        
  28.512 +def vm_image_linux(config, name, memory, image):
  28.513 +    """Create a VM for a linux image.
  28.514 +
  28.515 +    name      vm name
  28.516 +    memory    vm memory
  28.517 +    image     image config
  28.518 +
  28.519 +    returns vm
  28.520 +    """
  28.521 +    kernel = sxp.child_value(image, "kernel")
  28.522 +    cmdline = ""
  28.523 +    ip = sxp.child_value(image, "ip", "dhcp")
  28.524 +    if ip:
  28.525 +        cmdline += " ip=" + ip
  28.526 +    root = sxp.child_value(image, "root")
  28.527 +    if root:
  28.528 +        cmdline += " root=" + root
  28.529 +    args = sxp.child_value(image, "args")
  28.530 +    if args:
  28.531 +        cmdline += " " + args
  28.532 +    ramdisk = sxp.child_value(image, "ramdisk", '')
  28.533 +    vifs = config_devices(config, "vif")
  28.534 +    vm = xen_domain_create(config, "linux", name, memory, kernel,
  28.535 +                           ramdisk, cmdline, len(vifs))
  28.536 +    return vm
  28.537 +
  28.538 +def vm_image_netbsd(config, name, memory, image):
  28.539 +    """Create a VM for a bsd image.
  28.540 +
  28.541 +    name      vm name
  28.542 +    memory    vm memory
  28.543 +    image     image config
  28.544 +
  28.545 +    returns vm
  28.546 +    """
  28.547 +    #todo: Same as for linux. Is that right? If so can unify them.
  28.548 +    kernel = sxp.child_value(image, "kernel")
  28.549 +    cmdline = ""
  28.550 +    ip = sxp.child_value(image, "ip", "dhcp")
  28.551 +    if ip:
  28.552 +        cmdline += "ip=" + ip
  28.553 +    root = sxp.child_value(image, "root")
  28.554 +    if root:
  28.555 +        cmdline += "root=" + root
  28.556 +    args = sxp.child_value(image, "args")
  28.557 +    if args:
  28.558 +        cmdline += " " + args
  28.559 +    ramdisk = sxp.child_value(image, "ramdisk")
  28.560 +    vifs = config_devices(config, "vif")
  28.561 +    vm = xen_domain_create(config, "netbsd", name, memory, kernel,
  28.562 +                           ramdisk, cmdline, len(vifs))
  28.563 +    return vm
  28.564 +
  28.565 +
  28.566 +def vm_dev_vif(vm, val, index):
  28.567 +    """Create a virtual network interface (vif).
  28.568 +
  28.569 +    vm        virtual machine
  28.570 +    val       vif config
  28.571 +    index     vif index
  28.572 +    """
  28.573 +    vif = index #todo
  28.574 +    vmac = sxp.child_value(val, "mac")
  28.575 +    defer = make_vif(vm.dom, vif, vmac)
  28.576 +    def fn(id):
  28.577 +        dev = val + ['vif', vif]
  28.578 +        vm.add_device('vif', dev)
  28.579 +        print 'vm_dev_vif> created', dev
  28.580 +        return id
  28.581 +    defer.addCallback(fn)
  28.582 +    return defer
  28.583 +
  28.584 +def vm_dev_vbd(vm, val, index):
  28.585 +    """Create a virtual block device (vbd).
  28.586 +
  28.587 +    vm        virtual machine
  28.588 +    val       vbd config
  28.589 +    index     vbd index
  28.590 +    """
  28.591 +    uname = sxp.child_value(val, 'uname')
  28.592 +    if not uname:
  28.593 +        raise VMError('vbd: Missing uname')
  28.594 +    dev = sxp.child_value(val, 'dev')
  28.595 +    if not dev:
  28.596 +        raise VMError('vbd: Missing dev')
  28.597 +    mode = sxp.child_value(val, 'mode', 'r')
  28.598 +    sharing = sxp.child_value(val, 'sharing', 'rr')
  28.599 +    defer = make_disk(vm.dom, uname, dev, mode, sharing)
  28.600 +    def fn(vbd):
  28.601 +        vm.add_device('vbd', val)
  28.602 +        return vbd
  28.603 +    defer.addCallback(fn)
  28.604 +    return defer
  28.605 +
  28.606 +def vm_dev_pci(vm, val, index):
  28.607 +    bus = sxp.child_value(val, 'bus')
  28.608 +    if not bus:
  28.609 +        raise VMError('pci: Missing bus')
  28.610 +    dev = sxp.child_value(val, 'dev')
  28.611 +    if not dev:
  28.612 +        raise VMError('pci: Missing dev')
  28.613 +    func = sxp.child_value(val, 'func')
  28.614 +    if not func:
  28.615 +        raise VMError('pci: Missing func')
  28.616 +    rc = xc.physdev_pci_access_modify(dom=vm.dom, bus=bus, dev=dev, func=func, enable=1)
  28.617 +    if rc < 0:
  28.618 +        #todo non-fatal
  28.619 +        raise VMError('pci: Failed to configure device: bus=%s dev=%s func=%s' %
  28.620 +                      (bus, dev, func))
  28.621 +    return rc
  28.622 +    
  28.623 +
  28.624 +def vm_field_vfr(vm, config, val, index):
  28.625 +    """Handle a vfr field in a config.
  28.626 +
  28.627 +    vm        virtual machine
  28.628 +    config    vm config
  28.629 +    val       vfr field
  28.630 +    """
  28.631 +    # Get the rules and add them.
  28.632 +    # (vfr (vif (id foo) (ip x.x.x.x)) ... ) 
  28.633 +    list = sxp.children(val, 'vif')
  28.634 +    for v in list:
  28.635 +        id = sxp.child_value(v, 'id')
  28.636 +        if id is None:
  28.637 +            raise VmError('vfr: missing vif id')
  28.638 +        id = int(id)
  28.639 +        dev = vm.get_device_by_index('vif', id)
  28.640 +        if not dev:
  28.641 +            raise VmError('vfr: invalid vif id %d' % id)
  28.642 +        vif = sxp.child_value(dev, 'vif')
  28.643 +        ip = sxp.child_value(v, 'ip')
  28.644 +        if not ip:
  28.645 +            raise VmError('vfr: missing ip address')
  28.646 +        #Don't do this in new i/o model.
  28.647 +        #print 'vm_field_vfr> add rule', 'dom=', vm.dom, 'vif=', vif, 'ip=', ip
  28.648 +        #xenctl.ip.setup_vfr_rules_for_vif(vm.dom, vif, ip)
  28.649 +
  28.650 +def vnet_bridge(vnet, vmac, dom, idx):
  28.651 +    """Add the device for the vif to the bridge for its vnet.
  28.652 +    """
  28.653 +    vif = "vif%d.%d" % (dom, idx)
  28.654 +    try:
  28.655 +        cmd = "(vif.conn (vif %s) (vnet %s) (vmac %s))" % (vif, vnet, vmac)
  28.656 +        print "*** vnet_bridge>", cmd
  28.657 +        out = file("/proc/vnet/policy", "wb")
  28.658 +        out.write(cmd)
  28.659 +        err = out.close()
  28.660 +        print "vnet_bridge>", "err=", err
  28.661 +    except IOError, ex:
  28.662 +        print "vnet_bridge>", ex
  28.663 +    
  28.664 +def vm_field_vnet(vm, config, val, index):
  28.665 +    """Handle a vnet field in a config.
  28.666 +
  28.667 +    vm        virtual machine
  28.668 +    config    vm config
  28.669 +    val       vnet field
  28.670 +    index     index
  28.671 +    """
  28.672 +    # Get the vif children. For each vif look up the vif device
  28.673 +    # with the given id and configure its vnet.
  28.674 +    # (vnet (vif (id foo) (vnet 2) (mac x:x:x:x:x:x)) ... )
  28.675 +    vif_vnets = sxp.children(val, 'vif')
  28.676 +    for v in vif_vnets:
  28.677 +        id = sxp.child_value(v, 'id')
  28.678 +        if id is None:
  28.679 +            raise VmError('vnet: missing vif id')
  28.680 +        dev = vm.get_device_by_id('vif', id)
  28.681 +        if not sxp.elementp(dev, 'vif'):
  28.682 +            raise VmError('vnet: invalid vif id %s' % id)
  28.683 +        vnet = sxp.child_value(v, 'vnet', 1)
  28.684 +        mac = sxp.child_value(dev, 'mac')
  28.685 +        vif = sxp.child_value(dev, 'vif')
  28.686 +        vnet_bridge(vnet, mac, vm.dom, 0)
  28.687 +        vm.add_config([ 'vif.vnet', ['id', id], ['vnet', vnet], ['mac', mac]])
  28.688 +
  28.689 +# Register image handlers for linux and bsd.
  28.690 +add_image_handler('linux',  vm_image_linux)
  28.691 +add_image_handler('netbsd', vm_image_netbsd)
  28.692 +
  28.693 +# Register device handlers for vifs and vbds.
  28.694 +add_device_handler('vif',  vm_dev_vif)
  28.695 +add_device_handler('vbd',  vm_dev_vbd)
  28.696 +add_device_handler('pci',  vm_dev_pci)
  28.697 +
  28.698 +# Register config handlers for vfr and vnet.
  28.699 +add_config_handler('vfr',  vm_field_vfr)
  28.700 +add_config_handler('vnet', vm_field_vnet)
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/tools/xenmgr/lib/XendMigrate.py	Fri Jun 11 22:04:24 2004 +0000
    29.3 @@ -0,0 +1,103 @@
    29.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    29.5 +
    29.6 +import sys
    29.7 +import socket
    29.8 +
    29.9 +import sxp
   29.10 +import XendDB
   29.11 +import EventServer; eserver = EventServer.instance()
   29.12 +
   29.13 +class XendMigrateInfo:
   29.14 +
   29.15 +    # states: begin, active, failed, succeeded?
   29.16 +
   29.17 +    def __init__(self, id, dom, dst):
   29.18 +        self.id = id
   29.19 +        self.state = 'begin'
   29.20 +        self.src_host = socket.gethostname()
   29.21 +        self.src_dom = dom
   29.22 +        self.dst_host = dst
   29.23 +        self.dst_dom = None
   29.24 +        
   29.25 +    def set_state(self, state):
   29.26 +        self.state = state
   29.27 +
   29.28 +    def get_state(self):
   29.29 +        return self.state
   29.30 +
   29.31 +    def sxpr(self):
   29.32 +        sxpr = ['migrate', ['id', self.id], ['state', self.state] ]
   29.33 +        sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ]
   29.34 +        sxpr.append(sxpr_src)
   29.35 +        sxpr_dst = ['dst', ['host', self.dst] ]
   29.36 +        if self.dst_dom:
   29.37 +            sxpr_dst.append(['domain', self.dst_dom])
   29.38 +        sxpr.append(sxpr_dst)
   29.39 +        return sxpr
   29.40 +    
   29.41 +
   29.42 +class XendMigrate:
   29.43 +    # Represents migration in progress.
   29.44 +    # Use log for indications of begin/end/errors?
   29.45 +    # Need logging of: domain create/halt, migrate begin/end/fail
   29.46 +    # Log via event server?
   29.47 +
   29.48 +    dbpath = "migrate"
   29.49 +    
   29.50 +    def __init__(self):
   29.51 +        self.db = XendDB.XendDB(self.dbpath)
   29.52 +        self.migrate = {}
   29.53 +        self.migrate_db = self.db.fetchall("")
   29.54 +        self.id = 0
   29.55 +
   29.56 +    def nextid(self):
   29.57 +        self.id += 1
   29.58 +        return "%d" % self.id
   29.59 +
   29.60 +    def sync(self):
   29.61 +        self.db.saveall("", self.migrate_db)
   29.62 +
   29.63 +    def sync_migrate(self, id):
   29.64 +        self.db.save(id, self.migrate_db[id])
   29.65 +
   29.66 +    def close(self):
   29.67 +        pass
   29.68 +
   29.69 +    def _add_migrate(self, id, info):
   29.70 +        self.migrate[id] = info
   29.71 +        self.migrate_db[id] = info.sxpr()
   29.72 +        self.sync_migrate(id)
   29.73 +        #eserver.inject('xend.migrate.begin', info.sxpr())
   29.74 +
   29.75 +    def _delete_migrate(self, id):
   29.76 +        #eserver.inject('xend.migrate.end', id)
   29.77 +        del self.migrate[id]
   29.78 +        del self.migrate_db[id]
   29.79 +        self.db.delete(id)
   29.80 +
   29.81 +    def migrate_ls(self):
   29.82 +        return self.migrate.keys()
   29.83 +
   29.84 +    def migrates(self):
   29.85 +        return self.migrate.values()
   29.86 +
   29.87 +    def migrate_get(self, id):
   29.88 +        return self.migrate.get(id)
   29.89 +    
   29.90 +    def migrate_begin(self, dom, dst):
   29.91 +        # Check dom for existence, not migrating already.
   29.92 +        # Create migrate info, tell xend to migrate it?
   29.93 +        # - or fork migrate command ourselves?
   29.94 +        # Subscribe to migrate notifications (for updating).
   29.95 +        id = self.nextid()
   29.96 +        info = XenMigrateInfo(id, dom, dst)
   29.97 +        self._add_migrate(id, info)
   29.98 +        return id
   29.99 +
  29.100 +def instance():
  29.101 +    global inst
  29.102 +    try:
  29.103 +        inst
  29.104 +    except:
  29.105 +        inst = XendMigrate()
  29.106 +    return inst
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/tools/xenmgr/lib/XendNode.py	Fri Jun 11 22:04:24 2004 +0000
    30.3 @@ -0,0 +1,55 @@
    30.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    30.5 +
    30.6 +"""Handler for node operations.
    30.7 + Has some persistent state:
    30.8 + - logs
    30.9 + - notification urls
   30.10 +
   30.11 +"""
   30.12 +
   30.13 +import Xc
   30.14 +
   30.15 +class XendNodeInfo:
   30.16 +    """Node information record.
   30.17 +    """
   30.18 +
   30.19 +    def __init__(self):
   30.20 +        pass
   30.21 +
   30.22 +class XendNode:
   30.23 +
   30.24 +    def __init__(self):
   30.25 +        self.xc = Xc.new()
   30.26 +
   30.27 +    def shutdown(self):
   30.28 +        return 0
   30.29 +
   30.30 +    def reboot(self):
   30.31 +        return 0
   30.32 +
   30.33 +    def notify(self, uri):
   30.34 +        return 0
   30.35 +    
   30.36 +    def cpu_bvt_slice_set(self, slice):
   30.37 +        ret = 0
   30.38 +        #ret = self.xc.bvtsched_global_set(ctx_allow=slice)
   30.39 +        return ret
   30.40 +
   30.41 +    def cpu_bvt_slice_get(self, slice):
   30.42 +        ret = 0
   30.43 +        #ret = self.xc.bvtsched_global_get()
   30.44 +        return ret
   30.45 +    
   30.46 +    def cpu_rrobin_slice_set(self, slice):
   30.47 +        ret = 0
   30.48 +        #ret = self.xc.rrobin_global_set(slice)
   30.49 +        return ret
   30.50 +
   30.51 +def instance():
   30.52 +    global inst
   30.53 +    try:
   30.54 +        inst
   30.55 +    except:
   30.56 +        inst = XendNode()
   30.57 +    return inst
   30.58 +
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/tools/xenmgr/lib/XendRoot.py	Fri Jun 11 22:04:24 2004 +0000
    31.3 @@ -0,0 +1,156 @@
    31.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    31.5 +
    31.6 +"""Xend root class.
    31.7 +Creates the event server and handles configuration.
    31.8 +"""
    31.9 +
   31.10 +import os
   31.11 +import os.path
   31.12 +import sys
   31.13 +import EventServer
   31.14 +
   31.15 +# Initial create of the event server.
   31.16 +eserver = EventServer.instance()
   31.17 +
   31.18 +import sxp
   31.19 +
   31.20 +def reboots():
   31.21 +    """Get a list of system reboots from wtmp.
   31.22 +    """
   31.23 +    out = os.popen('/usr/bin/last reboot', 'r')
   31.24 +    list = [ x.strip() for x in out if x.startswith('reboot') ]
   31.25 +    return list
   31.26 +
   31.27 +def last_reboot():
   31.28 +    """Get the last known system reboot.
   31.29 +    """
   31.30 +    l = reboots()
   31.31 +    return (l and l[-1]) or None
   31.32 +
   31.33 +class XendRoot:
   31.34 +    """Root of the management classes."""
   31.35 +
   31.36 +    lastboot_default = "/etc/xen/xend/lastboot"
   31.37 +
   31.38 +    """Default path to the root of the database."""
   31.39 +    dbroot_default = "/etc/xen/xend/xenmgr-db"
   31.40 +
   31.41 +    """Default path to the config file."""
   31.42 +    config_default = "/etc/xen/xenmgr-config.sxp"
   31.43 +
   31.44 +    """Environment variable used to override config_default."""
   31.45 +    config_var     = "XEND_CONFIG"
   31.46 +
   31.47 +    def __init__(self):
   31.48 +        self.rebooted = 0
   31.49 +        self.last_reboot = None
   31.50 +        self.dbroot = None
   31.51 +        self.config_path = None
   31.52 +        self.config = None
   31.53 +        self.configure()
   31.54 +        self.check_lastboot()
   31.55 +        eserver.subscribe('xend.*', self.event_handler)
   31.56 +        #eserver.subscribe('xend.domain.created', self.event_handler)
   31.57 +        #eserver.subscribe('xend.domain.died', self.event_handler)
   31.58 +
   31.59 +    def start(self):
   31.60 +        eserver.inject('xend.start', self.rebooted)
   31.61 +
   31.62 +    def event_handler(self, event, val):
   31.63 +        print >> sys.stderr, "EVENT>", event, val
   31.64 +
   31.65 +    def read_lastboot(self):
   31.66 +        try:
   31.67 +            val = file(self.lastboot, 'rb').readlines()[0]
   31.68 +        except StandardError, ex:
   31.69 +            print 'warning: Error reading', self.lastboot, ex
   31.70 +            val = None
   31.71 +        return val
   31.72 +
   31.73 +    def write_lastboot(self, val):
   31.74 +        if not val: return
   31.75 +        try:
   31.76 +            fdir = os.path.dirname(self.lastboot)
   31.77 +            if not os.path.isdir(fdir):
   31.78 +                os.makedirs(fdir)
   31.79 +            out = file(self.lastboot, 'wb+')
   31.80 +            out.write(val)
   31.81 +            out.close()
   31.82 +        except IOError, ex:
   31.83 +            print 'warning: Error writing', self.lastboot, ex
   31.84 +            pass
   31.85 +
   31.86 +    def check_lastboot(self):
   31.87 +        """Check if there has been a system reboot since we saved lastboot.
   31.88 +        """
   31.89 +        last_val = self.read_lastboot()
   31.90 +        this_val = last_reboot()
   31.91 +        if this_val == last_val:
   31.92 +            self.rebooted = 0
   31.93 +        else:
   31.94 +            self.rebooted = 1
   31.95 +            self.write_lastboot(this_val)
   31.96 +        self.last_reboot = this_val
   31.97 +
   31.98 +    def get_last_reboot(self):
   31.99 +        return self.last_reboot
  31.100 +
  31.101 +    def get_rebooted(self):
  31.102 +        return self.rebooted
  31.103 +
  31.104 +    def configure(self):
  31.105 +        self.set_config()
  31.106 +        self.dbroot = self.get_config_value("dbroot", self.dbroot_default)
  31.107 +        self.lastboot = self.get_config_value("lastboot", self.lastboot_default)
  31.108 +
  31.109 +    def get_dbroot(self):
  31.110 +        """Get the path to the database root.
  31.111 +        """
  31.112 +        return self.dbroot
  31.113 +
  31.114 +    def set_config(self):
  31.115 +        """If the config file exists, read it. If not, ignore it.
  31.116 +
  31.117 +        The config file is a sequence of sxp forms.
  31.118 +        """
  31.119 +        self.config_path = os.getenv(self.config_var, self.config_default)
  31.120 +        if os.path.exists(self.config_path):
  31.121 +            fin = file(self.config_path, 'rb')
  31.122 +            try:
  31.123 +                config = sxp.parse(fin)
  31.124 +                config.insert(0, 'config')
  31.125 +                self.config = config
  31.126 +            finally:
  31.127 +                fin.close()
  31.128 +        else:
  31.129 +            self.config = ['config']
  31.130 +
  31.131 +    def get_config(self, name=None):
  31.132 +        """Get the configuration element with the given name, or
  31.133 +        the whole configuration if no name is given.
  31.134 +
  31.135 +        name	element name (optional)
  31.136 +        returns config or none
  31.137 +        """
  31.138 +        if name is None:
  31.139 +            val = self.config
  31.140 +        else:
  31.141 +            val = sxp.child(self.config, name)
  31.142 +        return val
  31.143 +
  31.144 +    def get_config_value(self, name, val=None):
  31.145 +        """Get the value of an atomic configuration element.
  31.146 +
  31.147 +        name	element name
  31.148 +        val	default value (optional, defaults to None)
  31.149 +        returns value
  31.150 +        """
  31.151 +        return sxp.child_value(self.config, name, val=val)
  31.152 +
  31.153 +def instance():
  31.154 +    global inst
  31.155 +    try:
  31.156 +        inst
  31.157 +    except:
  31.158 +        inst = XendRoot()
  31.159 +    return inst
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/tools/xenmgr/lib/XendVdisk.py	Fri Jun 11 22:04:24 2004 +0000
    32.3 @@ -0,0 +1,111 @@
    32.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    32.5 +
    32.6 +"""Handler for vdisk operations.
    32.7 +
    32.8 +"""
    32.9 +
   32.10 +import os
   32.11 +import os.path
   32.12 +
   32.13 +from xenctl import vdisk
   32.14 +    
   32.15 +import sxp
   32.16 +
   32.17 +class XendVdiskInfo:
   32.18 +
   32.19 +    def __init__(self, info):
   32.20 +        self.info = info
   32.21 +        self.id = info['vdisk_id']
   32.22 +
   32.23 +    def __str__(self):
   32.24 +        return ("vdisk id=%(vdisk_id)s size=%(size)d expires=%(expires)d expiry_time=%(expiry_time)d"
   32.25 +                % self.info)
   32.26 +
   32.27 +    def sxpr(self):
   32.28 +        val = ['vdisk']
   32.29 +        for (k,v) in self.info.items():
   32.30 +            val.append([k, str(v)])
   32.31 +        return val     
   32.32 +
   32.33 +class XendVdisk:
   32.34 +    """Index of all vdisks. Singleton.
   32.35 +    """
   32.36 +
   32.37 +    dbpath = "vdisk"
   32.38 +
   32.39 +    def __init__(self):
   32.40 +        # Table of vdisk info indexed by vdisk id.
   32.41 +        self.vdisk = {}
   32.42 +        if not os.path.isfile(vdisk.VD_DB_FILE):
   32.43 +            vdisk.vd_init_db(vdisk.VD_DB_FILE)
   32.44 +        self.vdisk_refresh()
   32.45 +
   32.46 +    def vdisk_refresh(self):
   32.47 +        # vdisk = {vdisk_id, size, expires, expiry_time}
   32.48 +        try:
   32.49 +            vdisks = vdisk.vd_list()
   32.50 +        except:
   32.51 +            vdisks = []
   32.52 +        for vdisk in vdisks:
   32.53 +            vdiskinfo = XendVdiskInfo(vdisk)
   32.54 +            self.vdisk[vdiskinfo.id] = vdiskinfo
   32.55 +
   32.56 +    def vdisk_ls(self):
   32.57 +        """List all vdisk ids.
   32.58 +        """
   32.59 +        return self.vdisk.keys()
   32.60 +
   32.61 +    def vdisks(self):
   32.62 +        return self.vdisk.values()
   32.63 +    
   32.64 +    def vdisk_get(self, id):
   32.65 +        """Get a vdisk.
   32.66 +
   32.67 +        id	vdisk id
   32.68 +        """
   32.69 +        return self.vdisk.get(id)
   32.70 +
   32.71 +    def vdisk_create(self, info):
   32.72 +        """Create a vdisk.
   32.73 +
   32.74 +        info	config
   32.75 +        """
   32.76 +        # Need to configure for real.
   32.77 +        # vdisk.vd_create(size, expiry)
   32.78 +
   32.79 +    def vdisk_configure(self, info):
   32.80 +        """Configure a vdisk.
   32.81 +        id	vdisk id
   32.82 +        info	config
   32.83 +        """
   32.84 +        # Need to configure for real.
   32.85 +        # Make bigger: vdisk.vd_enlarge(id, extra_size)
   32.86 +        # Update expiry time: vdisk.vd_refresh(id, expiry)
   32.87 +        # Try to recover an expired vdisk : vdisk.vd_undelete(id, expiry)
   32.88 +        
   32.89 +
   32.90 +    def vdisk_delete(self, id):
   32.91 +        """Delete a vdisk.
   32.92 +
   32.93 +        id	vdisk id
   32.94 +        """
   32.95 +        # Need to delete vdisk for real. What if fails?
   32.96 +        del self.vdisk[id]
   32.97 +        vdisk.vd_delete(id)
   32.98 +
   32.99 +    # def vdisk_copy: copy contents to file, vdisk still exists
  32.100 +    # def vdisk_export: copy contents to file then delete the vdisk 
  32.101 +    # def vdisk_import: create a vdisk from a file
  32.102 +    # def vdisk_space: space left for new vdisks
  32.103 +
  32.104 +    # def vdisk_recover: recover an expired vdisk
  32.105 +
  32.106 +    # def vdisk_init_partition: setup a physical partition for vdisks
  32.107 +
  32.108 +def instance():
  32.109 +    global inst
  32.110 +    try:
  32.111 +        inst
  32.112 +    except:
  32.113 +        inst = XendVdisk()
  32.114 +    return inst
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/tools/xenmgr/lib/XendVnet.py	Fri Jun 11 22:04:24 2004 +0000
    33.3 @@ -0,0 +1,69 @@
    33.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    33.5 +
    33.6 +"""Handler for vnet operations.
    33.7 +"""
    33.8 +
    33.9 +import sxp
   33.10 +import XendDB
   33.11 +
   33.12 +class XendVnet:
   33.13 +    """Index of all vnets. Singleton.
   33.14 +    """
   33.15 +
   33.16 +    dbpath = "vnet"
   33.17 +
   33.18 +    def __init__(self):
   33.19 +        # Table of vnet info indexed by vnet id.
   33.20 +        self.vnet = {}
   33.21 +        self.db = XendDB.XendDB(self.dbpath)
   33.22 +        self.vnet = self.db.fetchall("")
   33.23 +
   33.24 +    def vnet_ls(self):
   33.25 +        """List all vnets.
   33.26 +        """
   33.27 +        return self.vnet.keys()
   33.28 +
   33.29 +    def vnets(self):
   33.30 +        return self.vnet.values()
   33.31 +
   33.32 +    def vnet_get(self, id):
   33.33 +        """Get a vnet.
   33.34 +
   33.35 +        id	vnet id
   33.36 +        """
   33.37 +        return self.vnet.get(id)
   33.38 +
   33.39 +    def vnet_create(self, info):
   33.40 +        """Create a vnet.
   33.41 +
   33.42 +        info	config
   33.43 +        """
   33.44 +        self.vnet_configure(info)
   33.45 +
   33.46 +    def vnet_configure(self, info):
   33.47 +        """Configure a vnet.
   33.48 +        id	vnet id
   33.49 +        info	config
   33.50 +        """
   33.51 +        # Need to configure for real.
   33.52 +        # Only sync if succeeded - otherwise need to back out.
   33.53 +        self.vnet[info.id] = info
   33.54 +        self.db.save(info.id, info)
   33.55 +
   33.56 +    def vnet_delete(self, id):
   33.57 +        """Delete a vnet.
   33.58 +
   33.59 +        id	vnet id
   33.60 +        """
   33.61 +        # Need to delete for real. What if fails?
   33.62 +        if id in self.vnet:
   33.63 +            del self.vnet[id]
   33.64 +            self.db.delete(id)
   33.65 +
   33.66 +def instance():
   33.67 +    global inst
   33.68 +    try:
   33.69 +        inst
   33.70 +    except:
   33.71 +        inst = XendVnet()
   33.72 +    return inst
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/tools/xenmgr/lib/__init__.py	Fri Jun 11 22:04:24 2004 +0000
    34.3 @@ -0,0 +1,1 @@
    34.4 + 
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/tools/xenmgr/lib/encode.py	Fri Jun 11 22:04:24 2004 +0000
    35.3 @@ -0,0 +1,165 @@
    35.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    35.5 +"""Encoding for arguments to HTTP calls.
    35.6 +   Uses the url-encoding with MIME type 'application/x-www-form-urlencoded'
    35.7 +   if the data does not include files. Otherwise it uses the encoding with
    35.8 +   MIME type 'multipart/form-data'. See the HTML4 spec for details.
    35.9 +
   35.10 +   """
   35.11 +import sys
   35.12 +import types
   35.13 +from StringIO import StringIO
   35.14 +
   35.15 +import urllib
   35.16 +import httplib
   35.17 +import random
   35.18 +import md5
   35.19 +
   35.20 +# Extract from HTML4 spec.
   35.21 +## The following example illustrates "multipart/form-data"
   35.22 +## encoding. Suppose we have the following form:
   35.23 +
   35.24 +##  <FORM action="http://server.com/cgi/handle"
   35.25 +##        enctype="multipart/form-data"
   35.26 +##        method="post">
   35.27 +##    <P>
   35.28 +##    What is your name? <INPUT type="text" name="submit-name"><BR>
   35.29 +##    What files are you sending? <INPUT type="file" name="files"><BR>
   35.30 +##    <INPUT type="submit" value="Send"> <INPUT type="reset">
   35.31 +##  </FORM>
   35.32 +
   35.33 +## If the user enters "Larry" in the text input, and selects the text
   35.34 +## file "file1.txt", the user agent might send back the following data:
   35.35 +
   35.36 +##    Content-Type: multipart/form-data; boundary=AaB03x
   35.37 +
   35.38 +##    --AaB03x
   35.39 +##    Content-Disposition: form-data; name="submit-name"
   35.40 +
   35.41 +##    Larry
   35.42 +##    --AaB03x
   35.43 +##    Content-Disposition: form-data; name="files"; filename="file1.txt"
   35.44 +##    Content-Type: text/plain
   35.45 +
   35.46 +##    ... contents of file1.txt ...
   35.47 +##    --AaB03x--
   35.48 +
   35.49 +## If the user selected a second (image) file "file2.gif", the user agent
   35.50 +## might construct the parts as follows:
   35.51 +
   35.52 +##    Content-Type: multipart/form-data; boundary=AaB03x
   35.53 +
   35.54 +##    --AaB03x
   35.55 +##    Content-Disposition: form-data; name="submit-name"
   35.56 +
   35.57 +##    Larry
   35.58 +##    --AaB03x
   35.59 +##    Content-Disposition: form-data; name="files"
   35.60 +##    Content-Type: multipart/mixed; boundary=BbC04y
   35.61 +
   35.62 +##    --BbC04y
   35.63 +##    Content-Disposition: file; filename="file1.txt"
   35.64 +##    Content-Type: text/plain
   35.65 +
   35.66 +##    ... contents of file1.txt ...
   35.67 +##    --BbC04y
   35.68 +##    Content-Disposition: file; filename="file2.gif"
   35.69 +##    Content-Type: image/gif
   35.70 +##    Content-Transfer-Encoding: binary
   35.71 +
   35.72 +##    ...contents of file2.gif...
   35.73 +##    --BbC04y--
   35.74 +##    --AaB03x--
   35.75 +
   35.76 +__all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ]
   35.77 +
   35.78 +def data_values(d):
   35.79 +    if isinstance(d, types.DictType):
   35.80 +        return d.items()
   35.81 +    else:
   35.82 +        return d
   35.83 +
   35.84 +def encode_data(d):
   35.85 +    """Encode some data for HTTP transport.
   35.86 +    The encoding used is stored in 'Content-Type' in the headers.
   35.87 +
   35.88 +    d	data - sequence of tuples or dictionary
   35.89 +    returns a 2-tuple of the headers and the encoded data
   35.90 +    """
   35.91 +    val = ({}, None)
   35.92 +    if d is None: return val
   35.93 +    multipart = 0
   35.94 +    for (k, v) in data_values(d):
   35.95 +        if encode_isfile(v):
   35.96 +            multipart = 1
   35.97 +            break
   35.98 +    if multipart:
   35.99 +        val = encode_multipart(d)
  35.100 +    else:
  35.101 +        val = encode_form(d)
  35.102 +    return val
  35.103 +
  35.104 +def encode_isfile(v):
  35.105 +    if isinstance(v, types.FileType):
  35.106 +        return 1
  35.107 +    if hasattr(v, 'readlines'):
  35.108 +        return 1
  35.109 +    return 0
  35.110 +
  35.111 +def encode_multipart(d):
  35.112 +    boundary = mime_boundary()
  35.113 +    hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary }
  35.114 +    out = StringIO()
  35.115 +    for (k,v) in data_values(d):
  35.116 +        out.write('--')
  35.117 +        out.write(boundary)
  35.118 +        out.write('\r\n')
  35.119 +        if encode_isfile(v):
  35.120 +            out.write('Content-Disposition: form-data; name="')
  35.121 +            out.write(k)
  35.122 +            if hasattr(v, 'name'):
  35.123 +                out.write('"; filename="')
  35.124 +                out.write(v.name)
  35.125 +            out.write('"\r\n')
  35.126 +            out.write('Content-Type: application/octet-stream\r\n')
  35.127 +            out.write('\r\n')
  35.128 +            for l in v.readlines():
  35.129 +               out.write(l)  
  35.130 +        else:
  35.131 +            out.write('Content-Disposition: form-data; name="')
  35.132 +            out.write(k)
  35.133 +            out.write('"\r\n')
  35.134 +            out.write('\r\n')
  35.135 +            out.write(str(v))
  35.136 +            out.write('\r\n')
  35.137 +    out.write('--')
  35.138 +    out.write(boundary)
  35.139 +    out.write('--')
  35.140 +    out.write('\r\n')
  35.141 +    return (hdr, out.getvalue())
  35.142 +
  35.143 +def mime_boundary():
  35.144 +    random.seed()
  35.145 +    m = md5.new()
  35.146 +    for i in range(0, 10):
  35.147 +        c = chr(random.randint(1, 255))
  35.148 +        m.update(c)
  35.149 +    b = m.hexdigest()
  35.150 +    return b[0:16]
  35.151 +
  35.152 +def encode_form(d):
  35.153 +    hdr = { 'Content-Type': 'application/x-www-form-urlencoded' }
  35.154 +    val = urllib.urlencode(d)
  35.155 +    return (hdr, val)
  35.156 +
  35.157 +def main():
  35.158 +    #d = {'a': 1, 'b': 'x y', 'c': file('conf.sxp') }
  35.159 +    #d = {'a': 1, 'b': 'x y' }
  35.160 +    d = [ ('a', 1), ('b', 'x y'), ('c', file('conf.sxp')) ]
  35.161 +    #d = [ ('a', 1), ('b', 'x y')]
  35.162 +    v = encode_data(d)
  35.163 +    print v[0]
  35.164 +    sys.stdout.write(v[1])
  35.165 +    print
  35.166 +
  35.167 +if __name__ == "__main__":
  35.168 +    main()
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/tools/xenmgr/lib/server/SrvBase.py	Fri Jun 11 22:04:24 2004 +0000
    36.3 @@ -0,0 +1,137 @@
    36.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    36.5 +
    36.6 +import cgi
    36.7 +
    36.8 +import os
    36.9 +import sys
   36.10 +import types
   36.11 +import StringIO
   36.12 +
   36.13 +from twisted.internet import defer
   36.14 +from twisted.internet import reactor
   36.15 +from twisted.web import error
   36.16 +from twisted.web import resource
   36.17 +from twisted.web import server
   36.18 +
   36.19 +from xenmgr import sxp
   36.20 +from xenmgr import PrettyPrint
   36.21 +
   36.22 +def uri_pathlist(p):
   36.23 +    """Split a path into a list.
   36.24 +    p		path
   36.25 +    return list of path elements
   36.26 +    """
   36.27 +    l = []
   36.28 +    for x in p.split('/'):
   36.29 +        if x == '': continue
   36.30 +        l.append(x)
   36.31 +    return l
   36.32 +
   36.33 +class SrvBase(resource.Resource):
   36.34 +    """Base class for services.
   36.35 +    """
   36.36 +
   36.37 +    def parse_form(self, req, method):
   36.38 +        """Parse the data for a request, GET using the URL, POST using encoded data.
   36.39 +        Posts should use enctype='multipart/form-data' in the <form> tag,
   36.40 +        rather than 'application/x-www-form-urlencoded'. Only 'multipart/form-data'
   36.41 +        handles file upload.
   36.42 +
   36.43 +        req		request
   36.44 +        returns a cgi.FieldStorage instance
   36.45 +        """
   36.46 +        env = {}
   36.47 +        env['REQUEST_METHOD'] = method
   36.48 +        if self.query:
   36.49 +            env['QUERY_STRING'] = self.query
   36.50 +        val = cgi.FieldStorage(fp=req.rfile, headers=req.headers, environ=env)
   36.51 +        return val
   36.52 +    
   36.53 +    def use_sxp(self, req):
   36.54 +        """Determine whether to send an SXP response to a request.
   36.55 +        Uses SXP if there is no User-Agent, no Accept, or application/sxp is in Accept.
   36.56 +
   36.57 +        req		request
   36.58 +        returns 1 for SXP, 0 otherwise
   36.59 +        """
   36.60 +        ok = 0
   36.61 +        user_agent = req.getHeader('User-Agent')
   36.62 +        accept = req.getHeader('Accept')
   36.63 +        if (not user_agent) or (not accept) or (accept.find(sxp.mime_type) >= 0):
   36.64 +            ok = 1
   36.65 +        return ok
   36.66 +
   36.67 +    def get_op_method(self, op):
   36.68 +        """Get the method for an operation.
   36.69 +        For operation 'foo' looks for 'op_foo'.
   36.70 +
   36.71 +        op	operation name
   36.72 +        returns method or None
   36.73 +        """
   36.74 +        op_method_name = 'op_' + op
   36.75 +        return getattr(self, op_method_name, None)
   36.76 +        
   36.77 +    def perform(self, req):
   36.78 +        """General operation handler for posted operations.
   36.79 +        For operation 'foo' looks for a method op_foo and calls
   36.80 +        it with op_foo(op, req). Replies with code 500 if op_foo
   36.81 +        is not found.
   36.82 +
   36.83 +        The method must return a list when req.use_sxp is true
   36.84 +        and an HTML string otherwise (or list).
   36.85 +        Methods may also return a Deferred (for incomplete processing).
   36.86 +
   36.87 +        req	request
   36.88 +        """
   36.89 +        op = req.args.get('op')
   36.90 +        if op is None or len(op) != 1:
   36.91 +            req.setResponseCode(404, "Invalid")
   36.92 +            return ''
   36.93 +        op = op[0]
   36.94 +        op_method = self.get_op_method(op)
   36.95 +        if op_method is None:
   36.96 +            req.setResponseCode(501, "Not implemented")
   36.97 +            req.setHeader("Content-Type", "text/plain")
   36.98 +            req.write("Not implemented: " + op)
   36.99 +            return ''
  36.100 +        else:
  36.101 +            val = op_method(op, req)
  36.102 +            if isinstance(val, defer.Deferred):
  36.103 +                val.addCallback(self._cb_perform, req, 1)
  36.104 +                return server.NOT_DONE_YET
  36.105 +            else:
  36.106 +                self._cb_perform(val, req, 0)
  36.107 +                return ''
  36.108 +
  36.109 +    def _cb_perform(self, val, req, dfr):
  36.110 +        """Callback to complete the request.
  36.111 +        May be called from a Deferred.
  36.112 +        """
  36.113 +        if isinstance(val, error.ErrorPage):
  36.114 +            req.write(val.render(req))
  36.115 +        elif self.use_sxp(req):
  36.116 +            req.setHeader("Content-Type", sxp.mime_type)
  36.117 +            sxp.show(val, req)
  36.118 +        else:
  36.119 +            req.write('<html><head></head><body>')
  36.120 +            self.print_path(req)
  36.121 +            if isinstance(val, types.ListType):
  36.122 +                req.write('<code><pre>')
  36.123 +                PrettyPrint.prettyprint(val, out=req)
  36.124 +                req.write('</pre></code>')
  36.125 +            else:
  36.126 +                req.write(str(val))
  36.127 +            req.write('</body></html>')
  36.128 +        if dfr:
  36.129 +            req.finish()
  36.130 +
  36.131 +    def print_path(self, req):
  36.132 +        """Print the path with hyperlinks.
  36.133 +        """
  36.134 +        pathlist = [x for x in req.prepath if x != '' ]
  36.135 +        s = "/"
  36.136 +        req.write('<h1><a href="/">/</a>')
  36.137 +        for x in pathlist:
  36.138 +            s += x + "/"
  36.139 +            req.write(' <a href="%s">%s</a>/' % (s, x))
  36.140 +        req.write("</h1>")
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/tools/xenmgr/lib/server/SrvConsole.py	Fri Jun 11 22:04:24 2004 +0000
    37.3 @@ -0,0 +1,42 @@
    37.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    37.5 +
    37.6 +from xenmgr import sxp
    37.7 +from xenmgr import XendConsole
    37.8 +from SrvDir import SrvDir
    37.9 +
   37.10 +class SrvConsole(SrvDir):
   37.11 +    """An individual console.
   37.12 +    """
   37.13 +
   37.14 +    def __init__(self, info):
   37.15 +        SrvDir.__init__(self)
   37.16 +        self.info = info
   37.17 +        self.xc = XendConsole.instance()
   37.18 +
   37.19 +    def op_disconnect(self, op, req):
   37.20 +        val = self.xc.console_disconnect(self.info.id)
   37.21 +        return val
   37.22 +
   37.23 +    def render_POST(self, req):
   37.24 +        return self.perform(req)
   37.25 +        
   37.26 +    def render_GET(self, req):
   37.27 +        if self.use_sxp(req):
   37.28 +            req.setHeader("Content-Type", sxp.mime_type)
   37.29 +            sxp.show(self.info.sxpr(), out=req)
   37.30 +        else:
   37.31 +            req.write('<html><head></head><body>')
   37.32 +            self.print_path(req)
   37.33 +            #self.ls()
   37.34 +            req.write('<p>%s</p>' % self.info)
   37.35 +            req.write('<p><a href="%s">Connect to domain %d</a></p>'
   37.36 +                      % (self.info.uri(), self.info.dom2))
   37.37 +            self.form(req)
   37.38 +            req.write('</body></html>')
   37.39 +        return ''
   37.40 +
   37.41 +    def form(self, req):
   37.42 +        req.write('<form method="post" action="%s">' % req.prePathURL())
   37.43 +        if self.info.connection():
   37.44 +            req.write('<input type="submit" name="op" value="disconnect">')
   37.45 +        req.write('</form>')
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/tools/xenmgr/lib/server/SrvConsoleDir.py	Fri Jun 11 22:04:24 2004 +0000
    38.3 @@ -0,0 +1,58 @@
    38.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    38.5 +
    38.6 +from SrvDir import SrvDir
    38.7 +from SrvConsole import SrvConsole
    38.8 +from xenmgr import XendConsole
    38.9 +from xenmgr import sxp
   38.10 +
   38.11 +class SrvConsoleDir(SrvDir):
   38.12 +    """Console directory.
   38.13 +    """
   38.14 +
   38.15 +    def __init__(self):
   38.16 +        SrvDir.__init__(self)
   38.17 +        self.xconsole = XendConsole.instance()
   38.18 +
   38.19 +    def console(self, x):
   38.20 +        val = None
   38.21 +        try:
   38.22 +            info = self.xconsole.console_get(x)
   38.23 +            val = SrvConsole(info)
   38.24 +        except KeyError:
   38.25 +            pass
   38.26 +        return val
   38.27 +
   38.28 +    def get(self, x):
   38.29 +        v = SrvDir.get(self, x)
   38.30 +        if v is not None:
   38.31 +            return v
   38.32 +        v = self.console(x)
   38.33 +        return v
   38.34 +
   38.35 +    def render_GET(self, req):
   38.36 +        if self.use_sxp(req):
   38.37 +            req.setHeader("Content-Type", sxp.mime_type)
   38.38 +            self.ls_console(req, 1)
   38.39 +        else:
   38.40 +            req.write("<html><head></head><body>")
   38.41 +            self.print_path(req)
   38.42 +            self.ls(req)
   38.43 +            self.ls_console(req)
   38.44 +            #self.form(req.wfile)
   38.45 +            req.write("</body></html>")
   38.46 +        return ''
   38.47 +
   38.48 +    def ls_console(self, req, use_sxp=0):
   38.49 +        url = req.prePathURL()
   38.50 +        if not url.endswith('/'):
   38.51 +            url += '/'
   38.52 +        if use_sxp:
   38.53 +            consoles = self.xconsole.console_ls()
   38.54 +            sxp.show(consoles, out=req)
   38.55 +        else:
   38.56 +            consoles = self.xconsole.consoles()
   38.57 +            consoles.sort(lambda x, y: cmp(x.id, y.id))
   38.58 +            req.write('<ul>')
   38.59 +            for c in consoles:
   38.60 +                req.write('<li><a href="%s%s"> %s</a></li>' % (url, c.id, c))
   38.61 +            req.write('</ul>')
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/tools/xenmgr/lib/server/SrvConsoleServer.py	Fri Jun 11 22:04:24 2004 +0000
    39.3 @@ -0,0 +1,631 @@
    39.4 +###########################################################
    39.5 +## Xen controller daemon
    39.6 +## Copyright (c) 2004, K A Fraser (University of Cambridge)
    39.7 +## Copyright (C) 2004, Mike Wray <mike.wray@hp.com>
    39.8 +###########################################################
    39.9 +
   39.10 +import os
   39.11 +import os.path
   39.12 +import signal
   39.13 +import sys
   39.14 +import socket
   39.15 +import pwd
   39.16 +import re
   39.17 +import StringIO
   39.18 +
   39.19 +from twisted.internet import pollreactor
   39.20 +pollreactor.install()
   39.21 +
   39.22 +from twisted.internet import reactor
   39.23 +from twisted.internet import protocol
   39.24 +from twisted.internet import abstract
   39.25 +from twisted.internet import defer
   39.26 +
   39.27 +import xend.utils
   39.28 +
   39.29 +from xenmgr import sxp
   39.30 +from xenmgr import PrettyPrint
   39.31 +from xenmgr import EventServer
   39.32 +eserver = EventServer.instance()
   39.33 +
   39.34 +from xenmgr.server import SrvServer
   39.35 +
   39.36 +import channel
   39.37 +import blkif
   39.38 +import netif
   39.39 +import console
   39.40 +from params import *
   39.41 +
   39.42 +DEBUG = 1
   39.43 +
   39.44 +class MgmtProtocol(protocol.DatagramProtocol):
   39.45 +    """Handler for the management socket (unix-domain).
   39.46 +    """
   39.47 +
   39.48 +    def __init__(self, daemon):
   39.49 +        #protocol.DatagramProtocol.__init__(self)
   39.50 +        self.daemon = daemon
   39.51 +    
   39.52 +    def write(self, data, addr):
   39.53 +        return self.transport.write(data, addr)
   39.54 +
   39.55 +    def datagramReceived(self, data, addr):
   39.56 +        if DEBUG: print 'datagramReceived> addr=', addr, 'data=', data
   39.57 +        io = StringIO.StringIO(data)
   39.58 +        try:
   39.59 +            vals = sxp.parse(io)
   39.60 +            res = self.dispatch(vals[0])
   39.61 +            self.send_result(addr, res)
   39.62 +        except SystemExit:
   39.63 +            raise
   39.64 +        except:
   39.65 +            if DEBUG:
   39.66 +                raise
   39.67 +            else:
   39.68 +                self.send_error(addr)
   39.69 +
   39.70 +    def send_reply(self, addr, sxpr):
   39.71 +        io = StringIO.StringIO()
   39.72 +        sxp.show(sxpr, out=io)
   39.73 +        io.seek(0)
   39.74 +        self.write(io.getvalue(), addr)
   39.75 +
   39.76 +    def send_result(self, addr, res):
   39.77 +        
   39.78 +        def fn(res, self=self, addr=addr):
   39.79 +            self.send_reply(addr, ['ok', res])
   39.80 +            
   39.81 +        if isinstance(res, defer.Deferred):
   39.82 +            res.addCallback(fn)
   39.83 +        else:
   39.84 +            fn(res)
   39.85 +
   39.86 +    def send_error(self, addr):
   39.87 +        (extype, exval) = sys.exc_info()[:2]
   39.88 +        self.send_reply(addr, ['err',
   39.89 +                               ['type',  str(extype) ],
   39.90 +                               ['value', str(exval)  ] ] )
   39.91 +
   39.92 +    def opname(self, name):
   39.93 +        """Get the name of the method for an operation.
   39.94 +        """
   39.95 +        return 'op_' + name.replace('.', '_')
   39.96 +
   39.97 +    def operror(self, name, v):
   39.98 +        """Default operation handler - signals an error.
   39.99 +        """
  39.100 +        raise NotImplementedError('Invalid operation: ' +name)
  39.101 +
  39.102 +    def dispatch(self, req):
  39.103 +        """Dispatch a request to its handler.
  39.104 +        """
  39.105 +        op_name = sxp.name(req)
  39.106 +        op_method_name = self.opname(op_name)
  39.107 +        op_method = getattr(self, op_method_name, self.operror)
  39.108 +        return op_method(op_name, req)
  39.109 +
  39.110 +    def op_console_create(self, name, req):
  39.111 +        """Create a new control interface - console for a domain.
  39.112 +        """
  39.113 +        print name, req
  39.114 +        dom = sxp.child_value(req, 'domain')
  39.115 +        if not dom: raise ValueError('Missing domain')
  39.116 +        dom = int(dom)
  39.117 +        console_port = sxp.child_value(req, 'console_port')
  39.118 +        if console_port:
  39.119 +            console_port = int(console_port)
  39.120 +        resp = self.daemon.console_create(dom, console_port)
  39.121 +        print name, resp
  39.122 +        return resp
  39.123 +
  39.124 +    def op_consoles(self, name, req):
  39.125 +        """Get a list of the consoles.
  39.126 +        """
  39.127 +        return self.daemon.consoles()
  39.128 +
  39.129 +    def op_console_disconnect(self, name, req):
  39.130 +        id = sxp.child_value(req, 'id')
  39.131 +        if not id:
  39.132 +            raise ValueError('Missing console id')
  39.133 +        id = int(id)
  39.134 +        console = self.daemon.get_console(id)
  39.135 +        if not console:
  39.136 +            raise ValueError('Invalid console id')
  39.137 +        if console.conn:
  39.138 +            console.conn.loseConnection()
  39.139 +        return ['ok']
  39.140 +
  39.141 +    def op_blkifs(self, name, req):
  39.142 +        pass
  39.143 +    
  39.144 +    def op_blkif_devs(self, name, req):
  39.145 +        pass
  39.146 +
  39.147 +    def op_blkif_create(self, name, req):
  39.148 +        pass
  39.149 +    
  39.150 +    def op_blkif_dev_create(self, name, req):
  39.151 +        pass
  39.152 +
  39.153 +    def op_netifs(self, name, req):
  39.154 +        pass
  39.155 +
  39.156 +    def op_netif_devs(self, name, req):
  39.157 +        pass
  39.158 +
  39.159 +    def op_netif_create(self, name, req):
  39.160 +        pass
  39.161 +
  39.162 +    def op_netif_dev_create(self, name, req):
  39.163 +        pass
  39.164 +
  39.165 +class NotifierProtocol(protocol.Protocol):
  39.166 +    """Asynchronous handler for i/o on the notifier (event channel).
  39.167 +    """
  39.168 +
  39.169 +    def __init__(self, channelFactory):
  39.170 +        self.channelFactory = channelFactory
  39.171 +
  39.172 +    def notificationReceived(self, idx, type):
  39.173 +        #print 'NotifierProtocol>notificationReceived>', idx, type
  39.174 +        channel = self.channelFactory.getChannel(idx)
  39.175 +        if not channel:
  39.176 +            return
  39.177 +        #print 'NotifierProtocol>notificationReceived> channel', channel
  39.178 +        channel.notificationReceived(type)
  39.179 +
  39.180 +    def connectionLost(self, reason=None):
  39.181 +        pass
  39.182 +
  39.183 +    def doStart(self):
  39.184 +        pass
  39.185 +
  39.186 +    def doStop(self):
  39.187 +        pass
  39.188 +
  39.189 +    def startProtocol(self):
  39.190 +        pass
  39.191 +
  39.192 +    def stopProtocol(self):
  39.193 +        pass
  39.194 +
  39.195 +class NotifierPort(abstract.FileDescriptor):
  39.196 +    """Transport class for the event channel.
  39.197 +    """
  39.198 +
  39.199 +    def __init__(self, daemon, notifier, proto, reactor=None):
  39.200 +        assert isinstance(proto, NotifierProtocol)
  39.201 +        abstract.FileDescriptor.__init__(self, reactor)
  39.202 +        self.daemon = daemon
  39.203 +        self.notifier = notifier
  39.204 +        self.protocol = proto
  39.205 +
  39.206 +    def startListening(self):
  39.207 +        self._bindNotifier()
  39.208 +        self._connectToProtocol()
  39.209 +
  39.210 +    def stopListening(self):
  39.211 +        if self.connected:
  39.212 +            result = self.d = defer.Deferred()
  39.213 +        else:
  39.214 +            result = None
  39.215 +        self.loseConnection()
  39.216 +        return result
  39.217 +
  39.218 +    def fileno(self):
  39.219 +        return self.notifier.fileno()
  39.220 +
  39.221 +    def _bindNotifier(self):
  39.222 +        self.connected = 1
  39.223 +
  39.224 +    def _connectToProtocol(self):
  39.225 +        self.protocol.makeConnection(self)
  39.226 +        self.startReading()
  39.227 +
  39.228 +    def loseConnection(self):
  39.229 +        if self.connected:
  39.230 +            self.stopReading()
  39.231 +            self.disconnecting = 1
  39.232 +            reactor.callLater(0, self.connectionLost)
  39.233 +
  39.234 +    def connectionLost(self, reason=None):
  39.235 +        abstract.FileDescriptor.connectionLost(self, reason)
  39.236 +        if hasattr(self, 'protocol'):
  39.237 +            self.protocol.doStop()
  39.238 +        self.connected = 0
  39.239 +        #self.notifier.close() # Not implemented.
  39.240 +        os.close(self.fileno())
  39.241 +        del self.notifier
  39.242 +        if hasattr(self, 'd'):
  39.243 +            self.d.callback(None)
  39.244 +            del self.d
  39.245 +        
  39.246 +    def doRead(self):
  39.247 +        #print 'NotifierPort>doRead>', self
  39.248 +        count = 0
  39.249 +        while 1:            
  39.250 +            #print 'NotifierPort>doRead>', count
  39.251 +            notification = self.notifier.read()
  39.252 +            if not notification:
  39.253 +                break
  39.254 +            (idx, type) = notification
  39.255 +            self.protocol.notificationReceived(idx, type)
  39.256 +            self.notifier.unmask(idx)
  39.257 +            count += 1
  39.258 +        #print 'NotifierPort>doRead<'
  39.259 +
  39.260 +class EventProtocol(protocol.Protocol):
  39.261 +    """Asynchronous handler for a connected event socket.
  39.262 +    """
  39.263 +
  39.264 +    def __init__(self, daemon):
  39.265 +        #protocol.Protocol.__init__(self)
  39.266 +        self.daemon = daemon
  39.267 +        # Event queue.
  39.268 +        self.queue = []
  39.269 +        # Subscribed events.
  39.270 +        self.events = []
  39.271 +        self.parser = sxp.Parser()
  39.272 +        self.pretty = 0
  39.273 +
  39.274 +        # For debugging subscribe to everything and make output pretty.
  39.275 +        self.subscribe(['*'])
  39.276 +        self.pretty = 1
  39.277 +
  39.278 +    def dataReceived(self, data):
  39.279 +        try:
  39.280 +            self.parser.input(data)
  39.281 +            if self.parser.ready():
  39.282 +                val = self.parser.get_val()
  39.283 +                res = self.dispatch(val)
  39.284 +                self.send_result(res)
  39.285 +            if self.parser.at_eof():
  39.286 +                self.loseConnection()
  39.287 +        except SystemExit:
  39.288 +            raise
  39.289 +        except:
  39.290 +            if DEBUG:
  39.291 +                raise
  39.292 +            else:
  39.293 +                self.send_error()
  39.294 +
  39.295 +    def connectionLost(self, reason=None):
  39.296 +        self.unsubscribe()
  39.297 +
  39.298 +    def send_reply(self, sxpr):
  39.299 +        io = StringIO.StringIO()
  39.300 +        if self.pretty:
  39.301 +            PrettyPrint.prettyprint(sxpr, out=io)
  39.302 +        else:
  39.303 +            sxp.show(sxpr, out=io)
  39.304 +        print >> io
  39.305 +        io.seek(0)
  39.306 +        return self.transport.write(io.getvalue())
  39.307 +
  39.308 +    def send_result(self, res):
  39.309 +        return self.send_reply(['ok', res])
  39.310 +
  39.311 +    def send_error(self):
  39.312 +        (extype, exval) = sys.exc_info()[:2]
  39.313 +        return self.send_reply(['err',
  39.314 +                                ['type', str(extype)],
  39.315 +                                ['value', str(exval)]])
  39.316 +
  39.317 +    def send_event(self, val):
  39.318 +        return self.send_reply(['event', val[0], val[1]])
  39.319 +
  39.320 +    def unsubscribe(self):
  39.321 +        for event in self.events:
  39.322 +            eserver.unsubscribe(event, self.queue_event)
  39.323 +
  39.324 +    def subscribe(self, events):
  39.325 +        self.unsubscribe()
  39.326 +        for event in events:
  39.327 +            eserver.subscribe(event, self.queue_event)
  39.328 +        self.events = events
  39.329 +
  39.330 +    def queue_event(self, name, v):
  39.331 +        # Despite the name we dont' queue the event here.
  39.332 +        # We send it because the transport will queue it.
  39.333 +        self.send_event([name, v])
  39.334 +        
  39.335 +    def opname(self, name):
  39.336 +         return 'op_' + name.replace('.', '_')
  39.337 +
  39.338 +    def operror(self, name, req):
  39.339 +        raise NotImplementedError('Invalid operation: ' +name)
  39.340 +
  39.341 +    def dispatch(self, req):
  39.342 +        op_name = sxp.name(req)
  39.343 +        op_method_name = self.opname(op_name)
  39.344 +        op_method = getattr(self, op_method_name, self.operror)
  39.345 +        return op_method(op_name, req)
  39.346 +
  39.347 +    def op_help(self, name, req):
  39.348 +        def nameop(x):
  39.349 +            if x.startswith('op_'):
  39.350 +                return x[3:].replace('_', '.')
  39.351 +            else:
  39.352 +                return x
  39.353 +        
  39.354 +        l = [ nameop(k) for k in dir(self) if k.startswith('op_') ]
  39.355 +        return l
  39.356 +
  39.357 +    def op_quit(self, name, req):
  39.358 +        self.loseConnection()
  39.359 +
  39.360 +    def op_exit(self, name, req):
  39.361 +        sys.exit(0)
  39.362 +
  39.363 +    def op_pretty(self, name, req):
  39.364 +        self.pretty = 1
  39.365 +        return ['ok']
  39.366 +
  39.367 +    def op_console_disconnect(self, name, req):
  39.368 +        id = sxp.child_value(req, 'id')
  39.369 +        if not id:
  39.370 +            raise ValueError('Missing console id')
  39.371 +        self.daemon.console_disconnect(id)
  39.372 +        return ['ok']
  39.373 +
  39.374 +    def op_info(self, name, req):
  39.375 +        val = self.daemon.consoles()
  39.376 +        return val
  39.377 +
  39.378 +    def op_sys_subscribe(self, name, v):
  39.379 +        # (sys.subscribe event*)
  39.380 +        # Subscribe to the events:
  39.381 +        self.subscribe(v[1:])
  39.382 +        return ['ok']
  39.383 +
  39.384 +    def op_sys_inject(self, name, v):
  39.385 +        # (sys.inject event)
  39.386 +        event = v[1]
  39.387 +        eserver.inject(sxp.name(event), event)
  39.388 +        return ['ok']
  39.389 +
  39.390 +
  39.391 +class EventFactory(protocol.Factory):
  39.392 +    """Asynchronous handler for the event server socket.
  39.393 +    """
  39.394 +    protocol = EventProtocol
  39.395 +    service = None
  39.396 +
  39.397 +    def __init__(self, daemon):
  39.398 +        #protocol.Factory.__init__(self)
  39.399 +        self.daemon = daemon
  39.400 +
  39.401 +    def buildProtocol(self, addr):
  39.402 +        proto = self.protocol(self.daemon)
  39.403 +        proto.factory = self
  39.404 +        return proto
  39.405 +
  39.406 +class Daemon:
  39.407 +    """The xend daemon.
  39.408 +    """
  39.409 +    def __init__(self):
  39.410 +        self.shutdown = 0
  39.411 +
  39.412 +    def daemon_pids(self):
  39.413 +        pids = []
  39.414 +        pidex = '(?P<pid>\d+)'
  39.415 +        pythonex = '(?P<python>\S*python\S*)'
  39.416 +        cmdex = '(?P<cmd>.*)'
  39.417 +        procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex + '$')
  39.418 +        xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
  39.419 +        procs = os.popen('ps -e -o pid,args 2>/dev/null')
  39.420 +        for proc in procs:
  39.421 +            pm = procre.match(proc)
  39.422 +            if not pm: continue
  39.423 +            xm = xendre.match(pm.group('cmd'))
  39.424 +            if not xm: continue
  39.425 +            #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
  39.426 +            pids.append(int(pm.group('pid')))
  39.427 +        return pids
  39.428 +
  39.429 +    def new_cleanup(self, kill=0):
  39.430 +        err = 0
  39.431 +        pids = self.daemon_pids()
  39.432 +        if kill:
  39.433 +            for pid in pids:
  39.434 +                print "Killing daemon pid=%d" % pid
  39.435 +                os.kill(pid, signal.SIGHUP)
  39.436 +        elif pids:
  39.437 +            err = 1
  39.438 +            print "Daemon already running: ", pids
  39.439 +        return err
  39.440 +            
  39.441 +    def cleanup(self, kill=False):
  39.442 +        # No cleanup to do if PID_FILE is empty.
  39.443 +        if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE):
  39.444 +            return 0
  39.445 +        # Read the pid of the previous invocation and search active process list.
  39.446 +        pid = open(PID_FILE, 'r').read()
  39.447 +        lines = os.popen('ps ' + pid + ' 2>/dev/null').readlines()
  39.448 +        for line in lines:
  39.449 +            if re.search('^ *' + pid + '.+xend', line):
  39.450 +                if not kill:
  39.451 +                    print "Daemon is already running (pid %d)" % int(pid)
  39.452 +                    return 1
  39.453 +                # Old daemon is still active: terminate it.
  39.454 +                os.kill(int(pid), 1)
  39.455 +        # Delete the stale PID_FILE.
  39.456 +        os.remove(PID_FILE)
  39.457 +        return 0
  39.458 +
  39.459 +    def install_child_reaper(self):
  39.460 +        #signal.signal(signal.SIGCHLD, self.onSIGCHLD)
  39.461 +        # Ensure that zombie children are automatically reaped.
  39.462 +        xend.utils.autoreap()
  39.463 +
  39.464 +    def onSIGCHLD(self, signum, frame):
  39.465 +        code = 1
  39.466 +        while code > 0:
  39.467 +            code = os.waitpid(-1, os.WNOHANG)
  39.468 +
  39.469 +    def start(self):
  39.470 +        if self.cleanup(kill=False):
  39.471 +            return 1
  39.472 +
  39.473 +        # Detach from TTY.
  39.474 +        if not DEBUG:
  39.475 +            os.setsid()
  39.476 +
  39.477 +        if self.set_user():
  39.478 +            return 1
  39.479 +
  39.480 +        self.install_child_reaper()
  39.481 +
  39.482 +        # Fork -- parent writes PID_FILE and exits.
  39.483 +        pid = os.fork()
  39.484 +        if pid:
  39.485 +            # Parent
  39.486 +            pidfile = open(PID_FILE, 'w')
  39.487 +            pidfile.write(str(pid))
  39.488 +            pidfile.close()
  39.489 +            return 0
  39.490 +        # Child
  39.491 +        logfile = self.open_logfile()
  39.492 +        self.redirect_output(logfile)
  39.493 +        self.run()
  39.494 +        return 0
  39.495 +
  39.496 +    def open_logfile(self):
  39.497 +        if not os.path.exists(CONTROL_DIR):
  39.498 +            os.makedirs(CONTROL_DIR)
  39.499 +
  39.500 +        # Open log file. Truncate it if non-empty, and request line buffering.
  39.501 +        if os.path.isfile(LOG_FILE):
  39.502 +            os.rename(LOG_FILE, LOG_FILE+'.old')
  39.503 +        logfile = open(LOG_FILE, 'w+', 1)
  39.504 +        return logfile
  39.505 +
  39.506 +    def set_user(self):
  39.507 +        # Set the UID.
  39.508 +        try:
  39.509 +            os.setuid(pwd.getpwnam(USER)[2])
  39.510 +            return 0
  39.511 +        except KeyError, error:
  39.512 +            print "Error: no such user '%s'" % USER
  39.513 +            return 1
  39.514 +
  39.515 +    def redirect_output(self, logfile):
  39.516 +        if DEBUG: return
  39.517 +        # Close down standard file handles
  39.518 +        try:
  39.519 +            os.close(0) # stdin
  39.520 +            os.close(1) # stdout
  39.521 +            os.close(2) # stderr
  39.522 +        except:
  39.523 +            pass
  39.524 +        # Redirect output to log file.
  39.525 +        sys.stdout = sys.stderr = logfile
  39.526 +
  39.527 +    def stop(self):
  39.528 +        return self.cleanup(kill=True)
  39.529 +
  39.530 +    def run(self):
  39.531 +        self.createFactories()
  39.532 +        self.listenMgmt()
  39.533 +        self.listenEvent()
  39.534 +        self.listenNotifier()
  39.535 +        SrvServer.create()
  39.536 +        reactor.run()
  39.537 +
  39.538 +    def createFactories(self):
  39.539 +        self.channelF = channel.channelFactory()
  39.540 +        self.blkifCF = blkif.BlkifControllerFactory()
  39.541 +        self.netifCF = netif.NetifControllerFactory()
  39.542 +        self.consoleCF = console.ConsoleControllerFactory()
  39.543 +
  39.544 +    def listenMgmt(self):
  39.545 +        protocol = MgmtProtocol(self)
  39.546 +        s = os.path.join(CONTROL_DIR, MGMT_SOCK)
  39.547 +        if os.path.exists(s):
  39.548 +            os.unlink(s)
  39.549 +        return reactor.listenUNIXDatagram(s, protocol)
  39.550 +
  39.551 +    def listenEvent(self):
  39.552 +        protocol = EventFactory(self)
  39.553 +        return reactor.listenTCP(EVENT_PORT, protocol)
  39.554 +
  39.555 +    def listenNotifier(self):
  39.556 +        protocol = NotifierProtocol(self.channelF)
  39.557 +        p = NotifierPort(self, self.channelF.notifier, protocol, reactor)
  39.558 +        p.startListening()
  39.559 +        return p
  39.560 +
  39.561 +    def exit(self):
  39.562 +        reactor.diconnectAll()
  39.563 +        sys.exit(0)
  39.564 +
  39.565 +    def blkif_create(self, dom):
  39.566 +        """Create a block device interface controller.
  39.567 +        
  39.568 +        Returns Deferred
  39.569 +        """
  39.570 +        d = self.blkifCF.createInstance(dom)
  39.571 +        return d
  39.572 +
  39.573 +    def blkif_dev_create(self, dom, vdev, mode, segment):
  39.574 +        """Create a block device.
  39.575 +        
  39.576 +        Returns Deferred
  39.577 +        """
  39.578 +        ctrl = self.blkifCF.getInstanceByDom(dom)
  39.579 +        if not ctrl:
  39.580 +            raise ValueError('No blkif controller: %d' % dom)
  39.581 +        print 'blkif_dev_create>', dom, vdev, mode, segment
  39.582 +        d = ctrl.attach_device(vdev, mode, segment)
  39.583 +        return d
  39.584 +
  39.585 +    def netif_create(self, dom):
  39.586 +        """Create a network interface controller.
  39.587 +        
  39.588 +        """
  39.589 +        return self.netifCF.createInstance(dom)
  39.590 +
  39.591 +    def netif_dev_create(self, dom, vif, vmac):
  39.592 +        """Create a network device.
  39.593 +
  39.594 +        todo
  39.595 +        """
  39.596 +        ctrl = self.netifCF.getInstanceByDom(dom)
  39.597 +        if not ctrl:
  39.598 +            raise ValueError('No netif controller: %d' % dom)
  39.599 +        d = ctrl.attach_device(vif, vmac)
  39.600 +        return d
  39.601 +
  39.602 +    def console_create(self, dom, console_port=None):
  39.603 +        """Create a console for a domain.
  39.604 +        """
  39.605 +        console = self.consoleCF.getInstanceByDom(dom)
  39.606 +        if console is None:
  39.607 +            console = self.consoleCF.createInstance(dom, console_port)
  39.608 +        return console.sxpr()
  39.609 +
  39.610 +    def consoles(self):
  39.611 +        return [ c.sxpr() for c in self.consoleCF.getInstances() ]
  39.612 +
  39.613 +    def get_console(self, id):
  39.614 +        return self.consoleCF.getInstance(id)
  39.615 +
  39.616 +    def get_domain_console(self, dom):
  39.617 +        return self.consoleCF.getInstanceByDom(dom)
  39.618 +
  39.619 +    def console_disconnect(self, id):
  39.620 +        """Disconnect any connected console client.
  39.621 +        """
  39.622 +        console = self.get_console(id)
  39.623 +        if not console:
  39.624 +            raise ValueError('Invalid console id')
  39.625 +        if console.conn:
  39.626 +            console.conn.loseConnection()
  39.627 +
  39.628 +def instance():
  39.629 +    global inst
  39.630 +    try:
  39.631 +        inst
  39.632 +    except:
  39.633 +        inst = Daemon()
  39.634 +    return inst
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/tools/xenmgr/lib/server/SrvDeviceDir.py	Fri Jun 11 22:04:24 2004 +0000
    40.3 @@ -0,0 +1,9 @@
    40.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    40.5 +
    40.6 +from SrvDir import SrvDir
    40.7 +
    40.8 +class SrvDeviceDir(SrvDir):
    40.9 +    """Device directory.
   40.10 +    """
   40.11 +
   40.12 +    pass
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/tools/xenmgr/lib/server/SrvDir.py	Fri Jun 11 22:04:24 2004 +0000
    41.3 @@ -0,0 +1,91 @@
    41.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    41.5 +
    41.6 +from twisted.web import error
    41.7 +from xenmgr import sxp
    41.8 +from SrvBase import SrvBase
    41.9 +
   41.10 +class SrvConstructor:
   41.11 +    """Delayed constructor for sub-servers.
   41.12 +    Does not import the sub-server class or create the object until needed.
   41.13 +    """
   41.14 +    
   41.15 +    def __init__(self, klass):
   41.16 +        """Create a constructor. It is assumed that the class
   41.17 +        should be imported as 'import klass from klass'.
   41.18 +
   41.19 +        klass	name of its class
   41.20 +        """
   41.21 +        self.klass = klass
   41.22 +        self.obj = None
   41.23 +
   41.24 +    def getobj(self):
   41.25 +        """Get the sub-server object, importing its class and instantiating it if
   41.26 +        necessary.
   41.27 +        """
   41.28 +        if not self.obj:
   41.29 +            exec 'from %s import %s' % (self.klass, self.klass)
   41.30 +            klassobj = eval(self.klass)
   41.31 +            self.obj = klassobj()
   41.32 +        return self.obj
   41.33 +
   41.34 +class SrvDir(SrvBase):
   41.35 +    """Base class for directory servlets.
   41.36 +    """
   41.37 +    isLeaf = False
   41.38 +    
   41.39 +    def __init__(self):
   41.40 +        SrvBase.__init__(self)
   41.41 +        self.table = {}
   41.42 +        self.order = []
   41.43 +
   41.44 +    def getChild(self, x, req):
   41.45 +        if x == '': return self
   41.46 +        val = self.get(x)
   41.47 +        if val is None:
   41.48 +            return error.NoResource('Not found')
   41.49 +        else:
   41.50 +            return val
   41.51 +
   41.52 +    def get(self, x):
   41.53 +        val = self.table.get(x)
   41.54 +        if val is not None:
   41.55 +            val = val.getobj()
   41.56 +        return val
   41.57 +
   41.58 +    def add(self, x, xclass = None):
   41.59 +        if xclass is None:
   41.60 +            xclass = 'SrvDir'
   41.61 +        self.table[x] = SrvConstructor(xclass)
   41.62 +        self.order.append(x)
   41.63 +
   41.64 +    def render_GET(self, req):
   41.65 +        if self.use_sxp(req):
   41.66 +            req.setHeader("Content-type", sxp.mime_type)
   41.67 +            self.ls(req, 1)
   41.68 +        else:
   41.69 +            req.write('<html><head></head><body>')
   41.70 +            self.print_path(req)
   41.71 +            self.ls(req)
   41.72 +            self.form(req)
   41.73 +            req.write('</body></html>')
   41.74 +        return ''
   41.75 +            
   41.76 +    def ls(self, req, use_sxp=0):
   41.77 +        url = req.prePathURL()
   41.78 +        if not url.endswith('/'):
   41.79 +            url += '/'
   41.80 +        if use_sxp:
   41.81 +           req.write('(ls ')
   41.82 +           for k in self.order:
   41.83 +               req.write(' ' + k)
   41.84 +           req.write(')')
   41.85 +        else:
   41.86 +            req.write('<ul>')
   41.87 +            for k in self.order:
   41.88 +                v = self.get(k)
   41.89 +                req.write('<li><a href="%s%s">%s</a></li>'
   41.90 +                          % (url, k, k))
   41.91 +            req.write('</ul>')
   41.92 +
   41.93 +    def form(self, req):
   41.94 +        pass
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/tools/xenmgr/lib/server/SrvDomain.py	Fri Jun 11 22:04:24 2004 +0000
    42.3 @@ -0,0 +1,202 @@
    42.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    42.5 +
    42.6 +from xenmgr import sxp
    42.7 +from xenmgr import XendDomain
    42.8 +from xenmgr import XendConsole
    42.9 +from xenmgr import PrettyPrint
   42.10 +from xenmgr.Args import FormFn
   42.11 +
   42.12 +from SrvDir import SrvDir
   42.13 +
   42.14 +class SrvDomain(SrvDir):
   42.15 +    """Service managing a single domain.
   42.16 +    """
   42.17 +
   42.18 +    def __init__(self, dom):
   42.19 +        SrvDir.__init__(self)
   42.20 +        self.dom = dom
   42.21 +        self.xd = XendDomain.instance()
   42.22 +        self.xconsole = XendConsole.instance()
   42.23 +
   42.24 +    def op_start(self, op, req):
   42.25 +        val = self.xd.domain_start(self.dom.id)
   42.26 +        return val
   42.27 +        
   42.28 +    def op_stop(self, op, req):
   42.29 +        val = self.xd.domain_stop(self.dom.id)
   42.30 +        return val
   42.31 +
   42.32 +    def op_shutdown(self, op, req):
   42.33 +        val = self.xd.domain_shutdown(self.dom.id)
   42.34 +        req.setResponseCode(202)
   42.35 +        req.setHeader("Location", "%s/.." % req.prePathURL())
   42.36 +        return val
   42.37 +
   42.38 +    def op_halt(self, op, req):
   42.39 +        val = self.xd.domain_halt(self.dom.id)
   42.40 +        req.setHeader("Location", "%s/.." % req.prePathURL())
   42.41 +        return val
   42.42 +
   42.43 +    def op_save(self, op, req):
   42.44 +        fn = FormFn(self.xd.domain_save,
   42.45 +                    [['dom', 'int'],
   42.46 +                     ['dst', 'str']])
   42.47 +        val = fn(req.args, {'dom': self.dom.id})
   42.48 +        return val
   42.49 +
   42.50 +    def op_restore(self, op, req):
   42.51 +        fn = FormFn(self.xd.domain_restore,
   42.52 +                    [['dom', 'int'],
   42.53 +                     ['src', 'str']])
   42.54 +        val = fn(req.args, {'dom': self.dom.id})
   42.55 +        return val
   42.56 +        
   42.57 +    def op_migrate(self, op, req):
   42.58 +        fn = FormFn(self.xd.domain_migrate,
   42.59 +                    [['dom', 'int'],
   42.60 +                     ['destination', 'str']])
   42.61 +        val = fn(req.args, {'dom': self.dom.id})
   42.62 +        val = 0 # Some migrate id.
   42.63 +        req.setResponseCode(202)
   42.64 +        #req.send_header("Location", "%s/.." % self.path) # Some migrate url.
   42.65 +        return val
   42.66 +
   42.67 +    def op_pincpu(self, op, req):
   42.68 +        fn = FormFn(self.xd.domain_migrate,
   42.69 +                    [['dom', 'int'],
   42.70 +                     ['cpu', 'int']])
   42.71 +        val = fn(req.args, {'dom': self.dom.id})
   42.72 +        return val
   42.73 +
   42.74 +    def op_cpu_bvt_set(self, op, req):
   42.75 +        fn = FormFn(self.xd.domain_cpu_bvt_set,
   42.76 +                    [['dom', 'int'],
   42.77 +                     ['mcuadv', 'int'],
   42.78 +                     ['warp', 'int'],
   42.79 +                     ['warpl', 'int'],
   42.80 +                     ['warpu', 'int']])
   42.81 +        val = fn(req.args, {'dom': self.dom.id})
   42.82 +        return val
   42.83 +
   42.84 +    def op_cpu_atropos_set(self, op, req):
   42.85 +        fn = FormFn(self.xd.domain_cpu_atropos_set,
   42.86 +                    [['dom', 'int'],
   42.87 +                     ['period', 'int'],
   42.88 +                     ['slice', 'int'],
   42.89 +                     ['latency', 'int'],
   42.90 +                     ['xtratime', 'int']])
   42.91 +        val = fn(req.args, {'dom': self.dom.id})
   42.92 +        return val
   42.93 +
   42.94 +    def op_vifs(self, op, req):
   42.95 +        return self.xd.domain_vif_ls(self.dom.id)
   42.96 +
   42.97 +    def op_vif(self, op, req):
   42.98 +        fn = FormFn(self.xd.domain_vif_get,
   42.99 +                    [['dom', 'int'],
  42.100 +                     ['vif', 'int']])
  42.101 +        val = fn(req.args, {'dom': self.dom.id})
  42.102 +        return val
  42.103 +
  42.104 +    def op_vif_stats(self, op, req):
  42.105 +        #todo
  42.106 +        fn = FormFn(self.xd.domain_vif_stats,
  42.107 +                    [['dom', 'int'],
  42.108 +                     ['vif', 'int']])
  42.109 +        #val = fn(req.args, {'dom': self.dom.id})
  42.110 +        val = 999
  42.111 +        #return val
  42.112 +        return val
  42.113 +
  42.114 +    def op_vif_ip_add(self, op, req):
  42.115 +        fn = FormFn(self.xd.domain_vif_ip_add,
  42.116 +                    [['dom', 'int'],
  42.117 +                     ['vif', 'int'],
  42.118 +                     ['ip', 'str']])
  42.119 +        val = fn(req.args, {'dom': self.dom.id})
  42.120 +        return val
  42.121 +
  42.122 +    def op_vif_scheduler_set(self, op, req):
  42.123 +        fn = FormFn(self.xd.domain_vif_scheduler_set,
  42.124 +                    [['dom', 'int'],
  42.125 +                     ['vif', 'int'],
  42.126 +                     ['bytes', 'int'],
  42.127 +                     ['usecs', 'int']])
  42.128 +        val = fn(req.args, {'dom': self.dom.id})
  42.129 +        return val
  42.130 +
  42.131 +    def op_vif_scheduler_get(self, op, req):
  42.132 +        fn = FormFn(self.xd.domain_vif_scheduler_set,
  42.133 +                    [['dom', 'int'],
  42.134 +                     ['vif', 'int']])
  42.135 +        val = fn(req.args, {'dom': self.dom.id})
  42.136 +        return val
  42.137 +
  42.138 +    def op_vbds(self, op, req):
  42.139 +        return self.xd.domain_vbd_ls(self.dom.id)
  42.140 +
  42.141 +    def op_vbd(self, op, req):
  42.142 +        fn = FormFn(self.xd.domain_vbd_get,
  42.143 +                    [['dom', 'int'],
  42.144 +                     ['vbd', 'int']])
  42.145 +        val = fn(req.args, {'dom': self.dom.id})
  42.146 +        return val
  42.147 +
  42.148 +    def op_vbd_add(self, op, req):
  42.149 +        fn = FormFn(self.xd.domain_vbd_add,
  42.150 +                    [['dom', 'int'],
  42.151 +                     ['uname', 'str'],
  42.152 +                     ['dev', 'str'],
  42.153 +                     ['mode', 'str']])
  42.154 +        val = fn(req.args, {'dom': self.dom.id})
  42.155 +        return val
  42.156 +
  42.157 +    def op_vbd_remove(self, op, req):
  42.158 +        fn = FormFn(self.xd.domain_vbd_remove,
  42.159 +                    [['dom', 'int'],
  42.160 +                     ['dev', 'str']])
  42.161 +        val = fn(req.args, {'dom': self.dom.id})
  42.162 +        return val
  42.163 +
  42.164 +    def render_POST(self, req):
  42.165 +        return self.perform(req)
  42.166 +        
  42.167 +    def render_GET(self, req):
  42.168 +        op = req.args.get('op')
  42.169 +        if op and op[0] in ['vifs', 'vif', 'vif_stats', 'vbds', 'vbd']:
  42.170 +            return self.perform(req)
  42.171 +        if self.use_sxp(req):
  42.172 +            req.setHeader("Content-Type", sxp.mime_type)
  42.173 +            sxp.show(self.dom.sxpr(), out=req)
  42.174 +        else:
  42.175 +            req.write('<html><head></head><body>')
  42.176 +            self.print_path(req)
  42.177 +            #self.ls()
  42.178 +            req.write('<p>%s</p>' % self.dom)
  42.179 +            if self.dom.console:
  42.180 +                cinfo = self.dom.console
  42.181 +                cid = cinfo.id
  42.182 +                #todo: Local xref: need to know server prefix.
  42.183 +                req.write('<p><a href="/xend/console/%s">Console %s</a></p>'
  42.184 +                          % (cid, cid))
  42.185 +                req.write('<p><a href="%s">Connect to console</a></p>'
  42.186 +                          % cinfo.uri())
  42.187 +            if self.dom.config:
  42.188 +                req.write("<code><pre>")
  42.189 +                PrettyPrint.prettyprint(self.dom.config, out=req)
  42.190 +                req.write("</pre></code>")
  42.191 +            req.write('<a href="%s?op=vif_stats&vif=0">vif 0 stats</a>'
  42.192 +                      % req.prePathURL())
  42.193 +            self.form(req)
  42.194 +            req.write('</body></html>')
  42.195 +        return ''
  42.196 +
  42.197 +    def form(self, req):
  42.198 +        req.write('<form method="post" action="%s">' % req.prePathURL())
  42.199 +        req.write('<input type="submit" name="op" value="start">')
  42.200 +        req.write('<input type="submit" name="op" value="stop">')
  42.201 +        req.write('<input type="submit" name="op" value="shutdown">')
  42.202 +        req.write('<input type="submit" name="op" value="halt">')
  42.203 +        req.write('<br><input type="submit" name="op" value="migrate">')
  42.204 +        req.write('To: <input type="text" name="destination">')
  42.205 +        req.write('</form>')
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/tools/xenmgr/lib/server/SrvDomainDir.py	Fri Jun 11 22:04:24 2004 +0000
    43.3 @@ -0,0 +1,130 @@
    43.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    43.5 +
    43.6 +from StringIO import StringIO
    43.7 +
    43.8 +from twisted.protocols import http
    43.9 +from twisted.web import error
   43.10 +
   43.11 +from xenmgr import sxp
   43.12 +from xenmgr import XendDomain
   43.13 +
   43.14 +from SrvDir import SrvDir
   43.15 +from SrvDomain import SrvDomain
   43.16 +
   43.17 +class SrvDomainDir(SrvDir):
   43.18 +    """Service that manages the domain directory.
   43.19 +    """
   43.20 +
   43.21 +    def __init__(self):
   43.22 +        SrvDir.__init__(self)
   43.23 +        self.xd = XendDomain.instance()
   43.24 +
   43.25 +    def domain(self, x):
   43.26 +        val = None
   43.27 +        try:
   43.28 +            dom = self.xd.domain_get(x)
   43.29 +            val = SrvDomain(dom)
   43.30 +        except KeyError:
   43.31 +            pass
   43.32 +        return val
   43.33 +
   43.34 +    def get(self, x):
   43.35 +        v = SrvDir.get(self, x)
   43.36 +        if v is not None:
   43.37 +            return v
   43.38 +        v = self.domain(x)
   43.39 +        return v
   43.40 +
   43.41 +    def op_create(self, op, req):
   43.42 +        ok = 0
   43.43 +        try:
   43.44 +            configstring = req.args.get('config')[0]
   43.45 +            print 'config:', configstring
   43.46 +            pin = sxp.Parser()
   43.47 +            pin.input(configstring)
   43.48 +            pin.input_eof()
   43.49 +            config = pin.get_val()
   43.50 +            ok = 1
   43.51 +        except Exception, ex:
   43.52 +            print ex
   43.53 +        if not ok:
   43.54 +            req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
   43.55 +            return "Invalid configuration"
   43.56 +            return error.ErrorPage(http.BAD_REQUEST,
   43.57 +                                   "Invalid",
   43.58 +                                   "Invalid configuration")
   43.59 +        try:
   43.60 +            deferred = self.xd.domain_create(config)
   43.61 +            deferred.addCallback(self._cb_op_create, configstring, req)
   43.62 +            return deferred
   43.63 +        except Exception, ex:
   43.64 +            raise
   43.65 +            #return ['err', str(ex) ]
   43.66 +            #req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
   43.67 +            #return str(ex)
   43.68 +            #return error.ErrorPage(http.BAD_REQUEST,
   43.69 +            #                       "Error creating domain",
   43.70 +            #                       str(ex))
   43.71 +                                   
   43.72 +
   43.73 +    def _cb_op_create(self, dominfo, configstring, req):
   43.74 +        """Callback to handle deferred domain creation.
   43.75 +        """
   43.76 +        dom = dominfo.id
   43.77 +        domurl = "%s/%s" % (req.prePathURL(), dom)
   43.78 +        req.setResponseCode(201, "created")
   43.79 +        req.setHeader("Location", domurl)
   43.80 +        if self.use_sxp(req):
   43.81 +            return dominfo.sxpr()
   43.82 +        else:
   43.83 +            out = StringIO()
   43.84 +            print >> out, ('<p> Created <a href="%s">Domain %s</a></p>'
   43.85 +                           % (domurl, dom))
   43.86 +            print >> out, '<p><pre>'
   43.87 +            print >> out, configstring
   43.88 +            print >> out, '</pre></p>'
   43.89 +            val = out.getvalue()
   43.90 +            out.close()
   43.91 +            return val
   43.92 +
   43.93 +    def render_POST(self, req):
   43.94 +        return self.perform(req)
   43.95 +
   43.96 +    def render_GET(self, req):
   43.97 +        if self.use_sxp(req):
   43.98 +            req.setHeader("Content-Type", sxp.mime_type)
   43.99 +            self.ls_domain(req, 1)
  43.100 +        else:
  43.101 +            req.write("<html><head></head><body>")
  43.102 +            self.print_path(req)
  43.103 +            self.ls(req)
  43.104 +            self.ls_domain(req)
  43.105 +            self.form(req)
  43.106 +            req.write("</body></html>")
  43.107 +        return ''
  43.108 +
  43.109 +    def ls_domain(self, req, use_sxp=0):
  43.110 +        url = req.prePathURL()
  43.111 +        if not url.endswith('/'):
  43.112 +            url += '/'
  43.113 +        if use_sxp:
  43.114 +            domains = self.xd.domain_ls()
  43.115 +            sxp.show(domains, out=req)
  43.116 +        else:
  43.117 +            domains = self.xd.domains()
  43.118 +            domains.sort(lambda x, y: cmp(x.id, y.id))
  43.119 +            req.write('<ul>')
  43.120 +            for d in domains:
  43.121 +               req.write('<li><a href="%s%s"> Domain %s</a>'
  43.122 +                         % (url, d.id, d.id))
  43.123 +               req.write('name=%s' % d.name)
  43.124 +               req.write('memory=%d'% d.memory)
  43.125 +               req.write('</li>')
  43.126 +            req.write('</ul>')
  43.127 +
  43.128 +    def form(self, req):
  43.129 +        req.write('<form method="post" action="%s" enctype="multipart/form-data">'
  43.130 +                  % req.prePathURL())
  43.131 +        req.write('<button type="submit" name="op" value="create">Create Domain</button>')
  43.132 +        req.write('Config <input type="file" name="config"><br>')
  43.133 +        req.write('</form>')
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/tools/xenmgr/lib/server/SrvEventDir.py	Fri Jun 11 22:04:24 2004 +0000
    44.3 @@ -0,0 +1,41 @@
    44.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    44.5 +
    44.6 +from xenmgr import sxp
    44.7 +from xenmgr import EventServer
    44.8 +from SrvDir import SrvDir
    44.9 +
   44.10 +class SrvEventDir(SrvDir):
   44.11 +    """Event directory.
   44.12 +    """
   44.13 +
   44.14 +    def __init__(self):
   44.15 +        SrvDir.__init__(self)
   44.16 +        self.eserver = EventServer.instance()
   44.17 +
   44.18 +    def op_inject(self, op, req):
   44.19 +        eventstring = req.args.get('event')
   44.20 +        pin = sxp.Parser()
   44.21 +        pin.input(eventstring)
   44.22 +        pin.input_eof()
   44.23 +        sxpr = pin.get_val()
   44.24 +        self.eserver.inject(sxp.name(sxpr), sxpr)
   44.25 +        if req.use_sxp:
   44.26 +            sxp.name(sxpr)
   44.27 +        else:
   44.28 +            return '<code>' + eventstring + '</code>'
   44.29 +        
   44.30 +    def render_POST(self, req):
   44.31 +        return self.perform(req)
   44.32 +
   44.33 +    def form(self, req):
   44.34 +        action = req.prePathURL()
   44.35 +        req.write('<form method="post" action="%s" enctype="multipart/form-data">'
   44.36 +                  % action)
   44.37 +        req.write('<button type="submit" name="op" value="inject">Inject</button>')
   44.38 +        req.write('Event <input type="text" name="event" size="40"><br>')
   44.39 +        req.write('</form>')
   44.40 +        req.write('<form method="post" action="%s" enctype="multipart/form-data">'
   44.41 +                  % action)
   44.42 +        req.write('<button type="submit" name="op" value="inject">Inject</button>')
   44.43 +        req.write('Event file<input type="file" name="event"><br>')
   44.44 +        req.write('</form>')
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/tools/xenmgr/lib/server/SrvNode.py	Fri Jun 11 22:04:24 2004 +0000
    45.3 @@ -0,0 +1,59 @@
    45.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    45.5 +
    45.6 +import os
    45.7 +from SrvDir import SrvDir
    45.8 +from xenmgr import sxp
    45.9 +from xenmgr import XendNode
   45.10 +
   45.11 +class SrvNode(SrvDir):
   45.12 +    """Information about the node.
   45.13 +    """
   45.14 +
   45.15 +    def __init__(self):
   45.16 +        SrvDir.__init__(self)
   45.17 +        self.xn = XendNode.instance()
   45.18 +
   45.19 +    def op_shutdown(self, op, req):
   45.20 +        val = self.xn.shutdown()
   45.21 +        return val
   45.22 +
   45.23 +    def op_reboot(self, op, req):
   45.24 +        val = self.xn.reboot()
   45.25 +        return val
   45.26 +
   45.27 +    def op_cpu_rrobin_slice_set(self, op, req):
   45.28 +        fn = FormFn(self.xn.cpu_rrobin_slice_set,
   45.29 +                    [['slice', 'int']])
   45.30 +        val = fn(req.args, {})
   45.31 +        return val
   45.32 +
   45.33 +    def op_cpu_bvt_slice_set(self, op, req):
   45.34 +        fn = FormFn(self.xn.cpu_bvt_slice_set,
   45.35 +                    [['slice', 'int']])
   45.36 +        val = fn(req.args, {})
   45.37 +        return val
   45.38 +
   45.39 +    def render_POST(self, req):
   45.40 +        return self.perform(req)
   45.41 +
   45.42 +    def render_GET(self, req):
   45.43 +        if self.use_sxp(req):
   45.44 +            req.setHeader("Content-Type", sxp.mime_type)
   45.45 +            sxp.show(['node'] + self.info(), out=req)
   45.46 +        else:
   45.47 +            req.write('<html><head></head><body>')
   45.48 +            self.print_path(req)
   45.49 +            req.write('<ul>')
   45.50 +            for d in self.info():
   45.51 +                req.write('<li> %10s: %s' % (d[0], d[1]))
   45.52 +            req.write('</ul>')
   45.53 +            req.write('</body></html>')
   45.54 +        return ''
   45.55 +            
   45.56 +    def info(self):
   45.57 +        (sys, host, rel, ver, mch) = os.uname()
   45.58 +        return [['system',  sys],
   45.59 +                ['host',    host],
   45.60 +                ['release', rel],
   45.61 +                ['version', ver],
   45.62 +                ['machine', mch]]
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/tools/xenmgr/lib/server/SrvRoot.py	Fri Jun 11 22:04:24 2004 +0000
    46.3 @@ -0,0 +1,31 @@
    46.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    46.5 +
    46.6 +from xenmgr import XendRoot
    46.7 +xroot = XendRoot.instance()
    46.8 +from SrvDir import SrvDir
    46.9 +
   46.10 +class SrvRoot(SrvDir):
   46.11 +    """The root of the xend server.
   46.12 +    """
   46.13 +
   46.14 +    """Server sub-components. Each entry is (name, class), where
   46.15 +    'name' is the entry name and  'class' is the name of its class.
   46.16 +    """
   46.17 +    #todo Get this list from the XendRoot config.
   46.18 +    subdirs = [
   46.19 +        ('node',    'SrvNode'       ),
   46.20 +        ('domain',  'SrvDomainDir'  ),
   46.21 +        ('console', 'SrvConsoleDir' ),
   46.22 +        ('event',   'SrvEventDir'   ),
   46.23 +        ('vdisk',   'SrvVdiskDir'   ),
   46.24 +        ('device',  'SrvDeviceDir'  ),
   46.25 +        ('vnet',    'SrvVnetDir'    ),
   46.26 +        ]
   46.27 +
   46.28 +    def __init__(self):
   46.29 +        SrvDir.__init__(self)
   46.30 +        for (name, klass) in self.subdirs:
   46.31 +            self.add(name, klass)
   46.32 +        for (name, klass) in self.subdirs:
   46.33 +            self.get(name)
   46.34 +        xroot.start()
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/tools/xenmgr/lib/server/SrvServer.py	Fri Jun 11 22:04:24 2004 +0000
    47.3 @@ -0,0 +1,53 @@
    47.4 +#!/usr/bin/python2
    47.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    47.6 +
    47.7 +"""Example xend HTTP and console server.
    47.8 +
    47.9 +   Can be accessed from a browser or from a program.
   47.10 +   Do 'python SrvServer.py' to run the server.
   47.11 +   Then point a web browser at http://localhost:8000/xend and follow the links.
   47.12 +   Most are stubs, except /domain which has a list of domains and a 'create domain'
   47.13 +   button.
   47.14 +
   47.15 +   You can also access the server from a program.
   47.16 +   Do 'python XendClient.py' to run a few test operations.
   47.17 +
   47.18 +   The data served differs depending on the client (as defined by User-Agent
   47.19 +   and Accept in the HTTP headers). If the client is a browser, data
   47.20 +   is returned in HTML, with interactive forms. If the client is a program,
   47.21 +   data is returned in SXP format, with no forms.
   47.22 +
   47.23 +   The server serves to the world by default. To restrict it to the local host
   47.24 +   change 'interface' in main().
   47.25 +
   47.26 +   Mike Wray <mike.wray@hp.com>
   47.27 +"""
   47.28 +# todo Support security settings etc. in the config file.
   47.29 +# todo Support command-line args.
   47.30 +
   47.31 +from twisted.web import server
   47.32 +from twisted.web import resource
   47.33 +from twisted.internet import reactor
   47.34 +
   47.35 +from xenmgr import XendRoot
   47.36 +xroot = XendRoot.instance()
   47.37 +
   47.38 +from SrvRoot import SrvRoot
   47.39 +
   47.40 +def create(port=None, interface=None):
   47.41 +    if port is None: port = 8000
   47.42 +    if interface is None: interface = ''
   47.43 +    root = resource.Resource()
   47.44 +    xend = SrvRoot()
   47.45 +    root.putChild('xend', xend)
   47.46 +    site = server.Site(root)
   47.47 +    reactor.listenTCP(port, site, interface=interface)
   47.48 +    
   47.49 +
   47.50 +def main(port=None, interface=None):
   47.51 +    create(port, interface)
   47.52 +    reactor.run()
   47.53 +
   47.54 +
   47.55 +if __name__ == '__main__':
   47.56 +    main()
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/tools/xenmgr/lib/server/SrvVdisk.py	Fri Jun 11 22:04:24 2004 +0000
    48.3 @@ -0,0 +1,12 @@
    48.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    48.5 +
    48.6 +from xenmgr import XendVdisk
    48.7 +from SrvVdiskDir import SrvVdiskDir
    48.8 +
    48.9 +class SrvVdisk(SrvDir):
   48.10 +    """A virtual disk.
   48.11 +    """
   48.12 +
   48.13 +    def __init__(self):
   48.14 +        SrvDir.__init__(self)
   48.15 +        self.xvdisk = XendVdisk.instance()
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/tools/xenmgr/lib/server/SrvVdiskDir.py	Fri Jun 11 22:04:24 2004 +0000
    49.3 @@ -0,0 +1,28 @@
    49.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    49.5 +
    49.6 +from xenmgr import XendVdisk
    49.7 +from SrvDir import SrvDir
    49.8 +
    49.9 +class SrvVdiskDir(SrvDir):
   49.10 +    """Virtual disk directory.
   49.11 +    """
   49.12 +
   49.13 +    def __init__(self):
   49.14 +        SrvDir.__init__(self)
   49.15 +        self.xvdisk = XendVdisk.instance()
   49.16 +
   49.17 +    def vdisk(self, x):
   49.18 +        val = None
   49.19 +        try:
   49.20 +            dom = self.xvdisk.vdisk_get(x)
   49.21 +            val = SrvVdisk(dom)
   49.22 +        except KeyError:
   49.23 +            pass
   49.24 +        return val
   49.25 +
   49.26 +    def get(self, x):
   49.27 +        v = SrvDir.get(self, x)
   49.28 +        if v is not None:
   49.29 +            return v
   49.30 +        v = self.vdisk(x)
   49.31 +        return v
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/tools/xenmgr/lib/server/SrvVnetDir.py	Fri Jun 11 22:04:24 2004 +0000
    50.3 @@ -0,0 +1,9 @@
    50.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    50.5 +
    50.6 +from SrvDir import SrvDir
    50.7 +
    50.8 +class SrvVnetDir(SrvDir):
    50.9 +    """Vnet directory.
   50.10 +    """
   50.11 +
   50.12 +    pass
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/tools/xenmgr/lib/server/__init__.py	Fri Jun 11 22:04:24 2004 +0000
    51.3 @@ -0,0 +1,1 @@
    51.4 +
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/tools/xenmgr/lib/server/blkif.py	Fri Jun 11 22:04:24 2004 +0000
    52.3 @@ -0,0 +1,232 @@
    52.4 +import channel
    52.5 +import controller
    52.6 +from messages import *
    52.7 +
    52.8 +class BlkifControllerFactory(controller.ControllerFactory):
    52.9 +    """Factory for creating block device interface controllers.
   52.10 +    Also handles the 'back-end' channel to dom0.
   52.11 +    """
   52.12 +
   52.13 +    # todo: add support for setting dom controlling blkifs (don't assume 0).
   52.14 +    # todo: add support for 'recovery'.
   52.15 +
   52.16 +    def __init__(self):
   52.17 +        controller.ControllerFactory.__init__(self)
   52.18 +
   52.19 +        self.majorTypes = [ CMSG_BLKIF_BE ]
   52.20 +
   52.21 +        self.subTypes = {
   52.22 +            CMSG_BLKIF_BE_CREATE     : self.recv_be_create,
   52.23 +            CMSG_BLKIF_BE_CONNECT    : self.recv_be_connect,
   52.24 +            CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create,
   52.25 +            CMSG_BLKIF_BE_VBD_GROW   : self.recv_be_vbd_grow,
   52.26 +            CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
   52.27 +            }
   52.28 +        self.attached = 1
   52.29 +        self.registerChannel()
   52.30 +
   52.31 +    def createInstance(self, dom):
   52.32 +        d = self.addDeferred()
   52.33 +        blkif = self.getInstanceByDom(dom)
   52.34 +        if blkif:
   52.35 +            self.callDeferred(blkif)
   52.36 +        else:
   52.37 +            blkif = BlkifController(self, dom)
   52.38 +            self.addInstance(blkif)
   52.39 +            blkif.send_be_create()
   52.40 +        return d
   52.41 +
   52.42 +    def setControlDomain(self, dom):
   52.43 +        if self.channel:
   52.44 +            self.deregisterChannel()
   52.45 +            self.attached = 0
   52.46 +        self.dom = dom
   52.47 +        self.registerChannel()
   52.48 +        #
   52.49 +        #if xend.blkif.be_port:
   52.50 +        #    xend.blkif.recovery = True
   52.51 +        #xend.blkif.be_port = xend.main.port_from_dom(dom)
   52.52 +
   52.53 +    def recv_be_create(self, msg, req):
   52.54 +        #print 'recv_be_create>'
   52.55 +        val = unpackMsg('blkif_be_create_t', msg)
   52.56 +        blkif = self.getInstanceByDom(val['domid'])
   52.57 +        self.callDeferred(blkif)
   52.58 +    
   52.59 +    def recv_be_connect(self, msg, req):
   52.60 +        #print 'recv_be_create>'
   52.61 +        val = unpackMsg('blkif_be_connect_t', msg)
   52.62 +        blkif = self.getInstanceByDom(val['domid'])
   52.63 +        if blkif:
   52.64 +            blkif.send_fe_interface_status_changed()
   52.65 +        else:
   52.66 +            pass
   52.67 +    
   52.68 +    def recv_be_vbd_create(self, msg, req):
   52.69 +        #print 'recv_be_vbd_create>'
   52.70 +        val = unpackMsg('blkif_be_vbd_create_t', msg)
   52.71 +        blkif = self.getInstanceByDom(val['domid'])
   52.72 +        if blkif:
   52.73 +            blkif.send_be_vbd_grow(val['vdevice'])
   52.74 +        else:
   52.75 +            pass
   52.76 +    
   52.77 +    def recv_be_vbd_grow(self, msg, req):
   52.78 +        #print 'recv_be_vbd_grow>'
   52.79 +        val = unpackMsg('blkif_be_vbd_grow_t', msg)
   52.80 +        # Check status?
   52.81 +        if self.attached:
   52.82 +            self.callDeferred(0)
   52.83 +        else:
   52.84 +            self.reattach_device(val['domid'], val['vdevice'])
   52.85 +
   52.86 +    def reattach_device(self, dom, vdev):
   52.87 +        blkif = self.getInstanceByDom(dom)
   52.88 +        if blkif:
   52.89 +            blkif.reattach_device(vdev)
   52.90 +        attached = 1
   52.91 +        for blkif in self.getInstances():
   52.92 +            if not blkif.attached:
   52.93 +                attached = 0
   52.94 +                break
   52.95 +        self.attached = attached
   52.96 +        if self.attached:
   52.97 +            self.reattached()
   52.98 +
   52.99 +    def reattached(self):
  52.100 +        for blkif in self.getInstances():
  52.101 +            blkif.reattached()
  52.102 +
  52.103 +    def recv_be_driver_status_changed(self, msg, req):
  52.104 +        val = unpackMsg('blkif_be_driver_status_changed_t'. msg)
  52.105 +        status = val['status']
  52.106 +        if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
  52.107 +            for blkif in self.getInstances():
  52.108 +                blkif.detach()
  52.109 +
  52.110 +class BlkDev:
  52.111 +    """Info record for a block device.
  52.112 +    """
  52.113 +
  52.114 +    def __init__(self, vdev, mode, segment):
  52.115 +        self.vdev = vdev
  52.116 +        self.mode = mode
  52.117 +        self.device = segment['device']
  52.118 +        self.start_sector = segment['start_sector']
  52.119 +        self.nr_sectors = segment['nr_sectors']
  52.120 +        self.attached = 1
  52.121 +
  52.122 +    def readonly(self):
  52.123 +        return 'w' not in self.mode
  52.124 +        
  52.125 +class BlkifController(controller.Controller):
  52.126 +    """Block device interface controller. Handles all block devices
  52.127 +    for a domain.
  52.128 +    """
  52.129 +    
  52.130 +    def __init__(self, factory, dom):
  52.131 +        #print 'BlkifController> dom=', dom
  52.132 +        controller.Controller.__init__(self, factory, dom)
  52.133 +        self.devices = {}
  52.134 +
  52.135 +        self.majorTypes = [ CMSG_BLKIF_FE ]
  52.136 +
  52.137 +        self.subTypes = {
  52.138 +            CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED:
  52.139 +                self.recv_fe_driver_status_changed,
  52.140 +            CMSG_BLKIF_FE_INTERFACE_CONNECT    :
  52.141 +                self.recv_fe_interface_connect,
  52.142 +            }
  52.143 +        self.attached = 1
  52.144 +        self.registerChannel()
  52.145 +        #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
  52.146 +
  52.147 +    def attach_device(self, vdev, mode, segment):
  52.148 +        """Attach a device to the specified interface.
  52.149 +        """
  52.150 +        #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
  52.151 +        if vdev in self.devices: return -1
  52.152 +        dev = BlkDev(vdev, mode, segment)
  52.153 +        self.devices[vdev] = dev
  52.154 +        self.send_be_vbd_create(vdev)
  52.155 +        return self.factory.addDeferred()
  52.156 +
  52.157 +    def detach(self):
  52.158 +        self.attached = 0
  52.159 +        for dev in self.devices.values():
  52.160 +            dev.attached = 0
  52.161 +            self.send_be_vbd_create(vdev)
  52.162 +
  52.163 +    def reattach_device(self, vdev):
  52.164 +        dev = self.devices[vdev]
  52.165 +        dev.attached = 1
  52.166 +        attached = 1
  52.167 +        for dev in self.devices.values():
  52.168 +            if not dev.attached:
  52.169 +                attached = 0
  52.170 +                break
  52.171 +        self.attached = attached
  52.172 +        return self.attached
  52.173 +
  52.174 +    def reattached(self):
  52.175 +        msg = packMsg('blkif_fe_interface_status_changed_t',
  52.176 +                      { 'handle' : 0,
  52.177 +                        'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED})
  52.178 +        self.writeRequest(msg)
  52.179 +
  52.180 +    def recv_fe_driver_status_changed(self, msg, req):
  52.181 +        msg = packMsg('blkif_fe_interface_status_changed_t',
  52.182 +                      { 'handle' : 0,
  52.183 +                        'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED,
  52.184 +                        'evtchn' : 0 })
  52.185 +        self.writeRequest(msg)
  52.186 +    
  52.187 +    def recv_fe_interface_connect(self, msg, req):
  52.188 +        val = unpackMsg('blkif_fe_interface_connect_t', msg)
  52.189 +        self.evtchn = channel.eventChannel(0, self.dom)
  52.190 +        msg = packMsg('blkif_be_connect_t',
  52.191 +                      { 'domid'        : self.dom,
  52.192 +                        'blkif_handle' : val['handle'],
  52.193 +                        'evtchn'       : self.evtchn['port1'],
  52.194 +                        'shmem_frame'  : val['shmem_frame'] })
  52.195 +        self.factory.writeRequest(msg)
  52.196 +        pass
  52.197 +
  52.198 +    #def recv_fe_interface_status_changed(self, msg, req):
  52.199 +    #    (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
  52.200 +    #    print 'recv_fe_interface_status_changed>', hnd, status, chan
  52.201 +    #   pass
  52.202 +
  52.203 +    def send_fe_interface_status_changed(self):
  52.204 +        msg = packMsg('blkif_fe_interface_status_changed_t',
  52.205 +                      { 'handle' : 0,
  52.206 +                        'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
  52.207 +                        'evtchn' : self.evtchn['port2'] })
  52.208 +        self.writeRequest(msg)
  52.209 +
  52.210 +    def send_be_create(self):
  52.211 +        msg = packMsg('blkif_be_create_t',
  52.212 +                      { 'domid'        : self.dom,
  52.213 +                        'blkif_handle' : 0 })
  52.214 +        self.factory.writeRequest(msg)
  52.215 +
  52.216 +    def send_be_vbd_create(self, vdev):
  52.217 +        dev = self.devices[vdev]
  52.218 +        msg = packMsg('blkif_be_vbd_create_t',
  52.219 +                      { 'domid'        : self.dom,
  52.220 +                        'blkif_handle' : 0,
  52.221 +                        'vdevice'      : dev.vdev,
  52.222 +                        'readonly'     : dev.readonly() })
  52.223 +        self.factory.writeRequest(msg)
  52.224 +        
  52.225 +    def send_be_vbd_grow(self, vdev):
  52.226 +        dev = self.devices[vdev]
  52.227 +        msg = packMsg('blkif_be_vbd_grow_t',
  52.228 +                      { 'domid'                : self.dom,
  52.229 +                        'blkif_handle'         : 0,
  52.230 +                        'vdevice'              : dev.vdev,
  52.231 +                        'extent.device'        : dev.device,
  52.232 +                        'extent.sector_start'  : dev.start_sector,
  52.233 +                        'extent.sector_length' : dev.nr_sectors })
  52.234 +        self.factory.writeRequest(msg)
  52.235 +    
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/tools/xenmgr/lib/server/channel.py	Fri Jun 11 22:04:24 2004 +0000
    53.3 @@ -0,0 +1,259 @@
    53.4 +import Xc; xc = Xc.new()
    53.5 +import xend.utils
    53.6 +from messages import msgTypeName
    53.7 +
    53.8 +def eventChannel(dom1, dom2):
    53.9 +    return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2)
   53.10 +
   53.11 +class ChannelFactory:
   53.12 +    """Factory for creating channels.
   53.13 +    Maintains a table of channels.
   53.14 +    """
   53.15 +    
   53.16 +    channels = {}
   53.17 +
   53.18 +    def __init__(self):
   53.19 +        self.notifier = xend.utils.notifier()
   53.20 +    
   53.21 +    def addChannel(self, channel):
   53.22 +        idx = channel.idx
   53.23 +        self.channels[idx] = channel
   53.24 +        self.notifier.bind(idx)
   53.25 +        # Try to wake it up
   53.26 +        #self.notifier.unmask(idx)
   53.27 +        #channel.notify()
   53.28 +
   53.29 +    def getChannel(self, idx):
   53.30 +        return self.channels.get(idx)
   53.31 +
   53.32 +    def delChannel(self, idx):
   53.33 +        if idx in self.channels:
   53.34 +            del self.channels[idx]
   53.35 +            self.notifier.unbind(idx)
   53.36 +
   53.37 +    def domChannel(self, dom):
   53.38 +        for chan in self.channels.values():
   53.39 +            if chan.dom == dom:
   53.40 +                return chan
   53.41 +        chan = Channel(self, dom)
   53.42 +        self.addChannel(chan)
   53.43 +        return chan
   53.44 +
   53.45 +    def channelClosed(self, channel):
   53.46 +        self.delChannel(channel.idx)
   53.47 +
   53.48 +    def createPort(self, dom):
   53.49 +        return xend.utils.port(dom)
   53.50 +
   53.51 +def channelFactory():
   53.52 +    global inst
   53.53 +    try:
   53.54 +        inst
   53.55 +    except:
   53.56 +        inst = ChannelFactory()
   53.57 +    return inst
   53.58 +
   53.59 +class Channel:
   53.60 +    """A control channel to a domain. Messages for the domain device controllers
   53.61 +    are multiplexed over the channel (console, block devs, net devs).
   53.62 +    """
   53.63 +
   53.64 +    def __init__(self, factory, dom):
   53.65 +        self.factory = factory
   53.66 +        self.dom = dom
   53.67 +        self.port = self.factory.createPort(dom)
   53.68 +        self.idx = self.port.local_port
   53.69 +        self.devs = []
   53.70 +        self.devs_by_type = {}
   53.71 +        self.closed = 0
   53.72 +        self.queue = []
   53.73 +
   53.74 +    def getIndex(self):
   53.75 +        return self.idx
   53.76 +
   53.77 +    def getLocalPort(self):
   53.78 +        return self.port.local_port
   53.79 +
   53.80 +    def getRemotePort(self):
   53.81 +        return self.port.remote_port
   53.82 +
   53.83 +    def close(self):
   53.84 +        for d in self.devs:
   53.85 +            d.lostChannel()
   53.86 +        self.factory.channelClosed(self)
   53.87 +        del self.devs
   53.88 +        del self.devs_by_type
   53.89 +
   53.90 +    def registerDevice(self, types, dev):
   53.91 +        """Register a device controller.
   53.92 +
   53.93 +        @param types message types the controller handles
   53.94 +        @param dev   device controller
   53.95 +        """
   53.96 +        self.devs.append(dev)
   53.97 +        for ty in types:
   53.98 +            self.devs_by_type[ty] = dev
   53.99 +
  53.100 +    def unregisterDevice(self, dev):
  53.101 +        """Remove the registration for a device controller.
  53.102 +
  53.103 +        @param dev device controller
  53.104 +        """
  53.105 +        self.devs.remove(dev)
  53.106 +        types = [ ty for (ty, d) in self.devs_by_type.items()
  53.107 +                  if d == dev ]
  53.108 +        for ty in types:
  53.109 +            del devs_by_type[ty]
  53.110 +
  53.111 +    def getDevice(self, type):
  53.112 +        """Get the device controller handling a message type.
  53.113 +
  53.114 +        @param type message type
  53.115 +        @returns controller or None
  53.116 +        """
  53.117 +        return self.devs_by_type.get(type)
  53.118 +
  53.119 +    def getMessageType(self, msg):
  53.120 +        hdr = msg.get_header()
  53.121 +        return (hdr['type'], hdr.get('subtype'))
  53.122 +
  53.123 +    def __repr__(self):
  53.124 +        return ('<Channel dom=%d ports=%d:%d>'
  53.125 +                % (self.dom,
  53.126 +                   self.port.local_port,
  53.127 +                   self.port.remote_port))
  53.128 +
  53.129 +    def notificationReceived(self, type):
  53.130 +        #print 'notificationReceived> type=', type, self
  53.131 +        if self.closed: return
  53.132 +        if type == self.factory.notifier.EXCEPTION:
  53.133 +            print 'notificationReceived> EXCEPTION'
  53.134 +            info = xc.evtchn_status(self.idx)
  53.135 +            if info['status'] == 'unbound':
  53.136 +                print 'notificationReceived> EXCEPTION closing...'
  53.137 +                self.close()
  53.138 +                return
  53.139 +        work = 0
  53.140 +        work += self.handleRequests()
  53.141 +        work += self.handleResponses()
  53.142 +        work += self.handleWrites()
  53.143 +        if work:
  53.144 +            self.notify()
  53.145 +        #print 'notificationReceived<', work
  53.146 +
  53.147 +    def notify(self):
  53.148 +        #print 'notify>', self
  53.149 +        self.port.notify()
  53.150 +
  53.151 +    def handleRequests(self):
  53.152 +        #print 'handleRequests>'
  53.153 +        work = 0
  53.154 +        while 1:
  53.155 +            #print 'handleRequests>', work
  53.156 +            msg = self.readRequest()
  53.157 +            #print 'handleRequests> msg=', msg
  53.158 +            if not msg: break
  53.159 +            self.requestReceived(msg)
  53.160 +            work += 1
  53.161 +        #print 'handleRequests<', work
  53.162 +        return work
  53.163 +
  53.164 +    def requestReceived(self, msg):
  53.165 +        (ty, subty) = self.getMessageType(msg)
  53.166 +        #print 'requestReceived>', ty, subty, self
  53.167 +        #todo:  Must respond before writing any more messages.
  53.168 +        #todo:  Should automate this (respond on write)
  53.169 +        self.port.write_response(msg)
  53.170 +        dev = self.getDevice(ty)
  53.171 +        if dev:
  53.172 +            dev.requestReceived(msg, ty, subty)
  53.173 +        else:
  53.174 +            print ("requestReceived> No device: Message type %s %d:%d"
  53.175 +                   % (msgTypeName(ty, subty), ty, subty)), self
  53.176 +
  53.177 +    def handleResponses(self):
  53.178 +        #print 'handleResponses>', self
  53.179 +        work = 0
  53.180 +        while 1:
  53.181 +            #print 'handleResponses>', work
  53.182 +            msg = self.readResponse()
  53.183 +            #print 'handleResponses> msg=', msg
  53.184 +            if not msg: break
  53.185 +            self.responseReceived(msg)
  53.186 +            work += 1
  53.187 +        #print 'handleResponses<', work
  53.188 +        return work
  53.189 +
  53.190 +    def responseReceived(self, msg):
  53.191 +        (ty, subty) = self.getMessageType(msg)
  53.192 +        #print 'responseReceived>', ty, subty
  53.193 +        dev = self.getDevice(ty)
  53.194 +        if dev:
  53.195 +            dev.responseReceived(msg, ty, subty)
  53.196 +        else:
  53.197 +            print ("responseReceived> No device: Message type %d:%d"
  53.198 +                   % (msgTypeName(ty, subty), ty, subty)), self
  53.199 +
  53.200 +    def handleWrites(self):
  53.201 +        #print 'handleWrites>', self
  53.202 +        work = 0
  53.203 +        # Pull data from producers.
  53.204 +        #print 'handleWrites> pull...'
  53.205 +        for dev in self.devs:
  53.206 +            work += dev.produceRequests()
  53.207 +        # Flush the queue.
  53.208 +        #print 'handleWrites> flush...'
  53.209 +        while self.queue and self.port.space_to_write_request():
  53.210 +            msg = self.queue.pop(0)
  53.211 +            self.port.write_request(msg)
  53.212 +            work += 1
  53.213 +        #print 'handleWrites<', work
  53.214 +        return work
  53.215 +
  53.216 +    def writeRequest(self, msg, notify=1):
  53.217 +        #print 'writeRequest>', self
  53.218 +        if self.closed:
  53.219 +            val = -1
  53.220 +        elif self.writeReady():
  53.221 +            self.port.write_request(msg)
  53.222 +            if notify: self.notify()
  53.223 +            val = 1
  53.224 +        else:
  53.225 +            self.queue.append(msg)
  53.226 +            val = 0
  53.227 +        #print 'writeRequest<', val
  53.228 +        return val
  53.229 +
  53.230 +    def writeResponse(self, msg):
  53.231 +        #print 'writeResponse>', self
  53.232 +        if self.closed: return -1
  53.233 +        self.port.write_response(msg)
  53.234 +        return 1
  53.235 +
  53.236 +    def writeReady(self):
  53.237 +        if self.closed or self.queue: return 0
  53.238 +        return self.port.space_to_write_request()
  53.239 +
  53.240 +    def readRequest(self):
  53.241 +        #print 'readRequest>', self
  53.242 +        if self.closed:
  53.243 +            #print 'readRequest> closed'
  53.244 +            return None
  53.245 +        if self.port.request_to_read():
  53.246 +            val = self.port.read_request()
  53.247 +        else:
  53.248 +            val = None
  53.249 +        #print 'readRequest< ', val
  53.250 +        return val
  53.251 +        
  53.252 +    def readResponse(self):
  53.253 +        #print 'readResponse>', self
  53.254 +        if self.closed:
  53.255 +            #print 'readResponse> closed'
  53.256 +            return None
  53.257 +        if self.port.response_to_read():
  53.258 +            val = self.port.read_response()
  53.259 +        else:
  53.260 +            val = None
  53.261 +        #print 'readResponse<', val
  53.262 +        return val
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/tools/xenmgr/lib/server/console.py	Fri Jun 11 22:04:24 2004 +0000
    54.3 @@ -0,0 +1,220 @@
    54.4 +
    54.5 +from twisted.internet import reactor
    54.6 +from twisted.internet import protocol
    54.7 +from twisted.protocols import telnet
    54.8 +
    54.9 +import xend.utils
   54.10 +
   54.11 +from xenmgr import EventServer
   54.12 +eserver = EventServer.instance()
   54.13 +
   54.14 +import controller
   54.15 +from messages import *
   54.16 +from params import *
   54.17 +
   54.18 +"""Telnet binary option."""
   54.19 +TRANSMIT_BINARY = '0'
   54.20 +WILL = chr(251)
   54.21 +IAC = chr(255)
   54.22 +
   54.23 +class ConsoleProtocol(protocol.Protocol):
   54.24 +    """Asynchronous handler for a console TCP socket.
   54.25 +    """
   54.26 +
   54.27 +    def __init__(self, controller, idx):
   54.28 +        self.controller = controller
   54.29 +        self.idx = idx
   54.30 +        self.addr = None
   54.31 +        self.binary = 0
   54.32 +
   54.33 +    def connectionMade(self):
   54.34 +        peer = self.transport.getPeer()
   54.35 +        self.addr = (peer.host, peer.port)
   54.36 +        if self.controller.connect(self.addr, self):
   54.37 +            self.transport.write("Cannot connect to console %d on domain %d\n"
   54.38 +                                 % (self.idx, self.controller.dom))
   54.39 +            self.loseConnection()
   54.40 +            return
   54.41 +        else:
   54.42 +            self.transport.write("Connected to console %d on domain %d\n"
   54.43 +                                 % (self.idx, self.controller.dom))
   54.44 +            self.setTelnetTransmitBinary()
   54.45 +            eserver.inject('xend.console.connect',
   54.46 +                           [self.idx, self.addr[0], self.addr[1]])
   54.47 +
   54.48 +    def setTelnetTransmitBinary(self):
   54.49 +        """Send the sequence to set the telnet TRANSMIT-BINARY option.
   54.50 +        """
   54.51 +        self.write(IAC + WILL + TRANSMIT_BINARY)
   54.52 +
   54.53 +    def dataReceived(self, data):
   54.54 +        if self.controller.handleInput(self, data):
   54.55 +            self.loseConnection()
   54.56 +
   54.57 +    def write(self, data):
   54.58 +        #if not self.connected: return -1
   54.59 +        self.transport.write(data)
   54.60 +        return len(data)
   54.61 +
   54.62 +    def connectionLost(self, reason=None):
   54.63 +        eserver.inject('xend.console.disconnect',
   54.64 +                       [self.idx, self.addr[0], self.addr[1]])
   54.65 +        self.controller.disconnect()
   54.66 +
   54.67 +    def loseConnection(self):
   54.68 +        self.transport.loseConnection()
   54.69 +
   54.70 +class ConsoleFactory(protocol.ServerFactory):
   54.71 +    """Asynchronous handler for a console server socket.
   54.72 +    """
   54.73 +    protocol = ConsoleProtocol
   54.74 +    
   54.75 +    def __init__(self, controller, idx):
   54.76 +        #protocol.ServerFactory.__init__(self)
   54.77 +        self.controller = controller
   54.78 +        self.idx = idx
   54.79 +
   54.80 +    def buildProtocol(self, addr):
   54.81 +        proto = self.protocol(self.controller, self.idx)
   54.82 +        proto.factory = self
   54.83 +        return proto
   54.84 +
   54.85 +class ConsoleControllerFactory(controller.ControllerFactory):
   54.86 +    """Factory for creating console controllers.
   54.87 +    """
   54.88 +
   54.89 +    def createInstance(self, dom, console_port=None):
   54.90 +        if console_port is None:
   54.91 +            console_port = CONSOLE_PORT_BASE + dom
   54.92 +        console = ConsoleController(self, dom, console_port)
   54.93 +        self.addInstance(console)
   54.94 +        eserver.inject('xend.console.create',
   54.95 +                       [console.idx, console.dom, console.console_port])
   54.96 +        return console
   54.97 +        
   54.98 +    def consoleClosed(self, console):
   54.99 +        eserver.inject('xend.console.close', console.idx)
  54.100 +        self.delInstance(console)
  54.101 +
  54.102 +class ConsoleController(controller.Controller):
  54.103 +    """Console controller for a domain.
  54.104 +    Does not poll for i/o itself, but relies on the notifier to post console
  54.105 +    output and the connected TCP sockets to post console input.
  54.106 +    """
  54.107 +
  54.108 +    def __init__(self, factory, dom, console_port):
  54.109 +        #print 'ConsoleController> dom=', dom
  54.110 +        controller.Controller.__init__(self, factory, dom)
  54.111 +        self.majorTypes = [ CMSG_CONSOLE ]
  54.112 +        self.status = "new"
  54.113 +        self.addr = None
  54.114 +        self.conn = None
  54.115 +        self.rbuf = xend.utils.buffer()
  54.116 +        self.wbuf = xend.utils.buffer()
  54.117 +        self.console_port = console_port
  54.118 +
  54.119 +        self.registerChannel()
  54.120 +        self.listener = None
  54.121 +        self.listen()
  54.122 +        #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
  54.123 +
  54.124 +    def sxpr(self):
  54.125 +        val =['console',
  54.126 +              ['id',           self.idx ],
  54.127 +              ['domain',       self.dom ],
  54.128 +              ['local_port',   self.channel.getLocalPort() ],
  54.129 +              ['remote_port',  self.channel.getRemotePort() ],
  54.130 +              ['console_port', self.console_port ] ]
  54.131 +        if self.addr:
  54.132 +            val.append(['connected', self.addr[0], self.addr[1]])
  54.133 +        return val
  54.134 +
  54.135 +    def ready(self):
  54.136 +        return not (self.closed() or self.rbuf.empty())
  54.137 +
  54.138 +    def closed(self):
  54.139 +        return self.status == 'closed'
  54.140 +
  54.141 +    def connected(self):
  54.142 +        return self.status == 'connected'
  54.143 +
  54.144 +    def close(self):
  54.145 +        self.status = "closed"
  54.146 +        self.listener.stopListening()
  54.147 +        self.deregisterChannel()
  54.148 +        self.lostChannel()
  54.149 +
  54.150 +    def listen(self):
  54.151 +        """Listen for TCP connections to the console port..
  54.152 +        """
  54.153 +        if self.closed(): return
  54.154 +        self.status = "listening"
  54.155 +        if self.listener:
  54.156 +            #self.listener.startListening()
  54.157 +            pass
  54.158 +        else:
  54.159 +            f = ConsoleFactory(self, self.idx)
  54.160 +            self.listener = reactor.listenTCP(self.console_port, f)
  54.161 +
  54.162 +    def connect(self, addr, conn):
  54.163 +        if self.closed(): return -1
  54.164 +        if self.connected(): return -1
  54.165 +        self.addr = addr
  54.166 +        self.conn = conn
  54.167 +        self.status = "connected"
  54.168 +        self.handleOutput()
  54.169 +        return 0
  54.170 +
  54.171 +    def disconnect(self):
  54.172 +        self.addr = None
  54.173 +        self.conn = None
  54.174 +        self.listen()
  54.175 +
  54.176 +    def requestReceived(self, msg, type, subtype):
  54.177 +        #print '***Console', self.dom, msg.get_payload()
  54.178 +        self.rbuf.write(msg.get_payload())
  54.179 +        self.handleOutput()
  54.180 +        
  54.181 +    def responseReceived(self, msg, type, subtype):
  54.182 +        pass
  54.183 +
  54.184 +    def produceRequests(self):
  54.185 +        # Send as much pending console data as there is room for.
  54.186 +        work = 0
  54.187 +        while not self.wbuf.empty() and self.channel.writeReady():
  54.188 +            msg = xend.utils.message(CMSG_CONSOLE, 0, 0)
  54.189 +            msg.append_payload(self.wbuf.read(msg.MAX_PAYLOAD))
  54.190 +            work += self.channel.writeRequest(msg, notify=0)
  54.191 +        return work
  54.192 +
  54.193 +    def handleInput(self, conn, data):
  54.194 +        """Handle some external input aimed at the console.
  54.195 +        Called from a TCP connection (conn).
  54.196 +        """
  54.197 +        if self.closed(): return -1
  54.198 +        if conn != self.conn: return 0
  54.199 +        self.wbuf.write(data)
  54.200 +        if self.produceRequests():
  54.201 +            self.channel.notify()
  54.202 +        return 0
  54.203 +
  54.204 +    def handleOutput(self):
  54.205 +        """Handle buffered output from the console.
  54.206 +        Sends it to the connected console (if any).
  54.207 +        """
  54.208 +        if self.closed():
  54.209 +            #print 'Console>handleOutput> closed'
  54.210 +            return -1
  54.211 +        if not self.conn:
  54.212 +            #print 'Console>handleOutput> not connected'
  54.213 +            return 0
  54.214 +        while not self.rbuf.empty():
  54.215 +            try:
  54.216 +                #print 'Console>handleOutput> writing...'
  54.217 +                bytes = self.conn.write(self.rbuf.peek())
  54.218 +                if bytes > 0:
  54.219 +                    self.rbuf.discard(bytes)
  54.220 +            except socket.error, error:
  54.221 +                pass
  54.222 +        #print 'Console>handleOutput<'
  54.223 +        return 0
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/tools/xenmgr/lib/server/controller.py	Fri Jun 11 22:04:24 2004 +0000
    55.3 @@ -0,0 +1,133 @@
    55.4 +from twisted.internet import defer
    55.5 +
    55.6 +import channel
    55.7 +from messages import msgTypeName
    55.8 +
    55.9 +class CtrlMsgRcvr:
   55.10 +    """Abstract class for things that deal with a control interface to a domain.
   55.11 +    """
   55.12 +
   55.13 +
   55.14 +    def __init__(self):
   55.15 +        self.channelFactory = channel.channelFactory()
   55.16 +        self.majorTypes = [ ]
   55.17 +        self.subTypes = {}
   55.18 +        self.dom = None
   55.19 +        self.channel = None
   55.20 +        self.idx = None
   55.21 +
   55.22 +    def requestReceived(self, msg, type, subtype):
   55.23 +        method = self.subTypes.get(subtype)
   55.24 +        if method:
   55.25 +            method(msg, 1)
   55.26 +        else:
   55.27 +            print ('requestReceived> No handler: Message type %s %d:%d'
   55.28 +                   % (msgTypeName(type, subtype), type, subtype)), self
   55.29 +        
   55.30 +    def responseReceived(self, msg, type, subtype):
   55.31 +        method = self.subTypes.get(subtype)
   55.32 +        if method:
   55.33 +            method(msg, 0)
   55.34 +        else:
   55.35 +            print ('responseReceived> No handler: Message type %s %d:%d'
   55.36 +                   % (msgTypeName(type, subtype), type, subtype)), self
   55.37 +
   55.38 +    def lostChannel(self):
   55.39 +        pass
   55.40 +    
   55.41 +    def registerChannel(self):
   55.42 +        self.channel = self.channelFactory.domChannel(self.dom)
   55.43 +        #print 'registerChannel> channel=', self.channel, self
   55.44 +        self.idx = self.channel.getIndex()
   55.45 +        #print 'registerChannel> idx=', self.idx
   55.46 +        if self.majorTypes:
   55.47 +            self.channel.registerDevice(self.majorTypes, self)
   55.48 +        
   55.49 +    def deregisterChannel(self):
   55.50 +        if self.channel:
   55.51 +            self.channel.deregisterDevice(self)
   55.52 +            del self.channel
   55.53 +
   55.54 +    def produceRequests(self):
   55.55 +        return 0
   55.56 +
   55.57 +    def writeRequest(self, msg):
   55.58 +        if self.channel:
   55.59 +            self.channel.writeRequest(msg)
   55.60 +        else:
   55.61 +            print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
   55.62 +
   55.63 +    def writeResponse(self, msg):
   55.64 +        if self.channel:
   55.65 +            self.channel.writeResponse(msg)
   55.66 +        else:
   55.67 +            print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
   55.68 +            
   55.69 +class ControllerFactory(CtrlMsgRcvr):
   55.70 +    """Abstract class for factories creating controllers.
   55.71 +    Maintains a table of instances.
   55.72 +    """
   55.73 +
   55.74 +    def __init__(self):
   55.75 +        CtrlMsgRcvr.__init__(self)
   55.76 +        self.instances = {}
   55.77 +        self.dlist = []
   55.78 +        self.dom = 0
   55.79 +        
   55.80 +    def addInstance(self, instance):
   55.81 +        self.instances[instance.idx] = instance
   55.82 +
   55.83 +    def getInstance(self, idx):
   55.84 +        return self.instances.get(idx)
   55.85 +
   55.86 +    def getInstances(self):
   55.87 +        return self.instances.values()
   55.88 +
   55.89 +    def getInstanceByDom(self, dom):
   55.90 +        for inst in self.instances.values():
   55.91 +            if inst.dom == dom:
   55.92 +                return inst
   55.93 +        return None
   55.94 +
   55.95 +    def delInstance(self, instance):
   55.96 +        if instance in self.instances:
   55.97 +            del self.instances[instance.idx]
   55.98 +
   55.99 +    def createInstance(self, dom):
  55.100 +        raise NotImplementedError()
  55.101 +
  55.102 +    def instanceClosed(self, instance):
  55.103 +        self.delInstance(instance)
  55.104 +
  55.105 +    def addDeferred(self):
  55.106 +        d = defer.Deferred()
  55.107 +        self.dlist.append(d)
  55.108 +        return d
  55.109 +
  55.110 +    def callDeferred(self, *args):
  55.111 +        if self.dlist:
  55.112 +            d = self.dlist.pop(0)
  55.113 +            d.callback(*args)
  55.114 +
  55.115 +    def errDeferred(self, *args):
  55.116 +        if self.dlist:
  55.117 +            d = self.dlist.pop(0)
  55.118 +            d.errback(*args)
  55.119 +
  55.120 +class Controller(CtrlMsgRcvr):
  55.121 +    """Abstract class for a device controller attached to a domain.
  55.122 +    """
  55.123 +
  55.124 +    def __init__(self, factory, dom):
  55.125 +        CtrlMsgRcvr.__init__(self)
  55.126 +        self.factory = factory
  55.127 +        self.dom = dom
  55.128 +        self.channel = None
  55.129 +        self.idx = None
  55.130 +
  55.131 +    def close(self):
  55.132 +        self.deregisterChannel()
  55.133 +        self.lostChannel(self)
  55.134 +
  55.135 +    def lostChannel(self):
  55.136 +        self.factory.instanceClosed(self)
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/tools/xenmgr/lib/server/cstruct.py	Fri Jun 11 22:04:24 2004 +0000
    56.3 @@ -0,0 +1,269 @@
    56.4 +import struct
    56.5 +
    56.6 +class Struct:
    56.7 +
    56.8 +    maxDepth = 10
    56.9 +
   56.10 +    base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
   56.11 +
   56.12 +    sizes = {'B': 1,
   56.13 +            'H': 2,
   56.14 +            'I': 4,
   56.15 +            'L': 4,
   56.16 +            'Q': 8,
   56.17 +            'c': 1,
   56.18 +            'h': 2,
   56.19 +            'i': 4,
   56.20 +            'l': 4,
   56.21 +            'q': 8,
   56.22 +            'x': 1,
   56.23 +            }
   56.24 +
   56.25 +    formats = {
   56.26 +        'int8'          : 'B',
   56.27 +        'int16'         : 'H',
   56.28 +        'int32'         : 'I',
   56.29 +        'int64'         : 'Q',
   56.30 +        'u8'            : 'B',
   56.31 +        'u16'           : 'H',
   56.32 +        'u32'           : 'I',
   56.33 +        'u64'           : 'Q'
   56.34 +        }
   56.35 +
   56.36 +    def typedef(self, name, val):
   56.37 +        self.formats[name] = val
   56.38 +
   56.39 +    def struct(self, name, *f):
   56.40 +        self.typedef(name, StructInfo(self, f))
   56.41 +        
   56.42 +    def getType(self, name):
   56.43 +        return self.formats[name]
   56.44 +
   56.45 +    def format(self, ty):
   56.46 +        d = 0
   56.47 +        f = ty
   56.48 +        while d < self.maxDepth:
   56.49 +            d += 1
   56.50 +            f = self.formats[f]
   56.51 +            if isinstance(f, StructInfo):
   56.52 +                return f.format()
   56.53 +            if f in self.base:
   56.54 +                return f
   56.55 +        return -1
   56.56 +
   56.57 +    def alignedformat(self, ty):
   56.58 +        fmt = self.format(ty)
   56.59 +        #print 'alignedformat> %s |%s|' %(ty, fmt)
   56.60 +        afmt = self.align(fmt)
   56.61 +        #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
   56.62 +        return afmt
   56.63 +
   56.64 +    def align(self, fmt):
   56.65 +        n1 = 0
   56.66 +        afmt = ''
   56.67 +        for a in fmt:
   56.68 +            n2 = self.getSize(a)
   56.69 +            m = n1 % n2
   56.70 +            if m:
   56.71 +                d = (n2 - m)
   56.72 +                afmt += 'x' * d
   56.73 +                n1 += d
   56.74 +            afmt += a
   56.75 +            n1 += n2
   56.76 +        return afmt
   56.77 +
   56.78 +    def fmtsize(self, fmt):
   56.79 +        s = 0
   56.80 +        for f in fmt:
   56.81 +            s += self.getSize(f)
   56.82 +        return s
   56.83 +
   56.84 +    def getSize(self, f):
   56.85 +        return self.sizes[f]
   56.86 +
   56.87 +    def pack(self, ty, data):
   56.88 +        return self.getType(ty).pack(data)
   56.89 +
   56.90 +    def unpack(self, ty, data):
   56.91 +        return self.getType(ty).unpack(data)
   56.92 +
   56.93 +    def show(self):
   56.94 +        l = self.formats.keys()
   56.95 +        l.sort()
   56.96 +        for v in l:
   56.97 +            print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
   56.98 +
   56.99 +
  56.100 +class StructInfo:
  56.101 +
  56.102 +    def __init__(self, s, f):
  56.103 +        self.fmt = None
  56.104 +        self.structs = s
  56.105 +        self.fields = f
  56.106 +
  56.107 +    def alignedformat(self):
  56.108 +        if self.afmt: return self.afmt
  56.109 +        self.afmt = self.structs.align(self.format())
  56.110 +        return self.afmt
  56.111 +    
  56.112 +    def format(self):
  56.113 +        if self.fmt: return self.fmt
  56.114 +        fmt = ""
  56.115 +        for (ty, name) in self.fields:
  56.116 +            fmt += self.formatString(ty)
  56.117 +        self.fmt = fmt
  56.118 +        return fmt
  56.119 +
  56.120 +    def formatString(self, ty):
  56.121 +        if ty in self.fields:
  56.122 +            ty = self.fields[ty]
  56.123 +        return self.structs.format(ty)
  56.124 +
  56.125 +    def pack(self, *args):
  56.126 +        return struct.pack(self.alignedformat(), *args)
  56.127 +
  56.128 +    def unpack(self, data):
  56.129 +        return struct.unpack(self.alignedformat(), data)
  56.130 +
  56.131 +types = Struct()
  56.132 +
  56.133 +types.typedef('short'         , 'h')
  56.134 +types.typedef('int'           , 'i')
  56.135 +types.typedef('long'          , 'l')
  56.136 +types.typedef('unsigned short', 'H')
  56.137 +types.typedef('unsigned int'  , 'I')
  56.138 +types.typedef('unsigned long' , 'L')
  56.139 +types.typedef('domid_t'       , 'u64')
  56.140 +types.typedef('blkif_vdev_t'  , 'u16')
  56.141 +types.typedef('blkif_pdev_t'  , 'u16')
  56.142 +types.typedef('blkif_sector_t', 'u64')
  56.143 +
  56.144 +types.struct('u8[6]',
  56.145 +             ('u8', 'a1'),
  56.146 +             ('u8', 'a2'),
  56.147 +             ('u8', 'a3'),
  56.148 +             ('u8', 'a4'),
  56.149 +             ('u8', 'a5'),
  56.150 +             ('u8', 'a6'))
  56.151 +             
  56.152 +types.struct('blkif_fe_interface_status_changed_t',
  56.153 +    ('unsigned int',    'handle'),
  56.154 +    ('unsigned int',    'status'),
  56.155 +    ('unsigned int',    'evtchn'))
  56.156 +
  56.157 +types.struct('blkif_fe_driver_status_changed_t',
  56.158 +    ('unsigned int',    'status'),
  56.159 +    ('unsigned int',    'nr_interfaces'))
  56.160 +
  56.161 +types.struct('blkif_fe_interface_connect_t',
  56.162 +    ('unsigned int' ,   'handle'),
  56.163 +    ('unsigned long',   'shmem_frame'))
  56.164 +
  56.165 +types.struct('blkif_fe_interface_disconnect_t',
  56.166 +    ('unsigned int',   'handle'))
  56.167 +
  56.168 +types.struct('blkif_extent_t',
  56.169 +    ('blkif_pdev_t'  , 'device'),
  56.170 +    ('blkif_sector_t', 'sector_start'),
  56.171 +    ('blkif_sector_t', 'sector_length'))
  56.172 +
  56.173 +types.struct('blkif_be_create_t', 
  56.174 +    ('domid_t'     ,   'domid'),
  56.175 +    ('unsigned int',   'blkif_handle'),
  56.176 +    ('unsigned int',   'status'))
  56.177 +             
  56.178 +types.struct('blkif_be_destroy_t',
  56.179 +    ('domid_t'     ,   'domid'),
  56.180 +    ('unsigned int',   'blkif_handle'),
  56.181 +    ('unsigned int',   'status'))
  56.182 +
  56.183 +types.struct('blkif_be_connect_t',
  56.184 +    ('domid_t'      ,  'domid'),
  56.185 +    ('unsigned int' ,  'blkif_handle'),
  56.186 +    ('unsigned int' ,  'evtchn'),
  56.187 +    ('unsigned long',  'shmem_frame'),
  56.188 +    ('unsigned int' ,  'status'))
  56.189 +
  56.190 +types.struct('blkif_be_disconnect_t',
  56.191 +    ('domid_t'     ,   'domid'),
  56.192 +    ('unsigned int',   'blkif_handle'),
  56.193 +    ('unsigned int',   'status'))
  56.194 +
  56.195 +types.struct('blkif_be_vbd_create_t', 
  56.196 +    ('domid_t'     ,   'domid'),         #Q
  56.197 +    ('unsigned int',   'blkif_handle'),  #I
  56.198 +    ('blkif_vdev_t',   'vdevice'),       #H
  56.199 +    ('int'         ,   'readonly'),      #i
  56.200 +    ('unsigned int',   'status'))        #I
  56.201 +
  56.202 +types.struct('blkif_be_vbd_destroy_t', 
  56.203 +    ('domid_t'     ,   'domid'),
  56.204 +    ('unsigned int',   'blkif_handle'),
  56.205 +    ('blkif_vdev_t',   'vdevice'),
  56.206 +    ('unsigned int',   'status'))
  56.207 +
  56.208 +types.struct('blkif_be_vbd_grow_t', 
  56.209 +    ('domid_t'       , 'domid'),         #Q
  56.210 +    ('unsigned int'  , 'blkif_handle'),  #I
  56.211 +    ('blkif_vdev_t'  , 'vdevice'),       #H   
  56.212 +    ('blkif_extent_t', 'extent'),        #HQQ
  56.213 +    ('unsigned int'  , 'status'))        #I
  56.214 +
  56.215 +types.struct('blkif_be_vbd_shrink_t', 
  56.216 +    ('domid_t'     ,   'domid'),
  56.217 +    ('unsigned int',   'blkif_handle'),
  56.218 +    ('blkif_vdev_t',   'vdevice'),
  56.219 +    ('unsigned int',   'status'))
  56.220 +
  56.221 +types.struct('blkif_be_driver_status_changed_t',
  56.222 +    ('unsigned int',   'status'),
  56.223 +    ('unsigned int',   'nr_interfaces'))
  56.224 +
  56.225 +types.struct('netif_fe_interface_status_changed_t',
  56.226 +    ('unsigned int',   'handle'),
  56.227 +    ('unsigned int',   'status'),
  56.228 +    ('unsigned int',   'evtchn'),
  56.229 +    ('u8[6]',          'mac'))
  56.230 +
  56.231 +types.struct('netif_fe_driver_status_changed_t',
  56.232 +    ('unsigned int',   'status'),
  56.233 +    ('unsigned int',   'nr_interfaces'))
  56.234 +
  56.235 +types.struct('netif_fe_interface_connect_t',
  56.236 +    ('unsigned int',   'handle'),
  56.237 +    ('unsigned long',  'tx_shmem_frame'),
  56.238 +    ('unsigned long',  'rx_shmem_frame'))
  56.239 +
  56.240 +types.struct('netif_fe_interface_disconnect_t',
  56.241 +    ('unsigned int',   'handle'))
  56.242 +
  56.243 +types.struct('netif_be_create_t', 
  56.244 +    ('domid_t'     ,   'domid'),
  56.245 +    ('unsigned int',   'netif_handle'),
  56.246 +    ('u8[6]'       ,   'mac'),
  56.247 +    ('unsigned int',   'status'))
  56.248 +
  56.249 +types.struct('netif_be_destroy_t',
  56.250 +    ('domid_t'     ,   'domid'),
  56.251 +    ('unsigned int',   'netif_handle'),
  56.252 +    ('unsigned int',   'status'))
  56.253 +
  56.254 +types.struct('netif_be_connect_t', 
  56.255 +    ('domid_t'      ,  'domid'),
  56.256 +    ('unsigned int' ,  'netif_handle'),
  56.257 +    ('unsigned int' ,  'evtchn'),
  56.258 +    ('unsigned long',  'tx_shmem_frame'),
  56.259 +    ('unsigned long',  'rx_shmem_frame'),
  56.260 +    ('unsigned int' ,  'status'))
  56.261 +
  56.262 +types.struct('netif_be_disconnect_t',
  56.263 +    ('domid_t'     ,   'domid'),
  56.264 +    ('unsigned int',   'netif_handle'),
  56.265 +    ('unsigned int',   'status'))
  56.266 +
  56.267 +types.struct('netif_be_driver_status_changed_t',
  56.268 +    ('unsigned int',   'status'),
  56.269 +    ('unsigned int',   'nr_interfaces'))
  56.270 +
  56.271 +if 1 or __name__ == "__main__":
  56.272 +    types.show()
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/tools/xenmgr/lib/server/messages.py	Fri Jun 11 22:04:24 2004 +0000
    57.3 @@ -0,0 +1,186 @@
    57.4 +import struct
    57.5 +
    57.6 +import xend.utils
    57.7 +
    57.8 +""" All message formats.
    57.9 +Added to incrementally for the various message types.
   57.10 +See below.
   57.11 +"""
   57.12 +msg_formats = {}
   57.13 +
   57.14 +#============================================================================
   57.15 +# Console message types.
   57.16 +#============================================================================
   57.17 +
   57.18 +CMSG_CONSOLE  = 0
   57.19 +
   57.20 +console_formats = { 'console_data': (CMSG_CONSOLE, 0, "?") }
   57.21 +
   57.22 +msg_formats.update(console_formats)
   57.23 +
   57.24 +#============================================================================
   57.25 +# Block interface message types.
   57.26 +#============================================================================
   57.27 +
   57.28 +CMSG_BLKIF_BE = 1
   57.29 +CMSG_BLKIF_FE = 2
   57.30 +
   57.31 +CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED =  0
   57.32 +CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED    = 32
   57.33 +CMSG_BLKIF_FE_INTERFACE_CONNECT        = 33
   57.34 +CMSG_BLKIF_FE_INTERFACE_DISCONNECT     = 34
   57.35 +
   57.36 +CMSG_BLKIF_BE_CREATE      = 0
   57.37 +CMSG_BLKIF_BE_DESTROY     = 1
   57.38 +CMSG_BLKIF_BE_CONNECT     = 2
   57.39 +CMSG_BLKIF_BE_DISCONNECT  = 3
   57.40 +CMSG_BLKIF_BE_VBD_CREATE  = 4
   57.41 +CMSG_BLKIF_BE_VBD_DESTROY = 5
   57.42 +CMSG_BLKIF_BE_VBD_GROW    = 6
   57.43 +CMSG_BLKIF_BE_VBD_SHRINK  = 7
   57.44 +CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED    = 32
   57.45 +
   57.46 +BLKIF_DRIVER_STATUS_DOWN  = 0
   57.47 +BLKIF_DRIVER_STATUS_UP    = 1
   57.48 +
   57.49 +BLKIF_INTERFACE_STATUS_DESTROYED    = 0 #/* Interface doesn't exist.    */
   57.50 +BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
   57.51 +BLKIF_INTERFACE_STATUS_CONNECTED    = 2 #/* Exists and is connected.    */
   57.52 +
   57.53 +BLKIF_BE_STATUS_OKAY                = 0
   57.54 +BLKIF_BE_STATUS_ERROR               = 1
   57.55 +BLKIF_BE_STATUS_INTERFACE_EXISTS    = 2
   57.56 +BLKIF_BE_STATUS_INTERFACE_NOT_FOUND = 3
   57.57 +BLKIF_BE_STATUS_INTERFACE_CONNECTED = 4
   57.58 +BLKIF_BE_STATUS_VBD_EXISTS          = 5
   57.59 +BLKIF_BE_STATUS_VBD_NOT_FOUND       = 6
   57.60 +BLKIF_BE_STATUS_OUT_OF_MEMORY       = 7
   57.61 +BLKIF_BE_STATUS_EXTENT_NOT_FOUND    = 8
   57.62 +BLKIF_BE_STATUS_MAPPING_ERROR       = 9
   57.63 +
   57.64 +blkif_formats = {
   57.65 +    'blkif_be_connect_t':
   57.66 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT, "QIILI"),
   57.67 +
   57.68 +    'blkif_be_create_t':
   57.69 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE, "QII"),
   57.70 +
   57.71 +    'blkif_be_destroy_t':
   57.72 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY, "QII"),
   57.73 +
   57.74 +    'blkif_be_vbd_create_t':
   57.75 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE, "QIHII"),
   57.76 +
   57.77 +    'blkif_be_vbd_grow_t':
   57.78 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW , "QIHHHQQI"),
   57.79 +
   57.80 +    'blkif_fe_interface_status_changed_t':
   57.81 +    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED, "III"),
   57.82 +
   57.83 +    'blkif_fe_driver_status_changed_t':
   57.84 +    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED, "?"),
   57.85 +
   57.86 +    'blkif_fe_interface_connect_t':
   57.87 +    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT, "IL"),
   57.88 +}
   57.89 +
   57.90 +msg_formats.update(blkif_formats)
   57.91 +
   57.92 +#============================================================================
   57.93 +# Network interface message types.
   57.94 +#============================================================================
   57.95 +
   57.96 +CMSG_NETIF_BE = 3
   57.97 +CMSG_NETIF_FE = 4
   57.98 +
   57.99 +CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED =  0
  57.100 +CMSG_NETIF_FE_DRIVER_STATUS_CHANGED    = 32
  57.101 +CMSG_NETIF_FE_INTERFACE_CONNECT        = 33
  57.102 +CMSG_NETIF_FE_INTERFACE_DISCONNECT     = 34
  57.103 +
  57.104 +CMSG_NETIF_BE_CREATE      = 0
  57.105 +CMSG_NETIF_BE_DESTROY     = 1
  57.106 +CMSG_NETIF_BE_CONNECT     = 2
  57.107 +CMSG_NETIF_BE_DISCONNECT  = 3
  57.108 +CMSG_NETIF_BE_DRIVER_STATUS_CHANGED    = 32
  57.109 +
  57.110 +NETIF_INTERFACE_STATUS_DESTROYED    = 0 #/* Interface doesn't exist.    */
  57.111 +NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
  57.112 +NETIF_INTERFACE_STATUS_CONNECTED    = 2 #/* Exists and is connected.    */
  57.113 +
  57.114 +NETIF_DRIVER_STATUS_DOWN   = 0
  57.115 +NETIF_DRIVER_STATUS_UP     = 1
  57.116 +
  57.117 +netif_formats = {
  57.118 +    'netif_be_connect_t':
  57.119 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT, "QIILLI"),
  57.120 +
  57.121 +    'netif_be_create_t':
  57.122 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE, "QIBBBBBBBBI"),
  57.123 +
  57.124 +    'netif_be_destroy_t':
  57.125 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY, "QII"),
  57.126 +
  57.127 +    'netif_be_disconnect_t':
  57.128 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT, "QII"),
  57.129 +
  57.130 +    'netif_be_driver_status_changed_t':
  57.131 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED, "QII"),
  57.132 +
  57.133 +    'netif_fe_driver_status_changed_t':
  57.134 +    (CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED, "II"),
  57.135 +
  57.136 +    'netif_fe_interface_connect_t':
  57.137 +    (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT, "ILL"),
  57.138 +
  57.139 +    'netif_fe_interface_status_changed_t':
  57.140 +    (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, "IIIBBBBBBBB"),
  57.141 +    }
  57.142 +
  57.143 +msg_formats.update(netif_formats)
  57.144 +
  57.145 +#============================================================================
  57.146 +
  57.147 +class Msg:
  57.148 +    pass
  57.149 +
  57.150 +def packMsg(ty, params):
  57.151 +    print '>packMsg', ty, params
  57.152 +    (major, minor, packing) = msg_formats[ty]
  57.153 +    args = {}
  57.154 +    for (k, v) in params.items():
  57.155 +        if k == 'mac':
  57.156 +            for i in range(0, 6):
  57.157 +                args['mac[%d]' % i] = v[i]
  57.158 +        else:
  57.159 +            args[k] = v
  57.160 +    for (k, v) in args.items():
  57.161 +        print 'packMsg>', k, v, type(v)
  57.162 +    msgid = 0
  57.163 +    msg = xend.utils.message(major, minor, msgid, args)
  57.164 +    return msg
  57.165 +
  57.166 +def unpackMsg(ty, msg):
  57.167 +    args = msg.get_payload()
  57.168 +    mac = [0, 0, 0, 0, 0, 0]
  57.169 +    macs = []
  57.170 +    for (k, v) in args.items():
  57.171 +        if k.startswith('mac['):
  57.172 +            macs += k
  57.173 +            i = int(k[4:5])
  57.174 +            mac[i] = v
  57.175 +        else:
  57.176 +            pass
  57.177 +    if macs:
  57.178 +        args['mac'] = mac
  57.179 +        for k in macs:
  57.180 +            del args[k]
  57.181 +    print '<unpackMsg', ty, args
  57.182 +    return args
  57.183 +
  57.184 +def msgTypeName(ty, subty):
  57.185 +    for (name, info) in msg_formats.items():
  57.186 +        if info[0] == ty and info[1] == subty:
  57.187 +            return name
  57.188 +    return None
  57.189 +
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/tools/xenmgr/lib/server/netif.py	Fri Jun 11 22:04:24 2004 +0000
    58.3 @@ -0,0 +1,205 @@
    58.4 +import random
    58.5 +
    58.6 +import channel
    58.7 +import controller
    58.8 +from messages import *
    58.9 +
   58.10 +class NetifControllerFactory(controller.ControllerFactory):
   58.11 +    """Factory for creating network interface controllers.
   58.12 +    Also handles the 'back-end' channel to dom0.
   58.13 +    """
   58.14 +    # todo: add support for setting dom controlling blkifs (don't assume 0).
   58.15 +    # todo: add support for 'recovery'.
   58.16 +
   58.17 +    def __init__(self):
   58.18 +        controller.ControllerFactory.__init__(self)
   58.19 +
   58.20 +        self.majorTypes = [ CMSG_NETIF_BE ]
   58.21 +
   58.22 +        self.subTypes = {
   58.23 +            CMSG_NETIF_BE_CREATE : self.recv_be_create,
   58.24 +            CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
   58.25 +            CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
   58.26 +            }
   58.27 +        self.attached = 1
   58.28 +        self.registerChannel()
   58.29 +
   58.30 +    def createInstance(self, dom):
   58.31 +        #print 'netif>createInstance> dom=', dom
   58.32 +        netif = self.getInstanceByDom(dom)
   58.33 +        if netif is None:
   58.34 +            netif = NetifController(self, dom)
   58.35 +            self.addInstance(netif)
   58.36 +        return netif
   58.37 +        
   58.38 +    def setControlDomain(self, dom):
   58.39 +        self.deregisterChannel()
   58.40 +        self.attached = 0
   58.41 +        self.dom = dom
   58.42 +        self.registerChannel()
   58.43 +        #
   58.44 +        #if xend.netif.be_port.remote_dom != 0:
   58.45 +        #    xend.netif.recovery = True
   58.46 +        #    xend.netif.be_port = xend.main.port_from_dom(dom)
   58.47 +        #
   58.48 +        pass
   58.49 +
   58.50 +    def recv_be_create(self, msg, req):
   58.51 +        self.callDeferred(0)
   58.52 +    
   58.53 +    def recv_be_connect(self, msg, req):
   58.54 +        val = unpackMsg('netif_be_connect_t', msg)
   58.55 +        dom = val['domid']
   58.56 +        vif = val['netif_handle']
   58.57 +        netif = self.getInstanceByDom(dom)
   58.58 +        if netif:
   58.59 +            netif.send_interface_connected(vif)
   58.60 +        else:
   58.61 +            print "recv_be_connect> unknown vif=", vif
   58.62 +            pass
   58.63 +
   58.64 +    def recv_be_driver_status_changed(self, msg, req):
   58.65 +        val = unpackMsg('netif_be_driver_status_changed_t', msg)
   58.66 +        status = val['status']
   58.67 +        if status == NETIF_DRIVER_STATUS_UP and not self.attached:
   58.68 +            for netif in self.getInstances():
   58.69 +                netif.reattach_devices()
   58.70 +            self.attached = 1
   58.71 +
   58.72 +##         pl = msg.get_payload()
   58.73 +##         status = pl['status']
   58.74 +##         if status == NETIF_DRIVER_STATUS_UP:
   58.75 +##             if xend.netif.recovery:
   58.76 +##                 print "New netif backend now UP, notifying guests:"
   58.77 +##                 for netif_key in interface.list.keys():
   58.78 +##                     netif = interface.list[netif_key]
   58.79 +##                     netif.create()
   58.80 +##                     print "  Notifying %d" % netif.dom
   58.81 +##                     msg = xend.utils.message(
   58.82 +##                         CMSG_NETIF_FE,
   58.83 +##                         CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
   58.84 +##                         { 'handle' : 0, 'status' : 1 })
   58.85 +##                     netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
   58.86 +##                 print "Done notifying guests"
   58.87 +##                 recovery = False
   58.88 +                
   58.89 +class NetDev:
   58.90 +    """Info record for a network device.
   58.91 +    """
   58.92 +
   58.93 +    def __init__(self, vif, mac):
   58.94 +        self.vif = vif
   58.95 +        self.mac = mac
   58.96 +        self.evtchn = None
   58.97 +    
   58.98 +class NetifController(controller.Controller):
   58.99 +    """Network interface controller. Handles all network devices for a domain.
  58.100 +    """
  58.101 +    
  58.102 +    def __init__(self, factory, dom):
  58.103 +        #print 'NetifController> dom=', dom
  58.104 +        controller.Controller.__init__(self, factory, dom)
  58.105 +        self.devices = {}
  58.106 +        
  58.107 +        self.majorTypes = [ CMSG_NETIF_FE ]
  58.108 +
  58.109 +        self.subTypes = {
  58.110 +            CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
  58.111 +                self.recv_fe_driver_status_changed,
  58.112 +            CMSG_NETIF_FE_INTERFACE_CONNECT    :
  58.113 +                self.recv_fe_interface_connect,
  58.114 +            }
  58.115 +        self.registerChannel()
  58.116 +        #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
  58.117 +
  58.118 +
  58.119 +    def randomMAC(self):
  58.120 +        # VIFs get a random MAC address with a "special" vendor id.
  58.121 +        # 
  58.122 +        # NB. The vendor is currently an "obsolete" one that used to belong
  58.123 +        # to DEC (AA-00-00). Using it is probably a bit rude :-)
  58.124 +        # 
  58.125 +        # NB2. The first bit of the first random octet is set to zero for
  58.126 +        # all dynamic MAC addresses. This may allow us to manually specify
  58.127 +        # MAC addresses for some VIFs with no fear of clashes.
  58.128 +        mac = [ 0xaa, 0x00, 0x00,
  58.129 +                random.randint(0x00, 0x7f),
  58.130 +                random.randint(0x00, 0xff),
  58.131 +                random.randint(0x00, 0xff) ]
  58.132 +        return mac
  58.133 +
  58.134 +    def attach_device(self, vif, vmac):
  58.135 +        if vmac is None:
  58.136 +            mac = self.randomMAC()
  58.137 +        else:
  58.138 +            mac = [ int(x, 16) for x in vmac.split(':') ]
  58.139 +        if len(mac) != 6: raise ValueError("invalid mac")
  58.140 +        #print "attach_device>", "vif=", vif, "mac=", mac
  58.141 +        self.devices[vif] = NetDev(vif, mac)
  58.142 +        d = self.factory.addDeferred()
  58.143 +        self.send_be_create(vif)
  58.144 +        return d
  58.145 +
  58.146 +    def reattach_devices(self):
  58.147 +        d = self.factory.addDeferred()
  58.148 +        self.send_be_create(vif)
  58.149 +        self.attach_fe_devices(0)
  58.150 +
  58.151 +    def attach_fe_devices(self):
  58.152 +        for dev in self.devices.values():
  58.153 +            msg = packMsg('netif_fe_interface_status_changed_t',
  58.154 +                          { 'handle' : dev.vif,
  58.155 +                            'status' : NETIF_INTERFACE_STATUS_DISCONNECTED,
  58.156 +                            'evtchn' : 0,
  58.157 +                            'mac'    : dev.mac })
  58.158 +            self.writeRequest(msg)
  58.159 +    
  58.160 +    def recv_fe_driver_status_changed(self, msg, req):
  58.161 +        if not req: return
  58.162 +        msg = packMsg('netif_fe_driver_status_changed_t',
  58.163 +                      { 'status'        : NETIF_DRIVER_STATUS_UP,
  58.164 +                        'nr_interfaces' : len(self.devices) })
  58.165 +        self.writeRequest(msg)
  58.166 +        self.attach_fe_devices()
  58.167 +
  58.168 +    def recv_fe_interface_connect(self, msg, req):
  58.169 +        val = unpackMsg('netif_fe_interface_connect_t', msg)
  58.170 +        dev = self.devices[val['handle']]
  58.171 +        dev.evtchn = channel.eventChannel(0, self.dom)
  58.172 +        msg = packMsg('netif_be_connect_t',
  58.173 +                      { 'domid'          : self.dom,
  58.174 +                        'netif_handle'   : dev.vif,
  58.175 +                        'evtchn'         : dev.evtchn['port1'],
  58.176 +                        'tx_shmem_frame' : val['tx_shmem_frame'],
  58.177 +                        'rx_shmem_frame' : val['rx_shmem_frame'] })
  58.178 +        self.factory.writeRequest(msg)
  58.179 +
  58.180 +    #def recv_fe_interface_status_changed(self):
  58.181 +    #    print 'recv_fe_interface_status_changed>'
  58.182 +    #    pass
  58.183 +    
  58.184 +    def send_interface_connected(self, vif):
  58.185 +        dev = self.devices[vif]
  58.186 +        msg = packMsg('netif_fe_interface_status_changed_t',
  58.187 +                      { 'handle' : dev.vif,
  58.188 +                        'status' : NETIF_INTERFACE_STATUS_CONNECTED,
  58.189 +                        'evtchn' : dev.evtchn['port2'],
  58.190 +                        'mac'    : dev.mac })
  58.191 +        self.writeRequest(msg)
  58.192 +
  58.193 +    def send_be_create(self, vif):
  58.194 +        dev = self.devices[vif]
  58.195 +        msg = packMsg('netif_be_create_t',
  58.196 +                      { 'domid'        : self.dom,
  58.197 +                        'netif_handle' : dev.vif,
  58.198 +                        'mac'          : dev.mac })
  58.199 +        self.factory.writeRequest(msg)
  58.200 +
  58.201 +    def send_be_destroy(self, vif):
  58.202 +        print 'send_be_destroy>', 'dom=', self.dom, 'vif=', vif
  58.203 +        dev = self.devices[vif]
  58.204 +        del self.devices[vif]
  58.205 +        msg = packMsg('netif_be_destroy_t',
  58.206 +                      { 'domid'        : self.dom,
  58.207 +                        'netif_handle' : vif })
  58.208 +        self.factory.writeRequest(msg)
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/tools/xenmgr/lib/server/params.py	Fri Jun 11 22:04:24 2004 +0000
    59.3 @@ -0,0 +1,10 @@
    59.4 +# The following parameters could be placed in a configuration file.
    59.5 +PID_FILE  = '/var/run/xend.pid'
    59.6 +LOG_FILE  = '/var/log/xend.log'
    59.7 +USER = 'root'
    59.8 +CONTROL_DIR  = '/var/run/xend'
    59.9 +MGMT_SOCK    = 'xenmgrsock' # relative to CONTROL_DIR
   59.10 +EVENT_PORT = 8001
   59.11 +
   59.12 +CONSOLE_PORT_BASE = 9600
   59.13 +
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/tools/xenmgr/lib/sxp.py	Fri Jun 11 22:04:24 2004 +0000
    60.3 @@ -0,0 +1,557 @@
    60.4 +#!/usr/bin/python2
    60.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    60.6 +"""
    60.7 +Input-driven parsing for s-expression (sxp) format.
    60.8 +Create a parser: pin = Parser();
    60.9 +Then call pin.input(buf) with your input.
   60.10 +Call pin.input_eof() when done.
   60.11 +Use pin.read() to see if a value has been parsed, pin.get_val()
   60.12 +to get a parsed value. You can call ready and get_val at any time -
   60.13 +you don't have to wait until after calling input_eof.
   60.14 +
   60.15 +"""
   60.16 +from __future__ import generators
   60.17 +
   60.18 +import sys
   60.19 +import types
   60.20 +import errno
   60.21 +import string
   60.22 +
   60.23 +__all__ = [
   60.24 +    "mime_type", 
   60.25 +    "ParseError", 
   60.26 +    "Parser", 
   60.27 +    "atomp", 
   60.28 +    "show", 
   60.29 +    "show_xml", 
   60.30 +    "elementp", 
   60.31 +    "name", 
   60.32 +    "attributes", 
   60.33 +    "attribute", 
   60.34 +    "children", 
   60.35 +    "child", 
   60.36 +    "child_at", 
   60.37 +    "child0", 
   60.38 +    "child1", 
   60.39 +    "child2", 
   60.40 +    "child3", 
   60.41 +    "child4", 
   60.42 +    "child_value", 
   60.43 +    "has_id", 
   60.44 +    "with_id", 
   60.45 +    "child_with_id", 
   60.46 +    "elements", 
   60.47 +    "parse", 
   60.48 +    ]
   60.49 +
   60.50 +mime_type = "application/sxp"
   60.51 +
   60.52 +escapes = {
   60.53 +    'a': '\a',
   60.54 +    'b': '\b',
   60.55 +    't': '\t',
   60.56 +    'n': '\n',
   60.57 +    'v': '\v',
   60.58 +    'f': '\f',
   60.59 +    'r': '\r',
   60.60 +    '\\': '\\',
   60.61 +    '\'': '\'',
   60.62 +    '\"': '\"'}
   60.63 +
   60.64 +k_list_open  = "("
   60.65 +k_list_close = ")"
   60.66 +k_attr_open  = "@"
   60.67 +k_eval       = "!"
   60.68 +
   60.69 +escapes_rev = {}
   60.70 +for k in escapes:
   60.71 +    escapes_rev[escapes[k]] = k
   60.72 +
   60.73 +class ParseError(StandardError):
   60.74 +
   60.75 +    def __init__(self, parser, value):
   60.76 +        self.parser = parser
   60.77 +        self.value = value
   60.78 +
   60.79 +    def __str__(self):
   60.80 +        return self.value
   60.81 +
   60.82 +class ParserState:
   60.83 +
   60.84 +    def __init__(self, fn, parent=None):
   60.85 +        self.parent = parent
   60.86 +        self.buf = ''
   60.87 +        self.val = []
   60.88 +        self.delim = None
   60.89 +        self.fn = fn
   60.90 +
   60.91 +    def push(self, fn):
   60.92 +        return ParserState(fn, parent=self)
   60.93 +    
   60.94 +class Parser:
   60.95 +
   60.96 +    def __init__(self):
   60.97 +        self.error = sys.stderr
   60.98 +        self.reset()
   60.99 +
  60.100 +    def reset(self):
  60.101 +        self.val = []
  60.102 +        self.eof = 0
  60.103 +        self.err = 0
  60.104 +        self.line_no = 0
  60.105 +        self.char_no = 0
  60.106 +        self.state = None
  60.107 +
  60.108 +    def push_state(self, fn):
  60.109 +        self.state = self.state.push(fn)
  60.110 +
  60.111 +    def pop_state(self):
  60.112 +        val = self.state
  60.113 +        self.state = self.state.parent
  60.114 +        if self.state and self.state.fn == self.state_start:
  60.115 +            # Return to start state - produce the value.
  60.116 +            self.val += self.state.val
  60.117 +            self.state.val = []
  60.118 +        return val
  60.119 +
  60.120 +    def in_class(self, c, s):
  60.121 +        return s.find(c) >= 0
  60.122 +        
  60.123 +    def in_space_class(self, c):
  60.124 +        return self.in_class(c, ' \t\n\v\f\r')
  60.125 +
  60.126 +    def is_separator(self, c):
  60.127 +        return self.in_class(c, '{}()<>[]!;')
  60.128 +
  60.129 +    def in_comment_class(self, c):
  60.130 +        return self.in_class(c, '#')
  60.131 +
  60.132 +    def in_string_quote_class(self, c):
  60.133 +        return self.in_class(c, '"\'')
  60.134 +
  60.135 +    def in_printable_class(self, c):
  60.136 +        return self.in_class(c, string.printable)
  60.137 +
  60.138 +    def set_error_stream(self, error):
  60.139 +        self.error = error
  60.140 +
  60.141 +    def has_error(self):
  60.142 +        return self.err > 0
  60.143 +
  60.144 +    def at_eof(self):
  60.145 +        return self.eof
  60.146 +
  60.147 +    def input_eof(self):
  60.148 +        self.eof = 1
  60.149 +        self.input_char(-1)
  60.150 +
  60.151 +    def input(self, buf):
  60.152 +        if not buf or len(buf) == 0:
  60.153 +            self.input_eof()
  60.154 +        else:
  60.155 +            for c in buf:
  60.156 +                self.input_char(c)
  60.157 +
  60.158 +    def input_char(self, c):
  60.159 +        if self.at_eof():
  60.160 +            pass
  60.161 +        elif c == '\n':
  60.162 +            self.line_no += 1
  60.163 +            self.char_no = 0
  60.164 +        else:
  60.165 +           self.char_no += 1 
  60.166 +
  60.167 +        if self.state is None:
  60.168 +            self.begin_start(None)
  60.169 +        self.state.fn(c)
  60.170 +
  60.171 +    def ready(self):
  60.172 +        return len(self.val) > 0
  60.173 +
  60.174 +    def get_val(self):
  60.175 +        v = self.val[0]
  60.176 +        self.val = self.val[1:]
  60.177 +        return v
  60.178 +
  60.179 +    def get_all(self):
  60.180 +        return self.val
  60.181 +
  60.182 +    def begin_start(self, c):
  60.183 +        self.state = ParserState(self.state_start)
  60.184 +
  60.185 +    def end_start(self):
  60.186 +        self.val += self.state.val
  60.187 +        self.pop_state()
  60.188 +    
  60.189 +    def state_start(self, c):
  60.190 +        if self.at_eof():
  60.191 +            self.end_start()
  60.192 +        elif self.in_space_class(c):
  60.193 +            pass
  60.194 +        elif self.in_comment_class(c):
  60.195 +            self.begin_comment(c)
  60.196 +        elif c == k_list_open:
  60.197 +            self.begin_list(c)
  60.198 +        elif c == k_list_close:
  60.199 +            raise ParseError(self, "syntax error: "+c)
  60.200 +        elif self.in_string_quote_class(c):
  60.201 +            self.begin_string(c)
  60.202 +        elif self.in_printable_class(c):
  60.203 +            self.begin_atom(c)
  60.204 +        elif c == chr(4):
  60.205 +            # ctrl-D, EOT: end-of-text.
  60.206 +            self.input_eof()
  60.207 +        else:
  60.208 +            raise ParseError(self, "invalid character: code %d" % ord(c))
  60.209 +
  60.210 +    def begin_comment(self, c):
  60.211 +        self.push_state(self.state_comment)
  60.212 +        self.state.buf += c
  60.213 +
  60.214 +    def end_comment(self):
  60.215 +        self.pop_state()
  60.216 +    
  60.217 +    def state_comment(self, c):
  60.218 +        if c == '\n' or self.at_eof():
  60.219 +            self.end_comment()
  60.220 +        else:
  60.221 +            self.state.buf += c
  60.222 +
  60.223 +    def begin_string(self, c):
  60.224 +        self.push_state(self.state_string)
  60.225 +        self.state.delim = c
  60.226 +
  60.227 +    def end_string(self):
  60.228 +        val = self.state.buf
  60.229 +        self.state.parent.val.append(val)
  60.230 +        self.pop_state()
  60.231 +        
  60.232 +    def state_string(self, c):
  60.233 +        if self.at_eof():
  60.234 +            raise ParseError(self, "unexpected EOF")
  60.235 +        elif c == self.state.delim:
  60.236 +            self.end_string()
  60.237 +        elif c == '\\':
  60.238 +            self.push_state(self.state_escape)
  60.239 +        else:
  60.240 +            self.state.buf += c
  60.241 +
  60.242 +    def state_escape(self, c):
  60.243 +        if self.at_eof():
  60.244 +            raise ParseError(self, "unexpected EOF")
  60.245 +        d = escapes.get(c)
  60.246 +        if d:
  60.247 +            self.state.parent.buf += d
  60.248 +            self.pop_state()
  60.249 +        elif c == 'x':
  60.250 +            self.state.fn = self.state_hex
  60.251 +            self.state.val = 0
  60.252 +        else:
  60.253 +            self.state.fn = self.state_octal
  60.254 +            self.state.val = 0
  60.255 +            self.input_char(c)
  60.256 +
  60.257 +    def state_octal(self, c):
  60.258 +        def octaldigit(c):
  60.259 +            self.state.val *= 8
  60.260 +            self.state.val += ord(c) - ord('0')
  60.261 +            self.state.buf += c
  60.262 +            if self.state.val < 0 or self.state.val > 0xff:
  60.263 +                raise ParseError(self, "invalid octal escape: out of range " + self.state.buf)
  60.264 +            if len(self.state.buf) == 3:
  60.265 +               octaldone()
  60.266 +               
  60.267 +        def octaldone():
  60.268 +            d = chr(self.state.val)
  60.269 +            self.state.parent.buf += d
  60.270 +            self.pop_state()
  60.271 +            
  60.272 +        if self.at_eof():
  60.273 +            raise ParseError(self, "unexpected EOF")
  60.274 +        elif '0' <= c <= '7':
  60.275 +            octaldigit(c)
  60.276 +        elif len(self.buf):
  60.277 +            octaldone()
  60.278 +            self.input_char(c)
  60.279 +
  60.280 +    def state_hex(self, c):
  60.281 +        def hexdone():
  60.282 +            d = chr(self.state.val)
  60.283 +            self.state.parent.buf += d
  60.284 +            self.pop_state()
  60.285 +            
  60.286 +        def hexdigit(c, d):
  60.287 +            self.state.val *= 16
  60.288 +            self.state.val += ord(c) - ord(d)
  60.289 +            self.state.buf += c
  60.290 +            if self.state.val < 0 or self.state.val > 0xff:
  60.291 +                raise ParseError(self, "invalid hex escape: out of range " + self.state.buf)
  60.292 +            if len(self.state.buf) == 2:
  60.293 +                hexdone()
  60.294 +            
  60.295 +        if self.at_eof():
  60.296 +            raise ParseError(self, "unexpected EOF")
  60.297 +        elif '0' <= c <= '9':
  60.298 +            hexdigit(c, '0')
  60.299 +        elif 'A' <= c <= 'F':
  60.300 +            hexdigit(c, 'A')
  60.301 +        elif 'a' <= c <= 'f':
  60.302 +            hexdigit(c, 'a')
  60.303 +        elif len(buf):
  60.304 +            hexdone()
  60.305 +            self.input_char(c)
  60.306 +
  60.307 +    def begin_atom(self, c):
  60.308 +        self.push_state(self.state_atom)
  60.309 +        self.state.buf = c
  60.310 +
  60.311 +    def end_atom(self):
  60.312 +        val = self.state.buf
  60.313 +        self.state.parent.val.append(val)
  60.314 +        self.pop_state()
  60.315 +    
  60.316 +    def state_atom(self, c):
  60.317 +        if self.at_eof():
  60.318 +            self.end_atom()
  60.319 +        elif (self.is_separator(c) or
  60.320 +              self.in_space_class(c) or
  60.321 +              self.in_comment_class(c)):
  60.322 +            self.end_atom()
  60.323 +            self.input_char(c)
  60.324 +        else:
  60.325 +            self.state.buf += c
  60.326 +
  60.327 +    def begin_list(self, c):
  60.328 +        self.push_state(self.state_list)
  60.329 +
  60.330 +    def end_list(self):
  60.331 +        val = self.state.val
  60.332 +        self.state.parent.val.append(val)
  60.333 +        self.pop_state()
  60.334 +
  60.335 +    def state_list(self, c):
  60.336 +        if self.at_eof():
  60.337 +            raise ParseError(self, "unexpected EOF")
  60.338 +        elif c == k_list_close:
  60.339 +            self.end_list()
  60.340 +        else:
  60.341 +            self.state_start(c)
  60.342 +
  60.343 +def atomp(sxpr):
  60.344 +    if sxpr.isalnum() or sxpr == '@':
  60.345 +        return 1
  60.346 +    for c in sxpr:
  60.347 +        if c in string.whitespace: return 0
  60.348 +        if c in '"\'\\(){}[]<>$#&%^': return 0
  60.349 +        if c in string.ascii_letters: continue
  60.350 +        if c in string.digits: continue
  60.351 +        if c in '.-_:/~': continue
  60.352 +        return 0
  60.353 +    return 1
  60.354 +    
  60.355 +def show(sxpr, out=sys.stdout):
  60.356 +    if isinstance(sxpr, types.ListType):
  60.357 +        out.write(k_list_open)
  60.358 +        i = 0
  60.359 +        for x in sxpr:
  60.360 +            if i: out.write(' ')
  60.361 +            show(x, out)
  60.362 +            i += 1
  60.363 +        out.write(k_list_close)
  60.364 +    elif isinstance(sxpr, types.StringType) and atomp(sxpr):
  60.365 +        out.write(sxpr)
  60.366 +    else:
  60.367 +        #out.write("'" + str(sxpr) + "'")
  60.368 +        out.write(repr(str(sxpr)))
  60.369 +
  60.370 +def show_xml(sxpr, out=sys.stdout):
  60.371 +    if isinstance(sxpr, types.ListType):
  60.372 +        element = name(sxpr)
  60.373 +        out.write('<%s' % element)
  60.374 +        for attr in attributes(sxpr):
  60.375 +            out.write(' %s=%s' % (attr[0], attr[1]))
  60.376 +        out.write('>')
  60.377 +        i = 0
  60.378 +        for x in children(sxpr):
  60.379 +            if i: out.write(' ')
  60.380 +            show_xml(x, out)
  60.381 +            i += 1
  60.382 +        out.write('</%s>' % element)
  60.383 +    elif isinstance(sxpr, types.StringType) and atomp(sxpr):
  60.384 +        out.write(sxpr)
  60.385 +    else:
  60.386 +        out.write(str(sxpr))
  60.387 +
  60.388 +def elementp(sxpr, elt=None):
  60.389 +    return (isinstance(sxpr, types.ListType)
  60.390 +            and len(sxpr)
  60.391 +            and (None == elt or sxpr[0] == elt))
  60.392 +
  60.393 +def name(sxpr):
  60.394 +    val = None
  60.395 +    if isinstance(sxpr, types.StringType):
  60.396 +        val = sxpr
  60.397 +    elif isinstance(sxpr, types.ListType) and len(sxpr):
  60.398 +        val = sxpr[0]
  60.399 +    return val
  60.400 +
  60.401 +def attributes(sxpr):
  60.402 +    val = []
  60.403 +    if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
  60.404 +        attr = sxpr[1]
  60.405 +        if elementp(attr, k_attr_open):
  60.406 +            val = attr[1:]
  60.407 +    return val
  60.408 +
  60.409 +def attribute(sxpr, key, val=None):
  60.410 +    for x in attributes(sxpr):
  60.411 +        if x[0] == key:
  60.412 +            val = x[1]
  60.413 +            break
  60.414 +    return val
  60.415 +
  60.416 +def children(sxpr, elt=None):
  60.417 +    val = []
  60.418 +    if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
  60.419 +        i = 1
  60.420 +        x = sxpr[i]
  60.421 +        if elementp(x, k_attr_open):
  60.422 +            i += 1
  60.423 +        val = sxpr[i : ]
  60.424 +    if elt:
  60.425 +        def iselt(x):
  60.426 +            return elementp(x, elt)
  60.427 +        val = filter(iselt, val)
  60.428 +    return val
  60.429 +
  60.430 +def child(sxpr, elt, val=None):
  60.431 +    for x in children(sxpr):
  60.432 +        if elementp(x, elt):
  60.433 +            val = x
  60.434 +            break
  60.435 +    return val
  60.436 +
  60.437 +def child_at(sxpr, index, val=None):
  60.438 +    kids = children(sxpr)
  60.439 +    if len(kids) > index:
  60.440 +        val = kids[index]
  60.441 +    return val
  60.442 +
  60.443 +def child0(sxpr, val=None):
  60.444 +    return child_at(sxpr, 0, val)
  60.445 +
  60.446 +def child1(sxpr, val=None):
  60.447 +    return child_at(sxpr, 1, val)
  60.448 +
  60.449 +def child2(sxpr, val=None):
  60.450 +    return child_at(sxpr, 2, val)
  60.451 +
  60.452 +def child3(sxpr, val=None):
  60.453 +    return child_at(sxpr, 3, val)
  60.454 +
  60.455 +def child4(sxpr, val=None):
  60.456 +    return child_at(sxpr, 4, val)
  60.457 +
  60.458 +def child_value(sxpr, elt, val=None):
  60.459 +    kid = child(sxpr, elt)
  60.460 +    if kid:
  60.461 +        val = child_at(kid, 0, val)
  60.462 +    return val
  60.463 +
  60.464 +def has_id(sxpr, id):
  60.465 +    """Test if an s-expression has a given id.
  60.466 +    """
  60.467 +    return attribute(sxpr, 'id') == id
  60.468 +
  60.469 +def with_id(sxpr, id, val=None):
  60.470 +    """Find the first s-expression with a given id, at any depth.
  60.471 +
  60.472 +    sxpr   s-exp or list
  60.473 +    id     id
  60.474 +    val    value if not found (default None)
  60.475 +
  60.476 +    return s-exp or val
  60.477 +    """
  60.478 +    if isinstance(sxpr, types.ListType):
  60.479 +        for n in sxpr:
  60.480 +            if has_id(n, id):
  60.481 +                val = n
  60.482 +                break
  60.483 +            v = with_id(n, id)
  60.484 +            if v is None: continue
  60.485 +            val = v
  60.486 +            break
  60.487 +    return val
  60.488 +
  60.489 +def child_with_id(sxpr, id, val=None):
  60.490 +    """Find the first child with a given id.
  60.491 +
  60.492 +    sxpr   s-exp or list
  60.493 +    id     id
  60.494 +    val    value if not found (default None)
  60.495 +
  60.496 +    return s-exp or val
  60.497 +    """
  60.498 +    if isinstance(sxpr, types.ListType):
  60.499 +        for n in sxpr:
  60.500 +            if has_id(n, id):
  60.501 +                val = n
  60.502 +                break
  60.503 +    return val
  60.504 +
  60.505 +def elements(sxpr, ctxt=None):
  60.506 +    """Generate elements (at any depth).
  60.507 +    Visit elements in pre-order.
  60.508 +    Values generated are (node, context)
  60.509 +    The context is None if there is no parent, otherwise
  60.510 +    (index, parent, context) where index is the node's index w.r.t its parent,
  60.511 +    and context is the parent's context.
  60.512 +
  60.513 +    sxpr   s-exp
  60.514 +
  60.515 +    returns generator
  60.516 +    """
  60.517 +    yield (sxpr, ctxt)
  60.518 +    i = 0
  60.519 +    for n in children(sxpr):
  60.520 +        if isinstance(n, types.ListType):
  60.521 +            # Calling elements() recursively does not generate recursively,
  60.522 +            # it just returns a generator object. So we must iterate over it.
  60.523 +            for v in elements(n, (i, sxpr, ctxt)):
  60.524 +                yield v
  60.525 +        i += 1
  60.526 +
  60.527 +def parse(io):
  60.528 +    """Completely parse all input from 'io'.
  60.529 +
  60.530 +    io	input file object
  60.531 +    returns list of values, None if incomplete
  60.532 +    raises ParseError on parse error
  60.533 +    """
  60.534 +    pin = Parser()
  60.535 +    while 1:
  60.536 +        buf = io.readline()
  60.537 +        pin.input(buf)
  60.538 +        if len(buf) == 0:
  60.539 +            break
  60.540 +    if pin.ready():
  60.541 +        val = pin.get_all()
  60.542 +    else:
  60.543 +        val = None
  60.544 +    return val
  60.545 +   
  60.546 +
  60.547 +if __name__ == '__main__':
  60.548 +    print ">main"
  60.549 +    pin = Parser()
  60.550 +    while 1:
  60.551 +        buf = sys.stdin.read(1024)
  60.552 +        #buf = sys.stdin.readline()
  60.553 +        pin.input(buf)
  60.554 +        while pin.ready():
  60.555 +            val = pin.get_val()
  60.556 +            print
  60.557 +            print '****** val=', val
  60.558 +        if len(buf) == 0:
  60.559 +            break
  60.560 +
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/tools/xenmgr/netfix	Fri Jun 11 22:04:24 2004 +0000
    61.3 @@ -0,0 +1,150 @@
    61.4 +#!/usr/bin/python
    61.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    61.6 +#============================================================================
    61.7 +# Move the IP address from eth0 onto the Xen bridge (nbe-br).
    61.8 +# Works best if the bridge control utils (brctl) have been installed.
    61.9 +#============================================================================
   61.10 +import os
   61.11 +import os.path
   61.12 +import re
   61.13 +import sys
   61.14 +
   61.15 +from getopt import getopt
   61.16 +
   61.17 +CMD_IFCONFIG = '/sbin/ifconfig'
   61.18 +CMD_ROUTE    = '/sbin/route'
   61.19 +CMD_BRCTL    = '/usr/local/sbin/brctl'
   61.20 +
   61.21 +def routes():
   61.22 +    """Return a list of the routes.
   61.23 +    """
   61.24 +    fin = os.popen(CMD_ROUTE + ' -n', 'r')
   61.25 +    routes = []
   61.26 +    for x in fin:
   61.27 +        if x.startswith('Kernel'): continue
   61.28 +        if x.startswith('Destination'): continue
   61.29 +        x = x.strip()
   61.30 +        y = x.split()
   61.31 +        z = { 'destination': y[0],
   61.32 +              'gateway'    : y[1],
   61.33 +              'mask'       : y[2],
   61.34 +              'flags'      : y[3],
   61.35 +              'metric'     : y[4],
   61.36 +              'ref'        : y[5],
   61.37 +              'use'        : y[6],
   61.38 +              'interface'  : y[7] }
   61.39 +        routes.append(z)
   61.40 +    return routes
   61.41 +
   61.42 +def cmd(p, s):
   61.43 +    """Print and execute command 'p' with args 's'.
   61.44 +    """
   61.45 +    global opts
   61.46 +    c = p + ' ' + s
   61.47 +    if opts.verbose: print c
   61.48 +    if not opts.dryrun:
   61.49 +        os.system(c)
   61.50 +
   61.51 +def ifconfig(interface):
   61.52 +    """Return the ip config for an interface,
   61.53 +    """
   61.54 +    fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r')
   61.55 +    inetre = re.compile('\s*inet\s*addr:(?P<address>\S*)\s*Bcast:(?P<broadcast>\S*)\s*Mask:(?P<mask>\S*)')
   61.56 +    info = None
   61.57 +    for x in fin:
   61.58 +        m = inetre.match(x)
   61.59 +        if not m: continue
   61.60 +        info = m.groupdict()
   61.61 +        info['interface'] = interface
   61.62 +        break
   61.63 +    return info
   61.64 +
   61.65 +def reconfigure(interface, bridge):
   61.66 +    """Reconfigure an interface to be attached to a bridge, and give the bridge
   61.67 +    the IP address etc. from interface. Move the default route to the interface
   61.68 +    to the bridge.
   61.69 +    """
   61.70 +    intf_info = ifconfig(interface)
   61.71 +    if not intf_info:
   61.72 +        print 'Interface not found:', interface
   61.73 +        return
   61.74 +    #bridge_info = ifconfig(bridge)
   61.75 +    #if not bridge_info:
   61.76 +    #    print 'Bridge not found:', bridge
   61.77 +    #    return
   61.78 +    route_info = routes()
   61.79 +    intf_info['bridge'] = bridge
   61.80 +    intf_info['gateway'] = None
   61.81 +    for r in route_info:
   61.82 +        if (r['destination'] == '0.0.0.0' and
   61.83 +            'G' in r['flags'] and
   61.84 +            r['interface'] == interface):
   61.85 +            intf_info['gateway'] = r['gateway']
   61.86 +    if not intf_info['gateway']:
   61.87 +        print 'Gateway not found: ', interface
   61.88 +        return
   61.89 +    cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info)
   61.90 +    cmd(CMD_IFCONFIG, '%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up' % intf_info)
   61.91 +    cmd(CMD_ROUTE, 'add default gateway %(gateway)s dev %(bridge)s' % intf_info)
   61.92 +    if os.path.exists(CMD_BRCTL):
   61.93 +        cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info)
   61.94 +
   61.95 +defaults = {
   61.96 +    'interface': 'eth0',
   61.97 +    'bridge'   : 'nbe-br',
   61.98 +    'verbose'  : 1,
   61.99 +    'dryrun'   : 0,
  61.100 +    }
  61.101 +
  61.102 +short_options = 'hvqni:b:'
  61.103 +long_options  = ['help', 'verbose', 'quiet', 'interface=', 'bridge=']
  61.104 +
  61.105 +def usage():
  61.106 +    print """Usage:
  61.107 +    %s [options]
  61.108 +
  61.109 +    Reconfigure routing so that <bridge> has the IP address from
  61.110 +    <interface>. This lets IP carry on working when <interface>
  61.111 +    is attached to <bridge> for virtual networking.
  61.112 +    If brctl is available, <interface> is added to <bridge>,
  61.113 +    so this can be run before any domains have been created.
  61.114 +    """ % sys.argv[0]
  61.115 +    print """
  61.116 +    -i, --interface <interface>    interface, default %(interface)s.
  61.117 +    -b, --bridge <bridge>          bridge, default %(bridge)s.
  61.118 +    -v, --verbose                  Print commands.
  61.119 +    -q, --quiet                    Don't print commands.
  61.120 +    -n, --dry-run                  Don't execute commands.
  61.121 +    -h, --help                     Print this help.
  61.122 +    """ % defaults
  61.123 +    sys.exit(1)
  61.124 +
  61.125 +class Opts:
  61.126 +
  61.127 +    def __init__(self, defaults):
  61.128 +        for (k, v) in defaults.items():
  61.129 +            setattr(self, k, v)
  61.130 +        pass
  61.131 +
  61.132 +def main():
  61.133 +    global opts
  61.134 +    opts = Opts(defaults)
  61.135 +    (options, args) = getopt(sys.argv[1:], short_options, long_options)
  61.136 +    if args: usage()
  61.137 +    for k, v in options:
  61.138 +        if k in ['-h', '--help']:
  61.139 +            usage()
  61.140 +        elif k in ['-i', '--interface']:
  61.141 +            opts.interface = v
  61.142 +        elif k in ['-b', '--bridge']:
  61.143 +            opts.bridge = v
  61.144 +        elif k in ['-q', '--quiet']:
  61.145 +            opts.verbose = 0
  61.146 +        elif k in ['-v', '--verbose']:
  61.147 +            opts.verbose = 1
  61.148 +        elif k in ['-n', '--dry-run']:
  61.149 +            opts.dryrun = 1
  61.150 +    reconfigure(opts.interface, opts.bridge)
  61.151 +
  61.152 +if __name__ == '__main__':
  61.153 +    main()
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/tools/xenmgr/setup.py	Fri Jun 11 22:04:24 2004 +0000
    62.3 @@ -0,0 +1,14 @@
    62.4 +
    62.5 +from distutils.core import setup, Extension
    62.6 +
    62.7 +PACKAGE = 'xenmgr'
    62.8 +VERSION = '1.0'
    62.9 +
   62.10 +setup(name            = PACKAGE,
   62.11 +      version         = VERSION,
   62.12 +      description     = 'Xen Management API',
   62.13 +      author          = 'Mike Wray',
   62.14 +      author_email    = 'mike.wray@hp.com',
   62.15 +      packages        = [ PACKAGE, PACKAGE + '.server' ],
   62.16 +      package_dir     = { PACKAGE: 'lib' },
   62.17 +      )
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/tools/xenmgr/xend	Fri Jun 11 22:04:24 2004 +0000
    63.3 @@ -0,0 +1,40 @@
    63.4 +#!/usr/bin/python
    63.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    63.6 +
    63.7 +"""Xen management daemon. Lives in /usr/sbin.
    63.8 +   Provides console server and HTTP management api.
    63.9 +
   63.10 +   Run:
   63.11 +
   63.12 +   xend start
   63.13 +
   63.14 +   The daemon is stopped with:
   63.15 +
   63.16 +   xend stop
   63.17 +
   63.18 +   Unfortunately restarting it upsets the channel to dom0 and
   63.19 +   domain management stops working - needs a reboot to fix.
   63.20 +"""
   63.21 +import os
   63.22 +import sys
   63.23 +from xenmgr.server import SrvConsoleServer
   63.24 +
   63.25 +def main():
   63.26 +    daemon = SrvConsoleServer.instance()
   63.27 +    if not sys.argv[1:]:
   63.28 +        print 'usage: %s {start|stop|restart}' % sys.argv[0]
   63.29 +    elif os.fork():
   63.30 +        pid, status = os.wait()
   63.31 +        return status >> 8
   63.32 +    elif sys.argv[1] == 'start':
   63.33 +        return daemon.start()
   63.34 +    elif sys.argv[1] == 'stop':
   63.35 +        return daemon.stop()
   63.36 +    elif sys.argv[1] == 'restart':
   63.37 +        return daemon.stop() or daemon.start()
   63.38 +    else:
   63.39 +        print 'not an option:', sys.argv[1]
   63.40 +    return 1
   63.41 +
   63.42 +if __name__ == '__main__':
   63.43 +    sys.exit(main())
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/tools/xenmgr/xenmgrd	Fri Jun 11 22:04:24 2004 +0000
    64.3 @@ -0,0 +1,10 @@
    64.4 +#!/usr/bin/python
    64.5 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    64.6 +
    64.7 +"""Xen management daemon. Lives in /usr/sbin.
    64.8 +   Run after running xend to provide http access to the management API.
    64.9 +
   64.10 +   NO LONGER NEEDED.
   64.11 +"""
   64.12 +from xenmgr.server import SrvServer
   64.13 +SrvServer.main()
    65.1 --- a/xen/Makefile	Fri Jun 11 21:59:47 2004 +0000
    65.2 +++ b/xen/Makefile	Fri Jun 11 22:04:24 2004 +0000
    65.3 @@ -41,10 +41,9 @@ clean: delete-links
    65.4  
    65.5  make-links: delete-links
    65.6  	ln -sf asm-$(TARGET_ARCH) include/asm
    65.7 -	ln -sf arch-$(TARGET_ARCH) include/hypervisor-ifs/arch
    65.8  
    65.9  delete-links:
   65.10 -	rm -f include/asm include/hypervisor-ifs/arch
   65.11 +	rm -f include/asm
   65.12  
   65.13  # Blow away kernel.o because build info is stored statically within it.
   65.14  delete-unfresh-files:
    66.1 --- a/xen/arch/x86/Rules.mk	Fri Jun 11 21:59:47 2004 +0000
    66.2 +++ b/xen/arch/x86/Rules.mk	Fri Jun 11 22:04:24 2004 +0000
    66.3 @@ -13,7 +13,7 @@ LOAD_BASE    := 0x00100000
    66.4  CFLAGS  := -nostdinc -fno-builtin -fno-common -fno-strict-aliasing -O3
    66.5  CFLAGS  += -iwithprefix include -Wall -Werror -DMONITOR_BASE=$(MONITOR_BASE)
    66.6