[virt-tools-list] [PATCH 2/6] IPv6 support: update gui python processing

Cole Robinson crobinso at redhat.com
Tue Mar 26 22:32:18 UTC 2013


On 03/26/2013 07:05 AM, Gene Czarcinski wrote:
> Update the gui processing programs.  Some of this is
> also used by the Tui interface. With this patch, all needs for
> IPy.py in the gui portion of virt-manager have been removed and
> replaced with ipaddr from the prython-ipaddr package.  These updates
> also implement network display.
> 
> Currently, createnet.py only handles IPv4 network
> creation.
> Signed-off-by: Gene Czarcinski <gene at czarc.net>

Hi Gene,

Please squash this patch together with patch #1, the UI changes aren't much
useful in isolation.

Also, for testing UI it's quite useful to use the libvirt test driver if you
haven't:

./virt-manager --connect test:///`pwd`/tests/testdriver.xml

The UI has a couple quirks:
- There's a separator between the IPv4 config and IPv6 config, I'd remove it.
- Please hide the entire IPv6 frame if the network doesn't have any IPv6 bits.
This is similar to how the interface details panel works. The testdriver
should help show all the interface details bits
- If you have a suite of networks you are using to test the UI, please also
add them to tests/testdriver.xml so I can use them as well. It's as simple as
just copy+pasting the entire <network> XML into that file, in the same section
as the rest of the <network> instances.

Thanks,
Cole

