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:
parent
9ceaa2b427
commit
a7834f5d6c
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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")
|
||||
|
||||
|
||||
##############
|
||||
|
|
831
ui/vmm-host.ui
831
ui/vmm-host.ui
File diff suppressed because it is too large
Load Diff
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue