[Ovirt-devel] [PATCH node] Introduces the node-admin toolset.

Darryl L. Pierce dpierce at redhat.com
Fri Jul 31 20:03:52 UTC 2009


Defines a primary entry point that displays a menu of options that user
can use to administer the managed node. It leverages the code from
virtinst-python to do the heavy lifting and just provides a front end
for collecting user data.

Created a new configuration class to be used for all configuration
screens.

The user can select to create a node. They are then walked through the
steps to create a VM similar to virt-manager.

The user can list all domains on the system.

Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
 Makefile.am                |   12 ++
 node_admin/configscreen.py |   95 +++++++++++++++
 node_admin/createuser.py   |   22 ++++
 node_admin/definevm.py     |  284 ++++++++++++++++++++++++++++++++++++++++++++
 node_admin/listvms.py      |   67 +++++++++++
 node_admin/mainmenu.py     |   64 ++++++++++
 node_admin/node-admin.py   |   29 +++++
 node_admin/node.py         |  210 ++++++++++++++++++++++++++++++++
 node_admin/nodeconfig.py   |  123 +++++++++++++++++++
 node_admin/startvm.py      |   22 ++++
 node_admin/stopvm.py       |   22 ++++
 node_admin/undefinevm.py   |   22 ++++
 ovirt-node.spec.in         |    1 +
 13 files changed, 973 insertions(+), 0 deletions(-)
 create mode 100755 node_admin/__init__.py
 create mode 100644 node_admin/configscreen.py
 create mode 100755 node_admin/createuser.py
 create mode 100755 node_admin/definevm.py
 create mode 100755 node_admin/listvms.py
 create mode 100755 node_admin/mainmenu.py
 create mode 100755 node_admin/node-admin.py
 create mode 100755 node_admin/node.py
 create mode 100644 node_admin/nodeconfig.py
 create mode 100755 node_admin/startvm.py
 create mode 100755 node_admin/stopvm.py
 create mode 100755 node_admin/undefinevm.py

diff --git a/Makefile.am b/Makefile.am
index 0374f07..5b758b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,6 +26,18 @@ EXTRA_DIST =			\
   ovirt-node-selinux.fc		\
   images/grub-splash.xpm.gz	\
   images/syslinux-vesa-splash.jpg	\
+  node_admin/configscreen.py    \
+  node_admin/createuser.py      \
+  node_admin/definevm.py        \
+  node_admin/__init__.py        \
+  node_admin/listvms.py         \
+  node_admin/mainmenu.py        \
+  node_admin/node-admin.py      \
+  node_admin/node.py            \
+  node_admin/startvm.py         \
+  node_admin/stopvm.py          \
+  node_admin/undefinevm.py      \
+  node_admin/utils.py           \
   scripts/collectd		\
   scripts/collectd.conf.in	\
   scripts/ovirt			\
