[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