[Ovirt-devel] [PATCH 1/2] Users can now work with remote libvirt hosts.

Darryl L. Pierce dpierce at redhat.com
Wed Nov 11 15:51:22 UTC 2009


The user can:
 * select a remote machine
 * add a remote machine
 * remove a remote machine

Signed-off-by: Darryl L. Pierce <dpierce at redhat.com>
---
 Makefile.am                |    5 ++
 nodeadmin/addhost.py       |  129 ++++++++++++++++++++++++++++++++++++++++++++
 nodeadmin/changehost.py    |   58 ++++++++++++++++++++
 nodeadmin/configscreen.py  |   36 ++++++++++++-
 nodeadmin/definenet.py     |    1 +
 nodeadmin/hostconnect.py   |   29 ++++++++++
 nodeadmin/hostmenu.py      |   46 ++++++++++++++++
 nodeadmin/libvirtworker.py |   53 +++++++++++++++++-
 nodeadmin/mainmenu.py      |   14 +++--
 nodeadmin/removehost.py    |   66 ++++++++++++++++++++++
 ovirt-node.spec.in         |    5 ++
 11 files changed, 434 insertions(+), 8 deletions(-)
 create mode 100644 nodeadmin/addhost.py
 create mode 100644 nodeadmin/changehost.py
 create mode 100644 nodeadmin/hostconnect.py
 create mode 100644 nodeadmin/hostmenu.py
 create mode 100644 nodeadmin/removehost.py

diff --git a/Makefile.am b/Makefile.am
index b3929de..1671405 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,11 +28,15 @@ EXTRA_DIST =			\
   images/syslinux-vesa-splash.jpg	\
   nodeadmin/__init__.py         \
   nodeadmin/adddomain.py        \
+  nodeadmin/addhost.py          \
+  nodeadmin/changehost.py       \
   nodeadmin/configscreen.py     \
   nodeadmin/createnetwork.py    \
   nodeadmin/createuser.py       \
   nodeadmin/destroynetwork.py   \
   nodeadmin/halworker.py        \
+  nodeadmin/hostconnect.py      \
+  nodeadmin/hostmenu.py         \
   nodeadmin/libvirtworker.py    \
   nodeadmin/userworker.py       \
   nodeadmin/mainmenu.py         \
@@ -40,6 +44,7 @@ EXTRA_DIST =			\
   nodeadmin/netmenu.py          \
   nodeadmin/nodemenu.py         \
   nodeadmin/removedomain.py     \
+  nodeadmin/removehost.py       \
   nodeadmin/undefinenetwork.py  \
   nodeadmin/startdomain.py      \
   nodeadmin/stopdomain.py       \
