~ubuntu-branches/ubuntu/quantal/virtinst/quantal-proposed

« back to all changes in this revision

Viewing changes to virtinst/VirtualNetworkInterface.py

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-02-01 15:40:11 UTC
  • mfrom: (1.3.16 experimental)
  • Revision ID: james.westby@ubuntu.com-20110201154011-op0nusgc240xajvb
Tags: 0.500.5-1ubuntu1
* Merge from debian experimental. Remaining changes:
  - debian/patches/9001_Ubuntu.patch:
     + Updated to add maverick and natty to OS list and enable virtio
       for them.
  - debian/patches/9003-fix-path-to-hvmloader-in-testsuite.patch: adjust
    testsuite for 0001-fix-path-to-hvmloader.patch and
    0002-Fix-path-to-pygrub.patch. (refreshed)
  - debian/control: added acl package to depends.
  - Demote virt-viewer to Suggests, as it's in universe.
  - Recommends libvirt-bin
* Removed patches:
  - debian/patches/9002-libvirt_disk_format.patch: Upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
import _util
24
24
import VirtualDevice
 
25
from XMLBuilderDomain import _xml_property
25
26
from virtinst import _virtinst as _
26
27
 
 
28
def _countMACaddr(vms, searchmac):
 
29
    if not searchmac:
 
30
        return
 
31
 
 
32
    def count_cb(ctx):
 
33
        c = 0
 
34
 
 
35
        for mac in ctx.xpathEval("/domain/devices/interface/mac"):
 
36
            macaddr = mac.xpathEval("attribute::address")[0].content
 
37
            if macaddr and _util.compareMAC(searchmac, macaddr) == 0:
 
38
                c += 1
 
39
        return c
 
40
 
 
41
    count = 0
 
42
    for vm in vms:
 
43
        xml = vm.XMLDesc(0)
 
44
        count += _util.get_xml_path(xml, func=count_cb)
 
45
    return count
 
46
 
27
47
class VirtualNetworkInterface(VirtualDevice.VirtualDevice):
28
48
 
29
49
    _virtual_device_type = VirtualDevice.VirtualDevice.VIRTUAL_DEV_NET
30
50
 
31
 
    TYPE_BRIDGE  = "bridge"
32
 
    TYPE_VIRTUAL = "network"
33
 
    TYPE_USER    = "user"
34
 
    network_types = [TYPE_BRIDGE, TYPE_VIRTUAL, TYPE_USER]
 
51
    TYPE_BRIDGE     = "bridge"
 
52
    TYPE_VIRTUAL    = "network"
 
53
    TYPE_USER       = "user"
 
54
    TYPE_ETHERNET   = "ethernet"
 
55
    network_types = [TYPE_BRIDGE, TYPE_VIRTUAL, TYPE_USER, TYPE_ETHERNET]
35
56
 
36
57
    def get_network_type_desc(net_type):
37
58
        """
38
59
        Return human readable description for passed network type
39
60
        """
40
 
        desc = ""
 
61
        desc = net_type.capitalize()
41
62
 
42
63
        if net_type == VirtualNetworkInterface.TYPE_BRIDGE:
43
64
            desc = _("Shared physical device")
44
 
        elif net_type ==  VirtualNetworkInterface.TYPE_VIRTUAL:
 
65
        elif net_type == VirtualNetworkInterface.TYPE_VIRTUAL:
45
66
            desc = _("Virtual networking")
46
67
        elif net_type == VirtualNetworkInterface.TYPE_USER:
47
68
            desc = _("Usermode networking")
48
 
        else:
49
 
            raise ValueError(_("Unknown network type '%s'") % net_type)
50
69
 
51
70
        return desc
52
71
    get_network_type_desc = staticmethod(get_network_type_desc)
53
72
 
54
73
    def __init__(self, macaddr=None, type=TYPE_BRIDGE, bridge=None,
55
 
                 network=None, model=None, conn=None):
56
 
        VirtualDevice.VirtualDevice.__init__(self, conn)
 
74
                 network=None, model=None, conn=None,
 
75
                 parsexml=None, parsexmlnode=None, caps=None):
 
76
        VirtualDevice.VirtualDevice.__init__(self, conn, parsexml,
 
77
                                             parsexmlnode, caps)
57
78
 
58
79
        self._network = None
 
80
        self._bridge = None
59
81
        self._macaddr = None
60
82
        self._type = None
 
83
        self._model = None
 
84
        self._target_dev = None
 
85
        self._source_dev = None
 
86
 
 
87
        # Generate _random_mac
 
88
        self._random_mac = None
 
89
        self._default_bridge = None
 
90
 
 
91
        if self._is_parse():
 
92
            return
61
93
 
62
94
        self.type = type
63
95
        self.macaddr = macaddr
67
99
 
68
100
        if self.type == self.TYPE_VIRTUAL:
69
101
            if network is None:
70
 
                raise ValueError, _("A network name was not provided")
 
102
                raise ValueError(_("A network name was not provided"))
 
103
 
 
104
    def _generate_default_bridge(self):
 
105
        if not self._default_bridge:
 
106
            self._default_bridge = _util.default_bridge2(self.conn)
 
