[virt-tools-list] [PATCH] Add oVirt nodeadmin code to repo

Darryl L. Pierce dpierce at redhat.com
Mon Aug 16 15:08:17 UTC 2010


diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/__init__.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/__init__.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,19 @@
+# __init__.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from nodeadmin import NodeAdmin
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/adddomain.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/adddomain.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,512 @@
+#!/usr/bin/env python
+#
+# adddomain.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import os
+from createmeter  import CreateMeter
+from domainconfig import DomainConfig
+from configscreen import ConfigScreen
+import utils
+
+from virtinst import *
+
+VM_DETAILS_PAGE      =  1
+LOCAL_INSTALL_PAGE   =  2
+SELECT_CDROM_PAGE    =  3
+SELECT_ISO_PAGE      =  4
+NETWORK_INSTALL_PAGE =  5
+OS_TYPE_PAGE         =  6
+OS_VARIANT_PAGE      =  7
+RAM_CPU_PAGE         =  8
+ENABLE_STORAGE_PAGE  =  9
+LOCAL_STORAGE_PAGE   = 10
+SELECT_POOL_PAGE     = 11
+SELECT_VOLUME_PAGE   = 12
+BRIDGE_PAGE          = 13
+VIRT_DETAILS_PAGE    = 14
+CONFIRM_PAGE         = 15
+
+LOCATION="location"
+KICKSTART="kickstart"
+KERNELOPTS="kernel.options"
+OS_TYPE="os.type"
+OS_VARIANT="os.variant"
+MEMORY="memory"
+CPUS="cpus"
+
+class DomainConfigScreen(ConfigScreen):
+    def __init__(self):
+        ConfigScreen.__init__(self, "Create A New Virtual Machine")
+        self.__config = DomainConfig()
+        self.__config.set_architecture(self.get_libvirt().get_default_architecture())
+        self.__config.set_virt_type(self.get_libvirt().get_default_virt_type())
+
+    def get_elements_for_page(self, screen, page):
+        if page is VM_DETAILS_PAGE:        return self.get_vm_details_page(screen)
+        elif page is LOCAL_INSTALL_PAGE:   return self.get_local_install_page(screen)
+        elif page is SELECT_CDROM_PAGE:    return self.get_select_cdrom_page(screen)
+        elif page is SELECT_ISO_PAGE:      return self.get_select_iso_page(screen)
+        elif page is NETWORK_INSTALL_PAGE: return self.get_network_install_page(screen)
+        elif page is OS_TYPE_PAGE:         return self.get_os_type_page(screen)
+        elif page is OS_VARIANT_PAGE:      return self.get_os_variant_page(screen)
+        elif page is RAM_CPU_PAGE:         return self.get_ram_and_cpu_page(screen)
+        elif page is ENABLE_STORAGE_PAGE:  return self.get_enable_storage_page(screen)
+        elif page is LOCAL_STORAGE_PAGE:   return self.get_local_storage_page(screen)
+        elif page is SELECT_POOL_PAGE:     return self.get_select_pool_page(screen)
+        elif page is SELECT_VOLUME_PAGE:   return self.get_select_volume_page(screen)
+        elif page is BRIDGE_PAGE:          return self.get_bridge_page(screen)
+        elif page is VIRT_DETAILS_PAGE:    return self.get_virt_details_page(screen)
+        elif page is CONFIRM_PAGE:         return self.get_confirm_page(screen)
+        return []
+
+    def get_page_list(self):
+        return ["Virtual Machine Details",
+                "Local Installation Details",
+                "Setup CD-ROM Device",
+                "Setup ISO File",
+                "Setup Network Installation",
+                "Select Operating System Type",
+                "Select Operating System Variant",
+                "Set Memory Size",
+                "Enable Storage",
+                "Setup Local Storage",
+                "Select Storage Pool",
+                "Select Storage Volume",
+                "Setup Bridge",
+                "Review Virtual Machine Details",
+                "Confirm Virtual Machine"]
+
+    def validate_input(self, page, errors):
+        if page is VM_DETAILS_PAGE:
+            if len(self.__guest_name.value()) > 0:
+                if self.get_libvirt().domain_exists(self.__guest_name.value()):
+                    errors.append("Guest name '%s' is already in use." % self.__guest_name.value())
+                else:
+                    return True
+            else:
+                errors.append("Guest name must be a string between 0 and 50 characters.")
+        elif page is LOCAL_INSTALL_PAGE:
+            if self.__install_source.getSelection() == DomainConfig.INSTALL_SOURCE_CDROM:
+                return True
+            elif self.__install_source.getSelection() == DomainConfig.INSTALL_SOURCE_ISO:
+                return True
+        elif page is SELECT_CDROM_PAGE:
+            if self.__install_media.getSelection() != None:
+                if len(self.get_hal().list_installable_volumes()) == 0:
+                    errors.append("No installable media is available.")
+                else:
+                    return True
+            else:
+                errors.append("You must select an install media.")
+        elif page is SELECT_ISO_PAGE:
+            if len(self.__iso_path.value()) > 0:
+                if os.path.exists(self.__iso_path.value()):
+                    if os.path.isfile(self.__iso_path.value()):
+                        return True
+                    else:
+                        errors.append("%s is not a file." % self.__iso_path.value())
+                else:
+                    errors.append("No such install media exists:")
+                    errors.append(self.__iso_path.value())
+            else:
+                errors.append("An install media selection is required.")
+        elif page is NETWORK_INSTALL_PAGE:
+            if len(self.__install_url.value()) > 0:
+                return True
+            else:
+                errors.append("An install tree is required.")
+        elif page is OS_TYPE_PAGE: return True
+        elif page is OS_VARIANT_PAGE: return True
+        elif page is RAM_CPU_PAGE:
+            if (len(self.__memory.value()) > 0 and len(self.__cpus.value()) > 0) \
+                    and  (int(self.__memory.value()) > 0 and int(self.__cpus.value()) > 0):
+                return True
+            else:
+                if len(self.__memory.value()) == 0:
+                    errors.append("A value must be entered for memory.")
+                elif int(self.__memory.value()) <= 0:
+                    errors.append("A positive integer value must be entered for memory.")
+                if len(self.__cpus.value()) == 0:
+                    errors.append("A value must be entered for CPUs.")
+                elif int(self.__cpus.value()) <= 0:
+                    errors.append("A positive integer value must be entered for memory.")
+        elif page is ENABLE_STORAGE_PAGE: return True
+        elif page is LOCAL_STORAGE_PAGE:
+            if len(self.__storage_size.value()) > 0:
+                if float(self.__storage_size.value()) > 0:
+                    return True
+                else:
+                    errors.append("A positive value must be entered for the storage size.")
+            else:
+                errors.append("A value must be entered for the storage size.")
+        elif page is SELECT_POOL_PAGE:
+            if self.__storage_pool.getSelection() is not None:
+                return True
+            else:
+                errors.append("Please select a storage pool.")
+        elif page is SELECT_VOLUME_PAGE:
+            if self.__storage_volume.getSelection() is not None:
+                return True
+            else:
+                errors.append("Please select a storage volume.")
+        elif page is BRIDGE_PAGE:
+            if self.__network_bridges.getSelection() != None:
+                if len(self.__mac_address.value()) > 0:
+                    # TODO: regex check the format
+                    return True
+                else:
+                    errors.append("MAC address must be supplied.")
+            else:
+                errors.append("A network bridge must be selected.")
+        elif page is VIRT_DETAILS_PAGE:
+            if self.__virt_types.getSelection() != None and self.__architectures.getSelection() != None:
+                return True
+            if self.__virt_types.getSelection() is None:
+                errors.append("Please select a virtualization type.")
+            if self.__architectures.getSelection() is None:
+                errors.append("Please selection an architecture.")
+        elif page is CONFIRM_PAGE: return True
+        return False
+
+    def process_input(self, page):
+        if page is VM_DETAILS_PAGE:
+            self.__config.set_guest_name(self.__guest_name.value())
+            self.__config.set_install_type(self.__install_type.getSelection())
+        elif page is LOCAL_INSTALL_PAGE:
+            self.__config.set_use_cdrom_source(self.__install_source.getSelection() == DomainConfig.INSTALL_SOURCE_CDROM)
+        elif page is SELECT_CDROM_PAGE:
+            self.__config.set_install_media(self.__install_media.getSelection())
+        elif page is SELECT_ISO_PAGE:
+            self.__config.set_iso_path(self.__iso_path.value())
+        elif page is NETWORK_INSTALL_PAGE:
+            self.__config.set_install_url(self.__install_url.value())
+            self.__config.set_kickstart_url(self.__kickstart_url.value())
+            self.__config.set_kernel_options(self.__kernel_options.value())
+        elif page is OS_TYPE_PAGE:
+            self.__config.set_os_type(self.__os_types.getSelection())
+        elif page is OS_VARIANT_PAGE:
+            self.__config.set_os_variant(self.__os_variants.getSelection())
+        elif page is RAM_CPU_PAGE:
+            self.__config.set_memory(int(self.__memory.value()))
+            self.__config.set_cpus(int(self.__cpus.value()))
+        elif page is ENABLE_STORAGE_PAGE:
+            self.__config.set_enable_storage(self.__enable_storage.value())
+            if self.__storage_type.getSelection() == DomainConfig.NEW_STORAGE:
+                self.__config.set_use_local_storage(True)
+            elif self.__storage_type.getSelection() == DomainConfig.EXISTING_STORAGE:
+                self.__config.set_use_local_storage(False)
+        elif page is LOCAL_STORAGE_PAGE:
+            self.__config.set_storage_size(float(self.__storage_size.value()))
+            self.__config.set_allocate_storage(self.__allocate_storage.value())
+        elif page is SELECT_POOL_PAGE:
+            self.__config.set_use_local_storage(False)
+            self.__config.set_storage_pool(self.__storage_pool.getSelection())
+        elif page is SELECT_VOLUME_PAGE:
+            self.__config.set_storage_volume(self.__storage_volume.getSelection())
+            volume = self.get_libvirt().get_storage_volume(self.__config.get_storage_pool(),
+                                                           self.__config.get_storage_volume())
+            self.__config.set_storage_size(volume.info()[1] / 1024.0 ** 3)
+        elif page is BRIDGE_PAGE:
+            self.__config.set_network_bridge(self.__network_bridges.getSelection())
+        elif page is VIRT_DETAILS_PAGE:
+            self.__config.set_virt_type(self.__virt_types.getSelection())
+            self.__config.set_architecture(self.__architectures.getSelection())
+        elif page is CONFIRM_PAGE:
+            self.get_libvirt().define_domain(self.__config, CreateMeter())
+            self.set_finished()
+
+    def get_back_page(self, page):
+        result = page
+        if page is OS_TYPE_PAGE:
+            install_type = self.__config.get_install_type()
+            if install_type == DomainConfig.LOCAL_INSTALL:
+                if self.__config.get_use_cdrom_source():
+                    result = SELECT_CDROM_PAGE
+                else:
+                    result = SELECT_ISO_PAGE
+            elif install_type == DomainConfig.NETWORK_INSTALL:
+                result = NETWORK_INSTALL_PAGE
+            elif install_type == DomainConfig.PXE_INSTALL:
+                result = VM_DETAILS_PAGE
+        elif page is LOCAL_STORAGE_PAGE or page is SELECT_VOLUME_PAGE:
+            result = ENABLE_STORAGE_PAGE
+        elif page is SELECT_POOL_PAGE:
+            result = ENABLE_STORAGE_PAGE
+        elif page is NETWORK_INSTALL_PAGE:
+            result = VM_DETAILS_PAGE
+        elif page is SELECT_CDROM_PAGE or page == SELECT_ISO_PAGE:
+            result = LOCAL_INSTALL_PAGE
+        elif page is BRIDGE_PAGE:
+            if self.__config.get_use_local_storage():
+                result = LOCAL_STORAGE_PAGE
+            else:
+                result = SELECT_VOLUME_PAGE
+        else:
+            if page > 1: result = page - 1
+        return result
+
+    def get_next_page(self, page):
+        result = page
+        if page is VM_DETAILS_PAGE:
+            install_type = self.__config.get_install_type()
+            if install_type == DomainConfig.LOCAL_INSTALL:
+                result = LOCAL_INSTALL_PAGE
+            elif install_type == DomainConfig.NETWORK_INSTALL:
+                result = NETWORK_INSTALL_PAGE
+            elif install_type == DomainConfig.PXE_INSTALL:
+                result = OS_TYPE_PAGE
+        elif page is LOCAL_INSTALL_PAGE:
+            if self.__config.get_use_cdrom_source():
+                result = SELECT_CDROM_PAGE
+            else:
+                result = SELECT_ISO_PAGE
+        elif page is SELECT_CDROM_PAGE or page == SELECT_ISO_PAGE:
+            result = OS_TYPE_PAGE
+        elif page is NETWORK_INSTALL_PAGE:
+            result = OS_TYPE_PAGE
+        elif page is ENABLE_STORAGE_PAGE:
+            result = BRIDGE_PAGE
+            if self.__config.get_enable_storage():
+                if self.__config.get_use_local_storage():
+                    result = LOCAL_STORAGE_PAGE
+                else:
+                    result = SELECT_POOL_PAGE
+        elif page is LOCAL_STORAGE_PAGE:
+            result = BRIDGE_PAGE
+        else:
+            result = page + 1
+        return result
+
+    def page_has_finish(self, page):
+        if page is CONFIRM_PAGE: return True
+        return False
+
+    def page_has_next(self, page):
+        if   page is SELECT_POOL_PAGE: return self.__has_pools
+        elif page is SELECT_VOLUME_PAGE: return self.__has_volumes
+        elif page < CONFIRM_PAGE:
+            return True
+
+    def get_vm_details_page(self, screen):
+        self.__guest_name = Entry(50, self.__config.get_guest_name())
+        self.__install_type = RadioBar(screen, (("Local install media (ISO image or CDROM)",
+                                                 DomainConfig.LOCAL_INSTALL,
+                                                 self.__config.is_install_type(DomainConfig.LOCAL_INSTALL)),
+                                                ("Network Install (HTTP, FTP, or NFS)",
+                                                 DomainConfig.NETWORK_INSTALL,
+                                                 self.__config.is_install_type(DomainConfig.NETWORK_INSTALL)),
+                                                ("Network Boot (PXE)",
+                                                 DomainConfig.PXE_INSTALL,
+                                                 self.__config.is_install_type(DomainConfig.PXE_INSTALL))))
+        grid = Grid(2,3)
+        grid.setField(Label("Name:"), 0, 0, anchorRight = 1)
+        grid.setField(self.__guest_name, 1, 0, anchorLeft = 1)
+        grid.setField(Label("Choose how you would like to install the operating system"), 1, 1,
+                      anchorLeft = 1, anchorTop = 1)
+        grid.setField(self.__install_type, 1, 2, anchorLeft = 1)
+        return [Label("Enter your machine details"),
+                grid]
+
+    def get_local_install_page(self, screen):
+        self.__install_source = RadioBar(screen, (("Use CDROM or DVD",
+                                                   DomainConfig.INSTALL_SOURCE_CDROM,
+                                                   self.__config.get_use_cdrom_source()),
+                                                  ("Use ISO image",
+                                                   DomainConfig.INSTALL_SOURCE_ISO,
+                                                   self.__config.get_use_cdrom_source() is False)))
+        grid = Grid(1,1)
+        grid.setField(self.__install_source, 0, 0, anchorLeft = 1)
+        return [Label("Locate your install media"),
+                grid]
+
+    def get_select_cdrom_page(self, screen):
+        drives = []
+        media = self.get_hal().list_installable_volumes()
+        for drive in media.keys():
+            drives.append([media[drive], drive, self.__config.is_install_media(drive)])
+        self.__install_media = RadioBar(screen, (drives))
+        grid = Grid(1, 1)
+        grid.setField(self.__install_media, 0, 0)
+        return [Label("Select the install media"),
+                grid]
+
+    def get_select_iso_page(self, screen):
+        self.__iso_path = Entry(50, self.__config.get_iso_path())
+        grid = Grid(1, 2)
+        grid.setField(Label("Enter ISO path:"), 0, 0, anchorLeft = 1)
+        grid.setField(self.__iso_path, 0, 1, anchorLeft = 1)
+        return [Label("Enter the full path to an install ISO"),
+                grid]
+
+    def get_network_install_page(self, screen):
+        self.__install_url    = Entry(50, self.__config.get_install_url())
+        self.__kickstart_url  = Entry(50, self.__config.get_kickstart_url())
+        self.__kernel_options = Entry(50, self.__config.get_kernel_options())
+        grid = Grid(2,3)
+        grid.setField(Label("URL:"), 0, 0, anchorRight = 1)
+        grid.setField(self.__install_url, 1, 0, anchorLeft = 1)
+        grid.setField(Label("Kickstart URL:"), 0, 1, anchorRight = 1)
+        grid.setField(self.__kickstart_url, 1, 1, anchorLeft = 1)
+        grid.setField(Label("Kernel Options:"), 0, 2, anchorRight = 1)
+        grid.setField(self.__kernel_options, 1, 2, anchorLeft = 1)
+        return [Label("Provide the operating system URL"),
+                grid]
+
+    def get_os_type_page(self, screen):
+        types = []
+        for type in Guest.list_os_types():
+            types.append([Guest.get_os_type_label(type), type, self.__config.is_os_type(type)])
+        self.__os_types = RadioBar(screen, types)
+        grid = Grid(1, 1)
+        grid.setField(self.__os_types, 0, 0, anchorLeft = 1)
+        return [Label("Choose the operating system type"),
+                grid]
+
+    def get_os_variant_page(self, screen):
+        variants = []
+        type = self.__config.get_os_type()
+        for variant in Guest.list_os_variants(type):
+            variants.append([Guest.get_os_variant_label(type, variant), variant, self.__config.is_os_variant(variant)])
+        self.__os_variants = RadioBar(screen, variants)
+        grid = Grid(1, 1)
+        grid.setField(self.__os_variants, 0, 0, anchorLeft = 1)
+        return [Label("Choose the operating system version"),
+                grid]
+
+    def get_ram_and_cpu_page(self, screen):
+        self.__memory = Entry(10, str(self.__config.get_memory()))
+        self.__cpus   = Entry(10, str(self.__config.get_cpus()))
+        grid = Grid(2,2)
+        grid.setField(Label("Memory (RAM):"), 0, 0, anchorRight = 1)
+        grid.setField(self.__memory, 1, 0, anchorLeft = 1)
+        grid.setField(Label("CPUs:"), 0, 1, anchorRight = 1)
+        grid.setField(self.__cpus, 1, 1, anchorLeft = 1)
+        return [Label("Choose memory and CPU settings"),
+                grid]
+
+    def get_enable_storage_page(self, screen):
+        self.__enable_storage = Checkbox("Enable storage for this virtual machine", self.__config.get_enable_storage())
+        self.__storage_type     = RadioBar(screen,((["Create a disk image on the computer's hard disk",
+                                                     DomainConfig.NEW_STORAGE,
+                                                     self.__config.get_use_local_storage()]),
+                                                   (["Select managed or other existing storage",
+                                                     DomainConfig.EXISTING_STORAGE,
+                                                     self.__config.get_use_local_storage() is False])))
+        grid = Grid(1,2)
+        grid.setField(self.__enable_storage, 0, 0, anchorLeft = 1)
+        grid.setField(self.__storage_type, 0, 1, anchorLeft = 1)
+        return [Label("Configure storage"),
+                grid]
+
+    def get_local_storage_page(self, screen):
+        self.__storage_size     = Entry(6, str(self.__config.get_storage_size()))
+        self.__allocate_storage = Checkbox("Allocate entire disk now", self.__config.get_allocate_storage())
+        grid = Grid(2, 2)
+        grid.setField(self.__allocate_storage, 0, 0, growx = 1, anchorLeft = 1)
+        grid.setField(Label("Storage size (GB):"), 0, 1, anchorLeft = 1)
+        grid.setField(self.__storage_size, 1, 1)
+        return [Label("Configure local storage"),
+                grid]
+
+    def get_select_pool_page(self, screen):
+        pools = []
+        for pool in self.get_libvirt().list_storage_pools():
+            pools.append([pool, pool, pool == self.__config.get_storage_pool()])
+        if len(pools) > 0:
+            self.__storage_pool = RadioBar(screen, (pools))
+            grid = Grid(2, 1)
+            grid.setField(Label("Storage pool:"), 0, 0, anchorTop = 1)
+            grid.setField(self.__storage_pool, 1, 0)
+            self.__has_pools = True
+        else:
+            grid = Label("There are no storage pools available.")
+            self.__has_pools = False
+        return [Label("Configure Managed Storage: Select A Pool"),
+                grid]
+
+    def get_select_volume_page(self, screen):
+       volumes = []
+       for volume in self.get_libvirt().list_storage_volumes(self.__config.get_storage_pool()):
+           volumes.append([volume, volume, volume == self.__config.get_storage_volume()])
+       if len(volumes) > 0:
+           self.__storage_volume = RadioBar(screen, (volumes))
+           grid = Grid(2, 1)
+           grid.setField(Label("Storage volumes:"), 0, 0, anchorTop = 1)
+           grid.setField(self.__storage_volume, 1, 0)
+           self.__has_volumes = True
+       else:
+           grid = Label("This storage pool has no defined volumes.")
+           self.__has_volumes = False
+       return [Label("Configure Managed Storage: Select A Volume"),
+               grid]
+
+    def get_bridge_page(self, screen):
+        bridges = []
+        for bridge in self.get_libvirt().list_bridges():
+            bridges.append(["Virtual network '%s'" % bridge.name(), bridge.name(), self.__config.get_network_bridge() is bridge.name()])
+        self.__network_bridges = RadioBar(screen, (bridges))
+        if self.__config.get_mac_address() is None:
+            self.__config.set_mac_address(self.get_libvirt().generate_mac_address())
+        self.__mac_address = Entry(20, self.__config.get_mac_address())
+        grid = Grid(1, 1)
+        grid.setField(self.__network_bridges, 0, 0)
+        return [Label("Select an existing bridge"),
+                grid]
+
+    def get_virt_details_page(self, screen):
+        virt_types = []
+        for type in self.get_libvirt().list_virt_types():
+            virt_types.append([type, type, self.__config.is_virt_type(type)])
+        self.__virt_types = RadioBar(screen, (virt_types))
+        archs = []
+        for arch in self.get_libvirt().list_architectures():
+            archs.append([arch, arch, self.__config.is_architecture(arch)])
+        self.__architectures = RadioBar(screen, (archs))
+        grid = Grid(2, 2)
+        grid.setField(Label("Virt Type:"), 0, 0, anchorRight = 1, anchorTop = 1)
+        grid.setField(self.__virt_types, 1, 0, anchorLeft = 1)
+        grid.setField(Label("Architecture:"), 0, 1, anchorRight = 1, anchorTop = 1)
+        grid.setField(self.__architectures, 1, 1, anchorLeft = 1)
+        return [Label("Configure virtualization details"),
+                grid]
+
+    def get_confirm_page(self, screen):
+        grid = Grid(2, 6)
+        grid.setField(Label("OS:"), 0, 0, anchorRight = 1)
+        grid.setField(Label(Guest.get_os_variant_label(self.__config.get_os_type(),
+                                                       self.__config.get_os_variant())), 1, 0, anchorLeft = 1)
+        grid.setField(Label("Install:"), 0, 1, anchorRight = 1)
+        grid.setField(Label(self.__config.get_install_type_text()), 1, 1, anchorLeft = 1)
+        grid.setField(Label("Memory:"), 0, 2, anchorRight = 1)
+        grid.setField(Label("%s MB" % self.__config.get_memory()), 1, 2, anchorLeft = 1)
+        grid.setField(Label("CPUs:"), 0, 3, anchorRight = 1)
+        grid.setField(Label("%d" % self.__config.get_cpus()), 1, 3, anchorLeft = 1)
+        grid.setField(Label("Storage:"), 0, 4, anchorRight = 1)
+        grid.setField(Label("%s (on %s)" % (self.__config.get_storage_volume(),
+                                            self.__config.get_storage_pool())),
+                      1, 4, anchorLeft = 1)
+        grid.setField(Label("Network:"), 0, 5, anchorRight = 1)
+        grid.setField(Label(self.__config.get_network_bridge()), 1, 5, anchorLeft = 1)
+        return [Label("Ready to begin installation of %s" % self.__config.get_guest_name()),
+                grid]
+
+def AddDomain():
+    screen = DomainConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/addhost.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/addhost.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,135 @@
+# addhost.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from configscreen import *
+
+DETAILS_PAGE = 1
+CONFIRM_PAGE = 2
+
+HYPERVISOR_XEN      = "xen"
+HYPERVISOR_KVM      = "kvm"
+
+HYPERVISORS = {HYPERVISOR_XEN : "Xen",
+               HYPERVISOR_KVM : "QEMU/KVM"}
+
+CONNECTION_LOCAL    = "local"
+CONNECTION_KERBEROS = "kerberos"
+CONNECTION_SSL      = "ssl"
+CONNECTION_SSH      = "ssh"
+
+CONNECTIONS = {CONNECTION_LOCAL    : "Local",
+               CONNECTION_KERBEROS : "Remote Password or Kerberos",
+               CONNECTION_SSL      : "Remote SSL/TLS with x509 certificate",
+               CONNECTION_SSH      : "Remote tunnel over SSH"}
+
+class AddHostConfigScreen(ConfigScreen):
+    def __init__(self):
+        ConfigScreen.__init__(self, "Add A Remote Host")
+        self.__configured = False
+
+    def get_elements_for_page(self, screen, page):
+        if   page is DETAILS_PAGE: return self.get_details_page(screen)
+        elif page is CONFIRM_PAGE: return self.get_confirm_page(screen)
+
+    def page_has_next(self, page):
+        return page < CONFIRM_PAGE
+
+    def page_has_back(self, page):
+        return page > DETAILS_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_PAGE
+
+    def validate_input(self, page, errors):
+        if page is DETAILS_PAGE:
+            if self.__connection.getSelection() is CONNECTION_LOCAL:
+                return True
+            elif len(self.__hostname.value()) > 0:
+                return True
+            else:
+                errors.append("You must enter a remote hostname.")
+        elif page is CONFIRM_PAGE: return True
+        return False
+
+    def process_input(self, page):
+        if page is CONFIRM_PAGE:
+            hv       = self.__hypervisor.getSelection()
+            conn     = self.__connection.getSelection()
+            hostname = self.__hostname.value()
+
+            if   hv is HYPERVISOR_XEN:
+                if   conn is CONNECTION_LOCAL:    url = "xen:///"
+                elif conn is CONNECTION_KERBEROS: url = "xen+tcp:///" + hostname + "/"
+                elif conn is CONNECTION_SSL:      url = "xen+tls:///" + hostname + "/"
+                elif conn is CONNECTION_SSH:      url = "xen+ssh:///" + hostname + "/"
+            elif hv is HYPERVISOR_KVM:
+                if   conn is CONNECTION_LOCAL:    url = "qemu:///system"
+                elif conn is CONNECTION_KERBEROS: url = "qemu+tcp://" + hostname + "/system"
+                elif conn is CONNECTION_SSL:      url = "qemu+tls://" + hostname + "/system"
+                elif conn is CONNECTION_SSH:      url = "qemu+ssh://" + hostname + "/system"
+
+            self.get_virt_manager_config().add_connection(url)
+            self.set_finished()
+
+    def get_details_page(self, screen):
+        if not self.__configured:
+            self.__hypervisor = RadioBar(screen, ((HYPERVISORS[HYPERVISOR_XEN], HYPERVISOR_XEN, True),
+                                                  (HYPERVISORS[HYPERVISOR_KVM], HYPERVISOR_KVM, False)))
+            self.__connection = RadioBar(screen, ((CONNECTIONS[CONNECTION_LOCAL],    CONNECTION_LOCAL, True),
+                                                  (CONNECTIONS[CONNECTION_KERBEROS], CONNECTION_KERBEROS, False),
+                                                  (CONNECTIONS[CONNECTION_SSL],      CONNECTION_SSL, False),
+                                                  (CONNECTIONS[CONNECTION_SSH],      CONNECTION_SSH, False)))
+            self.__hostname = Entry(50, "")
+            self.__autoconnect = Checkbox("Autoconnect on Startup")
+            self.__configured = True
+        grid = Grid(2, 4)
+        grid.setField(Label("Hypervisor:"), 0, 0, anchorRight = 1, anchorTop = 1)
+        grid.setField(self.__hypervisor, 1, 0, anchorLeft = 1)
+        grid.setField(Label("Connection:"), 0, 1, anchorRight = 1, anchorTop = 1)
+        grid.setField(self.__connection, 1, 1, anchorLeft = 1)
+        grid.setField(Label("Hostname:"), 0, 2, anchorRight = 1)
+        grid.setField(self.__hostname, 1, 2, anchorLeft = 1)
+        grid.setField(Label(""), 0, 3, anchorRight = 1)
+        grid.setField(self.__autoconnect, 1, 3, anchorLeft = 1)
+        return [Label("Add Connection"),
+                grid]
+
+    def get_confirm_page(self, screen):
+        grid = Grid(2, 4)
+        grid.setField(Label("Hypervisor:"), 0, 0, anchorRight = 1)
+        grid.setField(Label(HYPERVISORS[self.__hypervisor.getSelection()]), 1, 0, anchorLeft = 1)
+        grid.setField(Label("Connection:"), 0, 1, anchorRight = 1)
+        grid.setField(Label(CONNECTIONS[self.__connection.getSelection()]), 1, 1, anchorLeft = 1)
+        if self.__connection.getSelection() is not CONNECTION_LOCAL:
+            hostname = self.__hostname.value()
+        else:
+            hostname = "local"
+        grid.setField(Label("Hostname:"), 0, 2, anchorRight = 1)
+        grid.setField(Label(hostname), 1, 2, anchorLeft = 1)
+        grid.setField(Label("Autoconnect on Startup:"), 0, 3, anchorRight = 1)
+        label = "Yes"
+        if not self.__autoconnect.value(): label = "No"
+        grid.setField(Label(label), 1, 3, anchorLeft = 1)
+        return [Label("Confirm Connection"),
+                grid]
+
+def AddHost():
+    screen = AddHostConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/addpool.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/addpool.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,187 @@
+# addstorage.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import traceback
+import utils
+
+from configscreen import *
+from poolconfig import PoolConfig
+from virtinst import Storage
+
+POOL_NAME_PAGE    = 1
+POOL_DETAILS_PAGE = 2
+CONFIRM_PAGE      = 3
+
+class AddStoragePoolConfigScreen(ConfigScreen):
+    def __init__(self):
+        ConfigScreen.__init__(self, "Add A Storage Pool")
+        self.__config = PoolConfig(self.get_libvirt())
+
+    def get_elements_for_page(self, screen, page):
+        if   page is POOL_NAME_PAGE:    return self.get_pool_name_page(screen)
+        elif page is POOL_DETAILS_PAGE: return self.get_pool_details_page(screen)
+        elif page is CONFIRM_PAGE:      return self.get_confirm_page(screen)
+
+    def page_has_next(self, page):
+        return page < CONFIRM_PAGE
+
+    def page_has_back(self, page):
+        return page > POOL_NAME_PAGE
+
+        return page > POOL_NAME_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_PAGE
+
+    def validate_input(self, page, errors):
+        if   page is POOL_NAME_PAGE:
+            if utils.string_is_not_blank(self.__name.value()):
+                if self.get_libvirt().storage_pool_exists(self.__name.value()):
+                    errors.append("Name '%s' already in use by another pool." % self.__name.value())
+                else:
+                    return True
+            else:
+                errors.append("Storage object name must be a string between 0 and 50 characters.")
+        elif page is POOL_DETAILS_PAGE:
+            result = True
+            if self.__config.needs_target_path():
+                if utils.string_is_not_blank(self.__target_path.value()):
+                    if self.__target_path.value()[0:1] is not '/':
+                        errors.append("'%s' is not an absolute path." % self.__target_path.value())
+                        result = False
+                else:
+                    errors.append("You must enter a target path.")
+                    result = False
+            if self.__config.needs_format():
+                if self.__formats.getSelection() is None:
+                    errors.append("You must select a pool format.")
+                    result = False
+            if self.__config.needs_hostname():
+                if not utils.string_is_not_blank(self.__hostname.value()):
+                    errors.append("You must enter a hostname.")
+                    result = False
+            if self.__config.needs_source_path():
+                if utils.string_is_not_blank(self.__source_path.value()):
+                    if self.__config.source_must_be_absolute():
+                        if self.__source_path.value()[0:1] is not '/':
+                            errors.append("'%s' is not an absolute path." % self.__source_path.value())
+                            result = False
+                else:
+                    errors.append("you  must enter a source path.")
+                    result = False
+            return result
+        elif page is CONFIRM_PAGE: return True
+        return False
+
+    def process_input(self, page):
+        if page is POOL_NAME_PAGE:
+            self.__config.set_name(self.__name.value())
+            self.__config.set_type(self.__type.getSelection())
+            #self._reset_flags(self.__type.current())
+        elif page is POOL_DETAILS_PAGE:
+            if self.__config.needs_target_path():
+                self.__config.set_target_path(self.__target_path.value())
+            if self.__config.needs_format():
+                self.__config.set_format(self.__formats.getSelection())
+            if self.__config.needs_hostname():
+                self.__config.set_hostname(self.__hostname.value())
+            if self.__config.needs_source_path():
+                self.__config.set_source_path(self.__source_path.value())
+            if self.__config.needs_build_pool():
+                self.__config.set_build_pool(self.__build_pool.value())
+        elif page is CONFIRM_PAGE:
+            self.get_libvirt().define_storage_pool(self.__config.get_name(), config = self.__config)
+            self.get_libvirt().create_storage_pool(self.__config.get_name())
+            self.set_finished()
+
+    def get_pool_name_page(self, screen):
+        self.__name = Entry(50, self.__config.get_name())
+        pooltypes = []
+        for pooltype in Storage.StoragePool.get_pool_types():
+            pooltypes.append(["%s: %s" % (pooltype, Storage.StoragePool.get_pool_type_desc(pooltype)),
+                              pooltype,
+                              self.__config.get_type() is pooltype])
+        self.__type = RadioBar(screen, pooltypes)
+        grid = Grid(2, 2)
+        grid.setField(Label("Name:"), 0, 0, anchorRight = 1)
+        grid.setField(self.__name, 1, 0, anchorLeft = 1)
+        grid.setField(Label("Type:"), 0, 1, anchorRight = 1, anchorTop = 1)
+        grid.setField(self.__type, 1, 1, anchorLeft = 1)
+        return [Label("Add Storage Pool"),
+                grid]
+
+    def get_pool_details_page(self, screen):
+        rows = 0
+        if self.__config.needs_target_path():
+            self.__target_path = Entry(50, self.__config.get_target_path())
+            rows += 1
+        if self.__config.needs_format():
+            formats = []
+            for format in self.__config.get_formats():
+                formats.append([format, format, format is self.__config.get_format()])
+            self.__formats = RadioBar(screen, formats)
+            rows += 1
+        if self.__config.needs_hostname():
+            self.__hostname = Entry(50, self.__config.get_hostname())
+            rows += 1
+        if self.__config.needs_source_path():
+            self.__source_path = Entry(50, self.__config.get_source_path())
+            rows += 1
+        if self.__config.needs_build_pool():
+            self.__build_pool = Checkbox("Build Pool", self.__config.get_build_pool())
+            rows += 1
+            self.__build_pool = Checkbox("Build Pool", self.__config.get_build_pool())
+            rows += 1
+        grid = Grid(2, rows)
+        currentrow = 0
+        if self.__config.needs_target_path():
+            grid.setField(Label("Target Path:"), 0, currentrow, anchorRight = 1)
+            grid.setField(self.__target_path, 1, currentrow, anchorLeft = 1)
+            currentrow += 1
+        if self.__config.needs_format():
+            grid.setField(Label("Format:"), 0, currentrow, anchorRight = 1, anchorTop = 1)
+            grid.setField(self.__formats, 1, currentrow, anchorLeft = 1)
+            currentrow += 1
+        if self.__config.needs_hostname():
+            grid.setField(Label("Host Name:"), 0, currentrow, anchorRight = 1)
+            grid.setField(self.__hostname, 1, currentrow, anchorRight = 1)
+            currentrow += 1
+        if self.__config.needs_source_path():
+            grid.setField(Label("Source Path:"), 0, currentrow, anchorRight = 1)
+            grid.setField(self.__source_path, 1, currentrow, anchorLeft = 1)
+            currentrow += 1
+        if self.__config.needs_build_pool():
+            grid.setField(Label(" "), 0, currentrow, anchorRight = 1)
+            grid.setField(self.__build_pool, 1, currentrow, anchorLeft = 1)
+            currentrow += 1
+        return [Label("Specify a storage location to be later split into virtual machine storage"),
+                grid]
+
+    def get_confirm_page(self, screen):
+        grid = Grid(2, 2)
+        grid.setField(Label("Name:"), 0, 0, anchorRight = 1)
+        grid.setField(Label(self.__config.get_name()), 1, 0, anchorLeft = 1)
+        grid.setField(Label("Target Path:"), 0, 1, anchorRight = 1)
+        grid.setField(Label(self.__config.get_target_path()), 1, 1, anchorLeft = 1)
+        return [Label("Confirm Pool Details"),
+                grid]
+
+def AddStoragePool():
+    screen = AddStoragePoolConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/addvolume.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/addvolume.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,178 @@
+# addvolume.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import traceback
+
+from createmeter import CreateMeter
+from configscreen import *
+from volumeconfig import StorageVolumeConfig
+from utils import *
+
+SELECT_POOL_PAGE   = 1
+VOLUME_NAME_PAGE   = 2
+VOLUME_FORMAT_PAGE = 3
+MAX_CAPACITY_PAGE  = 4
+CONFIRM_PAGE       = 5
+
+class AddVolumeConfigScreen(StorageListConfigScreen):
+    def __init__(self):
+        StorageListConfigScreen.__init__(self, "Add A New Storage Volume")
+        self.__config = StorageVolumeConfig()
+
+    def get_elements_for_page(self, screen, page):
+        if   page is SELECT_POOL_PAGE:   return self.get_storage_pool_list_page(screen)
+        elif page is VOLUME_NAME_PAGE:   return self.get_volume_name_page(screen)
+        elif page is VOLUME_FORMAT_PAGE: return self.get_volume_format_page(screen)
+        elif page is MAX_CAPACITY_PAGE:  return self.get_max_capacity_page(screen)
+        elif page is CONFIRM_PAGE:       return self.get_confirm_page(screen)
+
+    def page_has_next(self, page):
+        if page is SELECT_POOL_PAGE:
+            return self.has_selectable_pools()
+        else:
+            if page < CONFIRM_PAGE: return True
+        return False
+
+    def page_has_back(self, page):
+        if page > SELECT_POOL_PAGE: return True
+        return False
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_PAGE
+
+    def get_next_page(self, page):
+        if page is VOLUME_NAME_PAGE:
+            if self.__config.needs_format():
+                return VOLUME_FORMAT_PAGE
+            else:
+                return MAX_CAPACITY_PAGE
+        return StorageListConfigScreen.get_next_page(self, page)
+
+    def get_back_page(self, page):
+        if page is MAX_CAPACITY_PAGE:
+            if self.__config.needs_format():
+                return VOLUME_FORMAT_PATH
+            else:
+                return VOLUME_NAME_PAGE
+        return StorageListConfigScreen.get_back_page(self, page)
+
+    def validate_input(self, page, errors):
+        if page is SELECT_POOL_PAGE:
+            if self.get_selected_pool() is not None:
+                return True
+            else:
+                errors.append("You must select a storage pool.")
+        elif page is VOLUME_NAME_PAGE:
+            if string_is_not_blank(self.__name.value()):
+                return True
+            else:
+                errors.append("Storage object name can only contain alphanumeric, '_', '.', or '-' characters.")
+        elif page is VOLUME_FORMAT_PAGE:
+            if self.__formats.current() is not None:
+                return True
+            else:
+                errors.append("You must select a volume format.")
+        elif page is MAX_CAPACITY_PAGE:
+            if string_is_not_blank(self.__capacity.value()):
+                if string_is_not_blank(self.__allocation.value()):
+                    capacity = int(self.__capacity.value())
+                    allocation = int(self.__allocation.value())
+                    if capacity > 0:
+                        if capacity <= self.__config.get_pool().info()[3] / 1024**2:
+                            if allocation >= 0:
+                                if allocation <= capacity:
+                                    return True
+                                else:
+                                    errors.append("Allocation cannot exceed the maximum capacity.")
+                            else:
+                                errors.append("The allocation must be greater than or equal to 0.")
+                        else:
+                            errors.append("The maximum capacity cannot exceed the storage pool size.")
+                    else:
+                        errors.append("The capacity must be greater than zero.")
+                else:
+                    errors.append("An allocation value must be entered.")
+            else:
+                errors.append("A maximum volume capacity must be entered.")
+        elif page is CONFIRM_PAGE: return True
+        return False
+
+    def process_input(self, page):
+        if page is SELECT_POOL_PAGE:
+            self.__config.set_pool(self.get_libvirt().get_storage_pool(self.get_selected_pool()))
+        elif page is VOLUME_NAME_PAGE:
+            self.__config.set_name(self.__name.value())
+        elif page is VOLUME_FORMAT_PAGE:
+            self.__config.set_format(self.__formats.current())
+        elif page is MAX_CAPACITY_PAGE:
+            self.__config.set_max_capacity(int(self.__capacity.value()))
+            self.__config.set_allocation(int(self.__allocation.value()))
+        elif page is CONFIRM_PAGE:
+            self.get_libvirt().define_storage_volume(self.__config, CreateMeter())
+            self.set_finished()
+
+    def get_volume_name_page(self, screen):
+        self.__name = Entry(50, self.__config.get_name())
+        grid = Grid(2, 1)
+        grid.setField(Label("Name:"), 0, 0, anchorRight = 1)
+        grid.setField(self.__name, 1, 0, anchorLeft = 1)
+        return [Label("New Storage Volume"),
+                grid,
+                Label("Name of the volume to create. File extension may be appended.")]
+
+    def get_volume_format_page(self, screen):
+        self.__formats = Listbox(0)
+        for format in self.__config.get_formats_for_pool():
+            self.__formats.append(format, format)
+        grid = Grid(1, 1)
+        grid.setField(self.__formats, 0, 0)
+        return [Label("Select The Volume Format"),
+                grid]
+
+    def get_max_capacity_page(self, screen):
+        self.__capacity = Entry(6, str(self.__config.get_max_capacity()))
+        self.__allocation = Entry(6, str(self.__config.get_allocation()))
+        grid = Grid(2, 2)
+        grid.setField(Label("Max. Capacity (MB):"), 0, 0, anchorRight = 1)
+        grid.setField(self.__capacity, 1, 0, anchorLeft = 1)
+        grid.setField(Label("Allocation (MB):"), 0, 1, anchorRight = 1)
+        grid.setField(self.__allocation, 1, 1, anchorLeft = 1)
+        return [Label("Storage Volume Quota"),
+                Label("%s's available space: %s" % (self.__config.get_pool().name(),
+                                                    size_as_mb_or_gb(self.__config.get_pool().info()[3]))),
+                grid]
+
+    def get_confirm_page(self, screen):
+        grid = Grid(2, 5)
+        grid.setField(Label("Volume Name:"), 0, 0, anchorRight = 1)
+        grid.setField(Label("%s (%s)" % (self.__config.get_name(), self.__config.get_pool().name())), 1, 0, anchorLeft = 1)
+        if self.__config.needs_format():
+            grid.setField(Label("Format:"), 0, 1, anchorRight = 1)
+            grid.setField(Label(self.__config.get_format()), 1, 1, anchorLeft = 1)
+        # NOTE: here we multiply the sizes by 1024^2 since the size_as_mb_or_gb is expect bytes
+        grid.setField(Label("Max. Capacity:"), 0, 2, anchorRight = 1)
+        grid.setField(Label("%s" % (size_as_mb_or_gb(self.__config.get_max_capacity() * 1024**2))), 1, 2, anchorLeft = 1)
+        grid.setField(Label("Allocation:"), 0, 3, anchorRight = 1)
+        grid.setField(Label("%s" % (size_as_mb_or_gb(self.__config.get_allocation() * 1024**2))), 1, 3, anchorLeft = 1)
+        return [Label("Ready To Allocation New Storage Volume"),
+                grid]
+
+def AddStorageVolume():
+    screen = AddVolumeConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/changehost.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/changehost.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,60 @@
+# changehost.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+import logging
+import libvirtworker
+from configscreen import *
+
+CONNECTION_LIST_PAGE = 1
+CONNECTED_PAGE       = 2
+
+class ChangeHostConfigScreen(HostListConfigScreen):
+    def __init__(self):
+        HostListConfigScreen.__init__(self, "")
+
+    def get_title(self):
+        return "Currently: %s" % self.get_libvirt().get_url()
+
+    def get_elements_for_page(self, screen, page):
+        if   page is CONNECTION_LIST_PAGE: return self.get_connection_list_page(screen)
+        elif page is CONNECTED_PAGE:       return self.get_connected_page(screen)
+
+    def process_input(self, page):
+        if   page is CONNECTION_LIST_PAGE:
+            logging.info("Changing libvirt connection to %s" % self.get_selected_connection())
+            self.get_libvirt().open_connection(self.get_selected_connection())
+        elif page is CONNECTED_PAGE: self.set_finished()
+
+    def page_has_next(self, page):
+        if page is CONNECTION_LIST_PAGE: return self.has_selectable_connections()
+        return False
+
+    def page_has_back(self, page):
+        return page > CONNECTION_LIST_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONNECTED_PAGE
+
+    def get_connected_page(self, screen):
+        return [Label("Connected to %s" % self.get_selected_connection())]
+
+def ChangeHost():
+    screen = ChangeHostConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/configscreen.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/configscreen.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,295 @@
+# configscreen.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from halworker import HALWorker
+from libvirtworker import *
+import traceback
+
+BACK_BUTTON   = "back"
+NEXT_BUTTON   = "next"
+CANCEL_BUTTON = "cancel"
+FINISH_BUTTON = "finish"
+
+class ConfigScreen:
+    '''Enables the creation of navigable, multi-paged configuration screens.'''
+
+    def __init__(self, title):
+        self.__title = title
+        self.__current_page = 1
+        self.__finished = False
+        self.__hal = HALWorker()
+        self.__libvirt = LibvirtWorker()
+        self.__vm_config = VirtManagerConfig()
+
+    def get_title(self):
+        return self.__title
+
+    def get_hal(self):
+        return self.__hal
+
+    def get_libvirt(self):
+        return self.__libvirt
+
+    def get_virt_manager_config(self):
+        return self.__vm_config
+
+    def set_finished(self):
+        self.__finished = True
+
+    def get_elements_for_page(self, screen, page):
+        return []
+
+    def page_has_next(self, page):
+        return False
+
+    def page_has_finish(self, page):
+        return False
+
+    def get_back_page(self, page):
+        if page > 1: return page - 1
+        return page
+
+    def go_back(self):
+        self.__current_page = self.get_back_page(self.__current_page)
+
+    def get_next_page(self, page):
+        return page + 1
+
+    def go_next(self):
+        self.__current_page = self.get_next_page(self.__current_page)
+
+    def validate_input(self, page, errors):
+        return True
+
+    def process_input(self, page):
+        return
+
+    def get_page_list(self):
+        return []
+
+    def get_current_page(self):
+        0
+
+    def start(self):
+        active = True
+        while active and (self.__finished == False):
+            screen = SnackScreen()
+            elements = self.get_elements_for_page(screen, self.__current_page)
+            # TODO: need to set the form height to the number of elements on the page
+            gridform = GridForm(screen, self.get_title(), 2, 2)
+
+            # Here you would put the list of elements
+            # and programmatically set the indicator as
+            # they're rendered
+            pages = self.get_page_list()
+            if len(pages) > 0:
+                leftmenu = Grid(2, len(pages))
+                current_element = 0
+                for page in pages:
+                    leftmenu.setField(Label(page), 0, current_element, anchorLeft = 1)
+                    indicator = " "
+                    if current_element == self.__current_page - 1:
+                        indicator = "<-"
+                    leftmenu.setField(Label(indicator), 1, current_element)
+                    current_element += 1
+                gridform.add(leftmenu, 0, 0, anchorTop = 1, padding = (3, 0, 3, 0))
+
+            content = Grid(1, len(elements) + 1)
+            current_element = 0
+            for element in elements:
+                content.setField(element, 0, current_element)
+                current_element += 1
+            # create the navigation buttons
+            buttons = []
+            if self.__current_page > 1: buttons.append(["Back", BACK_BUTTON, "F11"])
+            if self.page_has_next(self.__current_page): buttons.append(["Next", NEXT_BUTTON, "F12"])
+            if self.page_has_finish(self.__current_page): buttons.append(["Finish", FINISH_BUTTON, "F10"])
+            buttons.append(["Cancel", CANCEL_BUTTON, "ESC"])
+            buttonbar = ButtonBar(screen, buttons)
+            content.setField(buttonbar, 0, current_element, growx = 1)
+            gridform.add(content, 1, 0, anchorTop = 1)
+            current_element += 1
+            try:
+                result = gridform.runOnce()
+                pressed = buttonbar.buttonPressed(result)
+                if pressed == BACK_BUTTON:
+                    self.go_back()
+                elif pressed == NEXT_BUTTON or pressed == FINISH_BUTTON:
+                    errors = []
+                    if self.validate_input(self.__current_page, errors):
+                        self.process_input(self.__current_page)
+                        self.go_next()
+                    else:
+                        error_text = ""
+                        for error in errors:
+                            error_text += "%s\n" % error
+                            ButtonChoiceWindow(screen,
+                                               "There Were Errors",
+                                               error_text,
+                                               buttons = ["OK"])
+                elif pressed == CANCEL_BUTTON:
+                    active = False
+            except Exception, error:
+                ButtonChoiceWindow(screen,
+                                   "An Exception Has Occurred",
+                                   str(error) + "\n" + traceback.format_exc(),
+                                   buttons = ["OK"])
+            screen.popWindow()
+            screen.finish()
+
+class DomainListConfigScreen(ConfigScreen):
+    '''Provides a base class for all config screens that require a domain list.'''
+
+    def __init__(self, title):
+        ConfigScreen.__init__(self, title)
+
+    def get_domain_list_page(self, screen, defined=True, created=True):
+        domains = self.get_libvirt().list_domains(defined, created)
+        result = None
+
+        if len(domains) > 0:
+            self.__has_domains = True
+            self.__domain_list = Listbox(0)
+            for name in domains:
+                self.__domain_list.append(name, name)
+            result = [self.__domain_list]
+        else:
+            self.__has_domains = False
+            grid = Grid(1, 1)
+            grid.setField(Label("There are no domains available."), 0, 0)
+            result = [grid]
+        return result
+
+    def get_selected_domain(self):
+        return self.__domain_list.current()
+
+    def has_selectable_domains(self):
+        return self.__has_domains
+
+class NetworkListConfigScreen(ConfigScreen):
+    '''Provides a base class for all config screens that require a network list.'''
+
+    def __init__(self, title):
+        ConfigScreen.__init__(self, title)
+
+    def get_network_list_page(self, screen, defined=True, created=True):
+        networks = self.get_libvirt().list_networks(defined, created)
+        result = None
+
+        if len(networks) > 0:
+            self.__has_networks = True
+            self.__network_list = Listbox(0)
+            for name in networks:
+                self.__network_list.append(name, name)
+            result = self.__network_list
+        else:
+            self.__has_networks = False
+            result = Label("There are no networks available.")
+        grid = Grid(1, 1)
+        grid.setField(result, 0, 0)
+        return [Label("Network List"),
+                grid]
+
+    def get_selected_network(self):
+        return self.__network_list.current()
+
+    def has_selectable_networks(self):
+        return self.__has_networks
+
+class StorageListConfigScreen(ConfigScreen):
+    '''Provides a base class for any configuration screen that deals with storage pool lists.'''
+
+    def __init__(self, title):
+        ConfigScreen.__init__(self, title)
+
+    def get_storage_pool_list_page(self, screen, defined=True, created=True):
+        pools = self.get_libvirt().list_storage_pools(defined=defined, created=created)
+        if len(pools) > 0:
+            self.__has_pools = True
+            self.__pools_list = Listbox(0)
+            for pool in pools:
+                self.__pools_list.append(pool, pool)
+            result = self.__pools_list
+        else:
+            self.__has_pools = False
+            result = Label("There are no storage pools available.")
+        grid = Grid(1, 1)
+        grid.setField(result, 0, 0)
+        return [Label("Storage Pool List"),
+                grid]
+
+    def get_selected_pool(self):
+        return self.__pools_list.current()
+
+    def has_selectable_pools(self):
+        return self.__has_pools
+
+    def get_storage_volume_list_page(self, screen):
+        '''Requires that self.__pools_list have a selected element.'''
+        pool = self.get_libvirt().get_storage_pool(self.get_selected_pool())
+        if len(pool.listVolumes()) > 0:
+            self.__has_volumes = True
+            self.__volumes_list = Listbox(0)
+            for volname in pool.listVolumes():
+                volume = pool.storageVolLookupByName(volname)
+                self.__volumes_list.append("%s (%0.2f GB)" % (volume.name(), volume.info()[2] / 1024**3), volume.name())
+            result = self.__volumes_list
+        else:
+            self.__has_volumes = False
+            result = Label("There are no storage volumes available.")
+        grid = Grid(1, 1)
+        grid.setField(result, 0, 0)
+        return [Label("Storage Volume List"),
+                grid]
+
+    def get_selected_volume(self):
+        return self.__volumes_list.current()
+
+    def has_selectable_volumes(self):
+        return self.__has_volumes
+
+class HostListConfigScreen(ConfigScreen):
+    '''Provides a base class for working with lists of libvirt hosts.'''
+
+    def __init__(self, title):
+        ConfigScreen.__init__(self, title)
+
+    def get_connection_list_page(self, screen):
+        connections = self.get_virt_manager_config().get_connection_list()
+        result = None
+
+        if len(connections) > 0:
+            self.__has_connections = True
+            self.__connection_list = Listbox(0)
+            for connection in connections:
+                self.__connection_list.append(connection, connection)
+            result = self.__connection_list
+        else:
+            self.__has_connections = False
+            result = Label("There are no defined connections.")
+        grid = Grid(1, 1)
+        grid.setField(result, 0, 0)
+        return [Label("Host List"),
+                grid]
+
+    def get_selected_connection(self):
+        return self.__connection_list.current()
+
+    def has_selectable_connections(self):
+        return self.__has_connections
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/createmeter.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/createmeter.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,30 @@
+# createmeter.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+import urlgrabber.progress as progress
+import logging
+
+class CreateMeter(progress.BaseMeter):
+    def _do_start(self, now = None):
+        logging.info("Starting...")
+
+    def _do_end(self, amount_read, now = None):
+        logging.info("Ending: read=%d" % amount_read)
+
+    def _do_update(self, amount_read, now = None):
+        logging.info("Update: read=%d" % amount_read)
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/createnetwork.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/createnetwork.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+#
+# createnetwork.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+LIST_PAGE   = 1
+CREATE_PAGE = 2
+
+class CreateNetworkConfigScreen(NetworkListConfigScreen):
+    def __init__(self):
+        NetworkListConfigScreen.__init__(self, "Create A Network")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_PAGE:   return self.get_network_list_page(screen, created = False)
+        elif page is CREATE_PAGE: return self.get_create_network_page(screen)
+
+    def page_has_next(self, page):
+        if page is LIST_PAGE: return self.has_selectable_networks()
+
+    def page_has_back(self, page):
+        return (page is CREATE_PAGE)
+
+    def validate_input(self, page, errors):
+        if page is LIST_PAGE:
+            self.get_libvirt().create_network(self.get_selected_network())
+            return True
+
+    def get_create_network_page(self, screen):
+        return [Label("Network Started"),
+                Label("%s was successfully started." % self.get_selected_network())]
+
+def CreateNetwork():
+    screen = CreateNetworkConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/createuser.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/createuser.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+#
+# createuser.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import ConfigScreen
+from userworker import UserWorker
+
+import libuser
+
+DETAILS_PAGE = 1
+CONFIRM_PAGE = 2
+
+class CreateUserConfigScreen(ConfigScreen):
+    def __init__(self):
+        ConfigScreen.__init__(self, "Create A User Account")
+        self.__username = None
+        self.__useradmin = libuser.admin()
+        self.__user_worker = UserWorker()
+
+    def get_elements_for_page(self, screen, page):
+        if   page is DETAILS_PAGE: return self.get_details_page(screen)
+        elif page is CONFIRM_PAGE: return self.get_confirm_page(screen)
+
+    def validate_input(self, page, errors):
+        if page is DETAILS_PAGE:
+            if len(self.__username.value()) > 0:
+                name = self.__username.value()
+                if self.__useradmin.lookupUserByName(name) is None:
+                    if len(self.__password.value()) > 0:
+                        if self.__password.value() == self.__confirm.value():
+                            return True
+                        else:
+                            errors.append("Passwords do not match.")
+                    else:
+                        errors.append("You must enter a password.")
+                else:
+                    errors.append("User %s already exists." % name)
+            else:
+                errors.append("You must enter a username.")
+            self.__confirm.value()
+        return False
+
+    def process_input(self, page):
+        if page is CONFIRM_PAGE:
+            self.__user_worker.create_user(self.__username.value(),
+                                           self.__password.value(),
+                                           "wheel" if self.__adminuser.value() else None)
+            self.set_finished()
+
+    def page_has_next(self, page):
+        return (page is DETAILS_PAGE)
+
+    def page_has_back(self, page):
+        return (page is CONFIRM_PAGE)
+
+    def page_has_finish(self, page):
+        return (page is CONFIRM_PAGE)
+
+    def get_details_page(self, screen):
+        if self.__username is None:
+            self.__username = Entry(50, "")
+            self.__password = Entry(50, "", password = 1)
+            self.__confirm  = Entry(50, "", password = 1)
+            self.__adminuser = Checkbox("This user is an administrator", False)
+        grid = Grid(2, 4)
+        grid.setField(Label("Username:"), 0, 0, anchorRight = 1)
+        grid.setField(self.__username, 1, 0, anchorLeft = 1)
+        grid.setField(Label("Password:"), 0, 1, anchorRight = 1)
+        grid.setField(self.__password, 1, 1, anchorLeft = 1)
+        grid.setField(Label("Confirm password:"), 0, 2, anchorRight = 1)
+        grid.setField(self.__confirm, 1, 2, anchorLeft = 1)
+        grid.setField(Label(" "), 0, 3)
+        grid.setField(self.__adminuser, 1, 3, anchorLeft = 1)
+        return [Label("Enter The User Details"),
+                grid]
+
+    def get_confirm_page(self, screen):
+        grid = Grid(1, 2)
+        grid.setField(Label("Username: %s" % self.__username.value()), 0, 0)
+        admin_label = "is not"
+        if self.__adminuser.value():
+            admin_label = "is"
+        grid.setField(Label("This user %s an administrator." % admin_label), 0, 1)
+        return [Label("Create this user account?"),
+                grid]
+
+def CreateUser():
+    screen = CreateUserConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/definenet.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/definenet.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,257 @@
+# definenet.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from IPy import IP
+import traceback
+import logging
+import re
+
+from configscreen  import ConfigScreen
+from networkconfig import NetworkConfig
+from utils import *
+
+NETWORK_NAME_PAGE            = 1
+IPV4_ADDRESS_PAGE            = 2
+PUBLIC_NETWORK_ALERT_PAGE    = 3
+NETWORK_DETAILS_PAGE         = 4
+DHCP_RANGE_PAGE              = 5
+NETWORK_TYPE_PAGE            = 6
+SELECT_PHYSICAL_NETWORK_PAGE = 7
+SUMMARY_PAGE                 = 8
+
+class DefineNetworkConfigScreen(ConfigScreen):
+    def __init__(self):
+        ConfigScreen.__init__(self, "Create A Virtual Network Interface")
+        self.__config = NetworkConfig()
+
+    def get_elements_for_page(self, screen, page):
+        if   page is NETWORK_NAME_PAGE:            return self.get_network_name_page(screen)
+        elif page is IPV4_ADDRESS_PAGE:            return self.get_ipv4_address_page(screen)
+        elif page is PUBLIC_NETWORK_ALERT_PAGE:    return self.get_public_network_alert_page(screen)
+        elif page is NETWORK_DETAILS_PAGE:         return self.get_network_details_page(screen)
+        elif page is DHCP_RANGE_PAGE:              return self.get_dhcp_range_page(screen)
+        elif page is NETWORK_TYPE_PAGE:            return self.get_network_type_page(screen)
+        elif page is SELECT_PHYSICAL_NETWORK_PAGE: return self.get_select_physical_network_page(screen)
+        elif page is SUMMARY_PAGE:                 return self.get_summary_page(screen)
+
+    def validate_input(self, page, errors):
+        if page is NETWORK_NAME_PAGE:
+            if len(self.__name.value()) > 0:
+                if re.match("^[a-zA-Z0-9_]*$", self.__name.value()):
+                    return True
+                else:
+                    errors.append("The network name can only contain letters, numbers and the underscore, and no spaces.")
+            else:
+                errors.append("Network name must be non-blank and less than 50 characters")
+        elif page is IPV4_ADDRESS_PAGE:
+            if len(self.__ipv4_address.value()) > 0:
+                try:
+                    self.__config.set_ipv4_address(self.__ipv4_address.value())
+                    return True
+                except Exception, error:
+                    errors.append("The network address could not be understood: %s" % str(error))
+            else:
+                errors.append("Network must be entered in the format 1.2.3.4/8")
+        elif page is PUBLIC_NETWORK_ALERT_PAGE: return True
+        elif page is NETWORK_DETAILS_PAGE: return True
+        elif page is DHCP_RANGE_PAGE:
+            try:
+                if len(self.__start_address.value()) > 0 and len(self.__end_address.value()) > 0:
+                    start = IP(self.__start_address.value(), )
+                    end   = IP(self.__end_address.value())
+                    if not self.__config.is_bad_address(start) and not self.__config.is_bad_address(end):
+                        return True
+                    else:
+                        errors.append("Start and/or end address are outside of the choosen network.")
+                else:
+                    errors.append("Start and end address must be non-blank.")
+            except Exception, error:
+                logging.error(str(error))
+                errors.append("The start and/or end addresses could not be understood.")
+        elif page is NETWORK_TYPE_PAGE: return True
+        elif page is SELECT_PHYSICAL_NETWORK_PAGE: return True
+        elif page is SUMMARY_PAGE: return True
+        return False
+
+    def process_input(self, page):
+        if page is NETWORK_NAME_PAGE:
+            self.__config.set_name(self.__name.value())
+        elif page is DHCP_RANGE_PAGE:
+            self.__config.set_ipv4_start_address(self.__start_address.value())
+            self.__config.set_ipv4_end_address(self.__end_address.value())
+        elif page is NETWORK_TYPE_PAGE:
+            self.__config.set_isolated_network(self.__isolated_network.value())
+        elif page is SELECT_PHYSICAL_NETWORK_PAGE:
+            self.__config.set_physical_device(self.__physical_devices.getSelection())
+        elif page is SUMMARY_PAGE:
+            self.get_libvirt().define_network(self.__config)
+            self.set_finished()
+
+    def get_next_page(self, page):
+        if page is IPV4_ADDRESS_PAGE:
+            if self.__config.is_public_ipv4_network():
+                return PUBLIC_NETWORK_ALERT_PAGE
+            else:
+                return NETWORK_DETAILS_PAGE
+        if page is NETWORK_TYPE_PAGE:
+            if self.__config.is_isolated_network():
+                return SUMMARY_PAGE
+            else:
+                return SELECT_PHYSICAL_NETWORK_PAGE
+        return ConfigScreen.get_next_page(self, page)
+
+    def get_back_page(self, page):
+        if page is NETWORK_DETAILS_PAGE:
+            return IPV4_ADDRESS_PAGE
+        if page is SUMMARY_PAGE:
+            if self.__config.is_isolated_network():
+                return NETWORK_TYPE_PAGE
+            else:
+                return SELECT_PHYSICAL_NETWORK_PAGE
+        return ConfigScreen.get_back_page(self, page)
+
+    def page_has_finish(self, page):
+        if page is SUMMARY_PAGE: return True
+        return False
+
+    def page_has_next(self, page):
+        if page < SUMMARY_PAGE: return True
+
+    def page_has_back(self, page):
+        if page > NETWORK_NAME_PAGE: return True
+        return False
+
+    def get_network_name_page(self, screen):
+        self.__name = Entry(50, self.__config.get_name())
+        grid = Grid(2, 1)
+        grid.setField(Label("Network Name:"), 0, 0)
+        grid.setField(self.__name, 1, 0)
+        return [Label("Please choose a name for your virtual network"),
+                grid]
+
+    def get_ipv4_address_page(self, screen):
+        self.__ipv4_address = Entry(18, self.__config.get_ipv4_address())
+        grid = Grid(2, 1)
+        grid.setField(Label("Network:"), 0, 0, anchorRight = 1)
+        grid.setField(self.__ipv4_address, 1, 0, anchorLeft = 1)
+        return [Label("You will need to choose an IPv4 address space for the virtual network:"),
+                grid,
+                Label("HINT: The network should be chosen from"),
+                Label("one of the IPv4 private address ranges;"),
+                Label("e.g., 10.0.0.0/8, 172.168.0.0/12, 192.168.0.0/16")]
+
+    def get_network_details_page(self, screen):
+        grid = Grid(2, 6)
+        grid.setField(Label("Network:"), 0, 0, anchorRight = 1)
+        grid.setField(Label(self.__config.get_ipv4_address()), 1, 0, anchorLeft = 1)
+        grid.setField(Label("Netmask:"), 0, 1, anchorRight = 1)
+        grid.setField(Label(self.__config.get_ipv4_netmask()), 1, 1, anchorLeft = 1)
+        grid.setField(Label("Broadcast:"), 0, 2, anchorRight = 1)
+        grid.setField(Label(self.__config.get_ipv4_broadcast()), 1, 2, anchorLeft = 1)
+        grid.setField(Label("Gateway:"), 0, 3, anchorRight = 1)
+        grid.setField(Label(self.__config.get_ipv4_gateway()), 1, 3, anchorLeft = 1)
+        grid.setField(Label("Size:"), 0, 4, anchorRight = 1)
+        grid.setField(Label("%d addresses" % self.__config.get_ipv4_max_addresses()), 1, 4, anchorLeft = 1)
+        grid.setField(Label("Type:"), 0, 5, anchorRight = 1)
+        grid.setField(Label(self.__config.get_ipv4_network_type()), 1, 5, anchorLeft = 1)
+        return [Label("Network Details"),
+                grid]
+
+    def get_public_network_alert_page(self, screen):
+        grid = Grid(1, 2)
+        grid.setField(Label("The network should normally use a private IPv4 address."), 0, 0, anchorLeft = 1)
+        grid.setField(Label("Use this non-private address anyway?"), 0, 1, anchorLeft = 1)
+        return [Label("Check Network Address"),
+                grid]
+
+    def get_dhcp_range_page(self, screen):
+        self.__start_address = Entry(15, self.__config.get_ipv4_start_address())
+        self.__end_address   = Entry(15, self.__config.get_ipv4_end_address())
+        grid = Grid(2,2)
+        grid.setField(Label("Start:"), 0, 0, anchorRight = 1)
+        grid.setField(self.__start_address, 1, 0, anchorLeft = 1)
+        grid.setField(Label("End:"), 0, 1, anchorRight = 1)
+        grid.setField(self.__end_address, 1, 1, anchorLeft = 1)
+        return [Label("Selecting The DHCP Range"),
+                grid,
+                Label("TIP: Unless you wish to reserve some addresses to allow static network"),
+                Label("configuration in virtual machines, these paraemters can be left with"),
+                Label("their default values.")]
+
+    def get_network_type_page(self, screen):
+        self.__isolated_network = Checkbox("Isolated virtual network",
+                                           self.__config.is_isolated_network())
+        grid = Grid(1, 3)
+        grid.setField(Label("Please indicate whether this virtual network should be"), 0, 0, anchorLeft = 1)
+        grid.setField(Label("connected to the physical network."), 0, 1, anchorLeft = 1)
+        grid.setField(self.__isolated_network, 0, 2)
+        return [Label("Connecting To Physical Network"),
+                grid]
+
+    def get_select_physical_network_page(self, screen):
+        devices = []
+        devices.append(["NAT to any physical device", "", self.__config.get_physical_device() == ""])
+        for device in self.get_hal().list_network_devices():
+            devices.append(["NAT to physical device %s" % device, device, self.__config.get_physical_device() == device])
+        self.__physical_devices = RadioBar(screen, (devices))
+        grid = Grid(1, 2)
+        grid.setField(Label("Forward to physical network:"), 0, 0)
+        grid.setField(self.__physical_devices, 0, 1)
+        return [Label("Connecting To Physical Network"),
+                grid]
+
+    def get_summary_page(self, screen):
+        grid1 = Grid(2, 1)
+        grid1.setField(Label("Network name:"), 0, 0, anchorRight = 1)
+        grid1.setField(Label(self.__config.get_name()), 1, 0, anchorLeft = 1)
+
+        grid2 = Grid(2, 3)
+        grid2.setField(Label("Network:"), 0, 0, anchorRight = 1)
+        grid2.setField(Label(self.__config.get_ipv4_address()), 1, 0, anchorLeft = 1)
+        grid2.setField(Label("Gateway:"), 0, 1, anchorRight = 1)
+        grid2.setField(Label(self.__config.get_ipv4_gateway()), 1, 1, anchorLeft = 1)
+        grid2.setField(Label("Netmask:"), 0, 2, anchorRight = 1)
+        grid2.setField(Label(self.__config.get_ipv4_netmask()), 1, 2, anchorLeft = 1)
+
+        grid3 = Grid(2, 2)
+        grid3.setField(Label("Start address:"), 0, 0, anchorRight = 1)
+        grid3.setField(Label(self.__config.get_ipv4_start_address()), 1, 0, anchorLeft = 1)
+        grid3.setField(Label("End address:"), 0, 1, anchorRight = 1)
+        grid3.setField(Label(self.__config.get_ipv4_end_address()), 1, 1, anchorLeft = 1)
+
+        grid4 = Grid(2, 1)
+        grid4.setField(Label("Connectivity:"), 0, 0, anchorRight = 1)
+        if self.__config.is_isolated_network():
+            grid4.setField(Label("Isolated virtual network"), 1, 0, anchorLeft = 1)
+        else:
+            grid4.setField(Label("NAT to %s" % self.__config.get_physical_device_text()), 1, 0, anchorLeft = 1)
+
+        return [Label("Ready To Create Network"),
+                Label("Summary"),
+                grid1,
+                Label("IPv4 Network"),
+                grid2,
+                Label("DHCP"),
+                grid3,
+                Label("Forwarding"),
+                grid4]
+
+def DefineNetwork():
+    screen = DefineNetworkConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/destroynetwork.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/destroynetwork.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#
+# destroynetwork.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+LIST_PAGE    = 1
+DESTROY_PAGE = 2
+
+class DestroyNetworkConfigScreen(NetworkListConfigScreen):
+    def __init__(self):
+        NetworkListConfigScreen.__init__(self, "Destroy A Network")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_PAGE:    return self.get_network_list_page(screen, defined = False)
+        elif page is DESTROY_PAGE: return self.get_destroy_network_page(screen)
+
+    def page_has_next(self, page):
+        if page is LIST_PAGE: return self.has_selectable_networks()
+        return False
+
+    def page_has_back(self, page):
+        if page is DESTROY_PAGE: return True
+        return False
+
+    def validate_input(self, page, errors):
+        if page is LIST_PAGE:
+            network = self.get_selected_network()
+            self.get_libvirt().destroy_network(network)
+            return True
+        return False
+
+    def get_destroy_network_page(self, screen):
+        return [Label("Network Destroyed"),
+                Label("%s has been destroyed." % self.get_selected_network())]
+
+def DestroyNetwork():
+    screen = DestroyNetworkConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/domainconfig.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/domainconfig.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,224 @@
+# domainconfig.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from virtinst import Guest
+
+class DomainConfig:
+    LOCAL_INSTALL   = "local"
+    NETWORK_INSTALL = "network"
+    PXE_INSTALL     = "pxe"
+    INSTALL_TYPE_TEXT = {LOCAL_INSTALL   : "Local CDROM/ISO",
+                         NETWORK_INSTALL : "URL INstall Tree",
+                         PXE_INSTALL     : "PXE Install"}
+
+    INSTALL_SOURCE_CDROM = "cdrom"
+    INSTALL_SOURCE_ISO   = "iso"
+
+    NEW_STORAGE      = "new"
+    EXISTING_STORAGE = "existing"
+
+    def __init__(self):
+        self.__guest_name = ""
+        self.__install_type = DomainConfig.LOCAL_INSTALL
+        self.__use_cdrom_source = True
+        self.__install_location = ""
+        self.__install_media = ""
+        self.__iso_path = ""
+        self.__install_url = ""
+        self.__kickstart_url = ""
+        self.__kernel_options = ""
+        self.__os_type = "other"
+        self.__os_variant = None
+        self.__memory = 512
+        self.__cpus = 1
+        self.__enable_storage = True
+        self.__use_local_storage = True
+        self.__storage_size = 8.0
+        self.__allocate_storage = True
+        self.__storage_pool = ""
+        self.__storage_volume = ""
+        self.__network_bridge = None
+        self.__mac_address = None
+        self.__virt_type = None
+        self.__architecture = None
+
+    def set_guest_name(self, name):
+        self.__guest_name = name
+
+    def get_guest_name(self):
+        return self.__guest_name
+
+    def set_install_type(self, type):
+        self.__install_type = type
+
+    def get_install_type(self):
+        return self.__install_type
+
+    def get_install_type_text(self):
+        return DomainConfig.INSTALL_TYPE_TEXT[self.get_install_type()]
+
+    def is_install_type(self, type):
+        return self.__install_type == type
+
+    def set_install_location(self, location):
+        self.__install_location = location
+
+    def set_use_cdrom_source(self, use):
+        self.__use_cdrom_source = use
+
+    def get_use_cdrom_source(self):
+        return self.__use_cdrom_source
+
+    def get_install_location(self):
+        return self.__install_location
+
+    def is_install_location(self, location):
+        return self.__install_location == location
+
+    def set_install_media(self, media):
+        self.__install_media = media
+
+    def get_install_media(self):
+        return self.__install_media
+
+    def is_install_media(self, media):
+        return self.__install_media == media
+
+    def set_iso_path(self, path):
+        self.__iso_path = path
+
+    def get_iso_path(self):
+        return self.__iso_path
+
+    def set_install_url(self, url):
+        self.__install_url = url
+
+    def get_install_url(self):
+        return self.__install_url
+
+    def set_kickstart_url(self, url):
+        self.__kickstart_url = url
+
+    def get_kickstart_url(self):
+        return self.__kickstart_url
+
+    def set_kernel_options(self, options):
+        self.__kernel_options = options
+
+    def get_kernel_options(self):
+        return self.__kernel_options
+
+    def set_os_type(self, type):
+        self.__os_type = type
+        self.__os_variant = Guest.list_os_variants(type)[0]
+
+    def get_os_type(self):
+        return self.__os_type
+
+    def is_os_type(self, type):
+        return self.__os_type == type
+
+    def set_os_variant(self, variant):
+        self.__os_variant = variant
+
+    def get_os_variant(self):
+        return self.__os_variant
+
+    def is_os_variant(self, variant):
+        return self.__os_variant == variant
+
+    def set_memory(self, memory):
+        self.__memory = int(memory)
+
+    def get_memory(self):
+        return self.__memory
+
+    def set_cpus(self, cpus):
+        self.__cpus = cpus
+
+    def get_cpus(self):
+        return self.__cpus
+
+    def set_enable_storage(self, enable):
+        self.__enable_storage = enable
+
+    def get_enable_storage(self):
+        return self.__enable_storage
+
+    def set_use_local_storage(self, use):
+        self.__use_local_storage = use
+
+    def get_use_local_storage(self):
+        return self.__use_local_storage
+
+    def set_storage_size(self, size):
+        self.__storage_size = size
+
+    def get_storage_size(self):
+        return self.__storage_size
+
+    def set_allocate_storage(self, allocate):
+        self.__allocate_storage = allocate
+
+    def get_allocate_storage(self):
+        return self.__allocate_storage
+
+    def set_storage_pool(self, pool):
+        self.__storage_pool = pool
+
+    def get_storage_pool(self):
+        return self.__storage_pool
+
+    def set_storage_volume(self, volume):
+        self.__storage_volume = volume
+
+    def get_storage_volume(self):
+        return self.__storage_volume
+
+    def is_existing_storage(self, storage):
+        return self.__existing_storage == storage
+
+    def set_network_bridge(self, bridge):
+        self.__network_bridge = bridge
+
+    def get_network_bridge(self):
+        return self.__network_bridge
+
+    def set_mac_address(self, address):
+        self.__mac_address = address
+
+    def get_mac_address(self):
+        return self.__mac_address
+
+    def set_virt_type(self, type):
+        self.__virt_type = type
+
+    def get_virt_type(self):
+        return self.__virt_type
+
+    def is_virt_type(self, type):
+        return self.__virt_type == type
+
+    def set_architecture(self, architecture):
+        self.__architecture = architecture
+
+    def get_architecture(self):
+        return self.__architecture
+
+    def is_architecture(self, architecture):
+        return self.__architecture == architecture
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/halworker.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/halworker.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,45 @@
+# halworker.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+import dbus
+import virtinst
+
+class HALWorker:
+    '''Provides utilities for working with HAL to get hardware information.'''
+    def __init__(self):
+        self.__bus = dbus.SystemBus()
+        hobj = self.__bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager")
+        self.__conn = dbus.Interface(hobj, "org.freedesktop.Hal.Manager")
+
+    def list_installable_volumes(self):
+        result = {}
+        for udi in self.__conn.FindDeviceByCapability("volume"):
+            device = self.__bus.get_object("org.freedesktop.Hal", udi)
+            info = dbus.Interface(device, "org.freedesktop.Hal.Device")
+            if info.GetProperty("volume.is_disc"):
+                if info.GetProperty("volume.disc.has_data"):
+                    result[str(info.GetProperty("block.device"))] = info.GetProperty("volume.label")
+        return result
+
+    def list_network_devices(self):
+        result = []
+        for udi in self.__conn.FindDeviceByCapability("net"):
+            device = self.__bus.get_object("org.freedesktop.Hal", udi)
+            info = dbus.Interface(device, "org.freedesktop.Hal.Device")
+            result.append(info.GetProperty("net.interface"))
+        return result
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/hostconnect.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/hostconnect.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,29 @@
+# hostconnect.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from configscreen import *
+
+class HostConnectConfigScreen(ConfigScreen):
+    def __init__(self):
+        ConfigScree
+
+def HostConnect():
+    screen = HostConnectConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/hostmenu.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/hostmenu.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,46 @@
+# hostmenu.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from menuscreen import MenuScreen
+from changehost import ChangeHost
+from addhost    import AddHost
+from removehost import RemoveHost
+
+SELECT_HOST = 1
+ADD_HOST    = 2
+REMOVE_HOST = 3
+
+class HostMenuScreen(MenuScreen):
+    def __init__(self):
+        MenuScreen.__init__(self, "Host Menu Screen")
+
+    def get_menu_items(self):
+        return (("Select A Host", SELECT_HOST),
+                ("Add A Host",    ADD_HOST),
+                ("Remove A Host", REMOVE_HOST))
+
+    def handle_selection(self, item):
+        if   item is SELECT_HOST: ChangeHost()
+        elif item is ADD_HOST:    AddHost()
+        elif item is REMOVE_HOST: RemoveHost()
+
+def HostMenu():
+    screen = HostMenuScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/libvirtworker.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/libvirtworker.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,461 @@
+# libvirtworker.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+import dbus
+import libvirt
+import os
+import virtinst
+import utils
+import logging
+
+from domainconfig import DomainConfig
+
+DEFAULT_POOL_TARGET_PATH="/var/lib/libvirt/images"
+DEFAULT_URL="qemu:///system"
+
+default_url = DEFAULT_URL
+
+def set_default_url(url):
+    logging.info("Changing DEFAULT_URL to %s" % url)
+    global default_url
+
+    default_url = url
+
+def get_default_url():
+    logging.info("Returning default URL of %s" % default_url)
+    return default_url
+
+class VirtManagerConfig:
+    def __init__(self, filename = "/etc/remote-libvirt.conf"):
+        self.__filename = filename
+
+    def get_connection_list(self):
+        result = []
+        if os.path.exists(self.__filename):
+            input = file(self.__filename, "r")
+            for entry in input: result.append(entry[0:-1])
+        return result
+
+    def add_connection(self, connection):
+        connections = self.get_connection_list()
+        if connections.count(connection) is 0:
+            connections.append(connection)
+            self._save_connections(connections)
+
+    def remove_connection(self, connection):
+        connections = self.get_connection_list()
+        if connections.count(connection) > 0:
+            connections.remove(connection)
+            self._save_connections(connections)
+
+    def _save_connections(self, connections):
+        output = file(self.__filename, "w")
+        for entry in connections:
+            print >> output, entry
+        output.close
+
+class LibvirtWorker:
+    '''Provides utilities for interfacing with libvirt.'''
+    def __init__(self, url = None):
+        if url is None: url = get_default_url()
+        logging.info("Connecting to libvirt: %s" % url)
+        self.__url  = None
+        self.__conn = None
+        self.open_connection(url)
+        self.__capabilities = virtinst.CapabilitiesParser.parse(self.__conn.getCapabilities())
+        self.__net = virtinst.VirtualNetworkInterface(conn = self.__conn)
+        self.__net.setup(self.__conn)
+        (self.__new_guest, self.__new_domain) = virtinst.CapabilitiesParser.guest_lookup(conn = self.__conn)
+
+    def get_connection(self):
+        '''Returns the underlying connection.'''
+        return self.__conn
+
+    def get_url(self):
+        return self.__url
+
+    def open_connection(self, url):
+        '''Lets the user change the url for the connection.'''
+        old_conn = self.__conn
+        old_url  = self.__url
+        try:
+            self.__conn = libvirt.open(url)
+            self.__url  = url
+            set_default_url(url)
+        except Exception, error:
+            self.__conn = old_conn
+            self.__url  = old_url
+            raise error
+
+    def list_domains(self, defined = True, started = True):
+        '''Lists all domains.'''
+        result = []
+        if defined:
+            result.extend(self.__conn.listDefinedDomains())
+        if started:
+            for id in self.__conn.listDomainsID():
+                result.append(self.__conn.lookupByID(id).name())
+        return result
+
+    def get_domain(self, name):
+        '''Returns the specified domain.'''
+        result = self.__conn.lookupByName(name)
+        if result is None: raise Exception("No such domain exists: %s" % name)
+
+        return result
+
+    def domain_exists(self, name):
+        '''Returns whether a domain with the specified node exists.'''
+        domains = self.list_domains()
+        if name in domains: return True
+        return False
+
+    def create_domain(self, name):
+        '''Creates the specified domain.'''
+        domain = self.get_domain(name)
+        domain.create()
+
+    def destroy_domain(self, name):
+        '''Destroys the specified domain.'''
+        domain = self.get_domain(name)
+        domain.destroy()
+
+    def undefine_domain(self, name):
+        '''Undefines the specified domain.'''
+        domain = self.get_domain(name)
+        domain.undefine()
+
+    def migrate_domain(self, name, target):
+        '''Migrates the specified domain to the target machine.'''
+        target_conn = libvirt.open(target)
+        virtmachine = self.get_domain(name)
+        virtmachine.migrate(target_conn, libvirt.VIR_MIGRATE_LIVE, None, None, 0)
+
+    def list_networks(self, defined = True, started = True):
+        '''Lists all networks.'''
+        result = []
+        if defined: result.extend(self.__conn.listDefinedNetworks())
+        if started: result.extend(self.__conn.listNetworks())
+        return result
+
+    def get_network(self, name):
+        '''Returns the specified network.'''
+        result = self.__conn.networkLookupByName(name)
+        if result is None: raise Exception("No such network exists: %s" % name)
+
+        return result
+
+    def network_exists(self, name):
+        '''Returns if a network with the given name already exists.'''
+        networks = self.list_networks()
+        if name in networks: return True
+        return False
+
+    def define_network(self, config):
+        '''Defines a new network.'''
+        # since there's no other way currently, we'll have to use XML
+        name = config.get_name()
+        ip = config.get_ipv4_address_raw()
+        start = config.get_ipv4_start_address()
+        end = config.get_ipv4_end_address()
+        fw = config.get_physical_device()
+
+        xml = "<network>" + \
+              "  <name>%s</name>\n" % name
+        if not config.is_public_ipv4_network():
+            if fw is not "":
+                xml += "  <forward dev='%s'/>\n" % fw[1]
+            else:
+                xml += "  <forward/>\n"
+
+        xml += "  <ip address='%s' netmask='%s'>\n" % (str(ip[1]), str(ip.netmask()))
+        xml += "    <dhcp>\n"
+        xml += "      <range start='%s' end='%s'/>\n" % (str(start), str(end))
+        xml += "    </dhcp>\n"
+        xml += "  </ip>\n"
+        xml += "</network>\n"
+
+        self.__conn.networkDefineXML(xml)
+
+    def create_network(self, name):
+        '''Creates a defined network.'''
+        network = self.get_network(name)
+        network.create()
+
+    def destroy_network(self, name):
+        '''Destroys the specified network.'''
+        network = self.get_network(name)
+        network.destroy()
+
+    def undefine_network(self, name):
+        '''Undefines the specified network.'''
+        network = self.get_network(name)
+        network.undefine()
+
+    def list_storage_pools(self, defined=True, created=True):
+        '''Returns the list of all defined storage pools.'''
+        pools = []
+        if defined: pools.extend(self.__conn.listDefinedStoragePools())
+        if created: pools.extend(self.__conn.listStoragePools())
+        return pools
+
+    def storage_pool_exists(self, name):
+        '''Returns whether a storage pool exists.'''
+        pools = self.list_storage_pools()
+        if name in pools: return True
+        return False
+
+    def create_storage_pool(self, name):
+        '''Starts the named storage pool if it is not currently started.'''
+        if name not in self.list_storage_pools(defined = False):
+            pool = self.get_storage_pool(name)
+            pool.create(0)
+
+    def destroy_storage_pool(self, name):
+        '''Stops the specified storage pool.'''
+        if name in self.list_storage_pools(defined = False):
+            pool = self.get_storage_pool(name)
+            pool.destroy()
+
+    def define_storage_pool(self, name, config = None, meter = None):
+        '''Defines a storage pool with the given name.'''
+        if config is None:
+            pool = virtinst.Storage.DirectoryPool(conn=self.__conn,
+                                                  name=name,
+                                                  target_path=DEFAULT_POOL_TARGET_PATH)
+            newpool = pool.install(build=True, create=True, meter=meter)
+            newpool.setAutostart(True)
+        else:
+            pool = config.get_pool()
+            pool.target_path = config.get_target_path()
+            if config.needs_hostname():
+                pool.host = config.get_hostname()
+            if config.needs_source_path():
+                pool.source_path = config.get_source_path()
+            if config.needs_format():
+                pool.format = config.get_format()
+            pool.conn = self.__conn
+            pool.get_xml_config()
+            newpool = pool.install(meter=meter,
+                                   build=True, # config.get_build_pool(),
+                                   create=True)
+            newpool.setAutostart(True)
+
+    def undefine_storage_pool(self, name):
+        '''Undefines the specified storage pool.'''
+        pool = self.get_storage_pool(name)
+        pool.undefine()
+
+    def get_storage_pool(self, name):
+        '''Returns the storage pool with the specified name.'''
+        return self.__conn.storagePoolLookupByName(name)
+
+    def list_storage_volumes(self, poolname):
+        '''Returns the list of all defined storage volumes for a given pool.'''
+        pool = self.get_storage_pool(poolname)
+        return pool.listVolumes()
+
+    def define_storage_volume(self, config, meter):
+        '''Defines a new storage volume.'''
+        self.create_storage_pool(config.get_pool().name())
+        volume = config.create_volume()
+        volume.install(meter = meter)
+
+    def remove_storage_volume(self, poolname, volumename):
+        '''Removes the specified storage volume.'''
+        volume = self.get_storage_volume(poolname, volumename)
+        volume.delete(0)
+
+    def get_storage_volume(self, poolname, volumename):
+        '''Returns a reference to the specified storage volume.'''
+        pool =self.get_storage_pool(poolname)
+        volume = pool.storageVolLookupByName(volumename)
+        return volume
+
+    def list_bridges(self):
+        '''Lists all defined and active bridges.'''
+        bridges = self.__conn.listNetworks()
+        bridges.extend(self.__conn.listDefinedNetworks())
+        result = []
+        for name in bridges:
+            bridge = self.__conn.networkLookupByName(name)
+            result.append(bridge)
+        return result
+
+    def generate_mac_address(self):
+        return self.__net.macaddr
+
+    def get_storage_size(self, poolname, volumename):
+        '''Returns the size of the specified storage volume.'''
+        volume = self.get_storage_volume(poolname, volumename)
+        return volume.info()[1] / (1024.0 ** 3)
+
+    def get_virt_types(self):
+        result = []
+        for guest in self.__capabilities.guests:
+            guest_type = guest.os_type
+            for domain in guest.domains:
+                domain_type = domain.hypervisor_type
+                label = domain_type
+
+                if domain_type is "kvm" and guest_type is "xen": label = "xenner"
+                elif domain_type is "xen":
+                    if guest_type is "xen":
+                        label = "xen (paravirt)"
+                    elif guest_type is "kvm":
+                        label = "xen (fullvirt)"
+                elif domain_type is "test":
+                    if guest_type is "xen":
+                        label = "test (xen)"
+                    elif guest_type is "hvm":
+                        label = "test (hvm)"
+
+                for row in result:
+                    if row[0] == label:
+                        label = None
+                        break
+                if label is None: continue
+
+                result.append([label, domain_type, guest_type])
+        return result
+
+    def list_virt_types(self):
+        virt_types = self.get_virt_types()
+        result = []
+        for type in virt_types:
+            result.append(type[0])
+        return result
+
+    def get_default_architecture(self):
+        '''Returns a default hypervisor type for new domains.'''
+        return self.__new_guest.arch
+
+    def get_hypervisor(self, virt_type):
+        virt_types = self.get_virt_types()
+        for type in virt_types:
+            if type[0] is virt_type: return type[1]
+        return None
+
+    def get_default_virt_type(self):
+        '''Returns the default virtualization type for new domains.'''
+        return self.__new_domain.hypervisor_type
+
+    def get_os_type(self, virt_type):
+        virt_types = self.get_virt_types()
+        for type in virt_types:
+            if type[0] is virt_type: return type[2]
+        return None
+
+    def list_architectures(self):
+        result = []
+        for guest in self.__capabilities.guests:
+            for domain in guest.domains:
+                label = guest.arch
+                for row in result:
+                    if row == label:
+                        label = None
+                        break
+                if label is None: continue
+
+                result.append(label)
+        return result
+
+    def define_domain(self, config, meter):
+        location = extra = kickstart = None
+
+        if config.get_install_type() == DomainConfig.LOCAL_INSTALL:
+            if config.get_use_cdrom_source():
+                iclass = virtinst.DistroInstaller
+                location = config.get_install_media()
+            else:
+                iclass = virtinst.LiveCDInstaller
+                location = config.get_iso_path()
+        elif config.get_install_type() == DomainConfig.NETWORK_INSTALL:
+            iclass = virtinst.DistroInstaller
+            location = config.get_install_url()
+            extra = config.get_kernel_options()
+            kickstart = config.get_kickstart_url()
+        elif config.get_install_type() == DomainConfig.PXE_INSTALL:
+            iclass = virtinst.PXEInstaller
+
+        installer = iclass(conn = self.__conn,
+                           type = self.get_hypervisor(config.get_virt_type()),
+                           os_type = self.get_os_type(config.get_virt_type()))
+        self.__guest = installer.guest_from_installer()
+        self.__guest.name = config.get_guest_name()
+        self.__guest.vcpus = config.get_cpus()
+        self.__guest.memory = config.get_memory()
+        self.__guest.maxmemory = config.get_memory()
+
+        self.__guest.installer.location = location
+        if config.get_use_cdrom_source(): self.__guest.installer.cdrom = True
+        extraargs = ""
+        if extra: extraargs += extra
+        if kickstart: extraargs += " ks=%s" % kickstart
+        if extraargs: self.__guest.installer.extraarags = extraargs
+
+        self.__guest.uuid = virtinst.util.uuidToString(virtinst.util.randomUUID())
+
+        if config.get_os_type() != "generic": self.__guest.os_type = config.get_os_type()
+        if config.get_os_variant() != "generic": self.__guest.os_variant = config.get_os_variant()
+
+        self.__guest._graphics_dev = virtinst.VirtualGraphics(type = virtinst.VirtualGraphics.TYPE_VNC)
+        self.__guest.sound_devs = []
+        self.__guest.sound_devs.append(virtinst.VirtualAudio(model = "es1370"))
+
+        self._setup_nics(config)
+        self._setup_disks(config)
+
+        self.__guest.conn = self.__conn
+        self.__domain = self.__guest.start_install(False, meter = meter)
+
+    def _setup_nics(self, config):
+        self.__guest.nics = []
+        nic = virtinst.VirtualNetworkInterface(type = virtinst.VirtualNetworkInterface.TYPE_VIRTUAL,
+                                               bridge = config.get_network_bridge(),
+                                               network = config.get_network_bridge(),
+                                               macaddr = config.get_mac_address())
+        self.__guest.nics.append(nic)
+        # ensure the network is running
+        if config.get_network_bridge() not in self.__conn.listNetworks():
+            network = self.__conn.networkLookupByName(config.get_network_bridge())
+            network.create()
+
+    def _setup_disks(self, config):
+        self.__guest.disks = []
+        if config.get_enable_storage():
+            path = None
+            if config.get_use_local_storage():
+                if self.storage_pool_exists("default") is False:
+                    self.define_storage_pool("default")
+                pool = self.__conn.storagePoolLookupByName("default")
+                path = virtinst.Storage.StorageVolume.find_free_name(config.get_guest_name(),
+                                                                     pool_object = pool,
+                                                                     suffix = ".img")
+                path = os.path.join(DEFAULT_POOL_TARGET_PATH, path)
+            else:
+                volume = self.get_storage_volume(config.get_storage_pool(),
+                                                 config.get_storage_volume())
+                path = volume.path()
+
+            if path is not None:
+                storage= virtinst.VirtualDisk(conn = self.__conn,
+                                              path = path,
+                                              size = config.get_storage_size())
+                self.__guest.disks.append(storage)
+        self.__guest.conn = self.__conn
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/listdomains.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/listdomains.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# listdomains.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from libvirtworker import LibvirtWorker
+from configscreen import *
+
+class ListDomainsConfigScreen(DomainListConfigScreen):
+    LIST_PAGE   = 1
+    DETAIL_PAGE = 2
+
+    def __init__(self):
+        DomainListConfigScreen.__init__(self, 'List Virtual Machines')
+
+    def page_has_next(self, page):
+        return (page == self.LIST_PAGE)
+
+    def page_has_back(self, page):
+        return (page == self.DETAIL_PAGE)
+
+    def validate_input(self, page, errors):
+        if page == self.LIST_PAGE:
+            if self.get_selected_domain() is None:
+                errors.append("Please select a virtual machine to view.")
+            else:
+                return True
+
+    def get_elements_for_page(self, screen, page):
+        if page == self.LIST_PAGE:
+            return self.get_domain_list_page(screen)
+        elif page == self.DETAIL_PAGE:
+            return self.get_detail_page_elements(screen)
+
+    def get_detail_page_elements(self, screen):
+        domain = self.get_libvirt().get_domain(self.get_selected_domain())
+        grid = Grid(2, 5)
+        grid.setField(Label("Name:  "), 0, 0, anchorRight = 1)
+        grid.setField(Label(domain.name()), 1, 0, anchorLeft = 1)
+        grid.setField(Label("UUID:  "), 0, 1, anchorRight = 1)
+        grid.setField(Label(domain.UUIDString()), 1, 1, anchorLeft = 1)
+        grid.setField(Label("OS Type:  "), 0, 2, anchorRight = 1)
+        grid.setField(Label(domain.OSType()), 1, 2, anchorLeft = 1)
+        grid.setField(Label("Max. Memory:  "), 0, 3, anchorRight = 1)
+        grid.setField(Label(str(domain.maxMemory())), 1, 3, anchorLeft = 1)
+        grid.setField(Label("Max. VCPUs:  "), 0, 4, anchorRight = 1)
+        grid.setField(Label(str(domain.maxVcpus())), 1, 4, anchorLeft = 1)
+        return [grid]
+
+def ListDomains():
+    screen = ListDomainsConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/listnetworks.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/listnetworks.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,55 @@
+# listnetworks.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from configscreen import *
+
+LIST_PAGE    = 1
+DETAILS_PAGE = 2
+
+class ListNetworksConfigScreen(NetworkListConfigScreen):
+    def __init__(self):
+        NetworkListConfigScreen.__init__(self, "List Networks")
+
+    def page_has_next(self, page):
+        return (page is LIST_PAGE) and self.has_selectable_networks()
+
+    def page_has_back(self, page):
+        return (page is DETAILS_PAGE)
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_PAGE:    return self.get_network_list_page(screen)
+        elif page is DETAILS_PAGE: return self.get_network_details_page(screen)
+
+    def get_network_details_page(self, screen):
+        network = self.get_libvirt().get_network(self.get_selected_network())
+        grid = Grid(2, 3)
+        grid.setField(Label("Name:"), 0, 0, anchorRight = 1)
+        grid.setField(Label(network.name()), 1, 0, anchorLeft = 1)
+        grid.setField(Label("Autostart:"), 0, 1, anchorRight = 1)
+        label = "No"
+        if network.autostart(): label = "Yes"
+        grid.setField(Label(label), 1, 1, anchorLeft = 1)
+        if network.bridgeName() is not "":
+            grid.setField(Label("Bridge:"), 0, 2, anchorRight = 1)
+            grid.setField(Label(network.bridgeName()), 1, 2, anchorLeft = 1)
+        return [Label("Network Interface Details"),
+                grid]
+
+def ListNetworks():
+    screen = ListNetworksConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/listpools.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/listpools.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,64 @@
+# listpools.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from configscreen import *
+from utils import *
+
+LIST_PAGE    = 1
+DETAILS_PAGE = 2
+
+class ListStoragePoolsConfigScreen(StorageListConfigScreen):
+    def __init__(self):
+        StorageListConfigScreen.__init__(self, "List Storage Pools")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_PAGE:    return self.get_storage_pool_list_page(screen)
+        elif page is DETAILS_PAGE: return self.get_pool_details_page(screen)
+
+    def page_has_next(self, page):
+        if page is LIST_PAGE and self.has_selectable_pools():
+                return True
+        return False
+
+    def page_has_back(self, page):
+        if page is DETAILS_PAGE: return True
+        return False
+
+    def get_pool_details_page(self, screen):
+        pool = self.get_libvirt().get_storage_pool(self.get_selected_pool())
+        volumes = Listbox(0);
+        for name in pool.listVolumes():
+            volume = pool.storageVolLookupByName(name)
+            volumes.append("%s (%s)" % (name, size_as_mb_or_gb(volume.info()[1])), name)
+        grid = Grid(2, 3)
+        grid.setField(Label("Name:"), 0, 0, anchorRight = 1)
+        grid.setField(Label(pool.name()), 1, 0, anchorLeft = 1)
+        grid.setField(Label("Volumes:"), 0, 1, anchorRight = 1)
+        grid.setField(volumes, 1, 1, anchorLeft = 1)
+        grid.setField(Label("Autostart:"), 0, 2, anchorRight = 1)
+        label = "No"
+        if pool.autostart(): label = "Yes"
+        grid.setField(Label(label), 1, 2, anchorLeft = 1)
+        return [Label("Details For Storage Pool: %s" % self.get_selected_pool()),
+                grid]
+
+def ListStoragePools():
+    screen = ListStoragePoolsConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/mainmenu.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/mainmenu.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,55 @@
+# mainmenu.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import traceback
+
+from menuscreen  import MenuScreen
+from nodemenu    import NodeMenu
+from netmenu     import NetworkMenu
+from storagemenu import StoragePoolMenu
+from hostmenu    import HostMenu
+
+import utils
+import logging
+
+NODE_MENU    =  1
+NETWORK_MENU =  2
+STORAGE_MENU =  3
+HOST_MENU    =  4
+EXIT_CONSOLE = 99
+
+class MainMenuScreen(MenuScreen):
+    def __init__(self):
+        MenuScreen.__init__(self, "Main Menu")
+
+    def get_menu_items(self):
+        return (("Node Administration",         NODE_MENU),
+                ("Network Administration",      NETWORK_MENU),
+                ("Storage Pool Administration", STORAGE_MENU),
+                ("Host Administration",         HOST_MENU))
+
+    def handle_selection(self, page):
+        if   page is NODE_MENU:    NodeMenu()
+        elif page is NETWORK_MENU: NetworkMenu()
+        elif page is STORAGE_MENU: StoragePoolMenu()
+        elif page is HOST_MENU:    HostMenu()
+
+def MainMenu():
+    screen = MainMenuScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/menuscreen.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/menuscreen.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,57 @@
+# mainmenu.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import traceback
+
+import utils
+import logging
+
+EXIT_MENU = 99
+
+class MenuScreen:
+    def __init__(self, title):
+        self.__title = title
+
+    def start(self):
+        finished = False
+        while finished == False:
+            screen = SnackScreen()
+            menu = Listbox(height = 0, width = 0, returnExit = 1)
+            for menu_item in self.get_menu_items():
+                menu.append(menu_item[0], menu_item[1])
+            menu.append("Exit Menu", EXIT_MENU)
+            gridform = GridForm(screen, self.__title, 1, 4)
+            gridform.add(menu, 0, 0)
+            result = gridform.run();
+            screen.popWindow()
+            screen.finish()
+
+            try:
+                if result.current() == EXIT_MENU: finished = True
+                else: self.handle_selection(result.current())
+            except Exception, error:
+                screen = SnackScreen()
+                logging.info("An exception occurred: %s" % str(error))
+                ButtonChoiceWindow(screen,
+                                   "An Exception Has Occurred",
+                                   str(error) + "\n" + traceback.format_exc(),
+                                   buttons = ["OK"])
+                screen.popWindow()
+                screen.finish()
+                finished = True
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/migratedomain.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/migratedomain.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+# migratedomain.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from libvirtworker import LibvirtWorker
+from configscreen import *
+
+LIST_DOMAINS  = 1
+SELECT_TARGET = 2
+CONFIRM_PAGE  = 3
+
+class MigrateDomainConfigScreen(DomainListConfigScreen):
+    def __init__(self):
+        DomainListConfigScreen.__init__(self, "Migrate Virtual Machine")
+        self.__configured = False
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_DOMAINS:  return self.get_domain_list_page(screen)
+        elif page is SELECT_TARGET: return self.get_target_page(screen)
+        elif page is CONFIRM_PAGE:  return self.get_confirm_page(screen)
+
+    def page_has_next(self, page):
+        if   page is LIST_DOMAINS: return self.has_selectable_domains()
+        else: return page < CONFIRM_PAGE
+
+    def page_has_back(self, page):
+        return page < CONFIRM_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_PAGE
+
+    def validate_input(self, page, errors):
+        if   page is LIST_DOMAINS: return self.get_selected_domain() is not None
+        elif page is SELECT_TARGET:
+            if self.__targets.current() is None:
+                errors.append("Please enter a target hostname or IP address.")
+                return False
+        elif page is CONFIRM_PAGE:
+            if not self.__confirm.value():
+                errors.append("You must confirm migrating this virtual machine to proceed.")
+                return False
+        return True
+
+    def process_input(self, page):
+        if page is CONFIRM_PAGE:
+            self.get_libvirt().migrate_domain(self.get_selected_domain(), self.__targets.current())
+            self.set_finished()
+
+    def get_target_page(self, screen):
+        self.__targets = Listbox(0)
+        for connection in self.get_virt_manager_config().get_connection_list():
+            self.__targets.append(connection, connection)
+        return [Label("Select A Target Host"),
+                self.__targets]
+
+    def get_confirm_page(self, screen):
+        self.__confirm = Checkbox("Confirm migrating this virtual machine.")
+        grid = Grid(1, 1)
+        grid.setField(self.__confirm, 0, 0)
+        return [grid]
+
+def MigrateDomain():
+    screen = MigrateDomainConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/netmenu.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/netmenu.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,58 @@
+# mainmenu.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import traceback
+
+from menuscreen      import MenuScreen
+from definenet       import DefineNetwork
+from createnetwork   import CreateNetwork
+from destroynetwork  import DestroyNetwork
+from undefinenetwork import UndefineNetwork
+from listnetworks    import ListNetworks
+
+import utils
+import logging
+
+DEFINE_NETWORK   = 1
+CREATE_NETWORK   = 2
+DESTROY_NETWORK  = 3
+UNDEFINE_NETWORK = 4
+LIST_NETWORKS    = 5
+
+class NetworkMenuScreen(MenuScreen):
+    def __init__(self):
+        MenuScreen.__init__(self, "Network Administration")
+
+    def get_menu_items(self):
+        return (("Define A Network",   DEFINE_NETWORK),
+                ("Create A Network",   CREATE_NETWORK),
+                ("Destroy A Network",  DESTROY_NETWORK),
+                ("Undefine A Network", UNDEFINE_NETWORK),
+                ("List Networks",      LIST_NETWORKS))
+
+    def handle_selection(self, item):
+        if   item is DEFINE_NETWORK:   DefineNetwork()
+        elif item is CREATE_NETWORK:   CreateNetwork()
+        elif item is DESTROY_NETWORK:  DestroyNetwork()
+        elif item is UNDEFINE_NETWORK: UndefineNetwork()
+        elif item is LIST_NETWORKS:    ListNetworks()
+
+def NetworkMenu():
+    screen = NetworkMenuScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/networkconfig.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/networkconfig.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,99 @@
+# networkconfig.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from IPy import IP
+import logging
+
+class NetworkConfig:
+    def __init__(self):
+        self.__name = ""
+        self.set_ipv4_address("192.168.100.0/24")
+        self.__isolated_network = True
+        self.__physical_device = ""
+
+    def set_name(self, name):
+        self.__name = name
+
+    def get_name(self):
+        return self.__name
+
+    def set_ipv4_address(self, address):
+        self.__ipv4_address = IP(address)
+        start = int(self.__ipv4_address.len() / 2)
+        end   = self.__ipv4_address.len() - 2
+        self.__ipv4_start = str(self.__ipv4_address[start])
+        self.__ipv4_end   = str(self.__ipv4_address[end])
+
+    def get_ipv4_address(self):
+        return self.__ipv4_address.strNormal()
+
+    def get_ipv4_address_raw(self):
+        return self.__ipv4_address
+
+    def get_ipv4_netmask(self):
+        return self.__ipv4_address.netmask().strNormal()
+
+    def get_ipv4_broadcast(self):
+        return self.__ipv4_address.broadcast().strNormal()
+
+    def get_ipv4_gateway(self):
+        return str(self.__ipv4_address[1])
+
+    def get_ipv4_max_addresses(self):
+        return self.__ipv4_address.len()
+
+    def get_ipv4_network_type(self):
+        return self.__ipv4_address.iptype()
+
+    def is_public_ipv4_network(self):
+        if self.__ipv4_address.iptype() is "PUBLIC":
+            return True
+        return False
+
+    def set_ipv4_start_address(self, address):
+        self.__ipv4_start = address
+
+    def get_ipv4_start_address(self):
+        return self.__ipv4_start
+
+    def set_ipv4_end_address(self, address):
+        self.__ipv4_end = address
+
+    def get_ipv4_end_address(self):
+        return self.__ipv4_end
+
+    def is_bad_address(self, address):
+        return not self.__ipv4_address.overlaps(address)
+
+    def set_isolated_network(self, isolated):
+        self.__isolated_network = isolated
+
+    def is_isolated_network(self):
+        return self.__isolated_network
+
+    def set_physical_device(self, device):
+        self.__physical_device = device
+
+    def get_physical_device(self):
+        return self.__physical_device
+
+    def get_physical_device_text(self):
+        if self.__physical_device == "":
+            return "any physical device"
+        else:
+            return "physical device %s" % self.__physical_device
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/nodeadmin.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/nodeadmin.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+#
+# node-admin - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+import sys
+
+from mainmenu import MainMenu
+
+def NodeAdmin():
+    MainMenu()
+
+if __name__ == "__main__":
+    sys.exit(NodeAdmin())
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/nodemenu.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/nodemenu.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,67 @@
+# mainmenu.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import traceback
+
+from menuscreen     import MenuScreen
+from configscreen   import ConfigScreen
+from adddomain      import AddDomain
+from startdomain    import StartDomain
+from stopdomain     import StopDomain
+from removedomain   import RemoveDomain
+from listdomains    import ListDomains
+from migratedomain  import MigrateDomain
+from createuser     import CreateUser
+
+import utils
+import logging
+
+ADD_DOMAIN     = 1
+START_DOMAIN   = 2
+STOP_DOMAIN    = 3
+REMOVE_DOMAIN  = 4
+LIST_DOMAINS   = 5
+MIGRATE_DOMAIN = 6
+CREATE_USER    = 7
+
+class NodeMenuScreen(MenuScreen):
+    def __init__(self):
+        MenuScreen.__init__(self, "Node Administration")
+
+    def get_menu_items(self):
+        return (("Add A Virtual Machine",     ADD_DOMAIN),
+                ("Start A Virtual Machine",  START_DOMAIN),
+                ("Stop A Virtual Machine",    STOP_DOMAIN),
+                ("Remove A Virtual Machine",  REMOVE_DOMAIN),
+                ("List All Virtual Machines", LIST_DOMAINS),
+                ("Migrate Virtual Machine",   MIGRATE_DOMAIN),
+                ("Create A User",             CREATE_USER))
+
+    def handle_selection(self, item):
+            if   item is ADD_DOMAIN:     AddDomain()
+            elif item is START_DOMAIN:   StartDomain()
+            elif item is STOP_DOMAIN:    StopDomain()
+            elif item is REMOVE_DOMAIN:  RemoveDomain()
+            elif item is LIST_DOMAINS:   ListDomains()
+            elif item is MIGRATE_DOMAIN: MigrateDomain()
+            elif item is CREATE_USER:    CreateUser()
+
+def NodeMenu():
+    screen = NodeMenuScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/poolconfig.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/poolconfig.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,145 @@
+# poolconfig.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from virtinst import Storage
+
+ROOT_TARGET_PATH="/var/lib/libvirt/images/%s"
+
+class PoolConfig:
+    def __init__(self, libvirt):
+        self.__libvirt = libvirt
+        self.__name = ""
+        self.set_type(None)
+        self.__format = None
+        self.__hostname = ""
+        self.__target_path = ""
+        self.__source_path = ""
+        self.__build_pool  = False
+
+    def get_pool(self):
+        return self.__pool
+
+    def set_name(self, name):
+        self.__name = name
+
+    def get_name(self):
+        return self.__name
+
+    def set_type(self, pooltype):
+        self.__type = pooltype
+        self.__needs_target_path = False
+        self.__needs_format      = False
+        self.__needs_target_path = False
+        self.__needs_format      = False
+        self.__needs_hostname    = False
+        self.__needs_source_path = False
+        self.__needs_build_pool  = False
+        if pooltype is not None:
+            if   pooltype is Storage.StoragePool.TYPE_DIR:
+                self.__needs_target_path = True
+                self.__target_path = ROOT_TARGET_PATH % self.__name
+                self.__build_pool = True
+            elif pooltype is Storage.StoragePool.TYPE_DISK:
+                self.__needs_target_path = True
+                self.__needs_format      = True
+                self.__needs_source_path = True
+                self.__needs_build_pool  = True
+            elif pooltype is Storage.StoragePool.TYPE_FS:
+                self.__needs_target_path = True
+                self.__needs_format      = True
+                self.__needs_source_path = True
+                self.__build_pool  = True
+            elif pooltype is Storage.StoragePool.TYPE_ISCSI:
+                self.__needs_target_path = True
+                self.__needs_hostname    = True
+                self.__needs_source_path = True
+                self.__build_pool  = False
+            elif pooltype is Storage.StoragePool.TYPE_LOGICAL:
+                self.__needs_target_path = True
+                self.__needs_source_path = True
+                self.__needs_build_pool  = True
+            elif pooltype is Storage.StoragePool.TYPE_NETFS:
+                self.__needs_target_path = True
+                self.__needs_format      = True
+                self.__needs_hostname    = True
+                self.__needs_source_path = True
+                self.__build_pool  = True
+            # create pool
+            pool_class = Storage.StoragePool.get_pool_class(self.__type)
+            self.__pool = pool_class(name = self.__name,
+                                     conn = self.__libvirt.get_connection())
+            if self.__needs_format:
+                self.__format = self.__pool.formats[0]
+        else:
+            self.__type = Storage.StoragePool.get_pool_types()[0]
+
+    def get_type(self):
+        return self.__type
+
+    def needs_target_path(self):
+        return self.__needs_target_path
+
+    def needs_format(self):
+        return self.__needs_format
+
+    def needs_hostname(self):
+        return self.__needs_hostname
+
+    def source_must_be_absolute(self):
+        if self.__type is Storage.StoragePool.TYPE_ISCSI:
+            return False
+        return True
+
+    def needs_source_path(self):
+        return self.__needs_source_path
+
+    def needs_build_pool(self):
+        return self.__needs_build_pool
+
+    def set_target_path(self, path):
+        self.__target_path = path
+
+    def get_target_path(self):
+        return self.__target_path
+
+    def get_formats(self):
+        return self.__pool.formats
+
+    def set_format(self, format):
+        self.__format = format
+
+    def get_format(self):
+        return self.__format
+
+    def set_hostname(self, hostname):
+        self.__hostname = hostname
+
+    def get_hostname(self):
+        return self.__hostname
+
+    def set_source_path(self, source_path):
+        self.__source_path = source_path
+
+    def get_source_path(self):
+        return self.__source_path
+
+    def set_build_pool(self, build_pool):
+        self.__build_pool = build_pool
+
+    def  get_build_pool(self):
+        return self.__build_pool
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/removedomain.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/removedomain.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+#
+# removedomain.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+class RemoveDomainConfigScreen(DomainListConfigScreen):
+    LIST_PAGE     = 1
+    CONFIRM_PAGE  = 2
+    REMOVE_PAGE = 3
+
+    def __init__(self):
+        DomainListConfigScreen.__init__(self, "Remove A Domain")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is self.LIST_PAGE:     return self.get_domain_list_page(screen)
+        elif page is self.CONFIRM_PAGE:  return self.get_confirm_page(screen)
+        elif page is self.REMOVE_PAGE: return self.get_remove_page(screen)
+
+    def page_has_next(self, page):
+        if   page is self.LIST_PAGE:     return self.has_selectable_domains()
+        elif page is self.CONFIRM_PAGE:  return True
+        return False
+
+    def page_has_back(self, page):
+        if   page is self.CONFIRM_PAGE:  return True
+        elif page is self.REMOVE_PAGE: return True
+        return False
+
+    def get_back_page(self, page):
+        if   page is self.CONFIRM_PAGE:  return self.LIST_PAGE
+        elif page is self.REMOVE_PAGE: return self.LIST_PAGE
+
+    def validate_input(self, page, errors):
+        if page is self.LIST_PAGE:
+            if self.get_selected_domain() is not None:
+                return True
+            else:
+                errors.append("You must first select a domain.")
+        elif page is self.CONFIRM_PAGE:
+            if self.__confirm_remove.value():
+                domain = self.get_selected_domain()
+                try:
+                    self.get_libvirt().undefine_domain(domain)
+                    return True
+                except Exception, error:
+                    errors.append("Failed to remove %s." % domain)
+                    errors.append(str(error))
+            else:
+                errors.append("You must confirm undefining the domain to proceed.")
+        return False
+
+    def get_confirm_page(self, screen):
+        self.__confirm_remove = Checkbox("Check here to confirm undefining %s." % self.get_selected_domain(), 0)
+        grid = Grid(1, 1)
+        grid.setField(self.__confirm_remove, 0, 0)
+        return [grid]
+
+    def get_remove_page(self, screen):
+        grid = Grid(1, 1)
+        grid.setField(Label("%s has been removed." % self.get_selected_domain()), 0, 0)
+        return [grid]
+
+def RemoveDomain():
+    screen = RemoveDomainConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/removehost.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/removehost.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,66 @@
+# removehost.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from configscreen import *
+
+SELECT_HOST_PAGE    = 1
+CONFIRM_REMOVE_PAGE = 2
+
+class RemoveHostConfigScreen(HostListConfigScreen):
+    def __init__(self):
+        HostListConfigScreen.__init__(self, "Remove Host Connection")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is SELECT_HOST_PAGE:    return self.get_connection_list_page(screen)
+        elif page is CONFIRM_REMOVE_PAGE: return self.get_confirm_remove_page(screen)
+
+    def page_has_next(self, page):
+        return page is SELECT_HOST_PAGE and self.has_selectable_connections()
+
+    def page_has_back(self, page):
+        return page is CONFIRM_REMOVE_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_REMOVE_PAGE
+
+    def validate_input(self, page, errors):
+        if   page is SELECT_HOST_PAGE: return True
+        elif page is CONFIRM_REMOVE_PAGE:
+            if self.__confirm.value():
+                return True
+            else:
+                errors.append("You must confirm removing the connection.")
+        return False
+
+    def process_input(self, page):
+        if page is CONFIRM_REMOVE_PAGE:
+            self.get_virt_manager_config().remove_connection(self.get_selected_connection())
+            self.set_finished()
+
+    def get_confirm_remove_page(self, screen):
+        self.__confirm = Checkbox("Remove this connection: %s" % self.get_selected_connection(), 0)
+        grid = Grid(1, 1)
+        grid.setField(self.__confirm, 0, 0)
+        return [Label("Remove Host Connection"),
+                grid]
+
+def RemoveHost():
+    screen = RemoveHostConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/removepool.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/removepool.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+#
+# removepool.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+LIST_POOLS_PAGE    = 1
+CONFIRM_PAGE       = 2
+
+class RemoveStoragePoolConfigScreen(StorageListConfigScreen):
+    def __init__(self):
+        StorageListConfigScreen.__init__(self, "Remove A Storage Pool")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_POOLS_PAGE: return self.get_storage_pool_list_page(screen)
+        elif page is CONFIRM_PAGE:    return self.get_confirm_page(screen)
+
+    def page_has_next(self, page):
+        return page is LIST_POOLS_PAGE and self.has_selectable_pools()
+
+    def page_has_back(self, page):
+        return False
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_PAGE
+
+    def validate_input(self, page, errors):
+        if page is LIST_POOLS_PAGE:
+            if self.get_selected_pool() is not None:
+                return True
+            else:
+                errors.append("Please select a storage pool to be removed.")
+        elif page is CONFIRM_PAGE:
+            if self.__confirm.value():
+                return True
+            else:
+                errors.append("You must confirm removing a storage pool.")
+        return False
+
+    def process_input(self, page):
+        if page is CONFIRM_PAGE:
+            self.get_libvirt().destroy_storage_pool(self.get_selected_pool())
+            self.get_libvirt().undefine_storage_pool(self.get_selected_pool())
+            self.set_finished()
+
+    def get_confirm_page(self, screen):
+        self.__confirm = Checkbox("Check here to confirm deleting pool: %s" % self.get_selected_pool())
+        grid = Grid(1, 1)
+        grid.setField(self.__confirm, 0, 0)
+        return [Label("Remove Selected Storage Pool"),
+                grid]
+
+def RemoveStoragePool():
+    screen = RemoveStoragePoolConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/removevolume.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/removevolume.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,76 @@
+# removevolume.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import traceback
+
+from createmeter import CreateMeter
+from configscreen import *
+from volumeconfig import StorageVolumeConfig
+from utils import *
+
+SELECT_POOL_PAGE   = 1
+SELECT_VOLUME_PAGE = 2
+CONFIRM_PAGE       = 3
+
+class RemoveVolumeConfigScreen(StorageListConfigScreen):
+    def __init__(self):
+        StorageListConfigScreen.__init__(self, "Add A New Storage Volume")
+        self.__config = StorageVolumeConfig()
+
+    def get_elements_for_page(self, screen, page):
+        if   page is SELECT_POOL_PAGE:   return self.get_storage_pool_list_page(screen)
+        elif page is SELECT_VOLUME_PAGE: return self.get_storage_volume_list_page(screen)
+        elif page is CONFIRM_PAGE:       return self.get_confirm_page(screen)
+
+    def page_has_next(self, page):
+        if   page is SELECT_POOL_PAGE:   return self.has_selectable_pools()
+        elif page is SELECT_VOLUME_PAGE: return self.has_selectable_volumes()
+        return False
+
+    def validate_input(self, page, errors):
+        if   page is SELECT_POOL_PAGE:   return self.get_selected_pool() is not None
+        elif page is SELECT_VOLUME_PAGE: return self.get_selected_volume() is not None
+        elif page is CONFIRM_PAGE:
+            if self.__confirm.value():
+                return True
+            else:
+                errors.append("You must confirm deleting a storage volume.")
+        return False
+
+    def process_input(self, page):
+        if page is CONFIRM_PAGE:
+            self.get_libvirt().remove_storage_volume(self.get_selected_pool(), self.get_selected_volume())
+            self.set_finished()
+
+    def page_has_back(self, page):
+        return page > SELECT_POOL_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_PAGE
+
+    def get_confirm_page(self, screen):
+        self.__confirm = Checkbox("Check here to confirm deleting volume: %s" % self.get_selected_volume())
+        grid = Grid(1, 1)
+        grid.setField(self.__confirm, 0, 0)
+        return [Label("Remove Selected Storage Volume"),
+                grid]
+
+def RemoveStorageVolume():
+    screen = RemoveVolumeConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/setup.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/setup.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,47 @@
+# setup.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from setuptools import setup, find_packages
+
+setup(name = "nodeadmin",
+      version = "1.9.3",
+      package_dir = {'nodeadmin': 'nodeadmin'},
+      packages = find_packages('.'),
+      entry_points = {
+        'console_scripts': [
+            'nodeadmin   = nodeadmin.nodeadmin:NodeAdmin',
+            'addvm       = nodeadmin.adddomain:AddDomain',
+            'startvm     = nodeadmin.startdomain:StartDomain',
+            'stopvm      = nodeadmin.stopdomain:StopDomain',
+            'rmvm        = nodeadmin.removedomain:RemoveDomain',
+            'migratevm   = nodeadmin.migratedomain:MigradeDomain',
+            'createuser  = nodeadmin.createuser:CreateUser',
+            'listvms     = nodeadmin.listdomains:ListDomains',
+            'definenet   = nodeadmin.definenet:DefineNetwork',
+            'createnet   = nodeadmin.createnetwork:CreateNetwork',
+            'destroynet  = nodeadmin.destroynetwork:DestroyNetwork',
+            'undefinenet = nodeadmin.undefinenetwork:UndefineNetwork',
+            'listnets    = nodeadmin.listnetworks:ListNetworks',
+            'addpool     = nodeadmin.addpool:AddStoragePool',
+            'rmpool      = nodeadmin.removepool:RemoveStoragePool',
+            'startpool   = nodeadmin.startpool:StartStoragePool',
+            'stoppool    = nodeadmin.stoppool:StopStoragePool',
+            'addvolume   = nodeadmin.addvolume:AddStorageVolume',
+            'rmvolume    = nodeadmin.removevolume:RemoveStorageVolume',
+            'listpools   = nodeadmin.listpools:ListPools']
+        })
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/startdomain.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/startdomain.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+#
+# startdomain.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+class StartDomainConfigScreen(DomainListConfigScreen):
+    LIST_PAGE  = 1
+    START_PAGE = 2
+
+    def __init__(self):
+        DomainListConfigScreen.__init__(self, "Start A Domain")
+
+    def get_elements_for_page(self, screen, page):
+        if page is self.LIST_PAGE:
+            return self.get_domain_list_page(screen, started = False)
+        elif page is self.START_PAGE:
+            return self.get_start_domain_page(screen)
+
+    def page_has_next(self, page):
+        if page is self.LIST_PAGE: return self.has_selectable_domains()
+        return False
+
+    def page_has_back(self, page):
+        if page is self.START_PAGE: return True
+        return False
+
+    def validate_input(self, page, errors):
+        if page is self.LIST_PAGE:
+            if self.get_selected_domain() is not None:
+                domain = self.get_selected_domain()
+                try:
+                    self.get_libvirt().create_domain(domain)
+                    return True
+                except Exception, error:
+                    errors.append("There was an error creating the domain: %s" % domain)
+                    errors.append(str(error))
+            else:
+                errors.append("You must first select a domain to start.")
+
+    def get_start_domain_page(self, screen):
+        grid = Grid(1, 1)
+        grid.setField(Label("%s was successfully started." % self.get_selected_domain()), 0, 0)
+        return [grid]
+
+def StartDomain():
+    screen = StartDomainConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/startpool.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/startpool.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#
+# startpool.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+LIST_POOLS_PAGE    = 1
+FINAL_PAGE         = 2
+
+class StartStoragePoolConfigScreen(StorageListConfigScreen):
+    def __init__(self):
+        StorageListConfigScreen.__init__(self, "Start A Storage Pool")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_POOLS_PAGE: return self.get_storage_pool_list_page(screen, created = False)
+        elif page is FINAL_PAGE:      return self.get_final_page(screen)
+
+    def page_has_next(self, page):
+        return page is LIST_POOLS_PAGE and self.has_selectable_pools()
+
+    def page_has_back(self, page):
+        return False
+
+    def page_has_finish(self, page):
+        return page is FINAL_PAGE
+
+    def validate_input(self, page, errors):
+        if page is LIST_POOLS_PAGE:
+            if self.get_selected_pool() is not None:
+                return True
+            else:
+                errors.append("Please select a storage pool to be started.")
+        return False
+
+    def process_input(self, page):
+        if page is LIST_POOLS_PAGE:
+            self.get_libvirt().create_storage_pool(self.get_selected_pool())
+            self.set_finished()
+
+    def get_final_page(self, screen):
+        return [Label("Storage pool started: %s" % self.get_selected_pool())]
+
+def StartStoragePool():
+    screen = StartStoragePoolConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/stopdomain.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/stopdomain.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# stopdomain.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+class StopDomainConfigScreen(DomainListConfigScreen):
+    LIST_PAGE    = 1
+    STOP_PAGE = 2
+
+    def __init__(self):
+        DomainListConfigScreen.__init__(self, "Stop A Domain")
+
+    def get_elements_for_page(self, screen, page):
+        if page is self.LIST_PAGE:
+            return self.get_domain_list_page(screen, defined = False)
+        elif page is self.STOP_PAGE:
+            return self.get_stop_page(screen)
+
+    def page_has_next(self, page):
+        if page is self.LIST_PAGE: return self.has_selectable_domains()
+        return False
+
+    def page_has_back(self, page):
+        if page is self.STOP_PAGE: return True
+        return False
+
+    def validate_input(self, page, errors):
+        if page is self.LIST_PAGE:
+            if self.get_selected_domain() is not None:
+                domain = self.get_selected_domain()
+                try:
+                    self.get_libvirt().destroy_domain(domain)
+                    return True
+                except Exception, error:
+                    errors.append("There was an error stop the domain: %s" % domain)
+                    errors.append(str(error))
+            else:
+                errors.append("You must first select a domain to stop.")
+        return False
+
+    def get_stop_page(self, screen):
+        grid = Grid(1, 1)
+        grid.setField(Label("%s was successfully stoped." % self.get_selected_domain()), 0, 0)
+        return [grid]
+
+def StopDomain():
+    screen = StopDomainConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/stoppool.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/stoppool.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+#
+# stoppool.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+LIST_POOLS_PAGE    = 1
+FINAL_PAGE         = 2
+
+class StopStoragePoolConfigScreen(StorageListConfigScreen):
+    def __init__(self):
+        StorageListConfigScreen.__init__(self, "Stop A Storage Pool")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_POOLS_PAGE: return self.get_storage_pool_list_page(screen, defined = False)
+        elif page is FINAL_PAGE:      return self.get_final_page(screen)
+
+    def page_has_next(self, page):
+        return page is LIST_POOLS_PAGE and self.has_selectable_pools()
+
+    def page_has_back(self, page):
+        return False
+
+    def page_has_finish(self, page):
+        return page is FINAL_PAGE
+
+    def validate_input(self, page, errors):
+        if page is LIST_POOLS_PAGE:
+            if self.get_selected_pool() is not None:
+                return True
+            else:
+                errors.append("Please select a storage pool to be stopped.")
+        return False
+
+    def process_input(self, page):
+        if page is LIST_POOLS_PAGE:
+            self.get_libvirt().destroy_storage_pool(self.get_selected_pool())
+            self.set_finished()
+
+    def get_final_page(self, screen):
+        return [Label("Storage pool stopped: %s" % self.get_selected_pool())]
+
+def StopStoragePool():
+    screen = StopStoragePoolConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/storagemenu.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/storagemenu.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,63 @@
+# storagemenu.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+import traceback
+
+from menuscreen    import MenuScreen
+from addpool       import AddStoragePool
+from startpool     import StartStoragePool
+from stoppool      import StopStoragePool
+from removepool    import RemoveStoragePool
+from addvolume     import AddStorageVolume
+from removevolume  import RemoveStorageVolume
+from listpools     import ListStoragePools
+
+ADD_POOL      = 1
+START_POOL    = 2
+STOP_POOL     = 3
+REMOVE_POOL   = 4
+ADD_VOLUME    = 5
+REMOVE_VOLUME = 6
+LIST_POOLS    = 7
+
+class StoragePoolMenuScreen(MenuScreen):
+    def __init__(self):
+        MenuScreen.__init__(self, "Storage Pool Administration")
+
+    def get_menu_items(self):
+        return (("Add A Storage Pool",      ADD_POOL),
+                ("Start A Storage Pool",    START_POOL),
+                ("Stop A Storage Pool",     STOP_POOL),
+                ("Remove A Storage Pool",   REMOVE_POOL),
+                ("Add A Storage Volume",    ADD_VOLUME),
+                ("Remove A Storage Volume", REMOVE_VOLUME),
+                ("List Storage Pools",      LIST_POOLS))
+
+    def handle_selection(self, item):
+        if   item is ADD_POOL:      AddStoragePool()
+        elif item is START_POOL:    StartStoragePool()
+        elif item is STOP_POOL:     StopStoragePool()
+        elif item is REMOVE_POOL:   RemoveStoragePool()
+        elif item is ADD_VOLUME:    AddStorageVolume()
+        elif item is REMOVE_VOLUME: RemoveStorageVolume()
+        elif item is LIST_POOLS:    ListStoragePools()
+
+def StoragePoolMenu():
+    screen = StoragePoolMenuScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/undefinenetwork.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/undefinenetwork.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#
+# undefinenetwork.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+from configscreen import *
+
+LIST_PAGE     = 1
+CONFIRM_PAGE  = 2
+UNDEFINE_PAGE = 3
+
+class UndefineNetworkConfigScreen(NetworkListConfigScreen):
+    def __init__(self):
+        NetworkListConfigScreen.__init__(self, "Undefine A Network")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is LIST_PAGE:     return self.get_network_list_page(screen, created = False)
+        elif page is CONFIRM_PAGE:  return self.get_confirm_page(screen)
+        elif page is UNDEFINE_PAGE: return self.get_undefine_network_page(screen)
+
+    def process_input(self, page, errors):
+        if page is LIST_PAGE:
+            network = self.get_selected_network()
+            self.get_libvirt().undefine_network(network)
+            return True
+
+    def page_has_next(self, page):
+        if page is LIST_PAGE:    return self.has_selectable_networks()
+        if page is CONFIRM_PAGE: return True
+        return False
+
+    def page_has_back(self, page):
+        if page is CONFIRM_PAGE: return True
+        if page is UNDEFINE_PAGE: return True
+        return False
+
+    def get_back_page(self, page):
+        if   page is CONFIRM_PAGE: return LIST_PAGE
+        elif page is UNDEFINE_PAGE: return LIST_PAGE
+
+    def validate_input(self, page, errors):
+        if   page is LIST_PAGE: return True
+        elif page is CONFIRM_PAGE:
+            if self.__confirm_undefine.value():
+                return True
+            else:
+                errors.append("You must confirm undefining %s." % self.get_selected_network())
+        elif page is UNDEFINE_PAGE: return True
+        return False
+
+    def process_input(self, page):
+        if   page is LIST_PAGE:     return True
+        elif page is CONFIRM_PAGE:
+            network = self.get_selected_network()
+            self.get_libvirt().undefine_network(network)
+            return True
+        elif page is UNDEFINE_PAGE: return True
+        return False
+
+    def get_confirm_page(self, screen):
+        self.__confirm_undefine = Checkbox("Check here to confirm undefining %s." % self.get_selected_network(), 0)
+        grid = Grid(1, 1)
+        grid.setField(self.__confirm_undefine, 0, 0)
+        return [grid]
+
+    def get_undefine_network_page(self, screen):
+        return [Label("Network Is Undefined"),
+                Label("Network has been undefined: %s" % self.get_selected_network())]
+
+def UndefineNetwork():
+    screen = UndefineNetworkConfigScreen()
+    screen.start()
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/userworker.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/userworker.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,37 @@
+# userworker.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+import libuser
+
+class UserWorker:
+    '''Provides APIs for creating, modifying and deleting user accounts.'''
+    def __init__(self):
+        self.__admin = libuser.admin()
+
+    def create_user(self, username, password, other_group):
+        '''Creates a new user account with the provides username,
+        password. The user is also added to the optional group
+        if one is specified.'''
+        user = self.__admin.initUser(username)
+        user.set('pw_passwd', password)
+        self.__admin.addUser(user)
+        if other_group is not None:
+            group = self.__admin.lookupGroupByName(other_group)
+            if group is None: raise Exception("Invalid group specified: %s" % other_group)
+            user.add('pw_gid', group.get('pw_gid')[0])
+            self.__admin.modifyUser(user)
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/utils.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/utils.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,44 @@
+# definedomain.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+import logging
+import re
+
+logging.basicConfig(level=logging.DEBUG,
+                    format='%(asctime)s %(levelname)-8s %(message)s',
+                    datefmt='%a, %d %b %Y %H:%M:%S',
+                    filename='/var/log/ovirt-nodeadmin.log',
+                    filemode='w')
+
+def string_is_not_blank(value):
+    if len(value) > 0: return True
+    return False
+
+def string_has_no_spaces(value):
+    if re.match("^[a-zA-Z0-9_]*$", value):
+        return True
+    return False
+
+def size_as_mb_or_gb(size):
+    '''Takes a size value in bytes and returns it as either a
+    value in megabytes or gigabytes.'''
+    if size / 1024.0**3 < 1.0:
+        result = "%0.2f MB" % (size / 1024.0**2)
+    else:
+        result = "%0.2f GB" % (size / 1024.0**3)
+    return result
diff -r a6184d2d4052 -r 23f2fc0a3cb2 src/virtManagerTui/volumeconfig.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virtManagerTui/volumeconfig.py	Mon Aug 16 10:06:35 2010 -0400
@@ -0,0 +1,83 @@
+# volumeconfig.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+import virtinst
+from virtinst import Storage
+
+class StorageVolumeConfig:
+    def __init__(self):
+        self.__pool = None
+        self.__name = ""
+        self.__formats = None
+        self.__format = None
+        self.__max_capacity = 10000
+        self.__allocation = 0
+
+    def set_pool(self, pool):
+        self.__pool = pool
+        self.__formats = None
+        self.__pool_type = virtinst.util.get_xml_path(self.__pool.XMLDesc(0), '/pool/@type')
+        self.__volume_class = Storage.StoragePool.get_volume_for_pool(self.__pool_type)
+
+    def get_pool(self):
+        return self.__pool
+
+    def create_volume(self):
+        volume = self.__volume_class(name       = self.__name + ".img",
+                                     allocation = self.__allocation * 1024**2,
+                                     capacity   = self.__max_capacity * 1024**2,
+                                     pool       = self.__pool)
+        volume.pool = self.__pool
+        if self.needs_format():
+            volume.format = self.__format
+        return volume
+
+    def set_name(self, name):
+        self.__name = name
+
+    def get_name(self):
+        return self.__name
+
+    def needs_format(self):
+        if self.__pool.__dict__.keys().count("get_formats_for_pool") > 0:
+            return self.__pool.get_formats_for_pool() is not 0
+        else:
+            return False
+
+    def get_formats_for_pool(self):
+        if self.__formats is None:
+            self.__formats = self.__volume_class.formats
+        return self.__formats
+
+    def set_format(self, format):
+        self.__format = format
+
+    def get_format(self):
+        return self.__format
+
+    def set_max_capacity(self, capacity):
+        self.__max_capacity = capacity
+
+    def get_max_capacity(self):
+        return self.__max_capacity
+
+    def set_allocation(self, allocation):
+        self.__allocation = allocation
+
+    def get_allocation(self):
+        return self.__allocation




More information about the virt-tools-list mailing list