> ---
>  virtManager/createnet.py |  67 +++++++++++----------
>  virtManager/host.py      |  32 +++++++++-
>  virtManager/network.py   | 151 +++++++++++++++++++++++++++++++++++++----------
>  3 files changed, 184 insertions(+), 66 deletions(-)
> 
> diff --git a/virtManager/createnet.py b/virtManager/createnet.py
> index 79dd249..846cfbf 100644
> --- a/virtManager/createnet.py
> +++ b/virtManager/createnet.py
> @@ -21,7 +21,7 @@
>  import logging
>  import re
>  
> -from IPy import IP
> +import ipaddr
>  
>  from gi.repository import Gtk
>  from gi.repository import Gdk
> @@ -153,7 +153,7 @@ class vmmCreateNetwork(vmmGObjectUI):
>          src.modify_text(Gtk.StateType.NORMAL, black)
>  
>          # No IP specified or invalid IP
> -        if ip is None or ip.version() != 4:
> +        if ip is None or ip.version != 4:
>              src.modify_base(Gtk.StateType.NORMAL, red)
>              self.widget("net-info-netmask").set_text("")
>              self.widget("net-info-broadcast").set_text("")
> @@ -162,26 +162,25 @@ class vmmCreateNetwork(vmmGObjectUI):
>              self.widget("net-info-type").set_text("")
>              return
>  
> +        # FIXME: handle other networks and not just private?
>          # We've got a valid IP
> -        if ip.len() < 4 or ip.iptype() != "PRIVATE":
> -            src.modify_base(Gtk.StateType.NORMAL, red)
> +        if ip.numhosts < 16 or not ip.is_private:
> +            src.modify_base(gtk.STATE_NORMAL, red)
>          else:
>              src.modify_base(Gtk.StateType.NORMAL, green)
> -        self.widget("net-info-netmask").set_text(str(ip.netmask()))
> -        self.widget("net-info-broadcast").set_text(str(ip.broadcast()))
> +        self.widget("net-info-netmask").set_text(str(ip.netmask))
> +        self.widget("net-info-broadcast").set_text(str(ip.broadcast))
>  
> -        if ip.len() <= 1:
> +        if ip.prefixlen == 32:
>              self.widget("net-info-gateway").set_text("")
>          else:
> -            self.widget("net-info-gateway").set_text(str(ip[1]))
> +            self.widget("net-info-gateway").set_text(str(ip.network + 1))
>          self.widget("net-info-size").set_text(_("%d addresses") %
> -                                                         (ip.len()))
> +                                                         (ip.numhosts))
>  
> -        if ip.iptype() == "PUBLIC":
> -            self.widget("net-info-type").set_text(_("Public"))
> -        elif ip.iptype() == "PRIVATE":
> +        if ip.is_private:
>              self.widget("net-info-type").set_text(_("Private"))
> -        elif ip.iptype() == "RESERVED":
> +        elif ip.is_reserved:
>              self.widget("net-info-type").set_text(_("Reserved"))
>          else:
>              self.widget("net-info-type").set_text(_("Other"))
> @@ -192,8 +191,8 @@ class vmmCreateNetwork(vmmGObjectUI):
>          self.widget("net-dhcp-end").set_sensitive(val)
>  
>      def change_dhcp_start(self, src):
> -        end = self.get_config_dhcp_start()
> -        self.change_dhcp(src, end)
> +        start = self.get_config_dhcp_start()
> +        self.change_dhcp(src, start)
>  
>      def change_dhcp_end(self, src):
>          end = self.get_config_dhcp_end()
> @@ -222,18 +221,18 @@ class vmmCreateNetwork(vmmGObjectUI):
>  
>      def get_config_ip4(self):
>          try:
> -            return IP(self.widget("net-network").get_text())
> +            return ipaddr.IPNetwork(self.widget("net-network").get_text())
>          except:
>              return None
>  
>      def get_config_dhcp_start(self):
>          try:
> -            return IP(self.widget("net-dhcp-start").get_text())
> +            return ipaddr.IPNetwork(self.widget("net-dhcp-start").get_text())
>          except:
>              return None
>      def get_config_dhcp_end(self):
>          try:
> -            return IP(self.widget("net-dhcp-end").get_text())
> +            return ipaddr.IPNetwork(self.widget("net-dhcp-end").get_text())
>          except:
>              return None
>  
> @@ -260,16 +259,16 @@ class vmmCreateNetwork(vmmGObjectUI):
>  
>          ip = self.get_config_ip4()
>          self.widget("summary-ip4-network").set_text(str(ip))
> -        self.widget("summary-ip4-gateway").set_text(str(ip[1]))
> -        self.widget("summary-ip4-netmask").set_text(str(ip.netmask()))
> +        self.widget("summary-ip4-gateway").set_text(str(ip.network + 1))
> +        self.widget("summary-ip4-netmask").set_text(str(ip.netmask))
>  
>          self.widget("label-dhcp-end").set_property("visible", dodhcp)
>          self.widget("summary-dhcp-end").set_property("visible", dodhcp)
>          if dodhcp:
>              start = self.get_config_dhcp_start()
>              end = self.get_config_dhcp_end()
> -            self.widget("summary-dhcp-start").set_text(str(start))
> -            self.widget("summary-dhcp-end").set_text(str(end))
> +            self.widget("summary-dhcp-start").set_text(str(start.network))
> +            self.widget("summary-dhcp-end").set_text(str(end.network))
>              self.widget("label-dhcp-start").set_text(_("Start address:"))
>              self.widget("label-dhcp-end").show()
>              self.widget("summary-dhcp-end").show()
> @@ -284,13 +283,13 @@ class vmmCreateNetwork(vmmGObjectUI):
>  
>      def populate_dhcp(self):
>          ip = self.get_config_ip4()
> -        start = int(ip.len() / 2)
> -        end = ip.len() - 2
> +        start = int(ip.numhosts / 2)
> +        end   = int(ip.numhosts - 2)
>  
>          if self.widget("net-dhcp-start").get_text() == "":
> -            self.widget("net-dhcp-start").set_text(str(ip[start]))
> +            self.widget("net-dhcp-start").set_text(str(ip.network + start))
>          if self.widget("net-dhcp-end").get_text() == "":
> -            self.widget("net-dhcp-end").set_text(str(ip[end]))
> +            self.widget("net-dhcp-end").set_text(str(ip.network + end))
>  
>      def page_changed(self, ignore1, ignore2, page_number):
>          if page_number == PAGE_NAME:
> @@ -331,13 +330,13 @@ class vmmCreateNetwork(vmmGObjectUI):
>              else:
>                  xml += "  <forward mode='%s'/>\n" % mode
>  
> -        xml += "  <ip address='%s' netmask='%s'>\n" % (str(ip[1]),
> -                                                       str(ip.netmask()))
> +        xml += "  <ip address='%s' netmask='%s'>\n" % (str(ip.network + 1),
> +                                                       str(ip.netmask))
>  
>          if self.get_config_dhcp_enable():
>              xml += "    <dhcp>\n"
> -            xml += "      <range start='%s' end='%s'/>\n" % (str(start),
> -                                                             str(end))
> +            xml += "      <range start='%s' end='%s'/>\n" % (str(start.network),
> +                                                             str(end.network))
>              xml += "    </dhcp>\n"
>  
>          xml += "  </ip>\n"
> @@ -372,15 +371,15 @@ class vmmCreateNetwork(vmmGObjectUI):
>              return self.err.val_err(_("Invalid Network Address"),
>                      _("The network address could not be understood"))
>  
> -        if ip.version() != 4:
> +        if ip.version != 4:
>              return self.err.val_err(_("Invalid Network Address"),
>                      _("The network must be an IPv4 address"))
>  
> -        if ip.len() < 4:
> +        if ip.numhosts < 16:
>              return self.err.val_err(_("Invalid Network Address"),
> -                    _("The network prefix must be at least /4 (16 addresses)"))
> +                    _("The network prefix must be at least /28 (16 addresses)"))
>  
> -        if ip.iptype() != "PRIVATE":
> +        if not ip.is_private:
>              res = self.err.yes_no(_("Check Network Address"),
>                      _("The network should normally use a private IPv4 "
>                        "address. Use this non-private address anyway?"))
> diff --git a/virtManager/host.py b/virtManager/host.py
> index ff50f82..e4502b6 100644
> --- a/virtManager/host.py
> +++ b/virtManager/host.py
> @@ -544,14 +544,37 @@ class vmmHost(vmmGObjectUI):
>          self.widget("net-autostart").set_active(autostart)
>          self.widget("net-autostart").set_label(autolabel)
>  
> -        network = net.get_ipv4_network()
> +        result = net.get_ipv4_network()
> +        network = result[0]
> +        dhcp = result[1]
> +        route = result[2]
>          self.widget("net-ip4-network").set_text(str(network))
>  
> -        dhcp = net.get_ipv4_dhcp_range()
>          start = dhcp and str(dhcp[0]) or _("Disabled")
>          end = dhcp and str(dhcp[1]) or _("Disabled")
>          self.widget("net-ip4-dhcp-start").set_text(start)
>          self.widget("net-ip4-dhcp-end").set_text(end)
> +        if route and route[0] and route[1]:
> +            routeVia = str(route[0]) + " via " + str(route[1])
> +        else:
> +            routeVia = _("None")
> +        self.widget("net-ip4-route-via").set_text(routeVia)
> +
> +        result = net.get_ipv6_network()
> +        network = result[0]
> +        dhcp = result[1]
> +        route = result[2]
> +        self.widget("net-ip6-network").set_text(str(network))
> +
> +        start = dhcp and str(dhcp[0]) or _("Disabled")
> +        end = dhcp and str(dhcp[1]) or _("Disabled")
> +        self.widget("net-ip6-dhcp-start").set_text(start)
> +        self.widget("net-ip6-dhcp-end").set_text(end)
> +        if route and route[0] and route[1]:
> +            routeVia = str(route[0]) + " via " + str(route[1])
> +        else:
> +            routeVia = "None"
> +        self.widget("net-ip6-route-via").set_text(routeVia)
>  
>          forward, ignore = net.get_ipv4_forward()
>          iconsize = Gtk.IconSize.MENU
> @@ -579,10 +602,15 @@ class vmmHost(vmmGObjectUI):
>          self.widget("net-ip4-network").set_text("")
>          self.widget("net-ip4-dhcp-start").set_text("")
>          self.widget("net-ip4-dhcp-end").set_text("")
> +        self.widget("net-ip4-route-via").set_text("")
>          self.widget("net-ip4-forwarding-icon").set_from_stock(
>                                      Gtk.STOCK_DISCONNECT, Gtk.IconSize.MENU)
>          self.widget("net-ip4-forwarding").set_text(
>                                      _("Isolated virtual network"))
> +        self.widget("net-ip6-network").set_text("")
> +        self.widget("net-ip6-dhcp-start").set_text("")
> +        self.widget("net-ip6-dhcp-end").set_text("")
> +        self.widget("net-ip6-route-via").set_text("")
>          self.widget("net-apply").set_sensitive(False)
>  
>      def repopulate_networks(self, src_ignore, uuid_ignore):
> diff --git a/virtManager/network.py b/virtManager/network.py
> index 13a16e3..3d85799 100644
> --- a/virtManager/network.py
> +++ b/virtManager/network.py
> @@ -18,9 +18,9 @@
>  # MA 02110-1301 USA.
>  #
>  
> -from IPy import IP
> -
>  from virtManager import util
> +import ipaddr
> +import libxml2
>  from virtManager.libvirtobject import vmmLibvirtObject
>  
>  class vmmNetwork(vmmLibvirtObject):
> @@ -97,27 +97,127 @@ class vmmNetwork(vmmLibvirtObject):
>          return self.net.autostart()
>  
>      def get_ipv4_network(self):
> +        doc = None
> +        ret = None
> +        goodNode = None
> +        dhcpstart = None
> +        dhcpend = None
> +        routeAddr = None
> +        routeVia = None
>          xml = self.get_xml()
> -        if util.xpath(xml, "/network/ip") is None:
> -            return None
> -        addrStr = util.xpath(xml, "/network/ip/@address")
> -        netmaskStr = util.xpath(xml, "/network/ip/@netmask")
> -        prefix = util.xpath(xml, "/network/ip/@prefix")
> -
> -        if prefix:
> -            prefix = int(prefix)
> -            binstr = ((prefix * "1") + ((32 - prefix) * "0"))
> -            netmaskStr = str(IP(int(binstr, base=2)))
> -
> -        if netmaskStr:
> -            netmask = IP(netmaskStr)
> -            gateway = IP(addrStr)
> -            network = IP(gateway.int() & netmask.int())
> -            ret = IP(str(network) + "/" + netmaskStr)
> +        doc = libxml2.parseDoc(xml)
> +        nodes = doc.xpathEval('//ip')
> +        for node in nodes:
> +            family = node.xpathEval('string(./@family)')
> +            if not family or family == 'ipv4':
> +                dhcp = node.xpathEval('string(./dhcp)')
> +                if dhcp:
> +                    dhcpstart = node.xpathEval('string(./dhcp/range[1]/@start)')
> +                    dhcpend = node.xpathEval('string(./dhcp/range[1]/@end)')
> +                    goodNode = node
> +                    break
> +
> +        for node in nodes:
> +            family = node.xpathEval('string(./@family)')
> +            if not family or family == 'ipv4':
> +                routeVia = node.xpathEval('string(./@via)')
> +                if routeVia:
> +                    routeAddr = node.xpathEval('string(./@address)')
> +                    break;
> +
> +        if goodNode == None:
> +            for node in nodes:
> +                family = node.xpathEval('string(./@family)')
> +                if not family or family == 'ipv4':
> +                    tmp = node.xpathEval('string(./@via)')
> +                    if tmp:
> +                        continue
> +                    goodNode = node;
> +                    break
> +
> +        if goodNode:
> +            addrStr    = goodNode.xpathEval('string(./@address)')
> +            netmaskStr = goodNode.xpathEval('string(./@netmask)')
> +            prefix     = goodNode.xpathEval('string(./@prefix)')
> +            if prefix:
> +                prefix = int(prefix)
> +                ret = str(ipaddr.IPNetwork(str(addrStr) + "/" + str(prefix)).masked())
> +            elif netmaskStr:
> +                netmask = ipaddr.IPAddress(netmaskStr)
> +                network = ipaddr.IPAddress(addrStr)
> +                ret = str(ipaddr.IPNetwork(str(network) + "/" + str(netmask)).masked())
> +            else:
> +                ret = str(ipaddr.IPNetwork(str(addrStr)))
> +        if doc:
> +            doc.freeDoc()
> +        if dhcpstart and dhcpend:
> +            dhcp = [str(ipaddr.IPAddress(dhcpstart)), str(ipaddr.IPAddress(dhcpend))]
>          else:
> -            ret = IP(str(addrStr))
> -
> -        return ret
> +            dhcp = None
> +        if routeAddr and routeVia:
> +            route = [str(ipaddr.IPAddress(routeAddr)), str(ipaddr.IPAddress(routeVia))]
> +        else:
> +            route = None
> +        return [ret, dhcp, route]
> +
> +    def get_ipv6_network(self):
> +        doc = None
> +        ret = None
> +        goodNode = None
> +        dhcpstart = None
> +        dhcpend = None
> +        routeAddr = None
> +        routeVia = None
> +        xml = self.get_xml()
> +        doc = libxml2.parseDoc(xml)
> +        nodes = doc.xpathEval('//ip')
> +        for node in nodes:
> +            family = node.xpathEval('string(./@family)')
> +            if family and family == 'ipv6':
> +                dhcp = node.xpathEval('string(./dhcp)')
> +                if dhcp:
> +                    dhcpstart = node.xpathEval('string(./dhcp/range[1]/@start)')
> +                    dhcpend = node.xpathEval('string(./dhcp/range[1]/@end)')
> +                    goodNode = node
> +                    break
> +
> +        for node in nodes:
> +            family = node.xpathEval('string(./@family)')
> +            if family and family == 'ipv6':
> +                routeVia = node.xpathEval('string(./@via)')
> +                if routeVia:
> +                    routeAddr = node.xpathEval('string(./@address)')
> +                    break;
> +
> +        if goodNode == None:
> +            for node in nodes:
> +                family = node.xpathEval('string(./@family)')
> +                if family and family == 'ipv6':
> +                    tmp = node.xpathEval('string(./@via)')
> +                    if tmp:
> +                        continue
> +                    goodNode = node;
> +                    break
> +
> +        if goodNode:
> +            addrStr    = goodNode.xpathEval('string(./@address)')
> +            prefix     = goodNode.xpathEval('string(./@prefix)')
> +            if prefix:
> +                prefix = int(prefix)
> +                ret = str(ipaddr.IPNetwork(str(addrStr) + "/" + str(prefix)).masked())
> +            else:
> +                ret = str(ipaddr.IPNetwork(str(addrStr)))
> +        if doc:
> +            doc.freeDoc()
> +        if dhcpstart and dhcpend:
> +            dhcp = [str(ipaddr.IPAddress(dhcpstart)), str(ipaddr.IPAddress(dhcpend))]
> +        else:
> +            dhcp = None
> +        if routeAddr and routeVia:
> +            route = [str(ipaddr.IPAddress(routeAddr)), str(ipaddr.IPAddress(routeVia))]
> +        else:
> +            route = None
> +        return [ret, dhcp, route]
>  
>      def get_ipv4_forward(self):
>          xml = self.get_xml()
> @@ -125,15 +225,6 @@ class vmmNetwork(vmmLibvirtObject):
>          forwardDev = util.xpath(xml, "/network/forward/@dev")
>          return [fw, forwardDev]
>  
> -    def get_ipv4_dhcp_range(self):
> -        xml = self.get_xml()
> -        dhcpstart = util.xpath(xml, "/network/ip/dhcp/range[1]/@start")
> -        dhcpend = util.xpath(xml, "/network/ip/dhcp/range[1]/@end")
> -        if not dhcpstart or not dhcpend:
> -            return None
> -
> -        return [IP(dhcpstart), IP(dhcpend)]
> -
>      def pretty_forward_mode(self):
>          forward, forwardDev = self.get_ipv4_forward()
>          return vmmNetwork.pretty_desc(forward, forwardDev)
> 




More information about the virt-tools-list mailing list