OLD | NEW |
(Empty) | |
| 1 """ |
| 2 Library to perform pre/post test setup for KVM autotest. |
| 3 """ |
| 4 import os, shutil, tempfile, re, ConfigParser, glob, inspect |
| 5 import logging, time |
| 6 from autotest_lib.client.common_lib import error |
| 7 from autotest_lib.client.bin import utils |
| 8 |
| 9 |
| 10 @error.context_aware |
| 11 def cleanup(dir): |
| 12 """ |
| 13 If dir is a mountpoint, do what is possible to unmount it. Afterwards, |
| 14 try to remove it. |
| 15 |
| 16 @param dir: Directory to be cleaned up. |
| 17 """ |
| 18 error.context("cleaning up unattended install directory %s" % dir) |
| 19 if os.path.ismount(dir): |
| 20 utils.run('fuser -k %s' % dir, ignore_status=True) |
| 21 utils.run('umount %s' % dir) |
| 22 if os.path.isdir(dir): |
| 23 shutil.rmtree(dir) |
| 24 |
| 25 |
| 26 @error.context_aware |
| 27 def clean_old_image(image): |
| 28 """ |
| 29 Clean a leftover image file from previous processes. If it contains a |
| 30 mounted file system, do the proper cleanup procedures. |
| 31 |
| 32 @param image: Path to image to be cleaned up. |
| 33 """ |
| 34 error.context("cleaning up old leftover image %s" % image) |
| 35 if os.path.exists(image): |
| 36 mtab = open('/etc/mtab', 'r') |
| 37 mtab_contents = mtab.read() |
| 38 mtab.close() |
| 39 if image in mtab_contents: |
| 40 utils.run('fuser -k %s' % image, ignore_status=True) |
| 41 utils.run('umount %s' % image) |
| 42 os.remove(image) |
| 43 |
| 44 |
| 45 def display_attributes(instance): |
| 46 """ |
| 47 Inspects a given class instance attributes and displays them, convenient |
| 48 for debugging. |
| 49 """ |
| 50 logging.debug("Attributes set:") |
| 51 for member in inspect.getmembers(instance): |
| 52 name, value = member |
| 53 attribute = getattr(instance, name) |
| 54 if not (name.startswith("__") or callable(attribute) or not value): |
| 55 logging.debug(" %s: %s", name, value) |
| 56 |
| 57 |
| 58 class Disk(object): |
| 59 """ |
| 60 Abstract class for Disk objects, with the common methods implemented. |
| 61 """ |
| 62 def __init__(self): |
| 63 self.path = None |
| 64 |
| 65 |
| 66 def setup_answer_file(self, filename, contents): |
| 67 utils.open_write_close(os.path.join(self.mount, filename), contents) |
| 68 |
| 69 |
| 70 def copy_to(self, src): |
| 71 dst = os.path.join(self.mount, os.path.basename(src)) |
| 72 if os.path.isdir(src): |
| 73 shutil.copytree(src, dst) |
| 74 elif os.path.isfile(src): |
| 75 shutil.copyfile(src, dst) |
| 76 |
| 77 |
| 78 def close(self): |
| 79 os.chmod(self.path, 0755) |
| 80 cleanup(self.mount) |
| 81 logging.debug("Disk %s successfuly set", self.path) |
| 82 |
| 83 |
| 84 class FloppyDisk(Disk): |
| 85 """ |
| 86 Represents a 1.44 MB floppy disk. We can copy files to it, and setup it in |
| 87 convenient ways. |
| 88 """ |
| 89 @error.context_aware |
| 90 def __init__(self, path, qemu_img_binary, tmpdir): |
| 91 error.context("Creating unattended install floppy image %s" % path) |
| 92 self.tmpdir = tmpdir |
| 93 self.mount = tempfile.mkdtemp(prefix='floppy_', dir=self.tmpdir) |
| 94 self.virtio_mount = None |
| 95 self.path = path |
| 96 clean_old_image(path) |
| 97 if not os.path.isdir(os.path.dirname(path)): |
| 98 os.makedirs(os.path.dirname(path)) |
| 99 |
| 100 try: |
| 101 c_cmd = '%s create -f raw %s 1440k' % (qemu_img_binary, path) |
| 102 utils.run(c_cmd) |
| 103 f_cmd = 'mkfs.msdos -s 1 %s' % path |
| 104 utils.run(f_cmd) |
| 105 m_cmd = 'mount -o loop,rw %s %s' % (path, self.mount) |
| 106 utils.run(m_cmd) |
| 107 except error.CmdError, e: |
| 108 cleanup(self.mount) |
| 109 raise |
| 110 |
| 111 |
| 112 def _copy_virtio_drivers(self, virtio_floppy): |
| 113 """ |
| 114 Copy the virtio drivers on the virtio floppy to the install floppy. |
| 115 |
| 116 1) Mount the floppy containing the viostor drivers |
| 117 2) Copy its contents to the root of the install floppy |
| 118 """ |
| 119 virtio_mount = tempfile.mkdtemp(prefix='virtio_floppy_', |
| 120 dir=self.tmpdir) |
| 121 |
| 122 pwd = os.getcwd() |
| 123 try: |
| 124 m_cmd = 'mount -o loop %s %s' % (virtio_floppy, virtio_mount) |
| 125 utils.run(m_cmd) |
| 126 os.chdir(virtio_mount) |
| 127 path_list = glob.glob('*') |
| 128 for path in path_list: |
| 129 self.copy_to(path) |
| 130 finally: |
| 131 os.chdir(pwd) |
| 132 cleanup(virtio_mount) |
| 133 |
| 134 |
| 135 def setup_virtio_win2003(self, virtio_floppy, virtio_oemsetup_id): |
| 136 """ |
| 137 Setup the install floppy with the virtio storage drivers, win2003 style. |
| 138 |
| 139 Win2003 and WinXP depend on the file txtsetup.oem file to install |
| 140 the virtio drivers from the floppy, which is a .ini file. |
| 141 Process: |
| 142 |
| 143 1) Copy the virtio drivers on the virtio floppy to the install floppy |
| 144 2) Parse the ini file with config parser |
| 145 3) Modify the identifier of the default session that is going to be |
| 146 executed on the config parser object |
| 147 4) Re-write the config file to the disk |
| 148 """ |
| 149 self._copy_virtio_drivers(virtio_floppy) |
| 150 txtsetup_oem = os.path.join(self.mount, 'txtsetup.oem') |
| 151 if not os.path.isfile(txtsetup_oem): |
| 152 raise IOError('File txtsetup.oem not found on the install ' |
| 153 'floppy. Please verify if your floppy virtio ' |
| 154 'driver image has this file') |
| 155 parser = ConfigParser.ConfigParser() |
| 156 parser.read(txtsetup_oem) |
| 157 if not parser.has_section('Defaults'): |
| 158 raise ValueError('File txtsetup.oem does not have the session ' |
| 159 '"Defaults". Please check txtsetup.oem') |
| 160 default_driver = parser.get('Defaults', 'SCSI') |
| 161 if default_driver != virtio_oemsetup_id: |
| 162 parser.set('Defaults', 'SCSI', virtio_oemsetup_id) |
| 163 fp = open(txtsetup_oem, 'w') |
| 164 parser.write(fp) |
| 165 fp.close() |
| 166 |
| 167 |
| 168 def setup_virtio_win2008(self, virtio_floppy): |
| 169 """ |
| 170 Setup the install floppy with the virtio storage drivers, win2008 style. |
| 171 |
| 172 Win2008, Vista and 7 require people to point out the path to the drivers |
| 173 on the unattended file, so we just need to copy the drivers to the |
| 174 driver floppy disk. |
| 175 Process: |
| 176 |
| 177 1) Copy the virtio drivers on the virtio floppy to the install floppy |
| 178 """ |
| 179 self._copy_virtio_drivers(virtio_floppy) |
| 180 |
| 181 |
| 182 class CdromDisk(Disk): |
| 183 """ |
| 184 Represents a CDROM disk that we can master according to our needs. |
| 185 """ |
| 186 def __init__(self, path, tmpdir): |
| 187 self.mount = tempfile.mkdtemp(prefix='cdrom_unattended_', dir=tmpdir) |
| 188 self.path = path |
| 189 clean_old_image(path) |
| 190 if not os.path.isdir(os.path.dirname(path)): |
| 191 os.makedirs(os.path.dirname(path)) |
| 192 |
| 193 |
| 194 @error.context_aware |
| 195 def close(self): |
| 196 error.context("Creating unattended install CD image %s" % self.path) |
| 197 g_cmd = ('mkisofs -o %s -max-iso9660-filenames ' |
| 198 '-relaxed-filenames -D --input-charset iso8859-1 ' |
| 199 '%s' % (self.path, self.mount)) |
| 200 utils.run(g_cmd) |
| 201 |
| 202 os.chmod(self.path, 0755) |
| 203 cleanup(self.mount) |
| 204 logging.debug("unattended install CD image %s successfuly created", |
| 205 self.path) |
| 206 |
| 207 |
| 208 class UnattendedInstallConfig(object): |
| 209 """ |
| 210 Creates a floppy disk image that will contain a config file for unattended |
| 211 OS install. The parameters to the script are retrieved from environment |
| 212 variables. |
| 213 """ |
| 214 def __init__(self, test, params): |
| 215 """ |
| 216 Sets class atributes from test parameters. |
| 217 |
| 218 @param test: KVM test object. |
| 219 @param params: Dictionary with test parameters. |
| 220 """ |
| 221 root_dir = test.bindir |
| 222 images_dir = os.path.join(root_dir, 'images') |
| 223 self.deps_dir = os.path.join(root_dir, 'deps') |
| 224 self.unattended_dir = os.path.join(root_dir, 'unattended') |
| 225 |
| 226 attributes = ['kernel_args', 'finish_program', 'cdrom_cd1', |
| 227 'unattended_file', 'medium', 'url', 'kernel', 'initrd', |
| 228 'nfs_server', 'nfs_dir', 'install_virtio', 'floppy', |
| 229 'cdrom_unattended', 'boot_path', 'extra_params', |
| 230 'qemu_img_binary'] |
| 231 |
| 232 for a in attributes: |
| 233 setattr(self, a, params.get(a, '')) |
| 234 |
| 235 if self.install_virtio == 'yes': |
| 236 v_attributes = ['virtio_floppy', 'virtio_storage_path', |
| 237 'virtio_network_path', 'virtio_oemsetup_id', |
| 238 'virtio_network_installer'] |
| 239 for va in v_attributes: |
| 240 setattr(self, va, params.get(va, '')) |
| 241 |
| 242 self.tmpdir = test.tmpdir |
| 243 |
| 244 if getattr(self, 'unattended_file'): |
| 245 self.unattended_file = os.path.join(root_dir, self.unattended_file) |
| 246 |
| 247 if getattr(self, 'qemu_img_binary'): |
| 248 if not os.path.isfile(getattr(self, 'qemu_img_binary')): |
| 249 self.qemu_img_binary = os.path.join(root_dir, |
| 250 self.qemu_img_binary) |
| 251 |
| 252 if getattr(self, 'cdrom_cd1'): |
| 253 self.cdrom_cd1 = os.path.join(root_dir, self.cdrom_cd1) |
| 254 self.cdrom_cd1_mount = tempfile.mkdtemp(prefix='cdrom_cd1_', |
| 255 dir=self.tmpdir) |
| 256 if self.medium == 'nfs': |
| 257 self.nfs_mount = tempfile.mkdtemp(prefix='nfs_', |
| 258 dir=self.tmpdir) |
| 259 |
| 260 if getattr(self, 'floppy'): |
| 261 self.floppy = os.path.join(root_dir, self.floppy) |
| 262 if not os.path.isdir(os.path.dirname(self.floppy)): |
| 263 os.makedirs(os.path.dirname(self.floppy)) |
| 264 |
| 265 self.image_path = os.path.dirname(self.kernel) |
| 266 |
| 267 |
| 268 @error.context_aware |
| 269 def render_answer_file(self): |
| 270 """ |
| 271 Replace KVM_TEST_CDKEY (in the unattended file) with the cdkey |
| 272 provided for this test and replace the KVM_TEST_MEDIUM with |
| 273 the tree url or nfs address provided for this test. |
| 274 |
| 275 @return: Answer file contents |
| 276 """ |
| 277 error.base_context('Rendering final answer file') |
| 278 error.context('Reading answer file %s' % self.unattended_file) |
| 279 unattended_contents = open(self.unattended_file).read() |
| 280 dummy_cdkey_re = r'\bKVM_TEST_CDKEY\b' |
| 281 real_cdkey = os.environ.get('KVM_TEST_cdkey') |
| 282 if re.search(dummy_cdkey_re, unattended_contents): |
| 283 if real_cdkey: |
| 284 unattended_contents = re.sub(dummy_cdkey_re, real_cdkey, |
| 285 unattended_contents) |
| 286 else: |
| 287 print ("WARNING: 'cdkey' required but not specified for " |
| 288 "this unattended installation") |
| 289 |
| 290 dummy_medium_re = r'\bKVM_TEST_MEDIUM\b' |
| 291 if self.medium == "cdrom": |
| 292 content = "cdrom" |
| 293 elif self.medium == "url": |
| 294 content = "url --url %s" % self.url |
| 295 elif self.medium == "nfs": |
| 296 content = "nfs --server=%s --dir=%s" % (self.nfs_server, |
| 297 self.nfs_dir) |
| 298 else: |
| 299 raise ValueError("Unexpected installation medium %s" % self.url) |
| 300 |
| 301 unattended_contents = re.sub(dummy_medium_re, content, |
| 302 unattended_contents) |
| 303 |
| 304 def replace_virtio_key(contents, dummy_re, env): |
| 305 """ |
| 306 Replace a virtio dummy string with contents. |
| 307 |
| 308 If install_virtio is not set, replace it with a dummy string. |
| 309 |
| 310 @param contents: Contents of the unattended file |
| 311 @param dummy_re: Regular expression used to search on the. |
| 312 unattended file contents. |
| 313 @param env: Name of the environment variable. |
| 314 """ |
| 315 dummy_path = "C:" |
| 316 driver = os.environ.get(env, '') |
| 317 |
| 318 if re.search(dummy_re, contents): |
| 319 if self.install_virtio == "yes": |
| 320 if driver.endswith("msi"): |
| 321 driver = 'msiexec /passive /package ' + driver |
| 322 else: |
| 323 try: |
| 324 # Let's escape windows style paths properly |
| 325 drive, path = driver.split(":") |
| 326 driver = drive + ":" + re.escape(path) |
| 327 except: |
| 328 pass |
| 329 contents = re.sub(dummy_re, driver, contents) |
| 330 else: |
| 331 contents = re.sub(dummy_re, dummy_path, contents) |
| 332 return contents |
| 333 |
| 334 vdict = {r'\bKVM_TEST_STORAGE_DRIVER_PATH\b': |
| 335 'KVM_TEST_virtio_storage_path', |
| 336 r'\bKVM_TEST_NETWORK_DRIVER_PATH\b': |
| 337 'KVM_TEST_virtio_network_path', |
| 338 r'\bKVM_TEST_VIRTIO_NETWORK_INSTALLER\b': |
| 339 'KVM_TEST_virtio_network_installer_path'} |
| 340 |
| 341 for vkey in vdict: |
| 342 unattended_contents = replace_virtio_key(unattended_contents, |
| 343 vkey, vdict[vkey]) |
| 344 |
| 345 logging.debug("Unattended install contents:") |
| 346 for line in unattended_contents.splitlines(): |
| 347 logging.debug(line) |
| 348 return unattended_contents |
| 349 |
| 350 |
| 351 def setup_boot_disk(self): |
| 352 answer_contents = self.render_answer_file() |
| 353 |
| 354 if self.unattended_file.endswith('.sif'): |
| 355 dest_fname = 'winnt.sif' |
| 356 setup_file = 'winnt.bat' |
| 357 boot_disk = FloppyDisk(self.floppy, self.qemu_img_binary, |
| 358 self.tmpdir) |
| 359 boot_disk.setup_answer_file(dest_fname, answer_contents) |
| 360 setup_file_path = os.path.join(self.unattended_dir, setup_file) |
| 361 boot_disk.copy_to(setup_file_path) |
| 362 if self.install_virtio == "yes": |
| 363 boot_disk.setup_virtio_win2003(self.virtio_floppy, |
| 364 self.virtio_oemsetup_id) |
| 365 boot_disk.copy_to(self.finish_program) |
| 366 |
| 367 elif self.unattended_file.endswith('.ks'): |
| 368 # Red Hat kickstart install |
| 369 dest_fname = 'ks.cfg' |
| 370 if self.cdrom_unattended: |
| 371 boot_disk = CdromDisk(self.cdrom_unattended, self.tmpdir) |
| 372 elif self.floppy: |
| 373 boot_disk = FloppyDisk(self.floppy, self.qemu_img_binary, |
| 374 self.tmpdir) |
| 375 else: |
| 376 raise ValueError("Neither cdrom_unattended nor floppy set " |
| 377 "on the config file, please verify") |
| 378 boot_disk.setup_answer_file(dest_fname, answer_contents) |
| 379 |
| 380 elif self.unattended_file.endswith('.xml'): |
| 381 if "autoyast" in self.extra_params: |
| 382 # SUSE autoyast install |
| 383 dest_fname = "autoinst.xml" |
| 384 if self.cdrom_unattended: |
| 385 boot_disk = CdromDisk(self.cdrom_unattended) |
| 386 elif self.floppy: |
| 387 boot_disk = FloppyDisk(self.floppy, self.qemu_img_binary, |
| 388 self.tmpdir) |
| 389 else: |
| 390 raise ValueError("Neither cdrom_unattended nor floppy set " |
| 391 "on the config file, please verify") |
| 392 boot_disk.setup_answer_file(dest_fname, answer_contents) |
| 393 |
| 394 else: |
| 395 # Windows unattended install |
| 396 dest_fname = "autounattend.xml" |
| 397 boot_disk = FloppyDisk(self.floppy, self.qemu_img_binary, |
| 398 self.tmpdir) |
| 399 boot_disk.setup_answer_file(dest_fname, answer_contents) |
| 400 if self.install_virtio == "yes": |
| 401 boot_disk.setup_virtio_win2008(self.virtio_floppy) |
| 402 boot_disk.copy_to(self.finish_program) |
| 403 |
| 404 else: |
| 405 raise ValueError('Unknown answer file type: %s' % |
| 406 self.unattended_file) |
| 407 |
| 408 boot_disk.close() |
| 409 |
| 410 |
| 411 @error.context_aware |
| 412 def setup_cdrom(self): |
| 413 """ |
| 414 Mount cdrom and copy vmlinuz and initrd.img. |
| 415 """ |
| 416 error.context("Copying vmlinuz and initrd.img from install cdrom %s" % |
| 417 self.cdrom_cd1) |
| 418 m_cmd = ('mount -t iso9660 -v -o loop,ro %s %s' % |
| 419 (self.cdrom_cd1, self.cdrom_cd1_mount)) |
| 420 utils.run(m_cmd) |
| 421 |
| 422 try: |
| 423 if not os.path.isdir(self.image_path): |
| 424 os.makedirs(self.image_path) |
| 425 kernel_fetch_cmd = ("cp %s/%s/%s %s" % |
| 426 (self.cdrom_cd1_mount, self.boot_path, |
| 427 os.path.basename(self.kernel), self.kernel)) |
| 428 utils.run(kernel_fetch_cmd) |
| 429 initrd_fetch_cmd = ("cp %s/%s/%s %s" % |
| 430 (self.cdrom_cd1_mount, self.boot_path, |
| 431 os.path.basename(self.initrd), self.initrd)) |
| 432 utils.run(initrd_fetch_cmd) |
| 433 finally: |
| 434 cleanup(self.cdrom_cd1_mount) |
| 435 |
| 436 |
| 437 @error.context_aware |
| 438 def setup_url(self): |
| 439 """ |
| 440 Download the vmlinuz and initrd.img from URL. |
| 441 """ |
| 442 error.context("downloading vmlinuz and initrd.img from %s" % self.url) |
| 443 os.chdir(self.image_path) |
| 444 kernel_fetch_cmd = "wget -q %s/%s/%s" % (self.url, self.boot_path, |
| 445 os.path.basename(self.kernel)) |
| 446 initrd_fetch_cmd = "wget -q %s/%s/%s" % (self.url, self.boot_path, |
| 447 os.path.basename(self.initrd)) |
| 448 |
| 449 if os.path.exists(self.kernel): |
| 450 os.remove(self.kernel) |
| 451 if os.path.exists(self.initrd): |
| 452 os.remove(self.initrd) |
| 453 |
| 454 utils.run(kernel_fetch_cmd) |
| 455 utils.run(initrd_fetch_cmd) |
| 456 |
| 457 |
| 458 def setup_nfs(self): |
| 459 """ |
| 460 Copy the vmlinuz and initrd.img from nfs. |
| 461 """ |
| 462 error.context("copying the vmlinuz and initrd.img from NFS share") |
| 463 |
| 464 m_cmd = ("mount %s:%s %s -o ro" % |
| 465 (self.nfs_server, self.nfs_dir, self.nfs_mount)) |
| 466 utils.run(m_cmd) |
| 467 |
| 468 try: |
| 469 kernel_fetch_cmd = ("cp %s/%s/%s %s" % |
| 470 (self.nfs_mount, self.boot_path, |
| 471 os.path.basename(self.kernel), self.image_path)) |
| 472 utils.run(kernel_fetch_cmd) |
| 473 initrd_fetch_cmd = ("cp %s/%s/%s %s" % |
| 474 (self.nfs_mount, self.boot_path, |
| 475 os.path.basename(self.initrd), self.image_path)) |
| 476 utils.run(initrd_fetch_cmd) |
| 477 finally: |
| 478 cleanup(self.nfs_mount) |
| 479 |
| 480 |
| 481 def setup(self): |
| 482 """ |
| 483 Configure the environment for unattended install. |
| 484 |
| 485 Uses an appropriate strategy according to each install model. |
| 486 """ |
| 487 logging.info("Starting unattended install setup") |
| 488 display_attributes(self) |
| 489 |
| 490 if self.unattended_file and (self.floppy or self.cdrom_unattended): |
| 491 self.setup_boot_disk() |
| 492 if self.medium == "cdrom": |
| 493 if self.kernel and self.initrd: |
| 494 self.setup_cdrom() |
| 495 elif self.medium == "url": |
| 496 self.setup_url() |
| 497 elif self.medium == "nfs": |
| 498 self.setup_nfs() |
| 499 else: |
| 500 raise ValueError("Unexpected installation method %s" % |
| 501 self.medium) |
| 502 |
| 503 |
| 504 class HugePageConfig(object): |
| 505 def __init__(self, params): |
| 506 """ |
| 507 Gets environment variable values and calculates the target number |
| 508 of huge memory pages. |
| 509 |
| 510 @param params: Dict like object containing parameters for the test. |
| 511 """ |
| 512 self.vms = len(params.objects("vms")) |
| 513 self.mem = int(params.get("mem")) |
| 514 self.max_vms = int(params.get("max_vms", 0)) |
| 515 self.hugepage_path = '/mnt/kvm_hugepage' |
| 516 self.hugepage_size = self.get_hugepage_size() |
| 517 self.target_hugepages = self.get_target_hugepages() |
| 518 self.kernel_hp_file = '/proc/sys/vm/nr_hugepages' |
| 519 |
| 520 |
| 521 def get_hugepage_size(self): |
| 522 """ |
| 523 Get the current system setting for huge memory page size. |
| 524 """ |
| 525 meminfo = open('/proc/meminfo', 'r').readlines() |
| 526 huge_line_list = [h for h in meminfo if h.startswith("Hugepagesize")] |
| 527 try: |
| 528 return int(huge_line_list[0].split()[1]) |
| 529 except ValueError, e: |
| 530 raise ValueError("Could not get huge page size setting from " |
| 531 "/proc/meminfo: %s" % e) |
| 532 |
| 533 |
| 534 def get_target_hugepages(self): |
| 535 """ |
| 536 Calculate the target number of hugepages for testing purposes. |
| 537 """ |
| 538 if self.vms < self.max_vms: |
| 539 self.vms = self.max_vms |
| 540 # memory of all VMs plus qemu overhead of 64MB per guest |
| 541 vmsm = (self.vms * self.mem) + (self.vms * 64) |
| 542 return int(vmsm * 1024 / self.hugepage_size) |
| 543 |
| 544 |
| 545 @error.context_aware |
| 546 def set_hugepages(self): |
| 547 """ |
| 548 Sets the hugepage limit to the target hugepage value calculated. |
| 549 """ |
| 550 error.context("setting hugepages limit to %s" % self.target_hugepages) |
| 551 hugepage_cfg = open(self.kernel_hp_file, "r+") |
| 552 hp = hugepage_cfg.readline() |
| 553 while int(hp) < self.target_hugepages: |
| 554 loop_hp = hp |
| 555 hugepage_cfg.write(str(self.target_hugepages)) |
| 556 hugepage_cfg.flush() |
| 557 hugepage_cfg.seek(0) |
| 558 hp = int(hugepage_cfg.readline()) |
| 559 if loop_hp == hp: |
| 560 raise ValueError("Cannot set the kernel hugepage setting " |
| 561 "to the target value of %d hugepages." % |
| 562 self.target_hugepages) |
| 563 hugepage_cfg.close() |
| 564 logging.debug("Successfuly set %s large memory pages on host ", |
| 565 self.target_hugepages) |
| 566 |
| 567 |
| 568 @error.context_aware |
| 569 def mount_hugepage_fs(self): |
| 570 """ |
| 571 Verify if there's a hugetlbfs mount set. If there's none, will set up |
| 572 a hugetlbfs mount using the class attribute that defines the mount |
| 573 point. |
| 574 """ |
| 575 error.context("mounting hugepages path") |
| 576 if not os.path.ismount(self.hugepage_path): |
| 577 if not os.path.isdir(self.hugepage_path): |
| 578 os.makedirs(self.hugepage_path) |
| 579 cmd = "mount -t hugetlbfs none %s" % self.hugepage_path |
| 580 utils.system(cmd) |
| 581 |
| 582 |
| 583 def setup(self): |
| 584 logging.debug("Number of VMs this test will use: %d", self.vms) |
| 585 logging.debug("Amount of memory used by each vm: %s", self.mem) |
| 586 logging.debug("System setting for large memory page size: %s", |
| 587 self.hugepage_size) |
| 588 logging.debug("Number of large memory pages needed for this test: %s", |
| 589 self.target_hugepages) |
| 590 self.set_hugepages() |
| 591 self.mount_hugepage_fs() |
| 592 |
| 593 |
| 594 @error.context_aware |
| 595 def cleanup(self): |
| 596 error.context("trying to dealocate hugepage memory") |
| 597 try: |
| 598 utils.system("umount %s" % self.hugepage_path) |
| 599 except error.CmdError: |
| 600 return |
| 601 utils.system("echo 0 > %s" % self.kernel_hp_file) |
| 602 logging.debug("Hugepage memory successfuly dealocated") |
| 603 |
| 604 |
| 605 class EnospcConfig(object): |
| 606 """ |
| 607 Performs setup for the test enospc. This is a borg class, similar to a |
| 608 singleton. The idea is to keep state in memory for when we call cleanup() |
| 609 on postprocessing. |
| 610 """ |
| 611 __shared_state = {} |
| 612 def __init__(self, test, params): |
| 613 self.__dict__ = self.__shared_state |
| 614 root_dir = test.bindir |
| 615 self.tmpdir = test.tmpdir |
| 616 self.qemu_img_binary = params.get('qemu_img_binary') |
| 617 if not os.path.isfile(self.qemu_img_binary): |
| 618 self.qemu_img_binary = os.path.join(root_dir, |
| 619 self.qemu_img_binary) |
| 620 self.raw_file_path = os.path.join(self.tmpdir, 'enospc.raw') |
| 621 # Here we're trying to choose fairly explanatory names so it's less |
| 622 # likely that we run in conflict with other devices in the system |
| 623 self.vgtest_name = params.get("vgtest_name") |
| 624 self.lvtest_name = params.get("lvtest_name") |
| 625 self.lvtest_device = "/dev/%s/%s" % (self.vgtest_name, self.lvtest_name) |
| 626 image_dir = os.path.dirname(params.get("image_name")) |
| 627 self.qcow_file_path = os.path.join(image_dir, 'enospc.qcow2') |
| 628 try: |
| 629 getattr(self, 'loopback') |
| 630 except AttributeError: |
| 631 self.loopback = '' |
| 632 |
| 633 |
| 634 @error.context_aware |
| 635 def setup(self): |
| 636 logging.debug("Starting enospc setup") |
| 637 error.context("performing enospc setup") |
| 638 display_attributes(self) |
| 639 # Double check if there aren't any leftovers |
| 640 self.cleanup() |
| 641 try: |
| 642 utils.run("%s create -f raw %s 10G" % |
| 643 (self.qemu_img_binary, self.raw_file_path)) |
| 644 # Associate a loopback device with the raw file. |
| 645 # Subject to race conditions, that's why try here to associate |
| 646 # it with the raw file as quickly as possible |
| 647 l_result = utils.run("losetup -f") |
| 648 utils.run("losetup -f %s" % self.raw_file_path) |
| 649 self.loopback = l_result.stdout.strip() |
| 650 # Add the loopback device configured to the list of pvs |
| 651 # recognized by LVM |
| 652 utils.run("pvcreate %s" % self.loopback) |
| 653 utils.run("vgcreate %s %s" % (self.vgtest_name, self.loopback)) |
| 654 # Create an lv inside the vg with starting size of 200M |
| 655 utils.run("lvcreate -L 200M -n %s %s" % |
| 656 (self.lvtest_name, self.vgtest_name)) |
| 657 # Create a 10GB qcow2 image in the logical volume |
| 658 utils.run("%s create -f qcow2 %s 10G" % |
| 659 (self.qemu_img_binary, self.lvtest_device)) |
| 660 # Let's symlink the logical volume with the image name that autotest |
| 661 # expects this device to have |
| 662 os.symlink(self.lvtest_device, self.qcow_file_path) |
| 663 except Exception, e: |
| 664 self.cleanup() |
| 665 raise |
| 666 |
| 667 @error.context_aware |
| 668 def cleanup(self): |
| 669 error.context("performing enospc cleanup") |
| 670 if os.path.isfile(self.lvtest_device): |
| 671 utils.run("fuser -k %s" % self.lvtest_device) |
| 672 time.sleep(2) |
| 673 l_result = utils.run("lvdisplay") |
| 674 # Let's remove all volumes inside the volume group created |
| 675 if self.lvtest_name in l_result.stdout: |
| 676 utils.run("lvremove -f %s" % self.lvtest_device) |
| 677 # Now, removing the volume group itself |
| 678 v_result = utils.run("vgdisplay") |
| 679 if self.vgtest_name in v_result.stdout: |
| 680 utils.run("vgremove -f %s" % self.vgtest_name) |
| 681 # Now, if we can, let's remove the physical volume from lvm list |
| 682 if self.loopback: |
| 683 p_result = utils.run("pvdisplay") |
| 684 if self.loopback in p_result.stdout: |
| 685 utils.run("pvremove -f %s" % self.loopback) |
| 686 l_result = utils.run('losetup -a') |
| 687 if self.loopback and (self.loopback in l_result.stdout): |
| 688 try: |
| 689 utils.run("losetup -d %s" % self.loopback) |
| 690 except error.CmdError: |
| 691 logging.error("Failed to liberate loopback %s", self.loopback) |
| 692 if os.path.islink(self.qcow_file_path): |
| 693 os.remove(self.qcow_file_path) |
| 694 if os.path.isfile(self.raw_file_path): |
| 695 os.remove(self.raw_file_path) |
OLD | NEW |