[Ovirt-devel] [PATCH node] Introduces the node-admin toolset.
Joey Boggs
jboggs at redhat.com
Mon Aug 31 20:48:41 UTC 2009
Darryl L. Pierce wrote:
> 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 domain similar to virt-manager.
>
> The user can create a defined domain.
>
> The user can destroy a created domain.
>
> The user can undefine a defined domain.
>
> The user can list all domains on the system.
>
> The user can create a new user account.
>
> When the RPM is created, a separate entry point is created for each
> node admin command. This allows the commands to be invoked individually
> as well as from the main menu.
>
> Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
> ---
> .gitignore | 1 +
> Makefile.am | 14 ++
> admin/__init__.py | 20 ++
> admin/configscreen.py | 150 +++++++++++++++
> admin/createdomain.py | 68 +++++++
> admin/createuser.py | 106 +++++++++++
> admin/definedomain.py | 470 +++++++++++++++++++++++++++++++++++++++++++++++
> admin/destroydomain.py | 66 +++++++
> admin/domainconfig.py | 217 ++++++++++++++++++++++
> admin/halworker.py | 37 ++++
> admin/libvirtworker.py | 248 +++++++++++++++++++++++++
> admin/listdomains.py | 68 +++++++
> admin/mainmenu.py | 71 +++++++
> admin/nodeadmin.py | 29 +++
> admin/setup.py.in | 34 ++++
> admin/undefinedomain.py | 83 +++++++++
> admin/userworker.py | 38 ++++
> configure.ac | 1 +
> ovirt-node.spec.in | 36 ++++
> 19 files changed, 1757 insertions(+), 0 deletions(-)
> create mode 100644 admin/__init__.py
> create mode 100644 admin/configscreen.py
> create mode 100755 admin/createdomain.py
> create mode 100755 admin/createuser.py
> create mode 100755 admin/definedomain.py
> create mode 100755 admin/destroydomain.py
> create mode 100644 admin/domainconfig.py
> create mode 100644 admin/halworker.py
> create mode 100644 admin/libvirtworker.py
> create mode 100755 admin/listdomains.py
> create mode 100755 admin/mainmenu.py
> create mode 100755 admin/nodeadmin.py
> create mode 100644 admin/setup.py.in
> create mode 100755 admin/undefinedomain.py
> create mode 100644 admin/userworker.py
>
> diff --git a/.gitignore b/.gitignore
> index 26a0210..19b15d1 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -13,3 +13,4 @@ missing
> stamp-h1
> ovirt-node*.gz
> ovirt-node.spec
> +*.pyc
> diff --git a/Makefile.am b/Makefile.am
> index 419cdf1..5cb0c67 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -26,6 +26,20 @@ EXTRA_DIST = \
> ovirt-node-selinux.fc \
> images/grub-splash.xpm.gz \
> images/syslinux-vesa-splash.jpg \
> + admin/configscreen.py \
> + admin/createuser.py \
> + admin/destroydomain.py \
> + admin/halworker.py \
> + admin/libvirtworker.py \
> + admin/userworker.py \
> + admin/mainmenu.py \
> + admin/undefinedomain.py \
> + admin/createdomain.py \
> + admin/definedomain.py \
> + admin/domainconfig.py \
> + admin/listdomains.py \
> + admin/nodeadmin.py \
> + admin/setup.py \
> scripts/collectd.conf.in \
> scripts/ovirt \
> scripts/ovirt-awake \
> diff --git a/admin/__init__.py b/admin/__init__.py
> new file mode 100644
> index 0000000..1f3c72c
> --- /dev/null
> +++ b/admin/__init__.py
> @@ -0,0 +1,20 @@
> +# __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 --git a/admin/configscreen.py b/admin/configscreen.py
> new file mode 100644
> index 0000000..0282eee
> --- /dev/null
> +++ b/admin/configscreen.py
> @@ -0,0 +1,150 @@
> +# 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 LibvirtWorker
> +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()
> +
> + def get_hal(self):
> + return self.__hal
> +
> + def get_libvirt(self):
> + return self.__libvirt
> +
> + 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 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", 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)
> + gridform.add(buttonbar, 0, current_element, growx = 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 self.get_libvirt().list_domains(defined, created):
> + 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
> diff --git a/admin/createdomain.py b/admin/createdomain.py
> new file mode 100755
> index 0000000..b73a09e
> --- /dev/null
> +++ b/admin/createdomain.py
> @@ -0,0 +1,68 @@
> +#!/usr/bin/env python
> +#
> +# createdomain.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 CreateDomainConfigScreen(DomainListConfigScreen):
> + LIST_PAGE = 1
> + CREATE_PAGE = 2
> +
> + def __init__(self):
> + DomainListConfigScreen.__init__(self, "Create A Domain")
> +
> + def get_elements_for_page(self, screen, page):
> + if page is self.LIST_PAGE:
> + return self.get_domain_list_page(screen, created = False)
> + elif page is self.CREATE_PAGE:
> + return self.get_create_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.CREATE_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 create.")
> +
> + def process_input(self, page):
> + print "foo"
> +
> + def get_create_domain_page(self, screen):
> + grid = Grid(1, 1)
> + grid.setField(Label("%s was successfully created." % self.get_selected_domain()), 0, 0)
> + return [grid]
> +
> +def CreateDomain():
> + screen = CreateDomainConfigScreen()
> + screen.start()
> diff --git a/admin/createuser.py b/admin/createuser.py
> new file mode 100755
> index 0000000..dbc4626
> --- /dev/null
> +++ b/admin/createuser.py
> @@ -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 --git a/admin/definedomain.py b/admin/definedomain.py
> new file mode 100755
> index 0000000..ea4c986
> --- /dev/null
> +++ b/admin/definedomain.py
> @@ -0,0 +1,470 @@
> +#!/usr/bin/env python
> +#
> +# 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.
> +
> +from snack import *
> +import os
> +from domainconfig import DomainConfig
> +from configscreen import ConfigScreen
> +import urlgrabber.progress as progress
> +
> +from virtinst import *
> +
> +VM_DETAILS_PAGE = 1
> +LOCAL_INSTALL_PAGE = 2
> +SELECT_CDROM_PAGE = 3
> +SELECT_ISO_PAGE = 4
> +NETWORK_INSTALL_PAGE = 10
> +OS_TYPE_PAGE = 11
> +OS_VARIANT_PAGE = 12
> +RAM_CPU_PAGE = 13
> +ENABLE_STORAGE_PAGE = 14
> +LOCAL_STORAGE_PAGE = 15
> +MANAGED_STORAGE_PAGE = 16
> +BRIDGE_PAGE = 17
> +VIRT_DETAILS_PAGE = 18
> +CONFIRM_PAGE = 19
> +
> +LOCATION="location"
> +KICKSTART="kickstart"
> +KERNELOPTS="kernel.options"
> +OS_TYPE="os.type"
> +OS_VARIANT="os.variant"
> +MEMORY="memory"
> +CPUS="cpus"
> +
> +class DummyMeter(progress.BaseMeter):
> +
> + def _do_start(self, now = None):
> + print "Starting..."
> +
> + def _do_end(self, amount_read, now = None):
> + print "Ending: read=%d" % amount_read
> +
> + def _do_update(self, amount_read, now = None):
> + print "Update: read=%d" % amount_read
> +
> +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 == VM_DETAILS_PAGE: return self.get_vm_details_page(screen)
> + elif page == LOCAL_INSTALL_PAGE: return self.get_local_install_page(screen)
> + elif page == SELECT_CDROM_PAGE: return self.get_select_cdrom_page(screen)
> + elif page == SELECT_ISO_PAGE: return self.get_select_iso_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 == ENABLE_STORAGE_PAGE: return self.get_enable_storage_page(screen)
> + elif page == LOCAL_STORAGE_PAGE: return self.get_local_storage_page(screen)
> + elif page == MANAGED_STORAGE_PAGE: return self.get_managed_storage_page(screen)
> + elif page == BRIDGE_PAGE: return self.get_bridge_page(screen)
> + elif page == VIRT_DETAILS_PAGE: return self.get_virt_details_page(screen)
> + elif page == CONFIRM_PAGE: return self.get_confirm_page(screen)
> + return []
> +
> + def validate_input(self, page, errors):
> + if page == 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 == 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 == 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 == 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 == NETWORK_INSTALL_PAGE:
> + if len(self.__install_url.value()) > 0:
> + return True
> + else:
> + errors.append("An install tree is required.")
> + 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
> + 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 == ENABLE_STORAGE_PAGE: return True
> + elif page == 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 == MANAGED_STORAGE_PAGE:
> + if self.__existing_storage.getSelection() is not None:
> + return True
> + else:
> + errors.append("Please select a storage volume.")
> + elif page == 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 == 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 == 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_use_cdrom_source(self.__install_source.getSelection() == DomainConfig.INSTALL_SOURCE_CDROM)
> + elif page == SELECT_CDROM_PAGE:
> + self.__config.set_install_media(self.__install_media.getSelection())
> + elif page == SELECT_ISO_PAGE:
> + self.__config.set_iso_path(self.__iso_path.value())
> + elif page == 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 == 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 == 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() == Node.STORAGE_TYPE_EXISTING:
> + self.__config.set_use_local_storage(False)
> + elif page == LOCAL_STORAGE_PAGE:
> + self.__config.set_storage_size(float(self.__storage_size.value()))
> + self.__config.set_allocate_storage(self.__allocate_storage.value())
> + elif page == MANAGED_STORAGE_PAGE:
> + self.__config.set_use_local_storage(False)
> + self.__config.set_existing_storage(self.__existing_storage.getSelection())
> + self.__config.set_storage_size(self.get_libvirt().get_storage_size(self.__existing_storage.getSelection()))
> + elif page == BRIDGE_PAGE:
> + self.__config.set_network_bridge(self.__network_bridges.getSelection())
> + elif page == VIRT_DETAILS_PAGE:
> + self.__config.set_virt_type(self.__virt_types.getSelection())
> + self.__config.set_architecture(self.__architectures.getSelection())
> + elif page == CONFIRM_PAGE:
> + self.get_libvirt().define_domain(self.__config, DummyMeter())
> + 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 == 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 == LOCAL_STORAGE_PAGE or page == MANAGED_STORAGE_PAGE:
> + result = ENABLE_STORAGE_PAGE
> + elif page == NETWORK_INSTALL_PAGE:
> + result = VM_DETAILS_PAGE
> + elif page == SELECT_CDROM_PAGE or page == SELECT_ISO_PAGE:
> + result = LOCAL_INSTALL_PAGE
> + elif page == BRIDGE_PAGE:
> + if self.__config.get_use_local_storage():
> + result = LOCAL_STORAGE_PAGE
> + else:
> + result = MANAGED_STORAGE_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 == 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 == LOCAL_INSTALL_PAGE:
> + if self.__config.get_use_cdrom_source():
> + result = SELECT_CDROM_PAGE
> + else:
> + result = SELECT_ISO_PAGE
> + elif page == SELECT_CDROM_PAGE or page == SELECT_ISO_PAGE:
> + result = OS_TYPE_PAGE
> + elif page == NETWORK_INSTALL_PAGE:
> + result = OS_TYPE_PAGE
> + elif page == 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 = MANAGED_STORAGE_PAGE
> + elif page == LOCAL_STORAGE_PAGE or page == MANAGED_STORAGE_PAGE:
> + result = BRIDGE_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)",
> + 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_managed_storage_page(self, screen):
> + volumes = []
> + for volume in self.get_libvirt().list_storage_volumes():
> + volumes.append(["%s (%d GB)" % (volume.name(), volume.info()[1] / (1024 ** 3)),
> + volume.name(),
> + self.__config.is_existing_storage(volume.name())])
> + self.__existing_storage = RadioBar(screen, (volumes))
> + grid = Grid(2, 1)
> + grid.setField(Label("Existing storage:"), 0, 0)
> + grid.setField(self.__existing_storage, 1, 0)
> + return [Label("Configure managed storage"),
> + 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() == bridge.name()])
> + self.__network_bridges = RadioBar(screen, (bridges))
> + if self.__config.get_mac_address() == 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(self.__config.get_existing_storage()), 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 DefineDomain():
> + screen = DomainConfigScreen()
> + screen.start()
> diff --git a/admin/destroydomain.py b/admin/destroydomain.py
> new file mode 100755
> index 0000000..350c32e
> --- /dev/null
> +++ b/admin/destroydomain.py
> @@ -0,0 +1,66 @@
> +#!/usr/bin/env python
> +#
> +# destroydomain.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 DestroyDomainConfigScreen(DomainListConfigScreen):
> + LIST_PAGE = 1
> + DESTROY_PAGE = 2
> +
> + def __init__(self):
> + DomainListConfigScreen.__init__(self, "Destroy 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.DESTROY_PAGE:
> + return self.get_destroy_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.DESTROY_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 destroy the domain: %s" % domain)
> + errors.append(str(error))
> + else:
> + errors.append("You must first select a domain to destroy.")
> + return False
> +
> + def get_destroy_page(self, screen):
> + grid = Grid(1, 1)
> + grid.setField(Label("%s was successfully destroyed." % self.get_selected_domain()), 0, 0)
> + return [grid]
> +
> +def DestroyDomain():
> + screen = DestroyDomainConfigScreen()
> + screen.start()
> diff --git a/admin/domainconfig.py b/admin/domainconfig.py
> new file mode 100644
> index 0000000..ef39fe0
> --- /dev/null
> +++ b/admin/domainconfig.py
> @@ -0,0 +1,217 @@
> +# 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.__existing_storage = ""
> + 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_existing_storage(self, storage):
> + self.__existing_storage = storage
> +
> + def get_existing_storage(self):
> + return self.__existing_storage
> +
> + 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 --git a/admin/halworker.py b/admin/halworker.py
> new file mode 100644
> index 0000000..448c22d
> --- /dev/null
> +++ b/admin/halworker.py
> @@ -0,0 +1,37 @@
> +# 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
> diff --git a/admin/libvirtworker.py b/admin/libvirtworker.py
> new file mode 100644
> index 0000000..054d09e
> --- /dev/null
> +++ b/admin/libvirtworker.py
> @@ -0,0 +1,248 @@
> +# 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
> +
> +from domainconfig import DomainConfig
> +
> +class LibvirtWorker:
> + '''Provides utilities for interfacing with libvirt.'''
> + def __init__(self, url = "qemu:///system"):
> + self.__conn = libvirt.open(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 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 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 list_storage_volumes(self):
> + '''Lists all defined storage volumes.'''
> + pools = self.__conn.listStoragePools()
> + pools.extend(self.__conn.listDefinedStoragePools())
> + result = []
> + for name in pools:
> + pool = self.__conn.storagePoolLookupByName(name)
> + for volname in pool.listVolumes():
> + volume = self.__conn.storageVolLookupByPath("/var/lib/libvirt/images/%s" % volname)
> + result.append(volume)
> + return result
> +
> + def get_storage_size(self, name):
> + '''Returns the size of the specified storage volume.'''
> + volume = self.__conn.storageVolLookupByPath("/var/lib/libvirt/images/%s" % name)
> + 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_is_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)
> +
> + def _setup_disks(self, config):
> + self.__guest.disks = []
> + if config.get_enable_storage():
> + path = None
> + if config.get_use_local_storage():
> + 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("/var/lib/libvirt/images/", 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 --git a/admin/listdomains.py b/admin/listdomains.py
> new file mode 100755
> index 0000000..1b51ee2
> --- /dev/null
> +++ b/admin/listdomains.py
> @@ -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 Domains')
> +
> + 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 domain 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 --git a/admin/mainmenu.py b/admin/mainmenu.py
> new file mode 100755
> index 0000000..2808dad
> --- /dev/null
> +++ b/admin/mainmenu.py
> @@ -0,0 +1,71 @@
> +# 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 configscreen import ConfigScreen
> +from definedomain import DefineDomain
> +from createdomain import CreateDomain
> +from destroydomain import DestroyDomain
> +from undefinedomain import UndefineDomain
> +from listdomains import ListDomains
> +from createuser import CreateUser
> +
> +DEFINE_DOMAIN = 1
> +CREATE_DOMAIN = 2
> +DESTROY_DOMAIN = 3
> +UNDEFINE_DOMAIN = 4
> +LIST_DOMAINS = 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 Domain", DEFINE_DOMAIN)
> + menu.append("Create A Domain", CREATE_DOMAIN)
> + menu.append("Destroy A Domain", DESTROY_DOMAIN)
> + menu.append("Undefine A Domain", UNDEFINE_DOMAIN)
> + menu.append("List All Domains", LIST_DOMAINS)
> + menu.append("Create A User", CREATE_USER)
> + menu.append("Exit Administration", EXIT_CONSOLE)
> + gridform = GridForm(screen, "Node Administration Console", 1, 4)
> + gridform.add(menu, 0, 0)
> + result = gridform.run();
> + screen.popWindow()
> + screen.finish()
> +
> + try:
> + if result.current() == DEFINE_DOMAIN: DefineDomain()
> + elif result.current() == CREATE_DOMAIN: CreateDomain()
> + elif result.current() == DESTROY_DOMAIN: DestroyDomain()
> + elif result.current() == UNDEFINE_DOMAIN: UndefineDomain()
> + elif result.current() == LIST_DOMAINS: ListDomains()
> + elif result.current() == CREATE_USER: CreateUser()
> + elif result.current() == EXIT_CONSOLE: finished = True
> + except Exception, error:
> + screen = SnackScreen()
> + ButtonChoiceWindow(screen,
> + "An Exception Has Occurred",
> + str(error) + "\n" + traceback.format_exc(),
> + buttons = ["OK"])
> + screen.popWindow()
> + screen.finish()
> + finished = True
> diff --git a/admin/nodeadmin.py b/admin/nodeadmin.py
> new file mode 100755
> index 0000000..864a4c0
> --- /dev/null
> +++ b/admin/nodeadmin.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 MainMenu
> +
> +def NodeAdmin():
> + MainMenu()
> +
> +if __name__ == "__main__":
> + sys.exit(NodeAdmin())
> diff --git a/admin/setup.py.in b/admin/setup.py.in
> new file mode 100644
> index 0000000..ac9981a
> --- /dev/null
> +++ b/admin/setup.py.in
> @@ -0,0 +1,34 @@
> +# 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 = "@VERSION@",
> + package_dir = {'nodeadmin': 'admin'},
> + packages = find_packages('.'),
> + entry_points = {
> + 'console_scripts': [
> + 'nodeadmin = nodeadmin.nodeadmin:NodeAdmin',
> + 'definedom = nodeadmin.definedomain:DefineDomain',
> + 'createdom = nodeadmin.createdomain:CreateDomain',
> + 'destroydom = nodeadmin.destroydomain:DestroyDomain',
> + 'undefinedom = nodeadmin.undefinedomain:UndefineDomain',
> + 'createuser = nodeadmin.createuser:CreateUser',
> + 'listdoms = nodeadmin.listdomains:ListDomains']
> + })
> diff --git a/admin/undefinedomain.py b/admin/undefinedomain.py
> new file mode 100755
> index 0000000..2620540
> --- /dev/null
> +++ b/admin/undefinedomain.py
> @@ -0,0 +1,83 @@
> +#!/usr/bin/env python
> +#
> +# undefinedomain.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 UndefineDomainConfigScreen(DomainListConfigScreen):
> + LIST_PAGE = 1
> + CONFIRM_PAGE = 2
> + UNDEFINE_PAGE = 3
> +
> + def __init__(self):
> + DomainListConfigScreen.__init__(self, "Undefine 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.UNDEFINE_PAGE: return self.get_undefine_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.UNDEFINE_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.UNDEFINE_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_undefine.value():
> + domain = self.get_selected_domain()
> + try:
> + self.get_libvirt().undefine_domain(domain)
> + return True
> + except Exception, error:
> + errors.append("Failed to undefine %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_undefine = Checkbox("Check here to confirm undefining %s." % self.get_selected_domain(), 0)
> + grid = Grid(1, 1)
> + grid.setField(self.__confirm_undefine, 0, 0)
> + return [grid]
> +
> + def get_undefine_page(self, screen):
> + grid = Grid(1, 1)
> + grid.setField(Label("%s has been undefined." % self.get_selected_domain()), 0, 0)
> + return [grid]
> +
> +def UndefineDomain():
> + screen = UndefineDomainConfigScreen()
> + screen.start()
> diff --git a/admin/userworker.py b/admin/userworker.py
> new file mode 100644
> index 0000000..167197b
> --- /dev/null
> +++ b/admin/userworker.py
> @@ -0,0 +1,38 @@
> +# 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 --git a/configure.ac b/configure.ac
> index d965a82..e778b10 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -8,6 +8,7 @@ test x"$ac_ct_CC:$CFLAGS" = 'xgcc:-g -O2' \
> && CFLAGS="$CFLAGS -Wshadow -Wall -Werror"
>
> AC_CONFIG_FILES([Makefile
> + admin/setup.py
> gptsync/Makefile
> ovirt-node.spec
> ])
> diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in
> index 12815c9..f9649ed 100644
> --- a/ovirt-node.spec.in
> +++ b/ovirt-node.spec.in
> @@ -1,5 +1,7 @@
> %define product_family oVirt Node
> %define beta Beta
> +%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
> +
>
> Summary: The oVirt Node daemons/scripts
> Name: ovirt-node
> @@ -21,6 +23,8 @@ Requires(post): /sbin/chkconfig
> Requires(preun): /sbin/chkconfig
> BuildRequires: libvirt-devel >= 0.5.1
> BuildRequires: dbus-devel hal-devel
> +BuildRequires: python-devel
> +BuildRequires: setuptool
> Requires: libvirt >= 0.6.3
> Requires: augeas >= 0.3.5
> Requires: libvirt-qpid >= 0.2.14-3
> @@ -44,6 +48,10 @@ Requires: nc
> Requires: grub
> Requires: /usr/sbin/crond
> Requires: anyterm
> +Requires: newt-python
> +Requires: libuser-python
> +Requires: dbus-python
> +
> ExclusiveArch: %{ix86} x86_64
>
> %define app_root %{_datadir}/%{name}
> @@ -144,6 +152,7 @@ cd -
> %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/cron.d
> %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/cron.hourly
> %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/logrotate.d
> +%{__install} -d -m0755 %{buildroot}%{python_sitelib}/nodeadmin
>
> %{__install} -p -m0755 scripts/ovirt-awake %{buildroot}%{_sbindir}
> %{__install} -p -m0755 scripts/ovirt-config-boot %{buildroot}%{_sbindir}
> @@ -164,6 +173,21 @@ cd -
> %{__install} -p -m0755 scripts/persist %{buildroot}%{_sbindir}
> %{__install} -p -m0755 scripts/unpersist %{buildroot}%{_sbindir}
>
> +# %{__install} -p -m0644 admin/__init__.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0644 admin/configscreen.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0755 admin/createdomain.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0755 admin/createuser.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0755 admin/definedomain.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0755 admin/destroydomain.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0644 admin/domainconfig.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0644 admin/halworker.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0644 admin/libvirtworker.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0644 admin/userworker.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0755 admin/listdomains.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0644 admin/mainmenu.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0755 admin/nodeadmin.py %{buildroot}%{python_sitelib}/nodeadmin
> +%{__install} -p -m0755 admin/undefinedomain.py %{buildroot}%{python_sitelib}/nodeadmin
> +
> # gptsync
> %{__install} -p -m0755 gptsync/gptsync %{buildroot}%{_sbindir}
> %{__install} -p -m0755 gptsync/showpart %{buildroot}%{_sbindir}
> @@ -182,6 +206,10 @@ cd -
> %{__install} -p -m0644 logrotate/ovirt-logrotate %{buildroot}%{_sysconfdir}/cron.d
> %{__install} -p -m0644 logrotate/ovirt-logrotate.conf %{buildroot}%{_sysconfdir}/logrotate.d
>
> +# install the admin tools
> +python admin/setup.py install --root %{buildroot}
> +rm -rf %{buildroot}%{python_sitelib}/nodeadmin- at VERSION@*
> +
> echo "oVirt Node release %{version}-%{release}" > %{buildroot}%{_sysconfdir}/ovirt-release
> mkdir -p %{buildroot}/%{_sysconfdir}/default
> touch %{buildroot}/%{_sysconfdir}/default/ovirt
> @@ -325,7 +353,15 @@ fi
> %{_sbindir}/ovirt-awake
> %{_initrddir}/ovirt-functions
> %defattr(-,root,root,0644)
> +%{_bindir}/nodeadmin
> +%{_bindir}/definedom
> +%{_bindir}/createdom
> +%{_bindir}/destroydom
> +%{_bindir}/undefinedom
> +%{_bindir}/listdoms
> +%{_bindir}/createuser
> %{_sysconfdir}/collectd.conf.in
> +%{python_sitelib}/nodeadmin
> %config %attr(0644,root,root) %{_sysconfdir}/ovirt-release
> %config %attr(0644,root,root) %{_sysconfdir}/default/ovirt
>
>
So I've got the tool set installed, but not fully tested just yet,
here's some things that need to be changed
python -m compileall /usr/lib/python2.6/site-packages/nodeadmin in
common-post.ks of ovirt-node-image otherwise they get removed during
blacklisting
# common-blacklist.ks:find / -name '*.py' -exec rm -f {} \;
__init__.py is commented out, cant get this to copy to buildroot for
some reason, still working on it any ideas?
# %{__install} -p -m0644 admin/__init__.py
%{buildroot}%{python_sitelib}/nodeadmin
missing dependencies, whether via rpm/python failures
+python-setuptools - (needed for load_entry_point in nodeadmin)
+dbus-python
+newt
+newt-python
+pkgconfig
+python-devel
+slang
+slang-devel
1.36MB increase from rpms
The egg creation in ovirt-node package for nodeadmin is failing
somewhere and the install doesnt complete during the build process,
which requires it to be run again on boot. I don't see any obvious
failures, what can I look for?
python admin/setup.py install --root
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64
running install
running build
running install_egg_info
running egg_info
creating nodeadmin.egg-info
writing nodeadmin.egg-info/PKG-INFO
writing top-level names to nodeadmin.egg-info/top_level.txt
writing dependency_links to nodeadmin.egg-info/dependency_links.txt
writing entry points to nodeadmin.egg-info/entry_points.txt
writing manifest file 'nodeadmin.egg-info/SOURCES.txt'
warning: manifest_maker: standard file 'setup.py' not found
reading manifest file 'nodeadmin.egg-info/SOURCES.txt'
writing manifest file 'nodeadmin.egg-info/SOURCES.txt'
Copying nodeadmin.egg-info to
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/lib/python2.6/site-packages/nodeadmin-1.0.2-py2.6.egg-info
running install_scripts
Installing definedom script to
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/bin
Installing undefinedom script to
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/bin
Installing nodeadmin script to
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/bin
Installing createdom script to
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/bin
Installing listdoms script to
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/bin
Installing createuser script to
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/bin
Installing destroydom script to
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/bin
+ rm -rf
/home/jboggs/rpm/BUILDROOT/ovirt-node-1.0.2-0.fc11.20090831204520git9646cd0.x86_64/usr/lib/python2.6/site-packages/nodeadmin-1.0.2-py2.6.egg-info
More information about the ovirt-devel
mailing list