107
        return self._default_bridge
 
108
 
 
109
    def _generate_random_mac(self):
 
110
        if self.conn and not self._random_mac:
 
111
            found = False
 
112
            for ignore in range(256):
 
113
                self._random_mac = _util.randomMAC(self.conn.getType().lower())
 
114
                ret = self.is_conflict_net(self.conn, self._random_mac)
 
115
                if ret[1] is not None:
 
116
                    continue
 
117
                found = True
 
118
                break
 
119
 
 
120
            if not found:
 
121
                logging.debug("Failed to generate non-conflicting MAC")
 
122
        return self._random_mac
 
123
 
 
124
    def get_source(self):
 
125
        """
 
126
        Convenince function, try to return the relevant <source> value
 
127
        per the network type.
 
128
        """
 
129
        if self.type == self.TYPE_VIRTUAL:
 
130
            return self.network
 
131
        if self.type == self.TYPE_BRIDGE:
 
132
            return self.bridge
 
133
        if self.type == self.TYPE_ETHERNET:
 
134
            return self.source_dev
 
135
        if self.type == self.TYPE_USER:
 
136
            return None
 
137
        return self.network or self.bridge or self.source_dev
71
138
 
72
139
    def get_type(self):
73
140
        return self._type
74
141
    def set_type(self, val):
75
142
        if val not in self.network_types:
76
 
            raise ValueError, _("Unknown network type %s") % val
 
143
            raise ValueError(_("Unknown network type %s") % val)
77
144
        self._type = val
78
 
    type = property(get_type, set_type)
 
145
    type = _xml_property(get_type, set_type,
 
146
                         xpath="./@type")
79
147
 
80
148
    def get_macaddr(self):
 
149
        if not self._macaddr:
 
150
            return self._generate_random_mac()
81
151
        return self._macaddr
82
152
    def set_macaddr(self, val):
83
153
        _util.validate_macaddr(val)
84
154
        self._macaddr = val
85
 
    macaddr = property(get_macaddr, set_macaddr)
 
155
    macaddr = _xml_property(get_macaddr, set_macaddr,
 
156
                            xpath="./mac/@address")
86
157
 
87
158
    def get_network(self):
88
159
        return self._network
89
160
    def set_network(self, newnet):
90
161
        def _is_net_active(netobj):
91
 
            """Apparently the 'info' command was never hooked up for
92
 
               libvirt virNetwork python apis."""
 
162
            # Apparently the 'info' command was never hooked up for
 
163
            # libvirt virNetwork python apis.
93
164
            if not self.conn:
94
165
                return True
95
166
            return self.conn.listNetworks().count(netobj.name())
105
176
                                   "started.") % newnet)
106
177
 
107
178
        self._network = newnet
108
 
    network = property(get_network, set_network)
109
 
 
110
 
    def is_conflict_net(self, conn):
111
 
        """is_conflict_net: determines if mac conflicts with others in system
112
 
 
113
 
           returns a two element tuple:
114
 
               first element is True if fatal collision occured
115
 
               second element is a string description of the collision.
116
 
           Non fatal collisions (mac addr collides with inactive guest) will
117
 
           return (False, "description of collision")"""
118
 
        if self.macaddr is None:
 
179
    network = _xml_property(get_network, set_network,
 
180
                            xpath="./source/@network")
 
181
 
 
182
    def get_bridge(self):
 
183
        if not self._bridge and self.type == self.TYPE_BRIDGE:
 
184
            return self._generate_default_bridge()
 
185
        return self._bridge
 
186
    def set_bridge(self, val):
 
187
        self._bridge = val
 
188
    bridge = _xml_property(get_bridge, set_bridge,
 
189
                           xpath="./source/@bridge")
 
190
 
 
191
    def get_model(self):
 
192
        return self._model
 
193
    def set_model(self, val):
 
194
        self._model = val
 
195
    model = _xml_property(get_model, set_model,
 
196
                          xpath="./model/@type")
 
197
 
 
198
    def get_target_dev(self):
 
199
        return self._target_dev
 
200
    def set_target_dev(self, val):
 
201
        self._target_dev = val
 
202
    target_dev = _xml_property(get_target_dev, set_target_dev,
 
203
                               xpath="./target/@dev")
 
204
 
 
205
    def get_source_dev(self):
 
206
        return self._source_dev
 
207
    def set_source_dev(self, val):
 
208
        self._source_dev = val
 
209
    source_dev = _xml_property(get_source_dev, set_source_dev,
 
210
                               xpath="./source/@dev")
 
211
 
 
212
    def is_conflict_net(self, conn, mac=None):
 
213
        """
 
214
        is_conflict_net: determines if mac conflicts with others in system
 
215
 
 
216
        returns a two element tuple:
 
217
            first element is True if fatal collision occured
 
218
            second element is a string description of the collision.
 
219
 
 
220
        Non fatal collisions (mac addr collides with inactive guest) will
 
221
        return (False, "description of collision")
 
222
        """
 
223
        mac = mac or self.macaddr
 
224
        if mac is None:
 
225
            return (False, None)
 