diff --git a/nodeadmin/addhost.py b/nodeadmin/addhost.py
new file mode 100644
index 0000000..ef35b7d
--- /dev/null
+++ b/nodeadmin/addhost.py
@@ -0,0 +1,129 @@
+# addhost.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from configscreen import *
+
+DETAILS_PAGE = 1
+CONFIRM_PAGE = 2
+
+HYPERVISOR_XEN      = "xen"
+HYPERVISOR_KVM      = "kvm"
+
+HYPERVISORS = {HYPERVISOR_XEN : "Xen",
+               HYPERVISOR_KVM : "QEMU/KVM"}
+
+CONNECTION_LOCAL    = "local"
+CONNECTION_KERBEROS = "kerberos"
+CONNECTION_SSL      = "ssl"
+CONNECTION_SSH      = "ssh"
+
+CONNECTIONS = {CONNECTION_LOCAL    : "Local",
+               CONNECTION_KERBEROS : "Remote Password or Kerberos",
+               CONNECTION_SSL      : "Remote SSL/TLS with x509 certificate",
+               CONNECTION_SSH      : "Remote tunnel over SSH"}
+
+class AddHostConfigScreen(ConfigScreen):
+    def __init__(self):
+        ConfigScreen.__init__(self, "Add A Remote Host")
+        self.__configured = False
+
+    def get_elements_for_page(self, screen, page):
+        if   page is DETAILS_PAGE: return self.get_details_page(screen)
+        elif page is CONFIRM_PAGE: return self.get_confirm_page(screen)
+
+    def page_has_next(self, page):
+        return page < CONFIRM_PAGE
+
+    def page_has_back(self, page):
+        return page > DETAILS_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_PAGE
+
+    def validate_input(self, page, errors):
+        if page is DETAILS_PAGE:
+            if len(self.__hostname.value()) > 0:
+                return True
+            else:
+                errors.append("You must enter a remote hostname.")
+        elif page is CONFIRM_PAGE: return True
+        return False
+
+    def process_input(self, page):
+        if page is CONFIRM_PAGE:
+            hv       = self.__hypervisor.getSelection()
+            conn     = self.__connection.getSelection()
+            hostname = self.__hostname.value()
+
+            if   hv is HYPERVISOR_XEN:
+                if   conn is CONNECTION_LOCAL:    url = "xen:///"
+                elif conn is CONNECTION_KERBEROS: url = "xen+tcp:///" + hostname + "/"
+                elif conn is CONNECTION_SSL:      url = "xen+tls:///" + hostname + "/"
+                elif conn is CONNECTION_SSH:      url = "xen+ssh:///" + hostname + "/"
+            elif hv is HYPERVISOR_KVM:
+                if   conn is CONNECTION_LOCAL:    url = "qemu:///system"
+                elif conn is CONNECTION_KERBEROS: url = "qemu+tcp://" + hostname + "/system"
+                elif conn is CONNECTION_SSL:      url = "qemu+tls://" + hostname + "/system"
+                elif conn is CONNECTION_SSH:      url = "qemu+ssh://" + hostname + "/system"
+
+            self.get_virt_manager_config().add_connection(url)
+            self.set_finished()
+
+    def get_details_page(self, screen):
+        if not self.__configured:
+            self.__hypervisor = RadioBar(screen, ((HYPERVISORS[HYPERVISOR_XEN], HYPERVISOR_XEN, True),
+                                                  (HYPERVISORS[HYPERVISOR_KVM], HYPERVISOR_KVM, False)))
+            self.__connection = RadioBar(screen, ((CONNECTIONS[CONNECTION_LOCAL],    CONNECTION_LOCAL, True),
+                                                  (CONNECTIONS[CONNECTION_KERBEROS], CONNECTION_KERBEROS, False),
+                                                  (CONNECTIONS[CONNECTION_SSL],      CONNECTION_SSL, False),
+                                                  (CONNECTIONS[CONNECTION_SSH],      CONNECTION_SSH, False)))
+            self.__hostname = Entry(50, "")
+            self.__autoconnect = Checkbox("Autoconnect on Startup")
+            self.__configured = True
+        grid = Grid(2, 4)
+        grid.setField(Label("Hypervisor:"), 0, 0, anchorRight = 1, anchorTop = 1)
+        grid.setField(self.__hypervisor, 1, 0, anchorLeft = 1)
+        grid.setField(Label("Connection:"), 0, 1, anchorRight = 1, anchorTop = 1)
+        grid.setField(self.__connection, 1, 1, anchorLeft = 1)
+        grid.setField(Label("Hostname:"), 0, 2, anchorRight = 1)
+        grid.setField(self.__hostname, 1, 2, anchorLeft = 1)
+        grid.setField(Label(""), 0, 3, anchorRight = 1)
+        grid.setField(self.__autoconnect, 1, 3, anchorLeft = 1)
+        return [Label("Add Connection"),
+                grid]
+
+    def get_confirm_page(self, screen):
+        grid = Grid(2, 4)
+        grid.setField(Label("Hypervisor:"), 0, 0, anchorRight = 1)
+        grid.setField(Label(HYPERVISORS[self.__hypervisor.getSelection()]), 1, 0, anchorLeft = 1)
+        grid.setField(Label("Connection:"), 0, 1, anchorRight = 1)
+        grid.setField(Label(CONNECTIONS[self.__connection.getSelection()]), 1, 1, anchorLeft = 1)
+        grid.setField(Label("Hostname:"), 0, 2, anchorRight = 1)
+        grid.setField(Label(self.__hostname.value()), 1, 2, anchorLeft = 1)
+        grid.setField(Label("Autoconnect on Startup:"), 0, 3, anchorRight = 1)
+        label = "Yes"
+        if not self.__autoconnect.value(): label = "No"
+        grid.setField(Label(label), 1, 3, anchorLeft = 1)
+        return [Label("Confirm Connection"),
+                grid]
+
+def AddHost():
+    screen = AddHostConfigScreen()
+    screen.start()
diff --git a/nodeadmin/changehost.py b/nodeadmin/changehost.py
new file mode 100644
index 0000000..23e6854
--- /dev/null
+++ b/nodeadmin/changehost.py
@@ -0,0 +1,58 @@
+# changehost.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+import logging
+import libvirtworker
+from configscreen import *
+
+CONNECTION_LIST_PAGE = 1
+CONNECTED_PAGE       = 2
+
+class ChangeHostConfigScreen(HostListConfigScreen):
+    def __init__(self):
+        HostListConfigScreen.__init__(self, "Change Host")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is CONNECTION_LIST_PAGE: return self.get_connection_list_page(screen)
+        elif page is CONNECTED_PAGE:       return self.get_connected_page(screen)
+
+    def process_input(self, page):
+        if   page is CONNECTION_LIST_PAGE:
+            logging.info("Changing libvirt connection to %s" % self.get_selected_connection())
+            libvirtworker.set_default_url(self.get_selected_connection())
+            self.get_libvirt().open_connection(self.get_selected_connection())
+        elif page is CONNECTED_PAGE: self.set_finished()
+
+    def page_has_next(self, page):
+        if page is CONNECTION_LIST_PAGE: return self.has_selectable_connections()
+        return False
+
+    def page_has_back(self, page):
+        return page > CONNECTION_LIST_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONNECTED_PAGE
+
+    def get_connected_page(self, screen):
+        return [Label("Connected to %s" % self.get_selected_connection())]
+
+def ChangeHost():
+    screen = ChangeHostConfigScreen()
+    screen.start()
diff --git a/nodeadmin/configscreen.py b/nodeadmin/configscreen.py
index f214aea..98e0338 100644
--- a/nodeadmin/configscreen.py
+++ b/nodeadmin/configscreen.py
@@ -18,7 +18,7 @@
 
 from snack import *
 from halworker import HALWorker
