Add Network class for parsing <network> XML

Convert virtManager/host.py, do some cleanups and modernization to the
UI there, add tests.

createnet.py hasn't really been touched yet, but still works because
it was building the XML by hand anyways.
This commit is contained in:
Cole Robinson 2013-09-20 20:40:07 -04:00
parent 9ceaa2b427
commit a7834f5d6c
10 changed files with 816 additions and 801 deletions

View File

@ -603,7 +603,7 @@
<network>
<name>ipv4_prefix</name>
<uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
<uuid>81ff0d90-c91e-6742-64da-4a736edb9122</uuid>
<forward dev='eth1' mode='nat'>
<interface dev='eth1'/>
</forward>

View File

@ -0,0 +1,25 @@
<network>
<name>ipv6_multirange</name>
<uuid>41b4afe4-87bb-8087-6724-5e208a2d483a</uuid>
<forward mode="nat"/>
<bridge name="virbr3" stp="on" delay="0" />
<domain name="net7"/>
<ip address="192.168.7.1" netmask="255.255.255.0">
<dhcp>
<range start="192.168.7.128" end="192.168.7.254" />
<host mac="52:54:00:60:7d:5d" name="paul" ip="192.168.7.2" />
<host mac="52:54:00:69:eb:91" name="badbob" ip="192.168.7.3" />
</dhcp>
</ip>
<ip family="ipv6" address="fd00:beef:10:7::1" prefix="64">
<dhcp>
<range start="fd00:beef:10:7::1:1" end="fd00:beef:10:7::1:f1" />
<host id="00:03:00:01:52:54:00:60:7d:5d" name="paul" ip="fd00:beef:10:7::7:2" />
<host id="00:03:00:01:52:54:00:69:eb:91" name="badbob" ip="fd00:beef:10:7::7:4" />
</dhcp>
</ip>
<ip family="ipv6" address="fd00:beef:12::" prefix="48" via="fd00:beef:10:7::7:2">
</ip>
<ip family="ipv4" address="192.168.19.0" netmask="255.255.255.0">
</ip>
</network>

View File

@ -0,0 +1,29 @@
<network ipv6="yes">
<name>new-foo</name>
<uuid>41b4afe4-87bb-8087-6724-5e208a2d1111</uuid>
<forward mode="route" dev="eth22"/>
<bridge name="virbr3new" stp="off" delay="2"/>
<domain name="newdom"/>
<ip address="192.168.8.1" netmask="255.255.254.0">
<dhcp>
<range start="192.168.8.128" end="192.168.8.254"/>
<host mac="52:54:00:60:7d:5d" name="paul" ip="192.168.7.2"/>
<host mac="52:54:00:69:eb:92" name="newname" ip="192.168.8.3"/>
<bootp file="pxeboot.img" server="1.2.3.4"/>
</dhcp>
<tftp root="/var/lib/tftproot"/>
</ip>
<ip family="ipv6" address="fd00:beef:10:7::1" prefix="63">
<dhcp>
<range start="fd00:beef:10:7::1:1" end="fd00:beef:10:7::1:f1"/>
<host id="00:03:00:01:52:54:00:60:7d:5d" name="paul" ip="fd00:beef:10:7::7:2"/>
<host id="00:03:00:01:52:54:00:69:eb:91" name="badbob" ip="fd00:beef:10:7::7:4"/>
</dhcp>
</ip>
<ip family="ipv6" address="fd00:beef:12::" prefix="48" via="fd00:beef:10:7::7:2">
</ip>
<ip family="ipv4" address="192.168.19.0" netmask="255.255.255.0">
</ip>
<mac address="52:54:00:69:eb:FF"/>
<route family="ipv4" address="192.168.8.0" prefix="24" gateway="192.168.8.10"/>
</network>

View File

