From 2fd4775c68160a8617fff5f7015542bf8c1501e5 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Fri, 12 Oct 2007 18:08:32 -0400 Subject: Teach the WebUI (and the backend for the WebUI) how to save multiple interfaces. Also clean up the error page display and include a link to go back so users can correct any data entry errors. --- cobbler/item_system.py | 45 ++++++++++++++++++------ cobbler/webui/CobblerWeb.py | 76 ++++++++++++++++++++++++++++++---------- webui_templates/error_page.tmpl | 7 +++- webui_templates/system_edit.tmpl | 22 +++++------- 4 files changed, 105 insertions(+), 45 deletions(-) diff --git a/cobbler/item_system.py b/cobbler/item_system.py index d7c71e1..749919a 100644 --- a/cobbler/item_system.py +++ b/cobbler/item_system.py @@ -14,7 +14,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import utils import item -import copy from cexceptions import * from rhpl.translate import _, N_, textdomain, utf8 @@ -41,6 +40,20 @@ class System(item.Item): self.virt_path = "<>" # use value in profile self.virt_type = "<>" # use value in profile + def delete_interface(self,name): + """ + Used to remove an interface. Not valid for intf0. + """ + if name == "intf0": + raise CX(_("the first interface cannot be deleted")) + if self.interfaces.has_key(name): + del self.interfaces[name] + else: + # NOTE: raising an exception here would break the WebUI as currently implemented + return False + return True + + def __get_interface(self,name): if name not in [ "intf0", "intf1", "intf2", "intf3", "intf4", "intf5", "intf6", "intf7" ]: @@ -199,14 +212,14 @@ class System(item.Item): Only works if manage_dhcp is set in /var/lib/cobbler/settings """ intf = self.__get_interface(interface) - if utils.is_ip(address): + if address == "" or utils.is_ip(address): intf["ip_address"] = address return True raise CX(_("invalid format for IP address (%s)") % address) def set_mac_address(self,address,interface="intf0"): intf = self.__get_interface(interface) - if utils.is_mac(address): + if address == "" or utils.is_mac(address): intf["mac_address"] = address return True raise CX(_("invalid format for MAC address (%s)" % address)) @@ -349,6 +362,22 @@ class System(item.Item): return buf + def modify_interface(self, hash): + """ + Used by the WUI to modify an interface more-efficiently + """ + for (key,value) in hash.iteritems(): + (field,interface) = key.split("-") + if field == "macaddress" : self.set_mac_address(value, interface) + if field == "ipaddress" : self.set_ip_address(value, interface) + if field == "hostname" : self.set_hostname(value, interface) + if field == "dhcptag" : self.set_dhcp_tag(value, interface) + if field == "subnet" : self.set_subnet(value, interface) + if field == "gateway" : self.set_gateway(value, interface) + if field == "virtbridge" : self.set_virt_bridge(value, interface) + return True + + def remote_methods(self): return { 'name' : self.set_name, @@ -356,17 +385,11 @@ class System(item.Item): 'kopts' : self.set_kernel_options, 'ksmeta' : self.set_ksmeta, 'hostname' : self.set_hostname, - 'ip-address' : self.set_ip_address, - 'ip' : self.set_ip_address, # alias - 'mac-address' : self.set_mac_address, - 'mac' : self.set_mac_address, # alias 'kickstart' : self.set_kickstart, 'netboot-enabled' : self.set_netboot_enabled, 'virt-path' : self.set_virt_path, 'virt-type' : self.set_virt_type, - 'dhcp-tag' : self.set_dhcp_tag, - 'gateway' : self.set_gateway, - 'virt-bridge' : self.set_virt_bridge, - 'subnet' : self.set_subnet + 'modify-interface' : self.modify_interface, + 'delete-interface' : self.delete_interface } diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py index b16758e..93b47da 100644 --- a/cobbler/webui/CobblerWeb.py +++ b/cobbler/webui/CobblerWeb.py @@ -23,6 +23,9 @@ import Cookie import time LOGGING_ENABLED = True + +## FIXME: move to htaccess and eliminate browser cookies? + COOKIE_TIMEOUT=29*60 if LOGGING_ENABLED: @@ -392,8 +395,8 @@ class CobblerWeb(object): # FIXME: implement handling of delete1, delete2 + renames def system_save(self,name=None,oldname=None,editmode="edit",profile=None, - new_or_edit=None, mac=None, ip=None, hostname=None, - kopts=None, ksmeta=None, netboot='n', dhcp_tag=None, + new_or_edit=None, + kopts=None, ksmeta=None, netboot='n', delete1=None, delete2=None, **args): if not self.__xmlrpc_setup(): @@ -415,15 +418,16 @@ class CobblerWeb(object): return self.error_page("could not delete %s, %s" % (name,str(e))) return self.system_list() + # obsolete -- just do this server side # more parameter checking - if mac is None and ip is None and hostname is None and not is_mac(name) and not is_ip(name): - return self.error_page("System must have at least one of MAC/IP/hostname.") - if hostname and not ip: - ip = resolve_ip( hostname ) - if mac and not is_mac( mac ): - return self.error_page("The provided MAC address appears to be invalid.") - if ip and not is_ip( ip ): - return self.error_page("The provided IP address appears to be invalid.") + #if mac is None and ip is None and hostname is None and not is_mac(name) and not is_ip(name): + # return self.error_page("System must have at least one of MAC/IP/hostname.") + #if hostname and not ip: + # ip = resolve_ip( hostname ) + #if mac and not is_mac( mac ): + # return self.error_page("The provided MAC address appears to be invalid.") + #if ip and not is_ip( ip ): + # return self.error_page("The provided IP address appears to be invalid.") # grab a reference to the object if new_or_edit == "edit" and editmode == "edit": @@ -438,26 +442,60 @@ class CobblerWeb(object): try: self.remote.modify_system(system, 'name', name, self.token ) self.remote.modify_system(system, 'profile', profile, self.token) - if mac: - self.remote.modify_system(system, 'mac', mac, self.token) - if ip: - self.remote.modify_system(system, 'ip', ip, self.token) - if hostname: - self.remote.modify_system(system, 'hostname', hostname, self.token) + #if mac: + # self.remote.modify_system(system, 'mac', mac, self.token) + #if ip: + # self.remote.modify_system(system, 'ip', ip, self.token) + #if hostname: + # self.remote.modify_system(system, 'hostname', hostname, self.token) if kopts: self.remote.modify_system(system, 'kopts', kopts, self.token) if ksmeta: self.remote.modify_system(system, 'ksmeta', ksmeta, self.token) if netboot: self.remote.modify_system(system, 'netboot-enabled', netboot, self.token) - if dhcp_tag: - self.remote.modify_system(system, 'dhcp-tag', dhcp_tag, self.token) + #if dhcp_tag: + # self.remote.modify_system(system, 'dhcp-tag', dhcp_tag, self.token) + + # raise str(args) + + for x in range(0,7): + interface = "intf%s" % x + macaddress = args.get("macaddress-%s" % interface, "") + ipaddress = args.get("ipaddress-%s" % interface, "") + hostname = args.get("hostname-%s" % interface, "") + virtbridge = args.get("virtbridge-%s" % interface, "") + dhcptag = args.get("dhcptag-%s" % interface, "") + subnet = args.get("subnet-%s" % interface, "") + gateway = args.get("gateway-%s" % interface, "") + if not (macaddress != "" or ipaddress != "" or hostname != "" or virtbridge != "" or dhcptag != "" or subnet != "" or gateway != ""): + # if we have nothing to modify, request that we remove the interface unless it's the + # the first interface, in which case it is NOT removeable + if not interface == "intf0": + self.remote.modify_system(system,'delete-interface', interface, self.token) + else: + # it looks like we have at least one value to submit, just send the ones over that are + # /not/ None (just to be paranoid about XMLRPC and allow-none) + mods = {} + mods["macaddress-%s" % interface] = macaddress + mods["ipaddress-%s" % interface] = ipaddress + mods["hostname-%s" % interface] = hostname + mods["virtbridge-%s" % interface] = virtbridge + mods["dhcptag-%s" % interface] = dhcptag + mods["subnet-%s" % interface] = subnet + mods["gateway-%s" % interface] = gateway + self.remote.modify_system(system,'modify-interface', mods, self.token) + + # now commit the edits self.remote.save_system( system, self.token) + except Exception, e: # FIXME: get the exact error message and display to the user. log_exc() return self.error_page("Error while saving system: %s" % str(e)) + + if editmode == "rename" and name != oldname: try: self.remote.system_remove(oldname, self.token) @@ -761,7 +799,7 @@ class CobblerWeb(object): # look as if they were locally generated and not exception-based. if message.endswith(">"): message = message[:-2] - message = message.replace(":","") + message = message.replace(":","",1) return self.__render( 'error_page.tmpl', { 'message': message diff --git a/webui_templates/error_page.tmpl b/webui_templates/error_page.tmpl index 9bf7473..ce9af93 100644 --- a/webui_templates/error_page.tmpl +++ b/webui_templates/error_page.tmpl @@ -2,5 +2,10 @@ #attr $title = "Cobbler: Error" #block body -

$message

+

Error

+ +

$message

+ +Go Back + #end block body diff --git a/webui_templates/system_edit.tmpl b/webui_templates/system_edit.tmpl index affe88f..f282ef4 100644 --- a/webui_templates/system_edit.tmpl +++ b/webui_templates/system_edit.tmpl @@ -7,7 +7,7 @@ ### ### FIXME: add gateway, subnet, and any other missing fields -#set $fields = [ "mac", "ip", "hostname", "dhcptag", "virtbridge", "subnet", "gateway"] +#set $fields = [ "macaddress", "ipaddress", "hostname", "dhcptag", "virtbridge", "subnet", "gateway"]