1*1456e906SDaniel P. Berrangé#!/usr/bin/env python3 2*1456e906SDaniel P. Berrangé# 3*1456e906SDaniel P. Berrangé# virtio-balloon tests 4*1456e906SDaniel P. Berrangé# 5*1456e906SDaniel P. Berrangé# This work is licensed under the terms of the GNU GPL, version 2 or 6*1456e906SDaniel P. Berrangé# later. See the COPYING file in the top-level directory. 7*1456e906SDaniel P. Berrangé 8*1456e906SDaniel P. Berrangéimport time 9*1456e906SDaniel P. Berrangé 10*1456e906SDaniel P. Berrangéfrom qemu_test import QemuSystemTest, Asset 11*1456e906SDaniel P. Berrangéfrom qemu_test import wait_for_console_pattern 12*1456e906SDaniel P. Berrangéfrom qemu_test import exec_command_and_wait_for_pattern 13*1456e906SDaniel P. Berrangé 14*1456e906SDaniel P. BerrangéUNSET_STATS_VALUE = 18446744073709551615 15*1456e906SDaniel P. Berrangé 16*1456e906SDaniel P. Berrangé 17*1456e906SDaniel P. Berrangéclass VirtioBalloonx86(QemuSystemTest): 18*1456e906SDaniel P. Berrangé 19*1456e906SDaniel P. Berrangé ASSET_KERNEL = Asset( 20*1456e906SDaniel P. Berrangé ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' 21*1456e906SDaniel P. Berrangé '/31/Server/x86_64/os/images/pxeboot/vmlinuz'), 22*1456e906SDaniel P. Berrangé 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129') 23*1456e906SDaniel P. Berrangé 24*1456e906SDaniel P. Berrangé ASSET_INITRD = Asset( 25*1456e906SDaniel P. Berrangé ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' 26*1456e906SDaniel P. Berrangé '/31/Server/x86_64/os/images/pxeboot/initrd.img'), 27*1456e906SDaniel P. Berrangé '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b') 28*1456e906SDaniel P. Berrangé 29*1456e906SDaniel P. Berrangé ASSET_DISKIMAGE = Asset( 30*1456e906SDaniel P. Berrangé ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' 31*1456e906SDaniel P. Berrangé '/31/Cloud/x86_64/images/Fedora-Cloud-Base-31-1.9.x86_64.qcow2'), 32*1456e906SDaniel P. Berrangé 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0') 33*1456e906SDaniel P. Berrangé 34*1456e906SDaniel P. Berrangé DEFAULT_KERNEL_PARAMS = ('root=/dev/vda1 console=ttyS0 net.ifnames=0 ' 35*1456e906SDaniel P. Berrangé 'rd.rescue') 36*1456e906SDaniel P. Berrangé 37*1456e906SDaniel P. Berrangé def wait_for_console_pattern(self, success_message, vm=None): 38*1456e906SDaniel P. Berrangé wait_for_console_pattern( 39*1456e906SDaniel P. Berrangé self, 40*1456e906SDaniel P. Berrangé success_message, 41*1456e906SDaniel P. Berrangé failure_message="Kernel panic - not syncing", 42*1456e906SDaniel P. Berrangé vm=vm, 43*1456e906SDaniel P. Berrangé ) 44*1456e906SDaniel P. Berrangé 45*1456e906SDaniel P. Berrangé def mount_root(self): 46*1456e906SDaniel P. Berrangé self.wait_for_console_pattern('Entering emergency mode.') 47*1456e906SDaniel P. Berrangé prompt = '# ' 48*1456e906SDaniel P. Berrangé self.wait_for_console_pattern(prompt) 49*1456e906SDaniel P. Berrangé 50*1456e906SDaniel P. Berrangé exec_command_and_wait_for_pattern(self, 'mount /dev/vda1 /sysroot', 51*1456e906SDaniel P. Berrangé prompt) 52*1456e906SDaniel P. Berrangé exec_command_and_wait_for_pattern(self, 'chroot /sysroot', 53*1456e906SDaniel P. Berrangé prompt) 54*1456e906SDaniel P. Berrangé exec_command_and_wait_for_pattern(self, "modprobe virtio-balloon", 55*1456e906SDaniel P. Berrangé prompt) 56*1456e906SDaniel P. Berrangé 57*1456e906SDaniel P. Berrangé def assert_initial_stats(self): 58*1456e906SDaniel P. Berrangé ret = self.vm.qmp('qom-get', 59*1456e906SDaniel P. Berrangé {'path': '/machine/peripheral/balloon', 60*1456e906SDaniel P. Berrangé 'property': 'guest-stats'})['return'] 61*1456e906SDaniel P. Berrangé when = ret.get('last-update') 62*1456e906SDaniel P. Berrangé assert when == 0 63*1456e906SDaniel P. Berrangé stats = ret.get('stats') 64*1456e906SDaniel P. Berrangé for name, val in stats.items(): 65*1456e906SDaniel P. Berrangé assert val == UNSET_STATS_VALUE 66*1456e906SDaniel P. Berrangé 67*1456e906SDaniel P. Berrangé def assert_running_stats(self, then): 68*1456e906SDaniel P. Berrangé ret = self.vm.qmp('qom-get', 69*1456e906SDaniel P. Berrangé {'path': '/machine/peripheral/balloon', 70*1456e906SDaniel P. Berrangé 'property': 'guest-stats'})['return'] 71*1456e906SDaniel P. Berrangé when = ret.get('last-update') 72*1456e906SDaniel P. Berrangé now = time.time() 73*1456e906SDaniel P. Berrangé 74*1456e906SDaniel P. Berrangé assert when > then and when < now 75*1456e906SDaniel P. Berrangé stats = ret.get('stats') 76*1456e906SDaniel P. Berrangé # Stat we expect this particular Kernel to have set 77*1456e906SDaniel P. Berrangé expectData = [ 78*1456e906SDaniel P. Berrangé "stat-available-memory", 79*1456e906SDaniel P. Berrangé "stat-disk-caches", 80*1456e906SDaniel P. Berrangé "stat-free-memory", 81*1456e906SDaniel P. Berrangé "stat-htlb-pgalloc", 82*1456e906SDaniel P. Berrangé "stat-htlb-pgfail", 83*1456e906SDaniel P. Berrangé "stat-major-faults", 84*1456e906SDaniel P. Berrangé "stat-minor-faults", 85*1456e906SDaniel P. Berrangé "stat-swap-in", 86*1456e906SDaniel P. Berrangé "stat-swap-out", 87*1456e906SDaniel P. Berrangé "stat-total-memory", 88*1456e906SDaniel P. Berrangé ] 89*1456e906SDaniel P. Berrangé for name, val in stats.items(): 90*1456e906SDaniel P. Berrangé if name in expectData: 91*1456e906SDaniel P. Berrangé assert val != UNSET_STATS_VALUE 92*1456e906SDaniel P. Berrangé else: 93*1456e906SDaniel P. Berrangé assert val == UNSET_STATS_VALUE 94*1456e906SDaniel P. Berrangé 95*1456e906SDaniel P. Berrangé def test_virtio_balloon_stats(self): 96*1456e906SDaniel P. Berrangé self.set_machine('q35') 97*1456e906SDaniel P. Berrangé kernel_path = self.ASSET_KERNEL.fetch() 98*1456e906SDaniel P. Berrangé initrd_path = self.ASSET_INITRD.fetch() 99*1456e906SDaniel P. Berrangé diskimage_path = self.ASSET_DISKIMAGE.fetch() 100*1456e906SDaniel P. Berrangé 101*1456e906SDaniel P. Berrangé self.vm.set_console() 102*1456e906SDaniel P. Berrangé self.vm.add_args("-S") 103*1456e906SDaniel P. Berrangé self.vm.add_args("-cpu", "max") 104*1456e906SDaniel P. Berrangé self.vm.add_args("-m", "2G") 105*1456e906SDaniel P. Berrangé # Slow down BIOS phase with boot menu, so that after a system 106*1456e906SDaniel P. Berrangé # reset, we can reliably catch the clean stats again in BIOS 107*1456e906SDaniel P. Berrangé # phase before the guest OS launches 108*1456e906SDaniel P. Berrangé self.vm.add_args("-boot", "menu=on") 109*1456e906SDaniel P. Berrangé self.vm.add_args("-machine", "q35,accel=kvm:tcg") 110*1456e906SDaniel P. Berrangé self.vm.add_args("-device", "virtio-balloon,id=balloon") 111*1456e906SDaniel P. Berrangé self.vm.add_args('-drive', 112*1456e906SDaniel P. Berrangé f'file={diskimage_path},if=none,id=drv0,snapshot=on') 113*1456e906SDaniel P. Berrangé self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' + 114*1456e906SDaniel P. Berrangé 'drive=drv0,id=virtio-disk0,bootindex=1') 115*1456e906SDaniel P. Berrangé 116*1456e906SDaniel P. Berrangé self.vm.add_args( 117*1456e906SDaniel P. Berrangé "-kernel", 118*1456e906SDaniel P. Berrangé kernel_path, 119*1456e906SDaniel P. Berrangé "-initrd", 120*1456e906SDaniel P. Berrangé initrd_path, 121*1456e906SDaniel P. Berrangé "-append", 122*1456e906SDaniel P. Berrangé self.DEFAULT_KERNEL_PARAMS 123*1456e906SDaniel P. Berrangé ) 124*1456e906SDaniel P. Berrangé self.vm.launch() 125*1456e906SDaniel P. Berrangé 126*1456e906SDaniel P. Berrangé # Poll stats at 100ms 127*1456e906SDaniel P. Berrangé self.vm.qmp('qom-set', 128*1456e906SDaniel P. Berrangé {'path': '/machine/peripheral/balloon', 129*1456e906SDaniel P. Berrangé 'property': 'guest-stats-polling-interval', 130*1456e906SDaniel P. Berrangé 'value': 100 }) 131*1456e906SDaniel P. Berrangé 132*1456e906SDaniel P. Berrangé # We've not run any guest code yet, neither BIOS or guest, 133*1456e906SDaniel P. Berrangé # so stats should be all default values 134*1456e906SDaniel P. Berrangé self.assert_initial_stats() 135*1456e906SDaniel P. Berrangé 136*1456e906SDaniel P. Berrangé self.vm.qmp('cont') 137*1456e906SDaniel P. Berrangé 138*1456e906SDaniel P. Berrangé then = time.time() 139*1456e906SDaniel P. Berrangé self.mount_root() 140*1456e906SDaniel P. Berrangé self.assert_running_stats(then) 141*1456e906SDaniel P. Berrangé 142*1456e906SDaniel P. Berrangé # Race window between these two commands, where we 143*1456e906SDaniel P. Berrangé # rely on '-boot menu=on' to (hopefully) ensure we're 144*1456e906SDaniel P. Berrangé # still executing the BIOS when QEMU processes the 145*1456e906SDaniel P. Berrangé # 'stop', and thus have not loaded the virtio-balloon 146*1456e906SDaniel P. Berrangé # driver in the guest 147*1456e906SDaniel P. Berrangé self.vm.qmp('system_reset') 148*1456e906SDaniel P. Berrangé self.vm.qmp('stop') 149*1456e906SDaniel P. Berrangé 150*1456e906SDaniel P. Berrangé # If the above assumption held, we're in BIOS now and 151*1456e906SDaniel P. Berrangé # stats should be all back at their default values 152*1456e906SDaniel P. Berrangé self.assert_initial_stats() 153*1456e906SDaniel P. Berrangé self.vm.qmp('cont') 154*1456e906SDaniel P. Berrangé 155*1456e906SDaniel P. Berrangé then = time.time() 156*1456e906SDaniel P. Berrangé self.mount_root() 157*1456e906SDaniel P. Berrangé self.assert_running_stats(then) 158*1456e906SDaniel P. Berrangé 159*1456e906SDaniel P. Berrangé 160*1456e906SDaniel P. Berrangéif __name__ == '__main__': 161*1456e906SDaniel P. Berrangé QemuSystemTest.main() 162