Revision d0bb3f24

b/lib/hypervisor/hv_xen.py
24 24
"""
25 25

  
26 26
import logging
27
import string # pylint: disable=W0402
27 28
from cStringIO import StringIO
28 29

  
29 30
from ganeti import constants
......
41 42
VIF_BRIDGE_SCRIPT = utils.PathJoin(pathutils.XEN_CONFIG_DIR,
42 43
                                   "scripts/vif-bridge")
43 44
_DOM0_NAME = "Domain-0"
45
_DISK_LETTERS = string.ascii_lowercase
46

  
47
_FILE_DRIVER_MAP = {
48
  constants.FD_LOOP: "file",
49
  constants.FD_BLKTAP: "tap:aio",
50
  }
44 51

  
45 52

  
46 53
def _CreateConfigCpus(cpu_mask):
......
254 261
  return _MergeInstanceInfo(_ParseNodeInfo(info), fn)
255 262

  
256 263

  
264
def _GetConfigFileDiskData(block_devices, blockdev_prefix,
265
                           _letters=_DISK_LETTERS):
266
  """Get disk directives for Xen config file.
267

  
268
  This method builds the xen config disk directive according to the
269
  given disk_template and block_devices.
270

  
271
  @param block_devices: list of tuples (cfdev, rldev):
272
      - cfdev: dict containing ganeti config disk part
273
      - rldev: ganeti.bdev.BlockDev object
274
  @param blockdev_prefix: a string containing blockdevice prefix,
275
                          e.g. "sd" for /dev/sda
276

  
277
  @return: string containing disk directive for xen instance config file
278

  
279
  """
280
  if len(block_devices) > len(_letters):
281
    raise errors.HypervisorError("Too many disks")
282

  
283
  disk_data = []
284

  
285
  for sd_suffix, (cfdev, dev_path) in zip(_letters, block_devices):
286
    sd_name = blockdev_prefix + sd_suffix
287

  
288
    if cfdev.mode == constants.DISK_RDWR:
289
      mode = "w"
290
    else:
291
      mode = "r"
292

  
293
    if cfdev.dev_type == constants.LD_FILE:
294
      driver = _FILE_DRIVER_MAP[cfdev.physical_id[0]]
295
    else:
296
      driver = "phy"
297

  
298
    disk_data.append("'%s:%s,%s,%s'" % (driver, dev_path, sd_name, mode))
299

  
300
  return disk_data
301

  
302

  
257 303
class XenHypervisor(hv_base.BaseHypervisor):
258 304
  """Xen generic hypervisor interface
259 305

  
......
506 552

  
507 553
    return None
508 554

  
509
  @staticmethod
510
  def _GetConfigFileDiskData(block_devices, blockdev_prefix):
511
    """Get disk directive for xen config file.
512

  
513
    This method builds the xen config disk directive according to the
514
    given disk_template and block_devices.
515

  
516
    @param block_devices: list of tuples (cfdev, rldev):
517
        - cfdev: dict containing ganeti config disk part
518
        - rldev: ganeti.bdev.BlockDev object
519
    @param blockdev_prefix: a string containing blockdevice prefix,
520
                            e.g. "sd" for /dev/sda
521

  
522
    @return: string containing disk directive for xen instance config file
523

  
524
    """
525
    FILE_DRIVER_MAP = {
526
      constants.FD_LOOP: "file",
527
      constants.FD_BLKTAP: "tap:aio",
528
      }
529
    disk_data = []
530
    if len(block_devices) > 24:
531
      # 'z' - 'a' = 24
532
      raise errors.HypervisorError("Too many disks")
533
    namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
534
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
535
      if cfdev.mode == constants.DISK_RDWR:
536
        mode = "w"
537
      else:
538
        mode = "r"
539
      if cfdev.dev_type == constants.LD_FILE:
540
        line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
541
                                  dev_path, sd_name, mode)
542
      else:
543
        line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
544
      disk_data.append(line)
545

  
546
    return disk_data
547

  
548 555
  def MigrationInfo(self, instance):