-from libvirtworker import LibvirtWorker
+from libvirtworker import *
 import traceback
 
 BACK_BUTTON   = "back"
@@ -35,6 +35,7 @@ class ConfigScreen:
         self.__finished = False
         self.__hal = HALWorker()
         self.__libvirt = LibvirtWorker()
+        self.__vm_config = VirtManagerConfig()
 
     def get_hal(self):
         return self.__hal
@@ -42,6 +43,9 @@ class ConfigScreen:
     def get_libvirt(self):
         return self.__libvirt
 
+    def get_virt_manager_config(self):
+        return self.__vm_config
+
     def set_finished(self):
         self.__finished = True
 
@@ -179,3 +183,33 @@ class NetworkListConfigScreen(ConfigScreen):
 
     def has_selectable_networks(self):
         return self.__has_networks
+
+class HostListConfigScreen(ConfigScreen):
+    '''Provides a base class for working with lists of libvirt hosts.'''
+
+    def __init__(self, title):
+        ConfigScreen.__init__(self, title)
+
+    def get_connection_list_page(self, screen):
+        connections = self.get_virt_manager_config().get_connection_list()
+        result = None
+
+        if len(connections) > 0:
+            self.__has_connections = True
+            self.__connection_list = Listbox(0)
+            for connection in connections:
+                self.__connection_list.append(connection, connection)
+            result = self.__connection_list
+        else:
+            self.__has_connections = False
+            result = Label("There are no defined connections.")
+        grid = Grid(1, 1)
+        grid.setField(result, 0, 0)
+        return [Label("Host List"),
+                grid]
+
+    def get_selected_connection(self):
+        return self.__connection_list.current()
+
+    def has_selectable_connections(self):
+        return self.__has_connections
diff --git a/nodeadmin/definenet.py b/nodeadmin/definenet.py
index 4aa37d5..6dff18f 100644
--- a/nodeadmin/definenet.py
+++ b/nodeadmin/definenet.py
@@ -20,6 +20,7 @@ from snack import *
 from IPy import IP
 import traceback
 import logging
+import re
 
 from configscreen  import ConfigScreen
 from networkconfig import NetworkConfig