@ -994,6 +994,56 @@ class XMLParseTest(unittest.TestCase):
utils.diff_compare(vol.get_xml_config(), outfile)
###################
# <network> tests #
###################
def testNetMulti(self):
basename = "network-multi"
infile = "tests/xmlparse-xml/%s-in.xml" % basename
outfile = "tests/xmlparse-xml/%s-out.xml" % basename
net = virtinst.Network(conn, parsexml=file(infile).read())
check = self._make_checker(net)
check("name", "ipv6_multirange", "new-foo")
check("uuid", "41b4afe4-87bb-8087-6724-5e208a2d483a",
"41b4afe4-87bb-8087-6724-5e208a2d1111")
check("bridge", "virbr3", "virbr3new")
check("stp", True, False)
check("delay", 0, 2)
check("domain_name", "net7", "newdom")
check("ipv6", None, True)
check("macaddr", None, "52:54:00:69:eb:FF")
check = self._make_checker(net.forward)
check("mode", "nat", "route")
check("dev", None, "eth22")
self.assertEqual(len(net.ips), 4)
check = self._make_checker(net.ips[0])
check("address", "192.168.7.1", "192.168.8.1")
check("netmask", "255.255.255.0", "255.255.254.0")
check("tftp", None, "/var/lib/tftproot")
check("bootp_file", None, "pxeboot.img")
check("bootp_server", None, "1.2.3.4")
check = self._make_checker(net.ips[0].ranges[0])
check("start", "192.168.7.128", "192.168.8.128")
check("end", "192.168.7.254", "192.168.8.254")
check = self._make_checker(net.ips[0].hosts[1])
check("macaddr", "52:54:00:69:eb:91", "52:54:00:69:eb:92")
check("name", "badbob", "newname")
check("ip", "192.168.7.3", "192.168.8.3")
check = self._make_checker(net.ips[1])
check("family", "ipv6", "ipv6")
check("prefix", 64, 63)
net.add_route("192.168.8.0", "24", "192.168.8.10")
utils.diff_compare(net.get_xml_config(), outfile)
utils.test_create(conn, net.get_xml_config(), "networkDefineXML")
##############

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,8 @@ from gi.repository import Gtk
from gi.repository import Gdk
# pylint: enable=E0611
from virtManager.network import vmmNetwork
from virtinst import Network
from virtManager.baseclass import vmmGObjectUI
PAGE_INTRO = 0
@ -751,9 +752,8 @@ class vmmCreateNetwork(vmmGObjectUI):
self.widget("summary-routev4-network").hide()
self.widget("summary-routev4-gateway").hide()
forward_txt = ""
dev, mode = self.get_config_forwarding()
forward_txt = vmmNetwork.pretty_desc(mode, dev)
forward_txt = Network.pretty_forward_desc(mode, dev)
self.widget("summary-ipv4-forwarding").set_text(forward_txt)
ip = self.get_config_ip6()

View File