549 556
    """Get instance information to perform a migration.
550 557

  
......
765 772
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
766 773
      vif_data.append("'%s'" % nic_str)
767 774

  
768
    disk_data = cls._GetConfigFileDiskData(block_devices,
769
                                           hvp[constants.HV_BLOCKDEV_PREFIX])
775
    disk_data = \
776
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
770 777

  
771 778
    config.write("vif = [%s]\n" % ",".join(vif_data))
772 779
    config.write("disk = [%s]\n" % ",".join(disk_data))
......
918 925

  
919 926
    config.write("vif = [%s]\n" % ",".join(vif_data))
920 927

  
921
    disk_data = cls._GetConfigFileDiskData(block_devices,
922
                                           hvp[constants.HV_BLOCKDEV_PREFIX])
928
    disk_data = \
929
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
923 930

  
924 931
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
925 932
    if iso_path:
b/test/py/ganeti.hypervisor.hv_xen_unittest.py
21 21

  
22 22
"""Script for testing ganeti.hypervisor.hv_lxc"""
23 23

  
24
import string # pylint: disable=W0402
24 25
import unittest
25 26

  
26 27
from ganeti import constants
......
213 214
      })
214 215

  
215 216

  
217
class TestGetConfigFileDiskData(unittest.TestCase):
218
  def testLetterCount(self):
219
    self.assertEqual(len(hv_xen._DISK_LETTERS), 26)
220

  
221
  def testNoDisks(self):
222
    self.assertEqual(hv_xen._GetConfigFileDiskData([], "hd"), [])
223

  
224
  def testManyDisks(self):
225
    for offset in [0, 1, 10]:
226
      disks = [(objects.Disk(dev_type=constants.LD_LV), "/tmp/disk/%s" % idx)
227
               for idx in range(len(hv_xen._DISK_LETTERS) + offset)]
228

  
229
      if offset == 0:
230
        result = hv_xen._GetConfigFileDiskData(disks, "hd")
231
        self.assertEqual(result, [
232
          "'phy:/tmp/disk/%s,hd%s,r'" % (idx, string.ascii_lowercase[idx])
233
          for idx in range(len(hv_xen._DISK_LETTERS) + offset)
234
          ])
235
      else:
236
        try:
237
          hv_xen._GetConfigFileDiskData(disks, "hd")
238
        except errors.HypervisorError, err:
239
          self.assertEqual(str(err), "Too many disks")
240
        else:
241
          self.fail("Exception was not raised")
242

  
243
  def testTwoLvDisksWithMode(self):
244
    disks = [
245
      (objects.Disk(dev_type=constants.LD_LV, mode=constants.DISK_RDWR),
246
       "/tmp/diskFirst"),
247
      (objects.Disk(dev_type=constants.LD_LV, mode=constants.DISK_RDONLY),
248
       "/tmp/diskLast"),
249
      ]
250

  
251
    result = hv_xen._GetConfigFileDiskData(disks, "hd")
252
    self.assertEqual(result, [
253
      "'phy:/tmp/diskFirst,hda,w'",
254
      "'phy:/tmp/diskLast,hdb,r'",
255
      ])
256

  
257
  def testFileDisks(self):
258
    disks = [
259
      (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDWR,
260
                    physical_id=[constants.FD_LOOP]),
261
       "/tmp/diskFirst"),
262
      (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDONLY,
263
                    physical_id=[constants.FD_BLKTAP]),
264
       "/tmp/diskTwo"),
265
      (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDWR,
266
                    physical_id=[constants.FD_LOOP]),
267
       "/tmp/diskThree"),
268
      (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDWR,
269
                    physical_id=[constants.FD_BLKTAP]),
270
       "/tmp/diskLast"),
271
      ]
272

  
273
    result = hv_xen._GetConfigFileDiskData(disks, "sd")
274
    self.assertEqual(result, [
275
      "'file:/tmp/diskFirst,sda,w'",
276
      "'tap:aio:/tmp/diskTwo,sdb,r'",
277
      "'file:/tmp/diskThree,sdc,w'",
278
      "'tap:aio:/tmp/diskLast,sdd,w'",
279
      ])
280

  
281
  def testInvalidFileDisk(self):
282
    disks = [
283
      (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDWR,
284
                    physical_id=["#unknown#"]),
285
       "/tmp/diskinvalid"),
286
      ]
287

  
288
    self.assertRaises(KeyError, hv_xen._GetConfigFileDiskData, disks, "sd")
289

  
290

  
216 291
if __name__ == "__main__":
217 292
  testutils.GanetiTestProgram()

Also available in: Unified diff