Revision 748e4b5a

b/Makefile.am
376 376
	test/ganeti.errors_unittest.py \
377 377
	test/ganeti.hooks_unittest.py \
378 378
	test/ganeti.http_unittest.py \
379
	test/ganeti.hypervisor.hv_kvm_unittest.py \
379 380
	test/ganeti.impexpd_unittest.py \
380 381
	test/ganeti.jqueue_unittest.py \
381 382
	test/ganeti.locking_unittest.py \
b/lib/hypervisor/hv_kvm.py
44 44
from ganeti import netutils
45 45

  
46 46

  
47
_KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
48

  
49

  
50
def _WriteNetScript(instance, nic, index):
51
  """Write a script to connect a net interface to the proper bridge.
52

  
53
  This can be used by any qemu-type hypervisor.
54

  
55
  @type instance: L{objects.Instance}
56
  @param instance: Instance object
57
  @type nic: L{objects.NIC}
58
  @param nic: NIC object
59
  @type index: int
60
  @param index: NIC index
61
  @return: Script
62
  @rtype: string
63

  
64
  """
65
  if instance.tags:
66
    tags = " ".join(instance.tags)
67
  else:
68
    tags = ""
69

  
70
  buf = StringIO()
71
  sw = utils.ShellWriter(buf)
72
  sw.Write("#!/bin/sh")
73
  sw.Write("# this is autogenerated by Ganeti, please do not edit")
74
  sw.Write("export PATH=$PATH:/sbin:/usr/sbin")
75
  sw.Write("export INSTANCE=%s", utils.ShellQuote(instance.name))
76
  sw.Write("export MAC=%s", utils.ShellQuote(nic.mac))
77
  sw.Write("export MODE=%s",
78
           utils.ShellQuote(nic.nicparams[constants.NIC_MODE]))
79
  sw.Write("export INTERFACE=\"$1\"")
80
  sw.Write("export TAGS=%s", utils.ShellQuote(tags))
81

  
82
  if nic.ip:
83
    sw.Write("export IP=%s", utils.ShellQuote(nic.ip))
84

  
85
  if nic.nicparams[constants.NIC_LINK]:
86
    sw.Write("export LINK=%s",
87
             utils.ShellQuote(nic.nicparams[constants.NIC_LINK]))
88

  
89
  if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
90
    sw.Write("export BRIDGE=%s",
91
             utils.ShellQuote(nic.nicparams[constants.NIC_LINK]))
92

  
93
  # TODO: make this configurable at ./configure time
94
  sw.Write("if [ -x %s ]; then", utils.ShellQuote(_KVM_NETWORK_SCRIPT))
95
  sw.IncIndent()
96
  try:
97
    sw.Write("# Execute the user-specific vif file")
98
    sw.Write(_KVM_NETWORK_SCRIPT)
99
  finally:
100
    sw.DecIndent()
101
  sw.Write("else")
102
  sw.IncIndent()
103
  try:
104
    sw.Write("ifconfig $INTERFACE 0.0.0.0 up")
105

  
106
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
107
      sw.Write("# Connect the interface to the bridge")
108
      sw.Write("brctl addif $BRIDGE $INTERFACE")
109

  
110
    elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED:
111
      if not nic.ip:
112
        raise errors.HypervisorError("nic/%d is routed, but has no IP"
113
                                     " address" % index)
114

  
115
      sw.Write("# Route traffic targeted at the IP to the interface")
116
      if nic.nicparams[constants.NIC_LINK]:
117
        sw.Write("while ip rule del dev $INTERFACE; do :; done")
118
        sw.Write("ip rule add dev $INTERFACE table $LINK")
119
        sw.Write("ip route replace $IP table $LINK proto static"
120
                 " dev $INTERFACE")
121
      else:
122
        sw.Write("ip route replace $IP proto static dev $INTERFACE")
123

  
124
      interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE"
125
      sw.Write(" if [ -d %s ]; then", interface_v4_conf)
126
      sw.IncIndent()
127
      try:
128
        sw.Write("echo 1 > %s/proxy_arp", interface_v4_conf)