226
 
 
227
        # Not supported for remote connections yet
 
228
        if self._is_remote():
119
229
            return (False, None)
120
230
 
121
231
        vms, inactive_vm = _util.fetch_all_guests(conn)
123
233
        # get the Host's NIC MACaddress
124
234
        hostdevs = _util.get_host_network_devices()
125
235
 
126
 
        if self.countMACaddr(vms) > 0:
127
 
            return (True, _("The MAC address you entered is already in use by another active virtual machine."))
128
 
        for (dummy, dummy, dummy, dummy, host_macaddr) in hostdevs:
 
236
        if _countMACaddr(vms, mac) > 0:
 
237
            return (True, _("The MAC address you entered is already in use "
 
238
                            "by another active virtual machine."))
 
239
 
 
240
        for dev in hostdevs:
 
241
            host_macaddr = dev[4]
129
242
            if self.macaddr.upper() == host_macaddr.upper():
130
 
                return (True, _("The MAC address you entered conflicts with a device on the physical host."))
131
 
        if self.countMACaddr(inactive_vm) > 0:
132
 
            return (False, _("The MAC address you entered is already in use by another inactive virtual machine."))
 
243
                return (True, _("The MAC address you entered conflicts with "
 
244
                                "a device on the physical host."))
 
245
 
 
246
        if _countMACaddr(inactive_vm, mac) > 0:
 
247
            return (False, _("The MAC address you entered is already in use "
 
248
                             "by another inactive virtual machine."))
 
249
 
133
250
        return (False, None)
134
251
 
135
252
    def setup_dev(self, conn=None, meter=None):
139
256
        """
140
257
        DEPRECATED: Please use setup_dev instead
141
258
        """
 
259
        # Access self.macaddr to generate a random one
 
260
        if not self.conn and conn:
 
261
            self.conn = conn
142
262
        if not conn:
143
263
            conn = self.conn
144
264
 
145
 
        if self.macaddr is None:
146
 
            while 1:
147
 
                self.macaddr = _util.randomMAC(type=conn.getType().lower())
148
 
                if self.is_conflict_net(conn)[1] is not None:
149
 
                    continue
150
 
                else:
151
 
                    break
152
 
        else:
 
265
        if self.macaddr:
153
266
            ret, msg = self.is_conflict_net(conn)
154
267
            if msg is not None:
155
268
                if ret is False:
157
270
                else:
158
271
                    raise RuntimeError(msg)
159
272
 
160
 
        if not self.bridge and self.type == "bridge":
161
 
            self.bridge = _util.default_bridge2(self.conn)
162
 
 
163
 
    def get_xml_config(self):
 
273
    def _get_xml_config(self):
164
274
        src_xml = ""
165
275
        model_xml = ""
 
276
        target_xml = ""
166
277
        if self.type == self.TYPE_BRIDGE:
167
 
            src_xml =   "      <source bridge='%s'/>\n" % self.bridge
 
278
            src_xml     = "      <source bridge='%s'/>\n" % self.bridge
168
279
        elif self.type == self.TYPE_VIRTUAL:
169
 
            src_xml =   "      <source network='%s'/>\n" % self.network
 
280
            src_xml     = "      <source network='%s'/>\n" % self.network
 
281
        elif self.type == self.TYPE_ETHERNET and self.source_dev:
 
282
            src_xml     = "      <source dev='%s'/>\n" % self.source_dev
170
283
 
171
284
        if self.model:
172
 
            model_xml = "      <model type='%s'/>\n" % self.model
173
 
 
174
 
        return "    <interface type='%s'>\n" % self.type + \
175
 
               src_xml + \
176
 
               "      <mac address='%s'/>\n" % self.macaddr + \
177
 
               model_xml + \
178
 
               "    </interface>"
179
 
 
180
 
    def countMACaddr(self, vms):
181
 
        if not self.macaddr:
182
 
            return
183
 
 
184
 
        def count_cb(ctx):
185
 
            c = 0
186
 
 
187
 
            for mac in ctx.xpathEval("/domain/devices/interface/mac"):
188
 
                macaddr = mac.xpathEval("attribute::address")[0].content
189
 
                if macaddr and _util.compareMAC(self.macaddr, macaddr) == 0:
190
 
                    c += 1
191
 
            return c
192
 
 
193
 
        count = 0
194
 
        for vm in vms:
195
 
            xml = vm.XMLDesc(0)
196
 
            count += _util.get_xml_path(xml, func = count_cb)
197
 
        return count
 
285
            model_xml   = "      <model type='%s'/>\n" % self.model
 
286
 
 
287
        if self.target_dev:
 
288
            target_xml  = "      <target dev='%s'/>\n" % self.target_dev
 
289
 
 
290
        xml  = "    <interface type='%s'>\n" % self.type
 
291
        xml += src_xml
 
292
        xml += "      <mac address='%s'/>\n" % self.macaddr
 
293
        xml += target_xml
 
294
        xml += model_xml
 
295
        xml += "    </interface>"
 
296
        return xml
198
297
 
199
298
# Back compat class to avoid ABI break
200
299
class XenNetworkInterface(VirtualNetworkInterface):