diff --git a/nodeadmin/hostconnect.py b/nodeadmin/hostconnect.py
new file mode 100644
index 0000000..a1be569
--- /dev/null
+++ b/nodeadmin/hostconnect.py
@@ -0,0 +1,29 @@
+# hostconnect.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from configscreen import *
+
+class HostConnectConfigScreen(ConfigScreen):
+    def __init__(self):
+        ConfigScree
+
+def HostConnect():
+    screen = HostConnectConfigScreen()
+    screen.start()
diff --git a/nodeadmin/hostmenu.py b/nodeadmin/hostmenu.py
new file mode 100644
index 0000000..4054d6b
--- /dev/null
+++ b/nodeadmin/hostmenu.py
@@ -0,0 +1,46 @@
+# hostmenu.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from menuscreen import MenuScreen
+from changehost import ChangeHost
+from addhost    import AddHost
+from removehost import RemoveHost
+
+SELECT_HOST = 1
+ADD_HOST    = 2
+REMOVE_HOST = 3
+
+class HostMenuScreen(MenuScreen):
+    def __init__(self):
+        MenuScreen.__init__(self, "Host Menu Screen")
+
+    def get_menu_items(self):
+        return (("Select A Host", SELECT_HOST),
+                ("Add A Host",    ADD_HOST),
+                ("Remove A Host", REMOVE_HOST))
+
+    def handle_selection(self, item):
+        if   item is SELECT_HOST: ChangeHost()
+        elif item is ADD_HOST:    AddHost()
+        elif item is REMOVE_HOST: RemoveHost()
+
+def HostMenu():
+    screen = HostMenuScreen()
+    screen.start()
diff --git a/nodeadmin/libvirtworker.py b/nodeadmin/libvirtworker.py
index ba07605..2998486 100644
--- a/nodeadmin/libvirtworker.py
+++ b/nodeadmin/libvirtworker.py
@@ -21,20 +21,69 @@ import libvirt
 import os
 import virtinst
 import utils
+import logging
 
 from domainconfig import DomainConfig
 
 DEFAULT_POOL_TARGET_PATH="/var/lib/libvirt/images"
+DEFAULT_URL="qemu:///system"
+
+default_url = DEFAULT_URL
+
+def set_default_url(url):
+    logging.info("Changing DEFAULT_URL to %s" % url)
+    global default_url
+
+    default_url = url
+
+def get_default_url():
+    logging.info("Returning default URL of %s" % default_url)
+    return default_url
+
+class VirtManagerConfig:
+    def __init__(self, filename = "/etc/remote-libvirt.conf"):
+        self.__filename = filename
+
+    def get_connection_list(self):
+        result = []
+        if os.path.exists(self.__filename):
+            input = file(self.__filename, "r")
+            for entry in input: result.append(entry[0:-1])
+        return result
+
+    def add_connection(self, connection):
+        connections = self.get_connection_list()
+        if connections.count(connection) is 0:
+            connections.append(connection)
+            self._save_connections(connections)
+
+    def remove_connection(self, connection):
+        connections = self.get_connection_list()
+        if connections.count(connection) > 0:
+            connections.remove(connection)
+            self._save_connections(connections)
+
+    def _save_connections(self, connections):
+        output = file(self.__filename, "w")
+        for entry in connections:
+            print >> output, entry
+        output.close
 
 class LibvirtWorker:
     '''Provides utilities for interfacing with libvirt.'''
-    def __init__(self, url = "qemu:///system"):
-        self.__conn = libvirt.open(url)
+    def __init__(self, url = None):
+        if url is None: url = get_default_url()
+        logging.info("Connecting to libvirt: %s" % url)
+        self.open_connection(url)
         self.__capabilities = virtinst.CapabilitiesParser.parse(self.__conn.getCapabilities())
         self.__net = virtinst.VirtualNetworkInterface(conn = self.__conn)
         self.__net.setup(self.__conn)
         (self.__new_guest, self.__new_domain) = virtinst.CapabilitiesParser.guest_lookup(conn = self.__conn)
 
+    def open_connection(self, url):
+        '''Lets the user change the url for the connection.'''
+        self.__conn = libvirt.open(url)
+
     def list_domains(self, defined = True, started = True):
         '''Lists all domains.'''
         result = []
diff --git a/nodeadmin/mainmenu.py b/nodeadmin/mainmenu.py
index 73501fa..944ffeb 100755
--- a/nodeadmin/mainmenu.py
+++ b/nodeadmin/mainmenu.py
@@ -19,15 +19,17 @@
 from snack import *
 import traceback
 
-from menuscreen     import MenuScreen
-from nodemenu       import NodeMenu
-from netmenu        import NetworkMenu
+from menuscreen import MenuScreen
+from nodemenu   import NodeMenu
+from netmenu    import NetworkMenu
+from hostmenu   import HostMenu
 
 import utils
 import logging
 
 NODE_MENU    = 1
 NETWORK_MENU = 2