diff --git a/node_admin/__init__.py b/node_admin/__init__.py
new file mode 100755
index 0000000..e69de29
diff --git a/node_admin/configscreen.py b/node_admin/configscreen.py
new file mode 100644
index 0000000..48aacd1
--- /dev/null
+++ b/node_admin/configscreen.py
@@ -0,0 +1,95 @@
+# 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 *
+
+class ConfigScreen:
+    '''Enables the creation of navigable, multi-paged configuration screens.'''
+
+    __BACK_BUTTON   = "back"
+    __NEXT_BUTTON   = "next"
+    __CANCEL_BUTTON = "cancel"
+    __FINISH_BUTTON = "finish"
+
+    def __init__(self, title):
+        self.__title = title
+        self.__current_page = 1
+        self.__finished = False
+
+    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):
+        return True
+
+    def process_input(self, page):
+        return
+
+    def start(self):
+        active = True
+        while active and (self.__finished == False):
+            screen = SnackScreen()
+            gridform = GridForm(screen, self.__title, 1, 4)
+            elements = self.get_elements_for_page(screen, self.__current_page)
+            current_element = 0
+            for element in elements:
+                gridform.add(element, 0, current_element)
+                current_element += 1
+            # create the navigation buttons
+            buttons = []
+            if self.__current_page > 1: buttons.append(["Back", self.__BACK_BUTTON])
+            if self.page_has_next(self.__current_page): buttons.append(["Next", self.__NEXT_BUTTON, "F12"])
+            if self.page_has_finish(self.__current_page): buttons.append(["Finish", self.__FINISH_BUTTON])
+            buttons.append(["Cancel", self.__CANCEL_BUTTON])
+            buttonbar = ButtonBar(screen, buttons)
+            gridform.add(buttonbar, 0, current_element, growx = 1)
+            current_element += 1
+            result = gridform.runOnce()
+            screen.popWindow()
+            screen.finish()
+            pressed = buttonbar.buttonPressed(result)
+            if pressed == self.__BACK_BUTTON:
+                self.go_back()
+            elif pressed == self.__NEXT_BUTTON or pressed == self.__FINISH_BUTTON:
+                if self.validate_input(self.__current_page):
+                    self.process_input(self.__current_page)
+                    self.go_next()
+            elif pressed == self.__CANCEL_BUTTON:
+                active = False
diff --git a/node_admin/createuser.py b/node_admin/createuser.py
new file mode 100755
index 0000000..e624570
--- /dev/null
+++ b/node_admin/createuser.py
@@ -0,0 +1,22 @@
+# definevm.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 *
+
+def createUser():
+    print "Create user!"
diff --git a/node_admin/definevm.py b/node_admin/definevm.py
new file mode 100755
index 0000000..d79f4ce
--- /dev/null
+++ b/node_admin/definevm.py
@@ -0,0 +1,284 @@
+# definevm.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 node import *
+from nodeutils import *
+import os
+from nodeconfig import NodeConfig
+from configscreen import ConfigScreen
+
+from virtinst import Guest, DistroInstaller, LiveCDInstaller, PXEInstaller
+
+VM_DETAILS_PAGE      = 1
+LOCAL_INSTALL_PAGE   = 2
+NETWORK_INSTALL_PAGE = 3
+OS_TYPE_PAGE         = 10
+OS_VARIANT_PAGE      = 11
+RAM_CPU_PAGE         = 12
+LOCAL_STORAGE_PAGE   = 13
+BRIDGE_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 VirtualMachineConfigScreen(ConfigScreen):
+
+    def __init__(self):
+        ConfigScreen.__init__(self, "Create A New Virtual Machine")
+        self.__config = NodeConfig()
+
+    def get_elements_for_page(self, screen, page):
+        if page == VM_DETAILS_PAGE:
+            return self.get_vm_details_page(screen)
+        elif page == LOCAL_INSTALL_PAGE:
+            return self.get_local_install_page(screen)
+        elif page == NETWORK_INSTALL_PAGE:
+            return self.get_network_install_page(screen)
+        elif page == OS_TYPE_PAGE:
+            return self.get_os_type_page(screen)
+        elif page == OS_VARIANT_PAGE:
+            return self.get_os_variant_page(screen)
+        elif page == RAM_CPU_PAGE:
+            return self.get_ram_and_cpu_page(screen)
+        elif page == LOCAL_STORAGE_PAGE:
+            return self.get_local_storage_page(screen)
+        elif page == BRIDGE_PAGE:
+            return self.get_bridge_page(screen)
+        elif page == CONFIRM_PAGE:
+            return self.get_confirm_page(screen)
+        return []
+
+    def validate_input(self, page):
+        if page == VM_DETAILS_PAGE:
+            if len(self.__guest_name.value()) > 0:
+                return True
+        elif page == LOCAL_INSTALL_PAGE:
+            if len(self.__install_source.value()) > 0 and os.path.exists(self.__install_source.value()):
+                return True
+        elif page == NETWORK_INSTALL_PAGE:
+            if len(self.__install_url.value()) > 0: return True
+        elif page == OS_TYPE_PAGE: return True
+        elif page == OS_VARIANT_PAGE: return True
+        elif page == 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
+        elif page == LOCAL_STORAGE_PAGE:
+            if self.__storage_type.getSelection() == Node.STORAGE_TYPE_NEW:
+                if len(self.__storage_size.value()) > 0:
+                    if float(self.__storage_size.value()) > 0: return True
+            elif self.__storage_type.getSelection() == Node.STORAGE_TYPE_EXISTING:
+                if os.path.exists(self.__existing_storage.value()): return true
+        elif page == BRIDGE_PAGE: return True
+        elif page == CONFIRM_PAGE: return True
+        return False
+
+    def process_input(self, page):
+        if page == VM_DETAILS_PAGE:
+            self.__config.set_guest_name(self.__guest_name.value())
+            self.__config.set_install_type(self.__install_type.getSelection())
+        elif page == LOCAL_INSTALL_PAGE:
+            self.__config.set_install_location(self.__install_source.value())
+        elif page == NETWORK_INSTALL_PAGE:
+            self.__config[LOCATION] = self.__install_url.value()
+            self.__config[KICKSTART] = self.__kickstart_url.value()
+            self.__config[KERNELOPTS] = self.__kernel_options.value()
+        elif page == OS_TYPE_PAGE:
+            self.__config.set_os_type(self.__os_types.getSelection())
+        elif page == OS_VARIANT_PAGE:
+            self.__config.set_os_variant(self.__os_variants.getSelection())
+        elif page == RAM_CPU_PAGE:
+            self.__config.set_memory(int(self.__memory.value()))
+            self.__config.set_cpus(int(self.__cpus.value()))
+        elif page == LOCAL_STORAGE_PAGE:
+            self.__config.set_enable_storage(self.__enable_storage.value())
+            if self.__config.set_enable_storage:
+                if self.__storage_type.getSelection() == NodeConfig.NEW_STORAGE:
+                    self.__config.set_use_local_storage(true)
+                    self.__config.set_storage_size(float(self.__storage_size.value()))
+                    self.__guest.set_allocate_storage(self.__allocate_storage.value())
+                elif self.__storage_type.getSelection() == Node.STORAGE_TYPE_EXISTING:
+                    self.__config.set_use_local_storage(false)
+                    self.__guest.set_existing_storage(self.__existing_storage.value())
+        elif page == CONFIRM_PAGE:
+            # save the VM
+            define_domain(self.__guest)
+            self.set_finished()
+
+    def get_back_page(self, page):
+        result = page
+        if page == OS_TYPE_PAGE:
+            install_type = self.__config.get_install_type()
+            if install_type == NodeConfig.LOCAL_INSTALL:
+                result = LOCAL_INSTALL_PAGE
+            elif install_type == NodeConfig.NETWORK_INSTALL:
+                result = NETWORK_INSTALL_PAGE
+            elif install_type == NodeConfig.PXE_INSTALL:
+                result = VM_DETAILS_PAGE
+        else:
+            if page > 1: result = page - 1
+        return result
+
+    def get_next_page(self, page):
+        result = page
+        if page == VM_DETAILS_PAGE:
+            install_type = self.__config.get_install_type()
+            if install_type == NodeConfig.LOCAL_INSTALL:
+                result = LOCAL_INSTALL_PAGE
+            elif install_type == NodeConfig.NETWORK_INSTALL:
+                result = NETWORK_INSTALL_PAGE
+            elif install_type == NodeConfig.PXE_INSTALL:
+                result = OS_TYPE_PAGE
+        elif page == LOCAL_INSTALL_PAGE or page == NETWORK_INSTALL_PAGE:
+            result = OS_TYPE_PAGE
+        else:
+            result = page + 1
+        return result
+
+    def page_has_finish(self, page):
+        if page == CONFIRM_PAGE: return True
+        return False
+
+    def page_has_next(self, page):
+        if 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)",
+                                                 NodeConfig.LOCAL_INSTALL,
+                                                 self.__config.is_install_type(NodeConfig.LOCAL_INSTALL)),
+                                                ("Network Install (HTTP, FTP, or NFS)",
+                                                 NodeConfig.NETWORK_INSTALL,
+                                                 self.__config.is_install_type(NodeConfig.NETWORK_INSTALL)),
+                                                ("Network Boot (PXE)",
+                                                 NodeConfig.PXE_INSTALL,
+                                                 self.__config.is_install_type(NodeConfig.PXE_INSTALL))))
+        grid = Grid(2,4)
+        grid.setField(Label("Enter your machine details"), 0, 0, growx = 1)
+        grid.setField(Label("Name:"), 0, 1, anchorLeft = 1)
+        grid.setField(self.__guest_name, 1, 1)
+        grid.setField(Label("Choose how you would like to install the operating system"), 0, 2, growx = 1)
+        grid.setField(self.__install_type, 0, 3)
+        return [grid]
+
+    def get_local_install_page(self, screen):
+        self.__install_source = Entry(50, self.__config.get_install_location())
+        grid = Grid(2,1)
+        grid.setField(Label("Install source:"), 0, 0)
+        grid.setField(self.__install_source, 1, 0)
+        return [grid]
+
+    def get_network_install_page(self, screen):
+        self.__install_url    = Entry(50, _get_field_str(self.__guest.get_location()))
+        self.__kickstart_url  = Entry(50, self.__guest.get_kickstart_url())
+        self.__kernel_options = Entry(50, self.__guest.get_kernel_options())
+        grid = Grid(2,4)
+        grid.setField(Label("Provide the operating system URL"), 0, 0, growx = 1)
+        grid.setField(Label("URL:"), 0, 1)
+        grid.setField(self.__install_url, 1, 1)
+        grid.setField(Label("Kickstart URL:"), 0, 2)
+        grid.setField(self.__kickstart_url, 1, 2)
+        grid.setField(Label("Kernel Options:"), 0, 3)
+        grid.setField(self.__kernel_options, 1, 3)
+        return [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(2, 1)
+        grid.setField(Label("OS Type:"), 0, 0)
+        grid.setField(self.__os_types, 1, 0)
+        return [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(2, 1)
+        grid.setField(Label("OS Variant:"), 0, 0)
+        grid.setField(self.__os_variants, 1, 0)
+        return [grid]
+
+    def get_ram_and_cpu_page(self, screen):
+        self.__memory = Entry(4, str(self.__config.get_memory()))
+        self.__cpus   = Entry(3, str(self.__config.get_cpus()))
+        grid = Grid(2,3)
+        grid.setField(Label("Choose memory and CPU settings"), 0, 0, growx = 1)
+        grid.setField(Label("Memory (RAM):"), 0, 1)
+        grid.setField(self.__memory, 1, 1)
+        grid.setField(Label("CPUs:"), 0, 2)
+        grid.setField(self.__cpus, 1, 2)
+        return [grid]
+
+    def get_local_storage_page(self, screen):
+        self.__enable_storage = Checkbox("Enable storage for this virtual machine", self.__config.get_enable_storage())
+        storage_types = []
+        for option in Node.STORAGE_TYPES.keys():
+            storage_types.append([Node.STORAGE_TYPES.get(option), option, self.__config.get_storage_type() == option])
+        self.__storage_type     = RadioBar(screen,storage_types,
+                                           ((["Create a disk image on the computer's hard disk",
+                                              NodeConfig.NEW_STORAGE,
+                                              self.__config.get_use_local_storage()]),
+                                            (["Select managed or other existing storage",
+                                              NodeConfig.EXISTING_STORAGE,
+                                              self.__config.get_use_local_storage() is False])))
+        self.__storage_size     = Entry(6, str(self.__config.get_storage_size()))
+        self.__allocate_storage = Checkbox("Allocate entire disk now", self.__config.get_allocate_storage())
+        self.__existing_storage = Entry(60, self.__config.get_existing_storage())
+        grid = Grid(2,5)
+        grid.setField(self.__enable_storage, 0, 0, growx = 1, anchorLeft = 1)
+        grid.setField(self.__storage_type, 1, 1, growx = 1)
+        grid.setField(self.__allocate_storage, 0, 2, growx = 1, anchorLeft = 1)
+        grid.setField(Label("Storage size (GB):"), 0, 3, anchorLeft = 1)
+        grid.setField(self.__storage_size, 1, 3)
+        grid.setField(Label("Existing storage:"), 0, 4)
+        grid.setField(self.__existing_storage, 1, 4)
+        return [grid]
+
+    def get_bridge_page(self, screen):
+        return []
+
+    def get_confirm_page(self, screen):
+        grid = Grid(2, 6)
+        grid.setField(Label("Ready to begin installation of %s" % self.__guest.get_name()), 0, 0, growx = 1)
+        grid.setField(Label("OS:"), 0, 1)
+        grid.setField(Label(self.__guest.get_os_type()), 1, 1)
+        grid.setField(Label("Install:"), 0, 2)
+        grid.setField(Label(self.__guest.get_boot_type_text()), 1, 2)
+        grid.setField(Label("Memory:"), 0, 3)
+        grid.setField(Label("%s MB" % self.__guest.get_memory()), 1, 3)
+        grid.setField(Label("CPUs:"), 0, 4)
+        grid.setField(Label("%d" % self.__guest.get_cpus()), 1, 4)
+        grid.setField(Label("Storage:"), 0, 5)
+        grid.setField(Label(self.__guest.get_existing_storage()), 1, 5)
+        return [grid]
+
+def defineVM():
+    vmconfig = VirtualMachineConfigScreen()
+    vmconfig.start()
diff --git a/node_admin/listvms.py b/node_admin/listvms.py
new file mode 100755
index 0000000..ff3e42e
--- /dev/null
+++ b/node_admin/listvms.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# definevm.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 ConfigScreen
+from snack import *
+from nodeutils import *
+
+class ListDomainsConfigScreen(ConfigScreen):
+    __LIST_PAGE   = 1
+    __DETAIL_PAGE = 2
+
+    def __init__(self):
+        ConfigScreen.__init__(self, 'List Domains')
+
+    def page_has_next(self, page):
+        return (page == self.__LIST_PAGE)
+
+    def page_has_back(self, page):
+        return (page == self.__DETAIL_PAGE)
+
+    def get_elements_for_page(self, screen, page):
+        if page == self.__LIST_PAGE:
+            return self.get_list_page_elements()
+        elif page == self.__DETAIL_PAGE:
+            return self.get_detail_page_elements()
+
+    def get_list_page_elements(self):
+        domains = get_domain_list()
+        self.__domain_list = Listbox(0)
+        for name in domains.keys():
+            self.__domain_list.append(name, name)
+        return [self.__domain_list]
+
+    def get_detail_page_elements(self):
+        domain = get_domain(self.__domain_list.current())
+        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 listVMs():
+    screen = ListDomainsConfigScreen()
+    screen.start()
diff --git a/node_admin/mainmenu.py b/node_admin/mainmenu.py
new file mode 100755
index 0000000..6b3d27e
--- /dev/null
+++ b/node_admin/mainmenu.py
@@ -0,0 +1,64 @@
+# 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 *
+from definevm import defineVM
+from listvms import listVMs
+
+DEFINE_VM    = 1
+START_VM     = 2
+STOP_VM      = 3
+UNDEFINE_VM  = 4
+LIST_VMS     = 5
+CREATE_USER  = 6
+EXIT_CONSOLE = 99
+
+def mainMenu():
+    finished = False
+    while finished == False:
+        screen = SnackScreen()
+        menu = Listbox(height = 0, width = 0, returnExit = 1)
+        menu.append("Define a new VM", DEFINE_VM)
+        menu.append("Start a VM", START_VM)
+        menu.append("Stop a running VM", STOP_VM)
+        menu.append("Undefine a VM", UNDEFINE_VM)
+        menu.append("List all VMs", LIST_VMS)
+        menu.append("Create a user", CREATE_USER)
+        menu.append("Exit Node Administration", EXIT_CONSOLE)
+        gridform = GridForm(screen, "Node Administration Console", 1, 4)
+        gridform.add(menu, 0, 0)
+        result = gridform.run();
+        screen.popWindow()
+        screen.finish()
+
+        if result.current() == DEFINE_VM:
+            defineVM()
+        elif result.current() == START_VM:
+            startVM()
+        elif result.current() == STOP_VM:
+            stopVM()
+        elif result.current() == UNDEFINE_VM:
+            destroyVM()
+        elif result.current() == LIST_VMS:
+            listVMs()
+        elif result.current() == CREATE_USER:
+            createUser()
+        elif result.current() == EXIT_CONSOLE:
+            finished = True
+        else:
+            print "Nope.\n"
diff --git a/node_admin/node-admin.py b/node_admin/node-admin.py
new file mode 100755
index 0000000..5061362
--- /dev/null
+++ b/node_admin/node-admin.py
@@ -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 *
+
+def main():
+    mainMenu()
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/node_admin/node.py b/node_admin/node.py
new file mode 100755
index 0000000..d566f87
--- /dev/null
+++ b/node_admin/node.py
@@ -0,0 +1,210 @@
+# node.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.
+
+class Node:
+    BOOT_TYPE_LOCAL   = "local"
+    BOOT_TYPE_NETWORK = "network"
+    BOOT_TYPE_PXE     = "pxe"
+    BOOT_TYPES = {BOOT_TYPE_LOCAL   : "Local install media (ISO image or CDROM)",
+                  BOOT_TYPE_NETWORK : "Network Install (HTTP, FTP, or NFS)",
+                  BOOT_TYPE_PXE     : "Network Boot (PXE)"}
+    OS_TYPES = {"generic" : "Generic",
+                "linux"   : "Linux",
+                "other"   : "Other",
+                "solaris" : "Solaris",
+                "unix"    : "UNIX",
+                "windows" : "Windows"}
+    OS_VERSIONS = ["Generic"]
+    STORAGE_TYPE_NEW      = "new"
+    STORAGE_TYPE_EXISTING = "existing"
+    STORAGE_TYPES = {STORAGE_TYPE_NEW      : "Create a disk image on the computer's hard disk",
+                     STORAGE_TYPE_EXISTING : "Select managed or other existing storage"}
+
+    def __init__(self):
+        self.__name             = ""
+        self.__boot_type        = Node.BOOT_TYPE_PXE
+        self.__install_source   = ""
+        self.__install_url      = ""
+        self.__kickstart_url    = ""
+        self.__kernel_options   = ""
+        self.__os_type          = "generic"
+        self.__os_version       = "generic"
+        self.__memory           = 512
+        self.__cpus             = 1
+        self.__storage_size     = 8.0
+        self.__allocate_storage = True
+        self.__storage_type     = Node.STORAGE_TYPE_NEW
+        self.__existing_storage = ""
+
+    def set_name(self, name):
+        self.__name = name
+
+    def get_name(self):
+        return self.__name
+
+    def set_boot_type(self, boot_type):
+        if Node.BOOT_TYPES.has_key(boot_type):
+            self.__boot_type = boot_type
+        else:
+            raise ValueError("Invalid boot type: %s" % boot_type)
+
+    def get_boot_type(self):
+        return self.__boot_type
+
+    def get_boot_device(self):
+        if self.__boot_type == Node.BOOT_TYPE_PXE:
+            return "network"
+        else:
+            return "disk"
+
+    def get_boot_type_text(self):
+        return Node.BOOT_TYPES.get(self.__boot_type)
+
+    def set_install_source(self, install_source):
+        if os.path.exist(install_source):
+            self.__install_source = install_source
+        else:
+            raise Error("Non-existent install source: %s" % install_source)
+
+    def get_install_source(self):
+        return self.__install_source
+
+    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, os_type):
+        if Node.OS_TYPES.has_key(os_type):
+            self.__os_type = os_type
+        else:
+            raise ValueError("Invalid OS type: %s" % os_type)
+
+    def get_os_type(self):
+        return self.__os_type
+
+    def set_os_version(self, os_version):
+        try:
+            if Node.OS_VERSIONS.index(os_version) >= 0: self.__os_version = os_version
+        except ValueError, error:
+            raise error
+
+    def get_os_version(self):
+        return self.__os_version
+
+    def set_memory(self, memory):
+        if int(memory) > 0:
+            self.__memory = memory
+        else:
+            raise ValueError("Invalid memory value: %d" % int(memory))
+
+    def get_memory(self):
+        return self.__memory
+
+    def set_cpus(self, cpus):
+        if int(cpus):
+            self.__cpus = cpus
+        else:
+            raise ValueError("Invalid number of cpus: %d" % int(cpus))
+
+    def get_cpus(self):
+        return self.__cpus
+
+    def has_local_storage(self):
+        if self.__storage_size > 0: return True
+        return False
+
+    def get_local_storage(self):
+        return "/var/lib/libvirt/images/%s.img" % self.get_name()
+
+    def set_storage_size(self, storage_size):
+        if float(storage_size) > 0.0:
+            self.__storage_size = storage_size
+        else:
+            raise ValueError("Invalid storage size: %f" % float(storage_size))
+
+    def get_storage_size(self):
+        return self.__storage_size
+
+    def set_allocate_storage(self, allocate_storage):
+        self.__allocate_storage = allocate_storage
+
+    def get_allocate_storage(self):
+        return self.__allocate_storage
+
+    def set_storage_type(self, storage_type):
+        if Node.STORAGE_TYPES.has_key(storage_type):
+            self.__storage_type = storage_type
+        else:
+            raise ValueError("Invalid storage type: %s" % storage_type)
+
+    def get_storage_type(self):
+        return self.__storage_type
+
+    def set_existing_storage(self, existing_storage):
+        if os.path.exist(existing_storage):
+            self.__existing_storage = existing_storage
+        else:
+            raise ValueError("No such file: %s" % existing_storage)
+
+    def get_existing_storage(self):
+        return self.__existing_storage
+
+    def get_xml(self):
+        result  = "<domain type='kvm'>\n"
+        result += "<name>%s</name>\n" % self.get_name()
+        result += "<memory>%d</memory>\n" % (self.get_memory() * 1024 * 1024)
+        result += "<vcpu>%d</vcpu>\n" % self.get_cpus()
+        result += "<os>\n"
+        result += "<type arch='%s' machine='%s'>%s</type>\n" % ('x86_64', 'pc', 'hvm')
+        result += "<boot dev='%s' />\n" % self.get_boot_device()
+        result += "</os>\n"
+        result += "<features>\n"
+        result += "<acpi />\n"
+        result += "<pae />\n"
+        result += "</features>\n"
+        result += "<clock offset='utc' />\n"
+        result += "<on_poweroff>destroy</on_poweroff>\n"
+        result += "<on_reboot>restart</on_reboot>\n"
+        result += "<on_crash>restart</on_crash>\n"
+        result += "<devices>\n"
+        if self.has_local_storage():
+            result += "<disk type='file' device='disk'>\n"
+            result += "<source file='%s' />\n" % self.get_local_storage()
+            result += "<target dev='vda' bus='virtio' />\n"
+            result += "</disk>\n"
+        result += "<serial type='pty' />\n"
+        result += "<console type='pty' />\n"
+        result += "<graphics type='vnc' port='-1' autoport='yes' keyman='en-us' />\n"
+        result += "</devices>\n"
+        result += "</domain>\n"
+
+        return result
diff --git a/node_admin/nodeconfig.py b/node_admin/nodeconfig.py
new file mode 100644
index 0000000..1e1106d
--- /dev/null
+++ b/node_admin/nodeconfig.py
@@ -0,0 +1,123 @@
+# nodeconfig.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 NodeConfig:
+    LOCAL_INSTALL   = "local"
+    NETWORK_INSTALL = "network"
+    PXE_INSTALL     = "pxe"
+
+    NEW_STORAGE      = "new"
+    EXISTING_STORAGE = "existing"
+
+    def __init__(self):
+        self.__guest_name = ""
+        self.__install_type = NodeConfig.LOCAL_INSTALL
+        self.__install_location = ""
+        self.__os_type = Guest.list_os_types()[0]
+        self.__os_variant = Guest.list_os_variants(self.__os_type)[0]
+        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.__existing_storage = ""
+
+    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 is_install_type(self, type):
+        return self.__install_type == type
+
+    def set_install_location(self, location):
+        self.__install_location = location
+
+    def get_install_location(self):
+        return self.__install_location
+
+    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_existing_storage(self, storage):
+        self.__existing_storage = storage
+
+    def get_existing_storage(self):
+        return self.__existing_storage
diff --git a/node_admin/startvm.py b/node_admin/startvm.py
new file mode 100755
index 0000000..00b4cd2
--- /dev/null
+++ b/node_admin/startvm.py
@@ -0,0 +1,22 @@
+# definevm.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 *
+
+def startVM():
+    print "Start VM!"
diff --git a/node_admin/stopvm.py b/node_admin/stopvm.py
new file mode 100755
index 0000000..656dfdc
--- /dev/null
+++ b/node_admin/stopvm.py
@@ -0,0 +1,22 @@
+# definevm.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 *
+
+def stopVM():
+    print "Stop VM!"
diff --git a/node_admin/undefinevm.py b/node_admin/undefinevm.py
new file mode 100755
index 0000000..7217985
--- /dev/null
+++ b/node_admin/undefinevm.py
@@ -0,0 +1,22 @@
+# definevm.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 *
+
+def defineVM():
+    print "Undefine VM!"
diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in
index 3138011..4fded95 100644
--- a/ovirt-node.spec.in
+++ b/ovirt-node.spec.in
@@ -43,6 +43,7 @@ Requires:       nc
 Requires:       grub
 Requires:       /usr/sbin/crond
 Requires:       anyterm
+Requires:       newt-python
 ExclusiveArch:  %{ix86} x86_64
 
 %define app_root %{_datadir}/%{name}
-- 
1.6.2.5




More information about the ovirt-devel mailing list