@ -548,24 +548,78 @@ class vmmHost(vmmGObjectUI):
self.widget("net-apply").set_sensitive(False)
def _populate_net_ipv4_state(self, net):
(netstr,
(dhcpstart, dhcpend),
(routeaddr, routevia)) = net.get_ipv4_network()
self.widget("net-ipv4-expander").set_visible(bool(netstr))
if not netstr:
return
forward = net.get_ipv4_forward_mode()
self.widget("net-ipv4-forwarding-icon").set_from_stock(
forward and Gtk.STOCK_CONNECT or Gtk.STOCK_DISCONNECT,
Gtk.IconSize.MENU)
self.widget("net-ipv4-forwarding").set_text(net.pretty_forward_mode())
dhcpstr = _("Disabled")
if dhcpstart:
dhcpstr = dhcpstart + " - " + dhcpend
self.widget("net-ipv4-dhcp-range").set_text(dhcpstr)
self.widget("net-ipv4-network").set_text(netstr)
uihelpers.set_grid_row_visible(
self.widget("net-ipv4-route"), bool(routevia))
if routevia:
routevia = routeaddr + ", gateway=" + routevia
self.widget("net-ipv4-route").set_text(routevia or "")
def _populate_net_ipv6_state(self, net):
(netstr,
(dhcpstart, dhcpend),
(routeaddr, routevia)) = net.get_ipv6_network()
self.widget("net-ipv6-expander").set_visible(bool(netstr))
self.widget("net-ipv6-forwarding-icon").set_from_stock(
netstr and Gtk.STOCK_CONNECT or Gtk.STOCK_DISCONNECT,
Gtk.IconSize.MENU)
if netstr:
prettymode = _("Routed network")
elif net.get_ipv6_enabled():
prettymode = _("Isolated network, internal routing only")
else:
prettymode = _("Isolated network, routing disabled")
self.widget("net-ipv6-forwarding").set_text(prettymode)
dhcpstr = _("Disabled")
if dhcpstart:
dhcpstr = dhcpstart + " - " + dhcpend
self.widget("net-ipv6-dhcp-range").set_text(dhcpstr)
self.widget("net-ipv6-network").set_text(netstr or "")
uihelpers.set_grid_row_visible(
self.widget("net-ipv6-route"), bool(routevia))
if routevia:
routevia = routeaddr + ", gateway=" + routevia
self.widget("net-ipv6-route").set_text(routevia or "")
def populate_net_state(self, net):
active = net.is_active()
self.widget("net-details").set_sensitive(True)
self.widget("net-name").set_text(net.get_name())
dns_name = net.get_name_domain()
if dns_name:
self.widget("net-name-domain").set_text(dns_name)
else:
self.widget("net-name-domain").set_text("")
self.widget("net-name").set_markup(
"<b>Network %s:</b>" % net.get_name())
self.widget("net-device").set_text(net.get_bridge_device() or "")
self.widget("net-name-domain").set_text(net.get_name_domain() or "")
uihelpers.set_grid_row_visible(self.widget("net-name-domain"),
bool(net.get_name_domain()))
dev = active and net.get_bridge_device() or ""
state = active and _("Active") or _("Inactive")
icon = (active and self.ICON_RUNNING or
self.ICON_SHUTOFF)
self.widget("net-device").set_text(dev)
self.widget("net-device").set_sensitive(active)
self.widget("net-state").set_text(state)
self.widget("net-state-icon").set_from_icon_name(icon,
Gtk.IconSize.MENU)
@ -579,82 +633,14 @@ class vmmHost(vmmGObjectUI):
self.widget("net-autostart").set_active(autostart)
self.widget("net-autostart").set_label(autolabel)
######### IPv4 #########
result = net.get_ipv4_network()
network = result[0]
dhcp = result[1]
route = result[2]
if network:
self.widget("net-frame-ip4").show()
else:
self.widget("net-frame-ip4").hide()
self.widget("net-ip4-network").set_text(str(network))
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]) + ", gateway=" + str(route[1])
self.widget("net-ip4-route-label").show()
else:
routeVia = ""
self.widget("net-ip4-route-label").hide()
self.widget("net-ip4-route-via").set_text(routeVia)
forward, ignore = net.get_ipv4_forward()
iconsize = Gtk.IconSize.MENU
icon = forward and Gtk.STOCK_CONNECT or Gtk.STOCK_DISCONNECT
self.widget("net-ip4-forwarding-icon").set_from_stock(icon, iconsize)
forward_str = net.pretty_forward_mode()
self.widget("net-ip4-forwarding").set_text(forward_str)
######### IPv6 #########
result = net.get_ipv6_network()
network = result[0]
dhcp = result[1]
route = result[2]
if network:
self.widget("net-frame-ip6").show()
iconsize = Gtk.IconSize.MENU
icon = Gtk.STOCK_CONNECT
self.widget("net-ip6-forwarding-icon").set_from_stock(icon, iconsize)
self.widget("net-ip6-forwarding").set_text(_("Routed network"))
else:
self.widget("net-frame-ip6").hide()
iconsize = Gtk.IconSize.MENU
icon = Gtk.STOCK_DISCONNECT
self.widget("net-ip6-forwarding-icon").set_from_stock(icon, iconsize)
ipv6 = net.get_ipv6_routing()
if ipv6:
self.widget("net-ip6-forwarding").set_text(
_("Isolated network, internal and host routing only"))
elif ipv6 == 'yes':
self.widget("net-ip6-forwarding").set_text(
_("Isolated network, internal routing only"))
else:
self.widget("net-ip6-forwarding").set_text(
_("Isolated network, routing disabled"))
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]) + ", gateway=" + str(route[1])
self.widget("net-ip6-route-label").show()
else:
routeVia = ""
self.widget("net-ip6-route-label").hide()
self.widget("net-ip6-route-via").set_text(routeVia)
self._populate_net_ipv4_state(net)
self._populate_net_ipv6_state(net)
def reset_net_state(self):
self.widget("net-details").set_sensitive(False)
self.widget("net-name").set_text("")
self.widget("net-device").set_text("")
self.widget("net-device").set_sensitive(False)
self.widget("net-state").set_text(_("Inactive"))
self.widget("net-state-icon").set_from_icon_name(self.ICON_SHUTOFF,
Gtk.IconSize.MENU)
@ -663,21 +649,17 @@ class vmmHost(vmmGObjectUI):
self.widget("net-delete").set_sensitive(False)
self.widget("net-autostart").set_label(_("Never"))
self.widget("net-autostart").set_active(False)
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-label").hide()
self.widget("net-ip4-route-via").set_text("")
self.widget("net-ip4-forwarding-icon").set_from_stock(
self.widget("net-ipv4-network").set_text("")
self.widget("net-ipv4-dhcp-range").set_text("")
self.widget("net-ipv4-route").set_text("")
self.widget("net-ipv4-forwarding-icon").set_from_stock(
Gtk.STOCK_DISCONNECT, Gtk.IconSize.MENU)
self.widget("net-ip4-forwarding").set_text(
self.widget("net-ipv4-forwarding").set_text(
_("Isolated 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-label").hide()
self.widget("net-ip6-route-via").set_text("")
self.widget("net-ip6-forwarding").set_text(
self.widget("net-ipv6-network").set_text("")
self.widget("net-ipv6-dhcp-range").set_text("")
self.widget("net-ipv6-route").set_text("")
self.widget("net-ipv6-forwarding").set_text(
_("Isolated network"))
self.widget("net-apply").set_sensitive(False)

View File

@ -19,40 +19,28 @@
#
import ipaddr
import libxml2
from virtinst import util
from virtinst import Network
from virtManager.libvirtobject import vmmLibvirtObject
def _make_addr_str(addrStr, prefix, netmaskStr):
if prefix:
return str(ipaddr.IPNetwork(str(addrStr) + "/" +
str(prefix)).masked())
elif netmaskStr:
netmask = ipaddr.IPAddress(netmaskStr)
network = ipaddr.IPAddress(addrStr)
return str(ipaddr.IPNetwork(str(network) + "/" +
str(netmask)).masked())
else:
return str(ipaddr.IPNetwork(str(addrStr)))
class vmmNetwork(vmmLibvirtObject):
@staticmethod
def pretty_desc(forward, forwardDev):
if forward or forwardDev:
if not forward or forward == "nat":
if forwardDev:
desc = _("NAT to %s") % forwardDev
else:
desc = _("NAT")
elif forward == "route":
if forwardDev:
desc = _("Route to %s") % forwardDev
else:
desc = _("Routed network")
else:
if forwardDev:
desc = "%s to %s" % (forward, forwardDev)
else:
desc = "%s network" % forward.capitalize()
else:
desc = _("Isolated network, internal and host routing only")
return desc
def __init__(self, conn, backend, key):
vmmLibvirtObject.__init__(self, conn, backend, key)
self._uuid = key
vmmLibvirtObject.__init__(self, conn, backend, key, parseclass=Network)
self._active = True
self._support_isactive = None
@ -60,7 +48,10 @@ class vmmNetwork(vmmLibvirtObject):
self.tick()
# Required class methods
##########################
# Required class methods #
##########################
def get_name(self):
return self._backend.name()
def _XMLDesc(self, flags):
@ -68,6 +59,21 @@ class vmmNetwork(vmmLibvirtObject):
def _define(self, xml):
return self.conn.define_network(xml)
###########
# Actions #
###########
def _backend_get_active(self):
if self._support_isactive is None:
self._support_isactive = self.conn.check_net_support(
self._backend,
self.conn.SUPPORT_NET_ISACTIVE)
if not self._support_isactive:
return True
return bool(self._backend.isActive())
def _set_active(self, state):
if state == self._active:
return
@ -77,18 +83,6 @@ class vmmNetwork(vmmLibvirtObject):
def is_active(self):
return self._active
def get_label(self):
return self.get_name()
def get_uuid(self):
return self._uuid
def get_bridge_device(self):
try:
return self._backend.bridgeName()
except:
return ""
def _kick_conn(self):
self.conn.schedule_priority_tick(pollnet=True)
@ -105,209 +99,93 @@ class vmmNetwork(vmmLibvirtObject):
self._backend = None
self._kick_conn()
def set_autostart(self, value):
self._backend.setAutostart(value)
def get_autostart(self):
return self._backend.autostart()
def _backend_get_active(self):
if self._support_isactive is None:
self._support_isactive = self.conn.check_net_support(
self._backend,
self.conn.SUPPORT_NET_ISACTIVE)
if not self._support_isactive:
return True
return bool(self._backend.isActive())
def set_autostart(self, value):
self._backend.setAutostart(value)
def tick(self):
self._set_active(self._backend_get_active())
########################
# XML parsing routines #
########################
def get_ipv4_static_route(self):
doc = None
ret = None
routeAddr = None
routeVia = None
xml = self.get_xml()
doc = libxml2.parseDoc(xml)
nodes = doc.xpathEval('//route')
for node in nodes:
family = node.xpathEval('string(./@family)')
if not family or family == 'ipv4':
addrStr = node.xpathEval('string(./@address)')
netmaskStr = node.xpathEval('string(./@netmask)')
gatewayStr = node.xpathEval('string(./@gateway)')
prefix = node.xpathEval('string(./@prefix)')
if prefix:
prefix = int(prefix)
routeAddr = str(ipaddr.IPNetwork(str(addrStr) + "/" + str(prefix)).masked())
elif netmaskStr:
netmask = ipaddr.IPAddress(netmaskStr)
network = ipaddr.IPAddress(addrStr)
routeAddr = str(ipaddr.IPNetwork(str(network) + "/" + str(netmask)).masked())
else:
routeAddr = str(ipaddr.IPNetwork(str(addrStr)))
routeVia = str(ipaddr.IPAddress(str(gatewayStr)))
break
if doc:
doc.freeDoc()
if routeAddr and routeVia:
ret = [routeAddr, routeVia]
else:
ret = None
return ret
def get_ipv4_network(self):
doc = None
ret = None
goodNode = None
dhcpstart = None
dhcpend = None
xml = self.get_xml()
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
if goodNode is None:
for node in nodes:
family = node.xpathEval('string(./@family)')
if not family or family == 'ipv4':
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:
dhcp = None
route = self.get_ipv4_static_route()
return [ret, dhcp, route]
def get_ipv6_static_route(self):
doc = None
ret = None
routeAddr = None
routeVia = None
xml = self.get_xml()
doc = libxml2.parseDoc(xml)
nodes = doc.xpathEval('//route')
for node in nodes:
family = node.xpathEval('string(./@family)')
if family and family == 'ipv6':
addrStr = node.xpathEval('string(./@address)')
prefix = node.xpathEval('string(./@prefix)')
gatewayStr = node.xpathEval('string(./@gateway)')
if prefix:
prefix = int(prefix)
routeAddr = str(ipaddr.IPNetwork(str(addrStr) + "/" + str(prefix)).masked())
else:
routeAddr = str(ipaddr.IPNetwork(str(addrStr)))
routeVia = str(ipaddr.IPAddress(str(gatewayStr)))
break
if doc:
doc.freeDoc()
if routeAddr and routeVia:
ret = [routeAddr, routeVia]
else:
ret = None
return ret
def get_ipv6_network(self):
doc = None
ret = None
goodNode = None
dhcpstart = None
dhcpend = 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
if goodNode is None:
for node in nodes:
family = node.xpathEval('string(./@family)')
if family and family == 'ipv6':
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
route = self.get_ipv6_static_route()
return [ret, dhcp, route]
###############
# XML parsing #
###############
def get_uuid(self):
return self._get_xmlobj().uuid
def get_bridge_device(self):
return self._get_xmlobj().bridge
def get_name_domain(self):
xml = self.get_xml()
name_domain = util.xpath(xml, "/network/domain/@name")
return name_domain
def get_ipv6_routing(self):
xml = self.get_xml()
ipv6_routing = util.xpath(xml, "/network/@ipv6")
return ipv6_routing
def get_ipv4_forward(self):
xml = self.get_xml()
fw = util.xpath(xml, "/network/forward/@mode")
forwardDev = util.xpath(xml, "/network/forward/@dev")
return [fw, forwardDev]
return self._get_xmlobj().domain_name
def get_ipv6_enabled(self):
return self._get_xmlobj().ipv6
def get_ipv4_forward_mode(self):
return self._get_xmlobj().forward.mode
def pretty_forward_mode(self):
forward, forwardDev = self.get_ipv4_forward()
return vmmNetwork.pretty_desc(forward, forwardDev)
return self._get_xmlobj().forward.pretty_desc()
def can_pxe(self):
xml = self.get_xml()
forward = self.get_ipv4_forward()[0]
forward = self.get_ipv4_forward_mode()
if forward and forward != "nat":
return True
return bool(util.xpath(xml, "/network/ip/dhcp/bootp/@file"))
for ip in self._get_xmlobj().ips:
if ip.bootp_file:
return True
return False
def _get_static_route(self, family):
xmlobj = self._get_xmlobj()
route = None
for r in xmlobj.routes:
if (r.family == family or (family == "ipv4" and not r.family)):
route = r
break
if not route:
return [None, None]
routeAddr = _make_addr_str(route.address, route.prefix, route.netmask)
routeVia = str(ipaddr.IPAddress(str(route.gateway)))
if not routeAddr or not routeVia:
return [None, None]
return [routeAddr, routeVia]
def _get_network(self, family):
dhcpstart = None
dhcpend = None
xmlobj = self._get_xmlobj()
ip = None
for i in xmlobj.ips:
if (i.family == family or
(family == "ipv4" and not i.family)):
if i.ranges:
ip = i
dhcpstart = i.ranges[0].start
dhcpend = i.ranges[0].end
break
if not ip:
for i in xmlobj.ips:
if (i.family == family or
(family == "ipv4" and not i.family)):
ip = i
break
ret = None
if ip:
ret = _make_addr_str(ip.address, ip.prefix, ip.netmask)
dhcp = [None, None]
if dhcpstart and dhcpend:
dhcp = [str(ipaddr.IPAddress(dhcpstart)),
str(ipaddr.IPAddress(dhcpend))]
return [ret, dhcp]
def get_ipv4_network(self):
ret = self._get_network("ipv4")
return ret + [self._get_static_route("ipv4")]
def get_ipv6_network(self):
ret = self._get_network("ipv6")
return ret + [self._get_static_route("ipv6")]

View File

@ -31,8 +31,9 @@ from virtinst.seclabel import Seclabel
import virtinst.nodedev as NodeDeviceParser
import virtinst.capabilities as CapabilitiesParser
from virtinst.storage import StoragePool, StorageVolume
from virtinst.interface import Interface, InterfaceProtocol
from virtinst.network import Network
from virtinst.storage import StoragePool, StorageVolume
from virtinst.device import VirtualDevice
from virtinst.deviceinterface import VirtualNetworkInterface

161
virtinst/network.py Normal file
View File

@ -0,0 +1,161 @@
#
# Copyright 2013 Red Hat, Inc.
# Cole Robinson <crobinso@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; either version 2 of the License, or
# (at your option) any later version.
#
# 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.
"""
Classes for building and installing libvirt <network> XML
"""
import libvirt
from virtinst import util
from virtinst.xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty
class _NetworkDHCPRange(XMLBuilder):
_XML_ROOT_NAME = "range"
start = XMLProperty("./@start")
end = XMLProperty("./@end")
class _NetworkDHCPHost(XMLBuilder):
_XML_ROOT_NAME = "host"
macaddr = XMLProperty("./@mac")
name = XMLProperty("./@name")
ip = XMLProperty("./@ip")
class _NetworkIP(XMLBuilder):
_XML_ROOT_NAME = "ip"
family = XMLProperty("./@family")
address = XMLProperty("./@address")
prefix = XMLProperty("./@prefix", is_int=True)
netmask = XMLProperty("./@netmask")
tftp = XMLProperty("./tftp/@root")
bootp_file = XMLProperty("./dhcp/bootp/@file")
bootp_server = XMLProperty("./dhcp/bootp/@server")
ranges = XMLChildProperty(_NetworkDHCPRange, relative_xpath="./dhcp")
hosts = XMLChildProperty(_NetworkDHCPHost, relative_xpath="./dhcp")
class _NetworkRoute(XMLBuilder):
_XML_ROOT_NAME = "route"
family = XMLProperty("./@family")
address = XMLProperty("./@address")
prefix = XMLProperty("./@prefix", is_int=True)
gateway = XMLProperty("./@gateway")
class _NetworkForward(XMLBuilder):
_XML_ROOT_NAME = "forward"
mode = XMLProperty("./@mode")
dev = XMLProperty("./@dev")
def pretty_desc(self):
return Network.pretty_forward_desc(self.mode, self.dev)
class Network(XMLBuilder):
"""
Top level class for <network> object XML
"""
@staticmethod
def pretty_forward_desc(mode, dev):
if mode or dev:
if not mode or mode == "nat":
if dev:
desc = _("NAT to %s") % dev
else:
desc = _("NAT")
elif mode == "route":
if dev:
desc = _("Route to %s") % dev
else:
desc = _("Routed network")
else:
if dev:
desc = "%s to %s" % (mode, dev)
else:
desc = "%s network" % mode.capitalize()
else:
desc = _("Isolated network, internal and host routing only")
return desc
def __init__(self, *args, **kwargs):
XMLBuilder.__init__(self, *args, **kwargs)
self._random_uuid = None
######################
# Validation helpers #
######################
def _check_name_collision(self, name):
try:
self.conn.networkLookupByName(name)
except libvirt.libvirtError:
return
raise ValueError(_("Name '%s' already in use by another network." %
name))
def _get_default_uuid(self):
if self._random_uuid is None:
self._random_uuid = util.generate_uuid(self.conn)
return self._random_uuid
##################
# XML properties #
##################
_XML_ROOT_NAME = "network"
_XML_PROP_ORDER = ["ipv6", "name", "uuid", "forward",
"bridge", "stp", "delay", "domain_name",
"macaddr", "ips", "routes"]
ipv6 = XMLProperty("./@ipv6", is_yesno=True)
name = XMLProperty("./name", validate_cb=_check_name_collision)
uuid = XMLProperty("./uuid",
validate_cb=lambda s, v: util.validate_uuid(v),
default_cb=_get_default_uuid)
# Not entirely correct, there can be multiple routes
forward = XMLChildProperty(_NetworkForward, is_single=True)
domain_name = XMLProperty("./domain/@name")
bridge = XMLProperty("./bridge/@name")
stp = XMLProperty("./bridge/@stp", is_onoff=True)
delay = XMLProperty("./bridge/@delay", is_int=True)
macaddr = XMLProperty("./mac/@address")
ips = XMLChildProperty(_NetworkIP)
routes = XMLChildProperty(_NetworkRoute)
def add_route(self, address, prefix, gateway):
route = _NetworkRoute(self.conn)
route.family = "ipv4"
route.address = address
route.prefix = prefix
route.gateway = gateway
self._add_child(route)