xref: /qemu/tests/functional/test_virtio_balloon.py (revision 1456e90653c46aceb3dd83a7b9889a32aad7700d)
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