129
        sw.Write("echo 1 > %s/forwarding", interface_v4_conf)
130
      finally:
131
        sw.DecIndent()
132
      sw.Write("fi")
133

  
134
      interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE"
135
      sw.Write("if [ -d %s ]; then", interface_v6_conf)
136
      sw.IncIndent()
137
      try:
138
        sw.Write("echo 1 > %s/proxy_ndp", interface_v6_conf)
139
        sw.Write("echo 1 > %s/forwarding", interface_v6_conf)
140
      finally:
141
        sw.DecIndent()
142
      sw.Write("fi")
143
  finally:
144
    sw.DecIndent()
145
  sw.Write("fi")
146

  
147
  return buf.getvalue()
148

  
149

  
47 150
class KVMHypervisor(hv_base.BaseHypervisor):
48 151
  """KVM hypervisor interface"""
49 152
  CAN_MIGRATE = True
......
108 211
  _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
109 212
  _MIGRATION_INFO_RETRY_DELAY = 2
110 213

  
111
  _KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge"
112

  
113 214
  ANCILLARY_FILES = [
114 215
    _KVM_NETWORK_SCRIPT,
115 216
    ]
......
298 399
      else:
299 400
        raise
300 401

  
301
  def _WriteNetScript(self, instance, seq, nic):
402
  @staticmethod
403
  def _WriteNetScriptFile(instance, seq, nic):
302 404
    """Write a script to connect a net interface to the proper bridge.
303 405

  
304 406
    This can be used by any qemu-type hypervisor.
......
313 415
    @rtype: string
314 416

  
315 417
    """
316
    script = StringIO()
317
    script.write("#!/bin/sh\n")
318
    script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
319
    script.write("PATH=$PATH:/sbin:/usr/sbin\n")
320
    script.write("export INSTANCE=%s\n" % instance.name)
321
    script.write("export MAC=%s\n" % nic.mac)
322
    if nic.ip:
323
      script.write("export IP=%s\n" % nic.ip)
