On Tue, Sep 29, 2009 at 05:12:58PM -0400, Mike Burns wrote: > On Wed, Sep 23, 2009 at 05:12:46PM -0400, Darryl L. Pierce wrote: > > Moved the node administration elements to a separate submenu. > > > > Created a new network administration menu. > > > > * users can define a network > > * users can create a network > > * users can destroy a network > > * users can undefine a network > > * users can list existing networks, including details > > > > Each new command is also available as a separate command line executable > > as well. > > > > Signed-off-by: Darryl L. Pierce <[email protected]> > > --- > > Makefile.am | 9 ++ > > nodeadmin/configscreen.py | 35 ++++++- > > nodeadmin/createdomain.py | 3 - > > nodeadmin/createnetwork.py | 52 +++++++++ > > nodeadmin/definenet.py | 255 > > ++++++++++++++++++++++++++++++++++++++++++ > > nodeadmin/destroynetwork.py | 56 +++++++++ > > nodeadmin/halworker.py | 8 ++ > > nodeadmin/libvirtworker.py | 61 ++++++++++ > > nodeadmin/listnetworks.py | 55 +++++++++ > > nodeadmin/mainmenu.py | 71 ++++-------- > > nodeadmin/menuscreen.py | 57 ++++++++++ > > nodeadmin/netmenu.py | 58 ++++++++++ > > nodeadmin/networkconfig.py | 99 ++++++++++++++++ > > nodeadmin/nodemenu.py | 63 +++++++++++ > > nodeadmin/setup.py.in | 7 +- > > nodeadmin/undefinenetwork.py | 88 +++++++++++++++ > > ovirt-node.spec.in | 33 +++++- > > 17 files changed, 948 insertions(+), 62 deletions(-) > > create mode 100644 nodeadmin/createnetwork.py > > create mode 100644 nodeadmin/definenet.py > > create mode 100644 nodeadmin/destroynetwork.py > > create mode 100644 nodeadmin/listnetworks.py > > create mode 100644 nodeadmin/menuscreen.py > > create mode 100755 nodeadmin/netmenu.py > > create mode 100644 nodeadmin/networkconfig.py > > create mode 100755 nodeadmin/nodemenu.py > > create mode 100644 nodeadmin/undefinenetwork.py > > > > diff --git a/Makefile.am b/Makefile.am > > index 2d195c0..abb7c33 100644 > > --- a/Makefile.am > > +++ b/Makefile.am > > @@ -28,17 +28,26 @@ EXTRA_DIST = \ > > images/syslinux-vesa-splash.jpg \ > > nodeadmin/__init__.py \ > > nodeadmin/configscreen.py \ > > + nodeadmin/createnetwork.py \ > > nodeadmin/createuser.py \ > > nodeadmin/destroydomain.py \ > > + nodeadmin/destroynetwork.py \ > > nodeadmin/halworker.py \ > > nodeadmin/libvirtworker.py \ > > nodeadmin/userworker.py \ > > nodeadmin/mainmenu.py \ > > + nodeadmin/menuscreen.py \ > > + nodeadmin/netmenu.py \ > > + nodeadmin/nodemenu.py \ > > nodeadmin/undefinedomain.py \ > > + nodeadmin/undefinenetwork.py \ > > nodeadmin/createdomain.py \ > > nodeadmin/definedomain.py \ > > + nodeadmin/definenet.py \ > > nodeadmin/domainconfig.py \ > > + nodeadmin/networkconfig.py \ > > nodeadmin/listdomains.py \ > > + nodeadmin/listnetworks.py \ > > nodeadmin/nodeadmin.py \ > > nodeadmin/setup.py \ > > nodeadmin/utils.py \ > > diff --git a/nodeadmin/configscreen.py b/nodeadmin/configscreen.py > > index 0282eee..f214aea 100644 > > --- a/nodeadmin/configscreen.py > > +++ b/nodeadmin/configscreen.py > > @@ -77,8 +77,9 @@ class ConfigScreen: > > 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) > > + # TODO: need to set the form height to the number of elements > > on the page > > + gridform = GridForm(screen, self.__title, 1, 10) > > current_element = 0 > > for element in elements: > > gridform.add(element, 0, current_element) > > @@ -133,7 +134,7 @@ class DomainListConfigScreen(ConfigScreen): > > if len(domains) > 0: > > self.__has_domains = True > > self.__domain_list = Listbox(0) > > - for name in self.get_libvirt().list_domains(defined, created): > > + for name in domains: > > self.__domain_list.append(name, name) > > result = [self.__domain_list] > > else: > > @@ -148,3 +149,33 @@ class DomainListConfigScreen(ConfigScreen): > > > > def has_selectable_domains(self): > > return self.__has_domains > > + > > +class NetworkListConfigScreen(ConfigScreen): > > + '''Provides a base class for all config screens that require a network > > list.''' > > + > > + def __init__(self, title): > > + ConfigScreen.__init__(self, title) > > + > > + def get_network_list_page(self, screen, defined=True, created=True): > > + networks = self.get_libvirt().list_networks(defined, created) > > + result = None > > + > > + if len(networks) > 0: > > + self.__has_networks = True > > + self.__network_list = Listbox(0) > > + for name in networks: > > + self.__network_list.append(name, name) > > + result = self.__network_list > > + else: > > + self.__has_networks = False > > + result = Label("There are no networks available.") > > + grid = Grid(1, 1) > > + grid.setField(result, 0, 0) > > + return [Label("Network List"), > > + grid] > > + > > + def get_selected_network(self): > > + return self.__network_list.current() > > + > > + def has_selectable_networks(self): > > + return self.__has_networks > > diff --git a/nodeadmin/createdomain.py b/nodeadmin/createdomain.py > > index b73a09e..6f10b44 100755 > > --- a/nodeadmin/createdomain.py > > +++ b/nodeadmin/createdomain.py > > @@ -55,9 +55,6 @@ class CreateDomainConfigScreen(DomainListConfigScreen): > > 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) > > diff --git a/nodeadmin/createnetwork.py b/nodeadmin/createnetwork.py > > new file mode 100644 > > index 0000000..6b40bb6 > > --- /dev/null > > +++ b/nodeadmin/createnetwork.py > > @@ -0,0 +1,52 @@ > > +#!/usr/bin/env python > > +# > > +# createnetwork.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from snack import * > > +from configscreen import * > > + > > +LIST_PAGE = 1 > > +CREATE_PAGE = 2 > > + > > +class CreateNetworkConfigScreen(NetworkListConfigScreen): > > + def __init__(self): > > + NetworkListConfigScreen.__init__(self, "Create A Network") > > + > > + def get_elements_for_page(self, screen, page): > > + if page is LIST_PAGE: return > > self.get_network_list_page(screen, created = False) > > + elif page is CREATE_PAGE: return > > self.get_create_network_page(screen) > > + > > + def page_has_next(self, page): > > + if page is LIST_PAGE: return self.has_selectable_networks() > > + > > + def page_has_back(self, page): > > + return (page is CREATE_PAGE) > > + > > + def validate_input(self, page, errors): > > + if page is LIST_PAGE: > > + self.get_libvirt().create_network(self.get_selected_network()) > > + return True > > + > > + def get_create_network_page(self, screen): > > + return [Label("Network Started"), > > + Label("%s was successfully started." % > > self.get_selected_network())] > > + > > +def CreateNetwork(): > > + screen = CreateNetworkConfigScreen() > > + screen.start() > > diff --git a/nodeadmin/definenet.py b/nodeadmin/definenet.py > > new file mode 100644 > > index 0000000..b76fe27 > > --- /dev/null > > +++ b/nodeadmin/definenet.py > > @@ -0,0 +1,255 @@ > > +# definenet.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from snack import * > > +from IPy import IP > > +import traceback > > +import re > > +import logging > > + > > +from configscreen import ConfigScreen > > +from networkconfig import NetworkConfig > > + > > +NETWORK_NAME_PAGE = 1 > > +IPV4_ADDRESS_PAGE = 2 > > +PUBLIC_NETWORK_ALERT_PAGE = 3 > > +NETWORK_DETAILS_PAGE = 4 > > +DHCP_RANGE_PAGE = 5 > > +NETWORK_TYPE_PAGE = 6 > > +SELECT_PHYSICAL_NETWORK_PAGE = 7 > > +SUMMARY_PAGE = 8 > > + > > +class DefineNetworkConfigScreen(ConfigScreen): > > + def __init__(self): > > + ConfigScreen.__init__(self, "Create A Virtual Network Interface") > > + self.__config = NetworkConfig() > > + > > + def get_elements_for_page(self, screen, page): > > + if page is NETWORK_NAME_PAGE: return > > self.get_network_name_page(screen) > > + elif page is IPV4_ADDRESS_PAGE: return > > self.get_ipv4_address_page(screen) > > + elif page is PUBLIC_NETWORK_ALERT_PAGE: return > > self.get_public_network_alert_page(screen) > > + elif page is NETWORK_DETAILS_PAGE: return > > self.get_network_details_page(screen) > > + elif page is DHCP_RANGE_PAGE: return > > self.get_dhcp_range_page(screen) > > + elif page is NETWORK_TYPE_PAGE: return > > self.get_network_type_page(screen) > > + elif page is SELECT_PHYSICAL_NETWORK_PAGE: return > > self.get_select_physical_network_page(screen) > > + elif page is SUMMARY_PAGE: return > > self.get_summary_page(screen) > > + > > + def validate_input(self, page, errors): > > + if page is NETWORK_NAME_PAGE: > > + if len(self.__name.value()) > 0: > > + if re.match("^[a-zA-Z0-9_]*$", self.__name.value()): > > + return True > > + else: > > + errors.append("The network name can only contain > > letters, numbers and the underscore, and no spaces.") > > + else: > > + errors.append("Network name must be non-blank and less > > than 50 characters") > > + elif page is IPV4_ADDRESS_PAGE: > > + if len(self.__ipv4_address.value()) > 0: > > + try: > > + > > self.__config.set_ipv4_address(self.__ipv4_address.value()) > > + return True > > + except Exception, error: > > + errors.append("The network address could not be > > understood: %s" % str(error)) > > + else: > > + errors.append("Network must be entered in the format > > 1.2.3.4/8") > > + elif page is PUBLIC_NETWORK_ALERT_PAGE: return True > > + elif page is NETWORK_DETAILS_PAGE: return True > > + elif page is DHCP_RANGE_PAGE: > > + try: > > + if len(self.__start_address.value()) > 0 and > > len(self.__end_address.value()) > 0: > > + start = IP(self.__start_address.value(), ) > > + end = IP(self.__end_address.value()) > > + if not self.__config.is_bad_address(start) and not > > self.__config.is_bad_address(end): > > + return True > > + else: > > + errors.append("Start and/or end address are > > outside of the choosen network.") > > + else: > > + errors.append("Start and end address must be > > non-blank.") > > + except Exception, error: > > + logging.error(str(error)) > > + errors.append("The start and/or end addresses could not be > > understood.") > > + elif page is NETWORK_TYPE_PAGE: return True > > + elif page is SELECT_PHYSICAL_NETWORK_PAGE: return True > > + elif page is SUMMARY_PAGE: return True > > + return False > > + > > + def process_input(self, page): > > + if page is NETWORK_NAME_PAGE: > > + self.__config.set_name(self.__name.value()) > > + elif page is DHCP_RANGE_PAGE: > > + > > self.__config.set_ipv4_start_address(self.__start_address.value()) > > + self.__config.set_ipv4_end_address(self.__end_address.value()) > > + elif page is NETWORK_TYPE_PAGE: > > + > > self.__config.set_isolated_network(self.__isolated_network.value()) > > + elif page is SELECT_PHYSICAL_NETWORK_PAGE: > > + > > self.__config.set_physical_device(self.__physical_devices.getSelection()) > > + elif page is SUMMARY_PAGE: > > + self.get_libvirt().define_network(self.__config) > > + self.set_finished() > > + > > + def get_next_page(self, page): > > + if page is IPV4_ADDRESS_PAGE: > > + if self.__config.is_public_ipv4_network(): > > + return PUBLIC_NETWORK_ALERT_PAGE > > + else: > > + return NETWORK_DETAILS_PAGE > > + if page is NETWORK_TYPE_PAGE: > > + if self.__config.is_isolated_network(): > > + return SUMMARY_PAGE > > + else: > > + return SELECT_PHYSICAL_NETWORK_PAGE > > + return ConfigScreen.get_next_page(self, page) > > + > > + def get_back_page(self, page): > > + if page is NETWORK_DETAILS_PAGE: > > + return IPV4_ADDRESS_PAGE > > + if page is SUMMARY_PAGE: > > + if self.__config.is_isolated_network(): > > + return NETWORK_TYPE_PAGE > > + else: > > + return SELECT_PHYSICAL_NETWORK_PAGE > > + return ConfigScreen.get_back_page(self, page) > > + > > + def page_has_finish(self, page): > > + if page is SUMMARY_PAGE: return True > > + return False > > + > > + def page_has_next(self, page): > > + if page < SUMMARY_PAGE: return True > > + > > + def page_has_back(self, page): > > + if page > NETWORK_NAME_PAGE: return True > > + return False > > + > > + def get_network_name_page(self, screen): > > + self.__name = Entry(50, self.__config.get_name()) > > + grid = Grid(2, 1) > > + grid.setField(Label("Network Name:"), 0, 0) > > + grid.setField(self.__name, 1, 0) > > + return [Label("Please choose a name for your virtual network"), > > + grid] > > + > > + def get_ipv4_address_page(self, screen): > > + self.__ipv4_address = Entry(18, self.__config.get_ipv4_address()) > > + grid = Grid(2, 1) > > + grid.setField(Label("Network:"), 0, 0, anchorRight = 1) > > + grid.setField(self.__ipv4_address, 1, 0, anchorLeft = 1) > > + return [Label("You will need to choose an IPv4 address space for > > the virtual network:"), > > + grid, > > + Label("HINT: The network should be chosen from"), > > + Label("one of the IPv4 private address ranges;"), > > + Label("e.g., 10.0.0.0/8, 172.168.0.0/12, 192.168.0.0/16")] > > + > > + def get_network_details_page(self, screen): > > + grid = Grid(2, 6) > > + grid.setField(Label("Network:"), 0, 0, anchorRight = 1) > > + grid.setField(Label(self.__config.get_ipv4_address()), 1, 0, > > anchorLeft = 1) > > + grid.setField(Label("Netmask:"), 0, 1, anchorRight = 1) > > + grid.setField(Label(self.__config.get_ipv4_netmask()), 1, 1, > > anchorLeft = 1) > > + grid.setField(Label("Broadcast:"), 0, 2, anchorRight = 1) > > + grid.setField(Label(self.__config.get_ipv4_broadcast()), 1, 2, > > anchorLeft = 1) > > + grid.setField(Label("Gateway:"), 0, 3, anchorRight = 1) > > + grid.setField(Label(self.__config.get_ipv4_gateway()), 1, 3, > > anchorLeft = 1) > > + grid.setField(Label("Size:"), 0, 4, anchorRight = 1) > > + grid.setField(Label("%d addresses" % > > self.__config.get_ipv4_max_addresses()), 1, 4, anchorLeft = 1) > > + grid.setField(Label("Type:"), 0, 5, anchorRight = 1) > > + grid.setField(Label(self.__config.get_ipv4_network_type()), 1, 5, > > anchorLeft = 1) > > + return [Label("Network Details"), > > + grid] > > + > > + def get_public_network_alert_page(self, screen): > > + grid = Grid(1, 2) > > + grid.setField(Label("The network should normally use a private > > IPv4 address."), 0, 0, anchorLeft = 1) > > + grid.setField(Label("Use this non-private address anyway?"), 0, 1, > > anchorLeft = 1) > > + return [Label("Check Network Address"), > > + grid] > > + > > + def get_dhcp_range_page(self, screen): > > + self.__start_address = Entry(15, > > self.__config.get_ipv4_start_address()) > > + self.__end_address = Entry(15, > > self.__config.get_ipv4_end_address()) > > + grid = Grid(2,2) > > + grid.setField(Label("Start:"), 0, 0, anchorRight = 1) > > + grid.setField(self.__start_address, 1, 0, anchorLeft = 1) > > + grid.setField(Label("End:"), 0, 1, anchorRight = 1) > > + grid.setField(self.__end_address, 1, 1, anchorLeft = 1) > > If possible we might want to expand the size of these fields 1 char. If you > have a max width IP address, the first char gets cut off from the display. > Functionally, this is no impact, but it was confusing at first glance. > > > > + return [Label("Selecting The DHCP Range"), > > + grid, > > + Label("TIP: Unless you wish to reserve some addresses to > > allow static network"), > > + Label("configuration in virtual machines, these paraemters > > can be left with"), > > + Label("their default values.")] > > + > > + def get_network_type_page(self, screen): > > + self.__isolated_network = Checkbox("Isolated virtual network", > > + > > self.__config.is_isolated_network()) > > + grid = Grid(1, 2) > > + grid.setField(Label("Please indicate whether this virtual network > > should be connected to the physical network."), 0, 0) > > On my vm, this label was too wide for the screen. I'm not sure if this is > only my system, but we might want to split into multiple lines. > > > + grid.setField(self.__isolated_network, 0, 1) > > + return [Label("Connecting To Physical Network"), > > + grid] > > + > > + def get_select_physical_network_page(self, screen): > > + devices = [] > > + devices.append(["NAT to any physical device", "", > > self.__config.get_physical_device() == ""]) > > + for device in self.get_hal().list_network_devices(): > > + devices.append(["NAT to physical device %s" % device, device, > > self.__config.get_physical_device() == device]) > > + self.__physical_devices = RadioBar(screen, (devices)) > > + grid = Grid(1, 2) > > + grid.setField(Label("Forward to physical network:"), 0, 0) > > + grid.setField(self.__physical_devices, 0, 1) > > + return [Label("Connecting To Physical Network"), > > + grid] > > + > > + def get_summary_page(self, screen): > > + grid1 = Grid(2, 1) > > + grid1.setField(Label("Network name:"), 0, 0, anchorRight = 1) > > + grid1.setField(Label(self.__config.get_name()), 1, 0, anchorLeft = > > 1) > > + > > + grid2 = Grid(2, 3) > > + grid2.setField(Label("Network:"), 0, 0, anchorRight = 1) > > + grid2.setField(Label(self.__config.get_ipv4_address()), 1, 0, > > anchorLeft = 1) > > + grid2.setField(Label("Gateway:"), 0, 1, anchorRight = 1) > > + grid2.setField(Label(self.__config.get_ipv4_gateway()), 1, 1, > > anchorLeft = 1) > > + grid2.setField(Label("Netmask:"), 0, 2, anchorRight = 1) > > + grid2.setField(Label(self.__config.get_ipv4_netmask()), 1, 2, > > anchorLeft = 1) > > + > > + grid3 = Grid(2, 2) > > + grid3.setField(Label("Start address:"), 0, 0, anchorRight = 1) > > + grid3.setField(Label(self.__config.get_ipv4_start_address()), 1, > > 0, anchorLeft = 1) > > + grid3.setField(Label("End address:"), 0, 1, anchorRight = 1) > > + grid3.setField(Label(self.__config.get_ipv4_end_address()), 1, 1, > > anchorLeft = 1) > > + > > + grid4 = Grid(2, 1) > > + grid4.setField(Label("Connectivity:"), 0, 0, anchorRight = 1) > > + if self.__config.is_isolated_network(): > > + grid4.setField(Label("Isolated virtual network"), 1, 0, > > anchorLeft = 1) > > + else: > > + grid4.setField(Label("NAT to %s" % > > self.__config.get_physical_device_text()), 1, 0, anchorLeft = 1) > > + > > + return [Label("Ready To Create Network"), > > + Label("Summary"), > > + grid1, > > + Label("IPv4 Network"), > > + grid2, > > + Label("DHCP"), > > + grid3, > > + Label("Forwarding"), > > + grid4] > > + > > +def DefineNetwork(): > > + screen = DefineNetworkConfigScreen() > > + screen.start() > > diff --git a/nodeadmin/destroynetwork.py b/nodeadmin/destroynetwork.py > > new file mode 100644 > > index 0000000..5fb3e82 > > --- /dev/null > > +++ b/nodeadmin/destroynetwork.py > > @@ -0,0 +1,56 @@ > > +#!/usr/bin/env python > > +# > > +# destroynetwork.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from snack import * > > +from configscreen import * > > + > > +LIST_PAGE = 1 > > +DESTROY_PAGE = 2 > > + > > +class DestroyNetworkConfigScreen(NetworkListConfigScreen): > > + def __init__(self): > > + NetworkListConfigScreen.__init__(self, "Destroy A Network") > > + > > + def get_elements_for_page(self, screen, page): > > + if page is LIST_PAGE: return > > self.get_network_list_page(screen, defined = False) > > + elif page is DESTROY_PAGE: return > > self.get_destroy_network_page(screen) > > + > > + def page_has_next(self, page): > > + if page is LIST_PAGE: return self.has_selectable_networks() > > + return False > > + > > + def page_has_back(self, page): > > + if page is DESTROY_PAGE: return True > > + return False > > + > > + def validate_input(self, page, errors): > > + if page is LIST_PAGE: > > + network = self.get_selected_network() > > + self.get_libvirt().destroy_network(network) > > + return True > > + return False > > + > > + def get_destroy_network_page(self, screen): > > + return [Label("Network Destroyed"), > > + Label("%s has been destroyed." % > > self.get_selected_network())] > > + > > +def DestroyNetwork(): > > + screen = DestroyNetworkConfigScreen() > > + screen.start() > > diff --git a/nodeadmin/halworker.py b/nodeadmin/halworker.py > > index 448c22d..7aa9a04 100644 > > --- a/nodeadmin/halworker.py > > +++ b/nodeadmin/halworker.py > > @@ -35,3 +35,11 @@ class HALWorker: > > if info.GetProperty("volume.disc.has_data"): > > result[str(info.GetProperty("block.device"))] = > > info.GetProperty("volume.label") > > return result > > + > > + def list_network_devices(self): > > + result = [] > > + for udi in self.__conn.FindDeviceByCapability("net"): > > + device = self.__bus.get_object("org.freedesktop.Hal", udi) > > + info = dbus.Interface(device, "org.freedesktop.Hal.Device") > > + result.append(info.GetProperty("net.interface")) > > + return result > > diff --git a/nodeadmin/libvirtworker.py b/nodeadmin/libvirtworker.py > > index adaea16..ba07605 100644 > > --- a/nodeadmin/libvirtworker.py > > +++ b/nodeadmin/libvirtworker.py > > @@ -73,6 +73,67 @@ class LibvirtWorker: > > domain = self.get_domain(name) > > domain.undefine() > > > > + def list_networks(self, defined = True, started = True): > > + '''Lists all networks.''' > > + result = [] > > + if defined: result.extend(self.__conn.listDefinedNetworks()) > > + if started: result.extend(self.__conn.listNetworks()) > > + return result > > + > > + def get_network(self, name): > > + '''Returns the specified network.''' > > + result = self.__conn.networkLookupByName(name) > > + if result is None: raise Exception("No such network exists: %s" % > > name) > > + > > + return result > > + > > + def network_exists(self, name): > > + '''Returns if a network with the given name already exists.''' > > + networks = self.list_networks() > > + if name in networks: return True > > + return False > > + > > + def define_network(self, config): > > + '''Defines a new network.''' > > + # since there's no other way currently, we'll have to use XML > > + name = config.get_name() > > + ip = config.get_ipv4_address_raw() > > + start = config.get_ipv4_start_address() > > + end = config.get_ipv4_end_address() > > + fw = config.get_physical_device() > > + > > + xml = "<network>" + \ > > + " <name>%s</name>\n" % name > > + if not config.is_public_ipv4_network(): > > + if fw is not "": > > + xml += " <forward dev='%s'/>\n" % fw[1] > > + else: > > + xml += " <forward/>\n" > > + > > + xml += " <ip address='%s' netmask='%s'>\n" % (str(ip[1]), > > str(ip.netmask())) > > + xml += " <dhcp>\n" > > + xml += " <range start='%s' end='%s'/>\n" % (str(start), > > str(end)) > > + xml += " </dhcp>\n" > > + xml += " </ip>\n" > > + xml += "</network>\n" > > + > > + self.__conn.networkDefineXML(xml) > > + > > + def create_network(self, name): > > + '''Creates a defined network.''' > > + network = self.get_network(name) > > + network.create() > > + > > + def destroy_network(self, name): > > + '''Destroys the specified network.''' > > + network = self.get_network(name) > > + network.destroy() > > + > > + def undefine_network(self, name): > > + '''Undefines the specified network.''' > > + network = self.get_network(name) > > + network.undefine() > > + > > def list_storage_pools(self): > > '''Returns the list of all defined storage pools.''' > > return self.__conn.listStoragePools() > > diff --git a/nodeadmin/listnetworks.py b/nodeadmin/listnetworks.py > > new file mode 100644 > > index 0000000..a53f898 > > --- /dev/null > > +++ b/nodeadmin/listnetworks.py > > @@ -0,0 +1,55 @@ > > +# listnetworks.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from configscreen import * > > + > > +LIST_PAGE = 1 > > +DETAILS_PAGE = 2 > > + > > +class ListNetworksConfigScreen(NetworkListConfigScreen): > > + def __init__(self): > > + NetworkListConfigScreen.__init__(self, "List Networks") > > + > > + def page_has_next(self, page): > > + return (page is LIST_PAGE) and self.has_selectable_networks() > > + > > + def page_has_back(self, page): > > + return (page is DETAILS_PAGE) > > + > > + def get_elements_for_page(self, screen, page): > > + if page is LIST_PAGE: return > > self.get_network_list_page(screen) > > + elif page is DETAILS_PAGE: return > > self.get_network_details_page(screen) > > + > > + def get_network_details_page(self, screen): > > + network = > > self.get_libvirt().get_network(self.get_selected_network()) > > + grid = Grid(2, 3) > > + grid.setField(Label("Name:"), 0, 0, anchorRight = 1) > > + grid.setField(Label(network.name()), 1, 0, anchorLeft = 1) > > + grid.setField(Label("Autostart:"), 0, 1, anchorRight = 1) > > + label = "No" > > + if network.autostart(): label = "Yes" > > + grid.setField(Label(label), 1, 1, anchorLeft = 1) > > + if network.bridgeName() is not "": > > + grid.setField(Label("Bridge:"), 0, 2, anchorRight = 1) > > + grid.setField(Label(network.bridgeName()), 1, 2, anchorLeft = > > 1) > > + return [Label("Network Interface Details"), > > + grid] > > + > > +def ListNetworks(): > > + screen = ListNetworksConfigScreen() > > + screen.start() > > diff --git a/nodeadmin/mainmenu.py b/nodeadmin/mainmenu.py > > index 497ad57..73501fa 100755 > > --- a/nodeadmin/mainmenu.py > > +++ b/nodeadmin/mainmenu.py > > @@ -18,57 +18,30 @@ > > > > 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 > > + > > +from menuscreen import MenuScreen > > +from nodemenu import NodeMenu > > +from netmenu import NetworkMenu > > + > > import utils > > import logging > > > > -DEFINE_DOMAIN = 1 > > -CREATE_DOMAIN = 2 > > -DESTROY_DOMAIN = 3 > > -UNDEFINE_DOMAIN = 4 > > -LIST_DOMAINS = 5 > > -CREATE_USER = 6 > > -EXIT_CONSOLE = 99 > > +NODE_MENU = 1 > > +NETWORK_MENU = 2 > > +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() > > +class MainMenuScreen(MenuScreen): > > + def __init__(self): > > + MenuScreen.__init__(self, "Main Menu") > > > > - 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() > > - logging.info("An exception occurred: %s" % str(error)) > > - ButtonChoiceWindow(screen, > > - "An Exception Has Occurred", > > - str(error) + "\n" + traceback.format_exc(), > > - buttons = ["OK"]) > > - screen.popWindow() > > - screen.finish() > > - finished = True > > + def get_menu_items(self): > > + return (("Node Administration", NODE_MENU), > > + ("Network Administration", NETWORK_MENU)) > > + > > + def handle_selection(self, page): > > + if page is NODE_MENU: NodeMenu() > > + elif page is NETWORK_MENU: NetworkMenu() > > + > > +def MainMenu(): > > + screen = MainMenuScreen() > > + screen.start() > > diff --git a/nodeadmin/menuscreen.py b/nodeadmin/menuscreen.py > > new file mode 100644 > > index 0000000..1700e8c > > --- /dev/null > > +++ b/nodeadmin/menuscreen.py > > @@ -0,0 +1,57 @@ > > +# mainmenu.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from snack import * > > +import traceback > > + > > +import utils > > +import logging > > + > > +EXIT_MENU = 99 > > + > > +class MenuScreen: > > + def __init__(self, title): > > + self.__title = title > > + > > + def start(self): > > + finished = False > > + while finished == False: > > + screen = SnackScreen() > > + menu = Listbox(height = 0, width = 0, returnExit = 1) > > + for menu_item in self.get_menu_items(): > > + menu.append(menu_item[0], menu_item[1]) > > + menu.append("Exit Menu", EXIT_MENU) > > + gridform = GridForm(screen, self.__title, 1, 4) > > + gridform.add(menu, 0, 0) > > + result = gridform.run(); > > + screen.popWindow() > > + screen.finish() > > + > > + try: > > + if result.current() == EXIT_MENU: finished = True > > + else: self.handle_selection(result.current()) > > + except Exception, error: > > + screen = SnackScreen() > > + logging.info("An exception occurred: %s" % str(error)) > > + ButtonChoiceWindow(screen, > > + "An Exception Has Occurred", > > + str(error) + "\n" + > > traceback.format_exc(), > > + buttons = ["OK"]) > > + screen.popWindow() > > + screen.finish() > > + finished = True > > diff --git a/nodeadmin/netmenu.py b/nodeadmin/netmenu.py > > new file mode 100755 > > index 0000000..88e159f > > --- /dev/null > > +++ b/nodeadmin/netmenu.py > > @@ -0,0 +1,58 @@ > > +# mainmenu.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from snack import * > > +import traceback > > + > > +from menuscreen import MenuScreen > > +from definenet import DefineNetwork > > +from createnetwork import CreateNetwork > > +from destroynetwork import DestroyNetwork > > +from undefinenetwork import UndefineNetwork > > +from listnetworks import ListNetworks > > + > > +import utils > > +import logging > > + > > +DEFINE_NETWORK = 1 > > +CREATE_NETWORK = 2 > > +DESTROY_NETWORK = 3 > > +UNDEFINE_NETWORK = 4 > > +LIST_NETWORKS = 5 > > + > > +class NetworkMenuScreen(MenuScreen): > > + def __init__(self): > > + MenuScreen.__init__(self, "Network Administration") > > + > > + def get_menu_items(self): > > + return (("Define A Network", DEFINE_NETWORK), > > + ("Create A Network", CREATE_NETWORK), > > + ("Destroy A Network", DESTROY_NETWORK), > > + ("Undefine A Network", UNDEFINE_NETWORK), > > + ("List Networks", LIST_NETWORKS)) > > + > > + def handle_selection(self, item): > > + if item is DEFINE_NETWORK: DefineNetwork() > > + elif item is CREATE_NETWORK: CreateNetwork() > > + elif item is DESTROY_NETWORK: DestroyNetwork() > > + elif item is UNDEFINE_NETWORK: UndefineNetwork() > > + elif item is LIST_NETWORKS: ListNetworks() > > + > > +def NetworkMenu(): > > + screen = NetworkMenuScreen() > > + screen.start() > > diff --git a/nodeadmin/networkconfig.py b/nodeadmin/networkconfig.py > > new file mode 100644 > > index 0000000..57d184d > > --- /dev/null > > +++ b/nodeadmin/networkconfig.py > > @@ -0,0 +1,99 @@ > > +# networkconfig.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from IPy import IP > > +import logging > > + > > +class NetworkConfig: > > + def __init__(self): > > + self.__name = "" > > + self.set_ipv4_address("192.168.100.0/24") > > + self.__isolated_network = True > > + self.__physical_device = "" > > + > > + def set_name(self, name): > > + self.__name = name > > + > > + def get_name(self): > > + return self.__name > > + > > + def set_ipv4_address(self, address): > > + self.__ipv4_address = IP(address) > > + start = int(self.__ipv4_address.len() / 2) > > + end = self.__ipv4_address.len() - 2 > > + self.__ipv4_start = str(self.__ipv4_address[start]) > > + self.__ipv4_end = str(self.__ipv4_address[end]) > > + > > + def get_ipv4_address(self): > > + return self.__ipv4_address.strNormal() > > + > > + def get_ipv4_address_raw(self): > > + return self.__ipv4_address > > + > > + def get_ipv4_netmask(self): > > + return self.__ipv4_address.netmask().strNormal() > > + > > + def get_ipv4_broadcast(self): > > + return self.__ipv4_address.broadcast().strNormal() > > + > > + def get_ipv4_gateway(self): > > + return str(self.__ipv4_address[1]) > > + > > + def get_ipv4_max_addresses(self): > > + return self.__ipv4_address.len() > > + > > + def get_ipv4_network_type(self): > > + return self.__ipv4_address.iptype() > > + > > + def is_public_ipv4_network(self): > > + if self.__ipv4_address.iptype() is "PUBLIC": > > + return True > > + return False > > + > > + def set_ipv4_start_address(self, address): > > + self.__ipv4_start = address > > + > > + def get_ipv4_start_address(self): > > + return self.__ipv4_start > > + > > + def set_ipv4_end_address(self, address): > > + self.__ipv4_end = address > > + > > + def get_ipv4_end_address(self): > > + return self.__ipv4_end > > + > > + def is_bad_address(self, address): > > + return not self.__ipv4_address.overlaps(address) > > + > > + def set_isolated_network(self, isolated): > > + self.__isolated_network = isolated > > + > > + def is_isolated_network(self): > > + return self.__isolated_network > > + > > + def set_physical_device(self, device): > > + self.__physical_device = device > > + > > + def get_physical_device(self): > > + return self.__physical_device > > + > > + def get_physical_device_text(self): > > + if self.__physical_device == "": > > + return "any physical device" > > + else: > > + return "physical device %s" % self.__physical_device > > diff --git a/nodeadmin/nodemenu.py b/nodeadmin/nodemenu.py > > new file mode 100755 > > index 0000000..9e339ff > > --- /dev/null > > +++ b/nodeadmin/nodemenu.py > > @@ -0,0 +1,63 @@ > > +# mainmenu.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from snack import * > > +import traceback > > + > > +from menuscreen import MenuScreen > > +from configscreen import ConfigScreen > > +from definedomain import DefineDomain > > +from createdomain import CreateDomain > > +from destroydomain import DestroyDomain > > +from undefinedomain import UndefineDomain > > +from listdomains import ListDomains > > +from createuser import CreateUser > > + > > +import utils > > +import logging > > + > > +DEFINE_DOMAIN = 1 > > +CREATE_DOMAIN = 2 > > +DESTROY_DOMAIN = 3 > > +UNDEFINE_DOMAIN = 4 > > +LIST_DOMAINS = 5 > > +CREATE_USER = 6 > > + > > +class NodeMenuScreen(MenuScreen): > > + def __init__(self): > > + MenuScreen.__init__(self, "Node Administration") > > + > > + def get_menu_items(self): > > + return (("Define A Domain", DEFINE_DOMAIN), > > + ("Create A Domain", CREATE_DOMAIN), > > + ("Destroy A Domain", DESTROY_DOMAIN), > > + ("Undefine A Domain", UNDEFINE_DOMAIN), > > + ("List All Domains", LIST_DOMAINS), > > + ("Create A User", CREATE_USER)) > > + > > + def handle_selection(self, item): > > + if item is DEFINE_DOMAIN: DefineDomain() > > + elif item is CREATE_DOMAIN: CreateDomain() > > + elif item is DESTROY_DOMAIN: DestroyDomain() > > + elif item is UNDEFINE_DOMAIN: UndefineDomain() > > + elif item is LIST_DOMAINS: ListDomains() > > + elif item is CREATE_USER: CreateUser() > > + > > +def NodeMenu(): > > + screen = NodeMenuScreen() > > + screen.start() > > diff --git a/nodeadmin/setup.py.in b/nodeadmin/setup.py.in > > index f51a34c..3635810 100644 > > --- a/nodeadmin/setup.py.in > > +++ b/nodeadmin/setup.py.in > > @@ -30,5 +30,10 @@ setup(name = "nodeadmin", > > 'destroydom = nodeadmin.destroydomain:DestroyDomain', > > 'undefinedom = nodeadmin.undefinedomain:UndefineDomain', > > 'createuser = nodeadmin.createuser:CreateUser', > > - 'listdoms = nodeadmin.listdomains:ListDomains'] > > + 'listdoms = nodeadmin.listdomains:ListDomains', > > + 'definenet = nodeadmin.definenet:DefineNetwork', > > + 'createnet = nodeadmin.createnetwork:CreateNetwork', > > + 'destroynet = nodeadmin.destroynetwork:DestroyNetwork', > > + 'undefinenet = nodeadmin.undefinenetwork:UndefineNetwork', > > + 'listnets = nodeadmin.listnetworks:ListNetworks'] > > }) > > diff --git a/nodeadmin/undefinenetwork.py b/nodeadmin/undefinenetwork.py > > new file mode 100644 > > index 0000000..f71bd20 > > --- /dev/null > > +++ b/nodeadmin/undefinenetwork.py > > @@ -0,0 +1,88 @@ > > +#!/usr/bin/env python > > +# > > +# undefinenetwork.py - Copyright (C) 2009 Red Hat, Inc. > > +# Written by Darryl L. Pierce <[email protected]> > > +# > > +# This program is free software; you can redistribute it and/or modify > > +# it under the terms of the GNU General Public License as published by > > +# the Free Software Foundation; version 2 of the License. > > +# > > +# This program is distributed in the hope that it will be useful, > > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > +# GNU General Public License for more details. > > +# > > +# You should have received a copy of the GNU General Public License > > +# along with this program; if not, write to the Free Software > > +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > > +# MA 02110-1301, USA. A copy of the GNU General Public License is > > +# also available at http://www.gnu.org/copyleft/gpl.html. > > + > > +from snack import * > > +from configscreen import * > > + > > +LIST_PAGE = 1 > > +CONFIRM_PAGE = 2 > > +UNDEFINE_PAGE = 3 > > + > > +class UndefineNetworkConfigScreen(NetworkListConfigScreen): > > + def __init__(self): > > + NetworkListConfigScreen.__init__(self, "Undefine A Network") > > + > > + def get_elements_for_page(self, screen, page): > > + if page is LIST_PAGE: return > > self.get_network_list_page(screen, created = False) > > + elif page is CONFIRM_PAGE: return self.get_confirm_page(screen) > > + elif page is UNDEFINE_PAGE: return > > self.get_undefine_network_page(screen) > > + > > + def process_input(self, page, errors): > > + if page is LIST_PAGE: > > + network = self.get_selected_network() > > + self.get_libvirt().undefine_network(network) > > + return True > > + > > + def page_has_next(self, page): > > + if page is LIST_PAGE: return self.has_selectable_networks() > > + if page is CONFIRM_PAGE: return True > > + return False > > + > > + def page_has_back(self, page): > > + if page is CONFIRM_PAGE: return True > > + if page is UNDEFINE_PAGE: return True > > + return False > > + > > + def get_back_page(self, page): > > + if page is CONFIRM_PAGE: return LIST_PAGE > > + elif page is UNDEFINE_PAGE: return LIST_PAGE > > + > > + def validate_input(self, page, errors): > > + if page is LIST_PAGE: return True > > + elif page is CONFIRM_PAGE: > > + if self.__confirm_undefine.value(): > > + return True > > + else: > > + errors.append("You must confirm undefining %s." % > > self.get_selected_network()) > > + elif page is UNDEFINE_PAGE: return True > > + return False > > + > > + def process_input(self, page): > > + if page is LIST_PAGE: return True > > + elif page is CONFIRM_PAGE: > > + network = self.get_selected_network() > > + self.get_libvirt().undefine_network(network) > > + return True > > + elif page is UNDEFINE_PAGE: return True > > + return False > > + > > + def get_confirm_page(self, screen): > > + self.__confirm_undefine = Checkbox("Check here to confirm > > undefining %s." % self.get_selected_network(), 0) > > + grid = Grid(1, 1) > > + grid.setField(self.__confirm_undefine, 0, 0) > > + return [grid] > > + > > + def get_undefine_network_page(self, screen): > > + return [Label("Network Is Undefined"), > > + Label("%s has been undefined." % > > self.get_selected_network())] > > + > > This label is awkward. Something like "Network %s has been undefined." seems > better to me. > > > +def UndefineNetwork(): > > + screen = UndefineNetworkConfigScreen() > > + screen.start() > > diff --git a/ovirt-node.spec.in b/ovirt-node.spec.in > > index ee1942b..2a6b7b6 100644 > > --- a/ovirt-node.spec.in > > +++ b/ovirt-node.spec.in > > @@ -51,6 +51,7 @@ Requires: anyterm > > Requires: newt-python > > Requires: libuser-python > > Requires: dbus-python > > +Requires: python-IPy > > > > ExclusiveArch: %{ix86} x86_64 > > > > @@ -175,19 +176,32 @@ cd - > > > > %{__install} -p -m0644 nodeadmin/__init__.py > > %{buildroot}%{python_sitelib}/nodeadmin > > %{__install} -p -m0644 nodeadmin/configscreen.py > > %{buildroot}%{python_sitelib}/nodeadmin > > -%{__install} -p -m0755 nodeadmin/createdomain.py > > %{buildroot}%{python_sitelib}/nodeadmin > > -%{__install} -p -m0755 nodeadmin/createuser.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0644 nodeadmin/menuscreen.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0755 nodeadmin/utils.py > > %{buildroot}%{python_sitelib}/nodeadmin > > + > > +%{__install} -p -m0755 nodeadmin/nodeadmin.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0644 nodeadmin/mainmenu.py > > %{buildroot}%{python_sitelib}/nodeadmin > > + > > +%{__install} -p -m0644 nodeadmin/nodemenu.py > > %{buildroot}%{python_sitelib}/nodeadmin > > %{__install} -p -m0755 nodeadmin/definedomain.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0755 nodeadmin/createdomain.py > > %{buildroot}%{python_sitelib}/nodeadmin > > %{__install} -p -m0755 nodeadmin/destroydomain.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0755 nodeadmin/undefinedomain.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0755 nodeadmin/listdomains.py > > %{buildroot}%{python_sitelib}/nodeadmin > > %{__install} -p -m0644 nodeadmin/domainconfig.py > > %{buildroot}%{python_sitelib}/nodeadmin > > + > > +%{__install} -p -m0644 nodeadmin/netmenu.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0644 nodeadmin/networkconfig.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0755 nodeadmin/definenet.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0755 nodeadmin/createnetwork.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0755 nodeadmin/destroynetwork.py > > %{buildroot}%{python_sitelib}/nodeadmin > > +%{__install} -p -m0755 nodeadmin/undefinenetwork.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 > > %{__install} -p -m0644 nodeadmin/libvirtworker.py > > %{buildroot}%{python_sitelib}/nodeadmin > > %{__install} -p -m0644 nodeadmin/userworker.py > > %{buildroot}%{python_sitelib}/nodeadmin > > -%{__install} -p -m0755 nodeadmin/listdomains.py > > %{buildroot}%{python_sitelib}/nodeadmin > > -%{__install} -p -m0644 nodeadmin/mainmenu.py > > %{buildroot}%{python_sitelib}/nodeadmin > > -%{__install} -p -m0755 nodeadmin/nodeadmin.py > > %{buildroot}%{python_sitelib}/nodeadmin > > -%{__install} -p -m0755 nodeadmin/undefinedomain.py > > %{buildroot}%{python_sitelib}/nodeadmin > > -%{__install} -p -m0755 nodeadmin/utils.py > > %{buildroot}%{python_sitelib}/nodeadmin > > > > # gptsync > > %{__install} -p -m0755 gptsync/gptsync %{buildroot}%{_sbindir} > > @@ -360,6 +374,11 @@ fi > > %{_bindir}/destroydom > > %{_bindir}/undefinedom > > %{_bindir}/listdoms > > +%{_bindir}/definenet > > +%{_bindir}/createnet > > +%{_bindir}/destroynet > > +%{_bindir}/undefinenet > > +%{_bindir}/listnets > > %{_bindir}/createuser > > %{_sysconfdir}/collectd.conf.in > > %{python_sitelib}/nodeadmin > > -- > > 1.6.2.5 > > > > _______________________________________________ > > Ovirt-devel mailing list > > [email protected] > > https://www.redhat.com/mailman/listinfo/ovirt-devel > > > > > This seems pretty good. There are a couple of nitpicks inline. The only > major thing I found is that we need to add /var/lib/dnsmasq to the r/o > filesystem overrides. If we don't we can't create or destroy networks. > > I tested defining and undefining networks, but without above entry to rwtab, > i can't create/destroy networks. I'll try rebuilding it with entry in rwtab, > but wanted to get comments out first. > > Oh, side note, I'm not an expert at python by any stretch, so most of the > testing was done using black box techniques. > > Mike
Ok, this works when you apply the patch that I will post to the list shortly. ACK, with the above comments. _______________________________________________ Ovirt-devel mailing list [email protected] https://www.redhat.com/mailman/listinfo/ovirt-devel