+HOST_MENU    = 3
 EXIT_CONSOLE = 99
 
 class MainMenuScreen(MenuScreen):
@@ -35,12 +37,14 @@ class MainMenuScreen(MenuScreen):
         MenuScreen.__init__(self, "Main Menu")
 
     def get_menu_items(self):
-        return (("Node Administration", NODE_MENU),
-                ("Network Administration", NETWORK_MENU))
+        return (("Node Administration",    NODE_MENU),
+                ("Network Administration", NETWORK_MENU),
+                ("Host Administration",    HOST_MENU))
 
     def handle_selection(self, page):
         if   page is NODE_MENU:    NodeMenu()
         elif page is NETWORK_MENU: NetworkMenu()
+        elif page is HOST_MENU:    HostMenu()
 
 def MainMenu():
     screen = MainMenuScreen()
diff --git a/nodeadmin/removehost.py b/nodeadmin/removehost.py
new file mode 100644
index 0000000..cf3c46c
--- /dev/null
+++ b/nodeadmin/removehost.py
@@ -0,0 +1,66 @@
+# removehost.py - Copyright (C) 2009 Red Hat, Inc.
+# Written by Darryl L. Pierce <dpierce at redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+from snack import *
+
+from configscreen import *
+
+SELECT_HOST_PAGE    = 1
+CONFIRM_REMOVE_PAGE = 2
+
+class RemoveHostConfigScreen(HostListConfigScreen):
+    def __init__(self):
+        HostListConfigScreen.__init__(self, "Remove Host Connection")
+
+    def get_elements_for_page(self, screen, page):
+        if   page is SELECT_HOST_PAGE:    return self.get_connection_list_page(screen)
+        elif page is CONFIRM_REMOVE_PAGE: return self.get_confirm_remove_page(screen)
+
+    def page_has_next(self, page):
+        return page is SELECT_HOST_PAGE and self.has_selectable_connections()
+
+    def page_has_back(self, page):
+        return page is CONFIRM_REMOVE_PAGE
+
+    def page_has_finish(self, page):
+        return page is CONFIRM_REMOVE_PAGE
+
+    def validate_input(self, page, errors):
+        if   page is SELECT_HOST_PAGE: return True
+        elif page is CONFIRM_REMOVE_PAGE:
+            if self.__confirm.value():
+                return True
+            else:
+                errors.append("You must confirm removing the connection.")
+        return False
+
+    def process_input(self, page):
+        if page is CONFIRM_REMOVE_PAGE:
+            self.get_virt_manager_config().remove_connection(self.get_selected_connection())
+            self.set_finished()
+
+    def get_confirm_remove_page(self, screen):
+        self.__confirm = Checkbox("Remove this connection: %s" % self.get_selected_connection(), 0)
+        grid = Grid(1, 1)
+        grid.setField(self.__confirm, 0, 0)
+        return [Label("Remove Host Connection"),
+                grid]
+
+def RemoveHost():
+    screen = RemoveHostConfigScreen()
+    screen.start()
diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in
index 00050a4..39d46b3 100644
--- a/ovirt-node.spec.in
+++ b/ovirt-node.spec.in
@@ -198,6 +198,11 @@ cd -
 %{__install} -p -m0755 nodeadmin/destroynetwork.py %{buildroot}%{python_sitelib}/nodeadmin
 %{__install} -p -m0755 nodeadmin/undefinenetwork.py %{buildroot}%{python_sitelib}/nodeadmin
 
+%{__install} -p -m0755 nodeadmin/addhost.py %{buildroot}%{python_sitelib}/nodeadmin
+%{__install} -p -m0644 nodeadmin/changehost.py %{buildroot}%{python_sitelib}/nodeadmin
+%{__install} -p -m0755 nodeadmin/hostmenu.py %{buildroot}%{python_sitelib}/nodeadmin
+%{__install} -p -m0755 nodeadmin/removehost.py %{buildroot}%{python_sitelib}/nodeadmin
+
 %{__install} -p -m0755 nodeadmin/createuser.py %{buildroot}%{python_sitelib}/nodeadmin
 
 %{__install} -p -m0644 nodeadmin/halworker.py %{buildroot}%{python_sitelib}/nodeadmin
-- 
1.6.2.5




More information about the ovirt-devel mailing list