324
    script.write("export MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
325
    if nic.nicparams[constants.NIC_LINK]:
326
      script.write("export LINK=%s\n" % nic.nicparams[constants.NIC_LINK])
327
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
328
      script.write("export BRIDGE=%s\n" % nic.nicparams[constants.NIC_LINK])
329
    script.write("export INTERFACE=$1\n")
330
    if instance.tags:
331
      script.write("export TAGS=\"%s\"\n" % " ".join(instance.tags))
332
    # TODO: make this configurable at ./configure time
333
    script.write("if [ -x '%s' ]; then\n" % self._KVM_NETWORK_SCRIPT)
334
    script.write("  # Execute the user-specific vif file\n")
335
    script.write("  %s\n" % self._KVM_NETWORK_SCRIPT)
336
    script.write("else\n")
337
    script.write("  ifconfig $INTERFACE 0.0.0.0 up\n")
338
    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
339
      script.write("  # Connect the interface to the bridge\n")
340
      script.write("  brctl addif $BRIDGE $INTERFACE\n")
341
    elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED:
342
      if not nic.ip:
343
        raise errors.HypervisorError("nic/%d is routed, but has no ip." % seq)
344
      script.write("  # Route traffic targeted at the IP to the interface\n")
345
      if nic.nicparams[constants.NIC_LINK]:
346
        script.write("  while ip rule del dev $INTERFACE; do :; done\n")
347
        script.write("  ip rule add dev $INTERFACE table $LINK\n")
348
        script.write("  ip route replace $IP table $LINK proto static"
349
                     " dev $INTERFACE\n")
350
      else:
351
        script.write("  ip route replace $IP proto static"
352
                     " dev $INTERFACE\n")
353
      interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE"
354
      interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE"
355
      script.write("  if [ -d %s ]; then\n" % interface_v4_conf)
356
      script.write("    echo 1 > %s/proxy_arp\n" % interface_v4_conf)
357
      script.write("    echo 1 > %s/forwarding\n" % interface_v4_conf)
358
      script.write("  fi\n")
359
      script.write("  if [ -d %s ]; then\n" % interface_v6_conf)
360
      script.write("    echo 1 > %s/proxy_ndp\n" % interface_v6_conf)
361
      script.write("    echo 1 > %s/forwarding\n" % interface_v6_conf)
362
      script.write("  fi\n")
363
    script.write("fi\n\n")
418
    script = _WriteNetScript(instance, nic, seq)
419

  
364 420
    # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
365 421
    # mounted noexec sometimes, so we'll have to find another place.
366 422
    (tmpfd, tmpfile_name) = tempfile.mkstemp()
367 423
    tmpfile = os.fdopen(tmpfd, 'w')
368 424
    try:
369
      tmpfile.write(script.getvalue())
425
      tmpfile.write(script)
370 426
    finally:
371 427
      tmpfile.close()
372 428
    os.chmod(tmpfile_name, 0755)
......
681 737

  
682 738
      for nic_seq, nic in enumerate(kvm_nics):
683 739
        nic_val = "nic,vlan=%s,macaddr=%s,%s" % (nic_seq, nic.mac, nic_model)
684
        script = self._WriteNetScript(instance, nic_seq, nic)
740
        script = self._WriteNetScriptFile(instance, nic_seq, nic)
685 741
        tap_val = "tap,vlan=%s,script=%s%s" % (nic_seq, script, tap_extra)
686 742
        kvm_cmd.extend(["-net", nic_val])
687 743
        kvm_cmd.extend(["-net", tap_val])
b/test/ganeti.hypervisor.hv_kvm_unittest.py
1
#!/usr/bin/python
2
#
3

  
4
# Copyright (C) 2010 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Script for testing the hypervisor.hv_kvm module"""
23

  
24
import unittest
25

  
26
from ganeti import constants
27
from ganeti import compat
28
from ganeti import objects
29
from ganeti import errors
30

  
31
from ganeti.hypervisor import hv_kvm
32

  
33
import testutils
34

  
35

  
36
class TestWriteNetScript(unittest.TestCase):
37
  def testBridged(self):
38
    inst = objects.Instance(name="inst1.example.com", tags=[])
39
    nic = objects.NIC(mac="01:23:45:67:89:0A",
40
                      nicparams={
41
                        constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
42
                        constants.NIC_LINK: "",
43
                        })
44

  
45
    script = hv_kvm._WriteNetScript(inst, nic, 0)
46
    self.assert_(isinstance(script, basestring))
47

  
48
  def testBridgedWithTags(self):
49
    inst = objects.Instance(name="inst1.example.com", tags=["Hello", "World"])
50
    nic = objects.NIC(mac="01:23:45:67:89:0A",
51
                      nicparams={
52
                        constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
53
                        constants.NIC_LINK: "",
54
                        })
55

  
56
    script = hv_kvm._WriteNetScript(inst, nic, 0)
57
    self.assert_(isinstance(script, basestring))
58

  
59
  def testRouted(self):
60
    inst = objects.Instance(name="inst2.example.com", tags=[])
61
    nic = objects.NIC(mac="A0:98:76:54:32:10",
62
                      ip="192.0.2.4",
63
                      nicparams={
64
                        constants.NIC_MODE: constants.NIC_MODE_ROUTED,
65
                        constants.NIC_LINK: "eth0",
66
                        })
67

  
68
    script = hv_kvm._WriteNetScript(inst, nic, 4)
69
    self.assert_(isinstance(script, basestring))
70

  
71
  def testRoutedNoIpAddress(self):
72
    inst = objects.Instance(name="eiphei1e.example.com", tags=[])
73
    nic = objects.NIC(mac="93:28:76:54:32:10",
74
                      nicparams={
75
                        constants.NIC_MODE: constants.NIC_MODE_ROUTED,
76
                        constants.NIC_LINK: "",
77
                        })
78

  
79
    self.assertRaises(errors.HypervisorError, hv_kvm._WriteNetScript,
80
                      inst, nic, 2)
81

  
82

  
83
if __name__ == "__main__":
84
  testutils.GanetiTestProgram()

Also available in: Unified diff