Skip to content

Commit b5e0ed2

Browse files
committed
libvirt: Add configuration options to set SPICE compression settings
This patch adds the following SPICE-related options to the 'spice' configuration group of a Nova configuration: - image_compression - jpeg_compression - zlib_compression - playback_compression - streaming_mode These configuration options can be used to enable and set the SPICE compression settings for libvirt (QEMU/KVM) provisioned instances. Each configuration option is optional and can be set explictly to configure the associated SPICE compression setting for libvirt. If all configuration options are not set, then none of the SPICE compression settings will be configured for libvirt, which corresponds to the behavior before this change. In this case, the built-in defaults from the libvirt backend (e.g. QEMU) are used. Note that those options are only taken into account if SPICE support is enabled (and the VNC support is disabled). Implements: blueprint nova-support-spice-compression-algorithm Change-Id: Ia7efeb1b1a04504721e1a5bdd1b5fa7a87cdb810
1 parent 26f24b7 commit b5e0ed2

File tree

7 files changed

+204
-1
lines changed

7 files changed

+204
-1
lines changed

doc/source/admin/remote-console-access.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,16 @@ Replace ``IP_ADDRESS`` with the IP address from which the proxy is accessible
366366
by the outside world. For example, this may be the management interface IP
367367
address of the controller or the VIP.
368368

369+
Optionally, the :program:`nova-compute` service supports the following
370+
additional options to configure compression settings (algorithms and modes)
371+
for SPICE consoles.
372+
373+
- :oslo.config:option:`spice.image_compression`
374+
- :oslo.config:option:`spice.jpeg_compression`
375+
- :oslo.config:option:`spice.zlib_compression`
376+
- :oslo.config:option:`spice.playback_compression`
377+
- :oslo.config:option:`spice.streaming_mode`
378+
369379

370380
Serial
371381
------

nova/conf/spice.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,59 @@
8484
* Better mouse integration - The mouse can be captured and released without
8585
needing to click inside the console or press keys to release it. The
8686
performance of mouse movement is also improved.
87+
"""),
88+
cfg.StrOpt('image_compression',
89+
advanced=True,
90+
choices=[
91+
('auto_glz', 'enable image compression mode to choose between glz '
92+
'and quic algorithm, based on image properties'),
93+
('auto_lz', 'enable image compression mode to choose between lz '
94+
'and quic algorithm, based on image properties'),
95+
('quic', 'enable image compression based on the SFALIC algorithm'),
96+
('glz', 'enable image compression using lz with history based '
97+
'global dictionary'),
98+
('lz', 'enable image compression with the Lempel-Ziv algorithm'),
99+
('off', 'disable image compression')
100+
],
101+
help="""
102+
Configure the SPICE image compression (lossless).
103+
"""),
104+
cfg.StrOpt('jpeg_compression',
105+
advanced=True,
106+
choices=[
107+
('auto', 'enable JPEG image compression automatically'),
108+
('never', 'disable JPEG image compression'),
109+
('always', 'enable JPEG image compression')
110+
],
111+
help="""
112+
Configure the SPICE wan image compression (lossy for slow links).
113+
"""),
114+
cfg.StrOpt('zlib_compression',
115+
advanced=True,
116+
choices=[
117+
('auto', 'enable zlib image compression automatically'),
118+
('never', 'disable zlib image compression'),
119+
('always', 'enable zlib image compression')
120+
],
121+
help="""
122+
Configure the SPICE wan image compression (lossless for slow links).
123+
"""),
124+
cfg.BoolOpt('playback_compression',
125+
advanced=True,
126+
help="""
127+
Enable the SPICE audio stream compression (using celt).
128+
"""),
129+
cfg.StrOpt('streaming_mode',
130+
advanced=True,
131+
choices=[
132+
('filter', 'SPICE server adds additional filters to decide if '
133+
'video streaming should be activated'),
134+
('all', 'any fast-refreshing window can be encoded into a video '
135+
'stream'),
136+
('off', 'no video detection and (lossy) compression is performed')
137+
],
138+
help="""
139+
Configure the SPICE video stream detection and (lossy) compression.
87140
"""),
88141
cfg.URIOpt('html5proxy_base_url',
89142
default='http://127.0.0.1:6082/spice_auto.html',

nova/tests/unit/virt/libvirt/test_config.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1537,7 +1537,7 @@ def test_config_input(self):
15371537

15381538
class LibvirtConfigGuestGraphicsTest(LibvirtConfigBaseTest):
15391539

1540-
def test_config_graphics(self):
1540+
def test_config_graphics_vnc(self):
15411541
obj = config.LibvirtConfigGuestGraphics()
15421542
obj.type = "vnc"
15431543
obj.autoport = True
@@ -1549,6 +1549,30 @@ def test_config_graphics(self):
15491549
<graphics type="vnc" autoport="yes" keymap="en_US" listen="127.0.0.1"/>
15501550
""")
15511551

1552+
def test_config_graphics_spice(self):
1553+
obj = config.LibvirtConfigGuestGraphics()
1554+
obj.type = "spice"
1555+
obj.autoport = False
1556+
obj.keymap = "en_US"
1557+
obj.listen = "127.0.0.1"
1558+
1559+
obj.image_compression = "auto_glz"
1560+
obj.jpeg_compression = "auto"
1561+
obj.zlib_compression = "always"
1562+
obj.playback_compression = True
1563+
obj.streaming_mode = "filter"
1564+
1565+
xml = obj.to_xml()
1566+
self.assertXmlEqual(xml, """
1567+
<graphics type="spice" autoport="no" keymap="en_US" listen="127.0.0.1">
1568+
<image compression="auto_glz"/>
1569+
<jpeg compression="auto"/>
1570+
<zlib compression="always"/>
1571+
<playback compression="on"/>
1572+
<streaming mode="filter"/>
1573+
</graphics>
1574+
""")
1575+
15521576

15531577
class LibvirtConfigGuestHostdev(LibvirtConfigBaseTest):
15541578

nova/tests/unit/virt/libvirt/test_driver.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5793,6 +5793,11 @@ def test_get_guest_config_with_vnc(self):
57935793
self.assertEqual(cfg.devices[3].type, 'vnc')
57945794
self.assertEqual(cfg.devices[3].listen, '10.0.0.1')
57955795
self.assertIsNone(cfg.devices[3].keymap)
5796+
self.assertIsNone(cfg.devices[3].image_compression)
5797+
self.assertIsNone(cfg.devices[3].jpeg_compression)
5798+
self.assertIsNone(cfg.devices[3].zlib_compression)
5799+
self.assertIsNone(cfg.devices[3].playback_compression)
5800+
self.assertIsNone(cfg.devices[3].streaming_mode)
57965801

57975802
def test_get_guest_config_with_vnc_and_tablet(self):
57985803
self.flags(enabled=True, group='vnc')
@@ -5823,6 +5828,11 @@ def test_get_guest_config_with_vnc_and_tablet(self):
58235828
vconfig.LibvirtConfigMemoryBalloon)
58245829

58255830
self.assertEqual(cfg.devices[3].type, 'vnc')
5831+
self.assertIsNone(cfg.devices[3].image_compression)
5832+
self.assertIsNone(cfg.devices[3].jpeg_compression)
5833+
self.assertIsNone(cfg.devices[3].zlib_compression)
5834+
self.assertIsNone(cfg.devices[3].playback_compression)
5835+
self.assertIsNone(cfg.devices[3].streaming_mode)
58265836
self.assertEqual(cfg.devices[5].type, 'tablet')
58275837

58285838
def test_get_guest_config_with_spice_and_tablet(self):
@@ -5859,6 +5869,11 @@ def test_get_guest_config_with_spice_and_tablet(self):
58595869
self.assertEqual(cfg.devices[3].type, 'spice')
58605870
self.assertEqual(cfg.devices[3].listen, '10.0.0.1')
58615871
self.assertIsNone(cfg.devices[3].keymap)
5872+
self.assertIsNone(cfg.devices[3].image_compression)
5873+
self.assertIsNone(cfg.devices[3].jpeg_compression)
5874+
self.assertIsNone(cfg.devices[3].zlib_compression)
5875+
self.assertIsNone(cfg.devices[3].playback_compression)
5876+
self.assertIsNone(cfg.devices[3].streaming_mode)
58625877
self.assertEqual(cfg.devices[5].type, 'tablet')
58635878

58645879
@mock.patch.object(host.Host, "_check_machine_type", new=mock.Mock())
@@ -5918,8 +5933,57 @@ def test_get_guest_config_with_spice_and_agent(self):
59185933
self.assertEqual(cfg.devices[3].target_name, "com.redhat.spice.0")
59195934
self.assertEqual(cfg.devices[3].type, 'spicevmc')
59205935
self.assertEqual(cfg.devices[4].type, "spice")
5936+
self.assertIsNone(cfg.devices[4].image_compression)
5937+
self.assertIsNone(cfg.devices[4].jpeg_compression)
5938+
self.assertIsNone(cfg.devices[4].zlib_compression)
5939+
self.assertIsNone(cfg.devices[4].playback_compression)
5940+
self.assertIsNone(cfg.devices[4].streaming_mode)
59215941
self.assertEqual(cfg.devices[5].type, video_type)
59225942

5943+
def test_get_guest_config_with_spice_compression(self):
5944+
self.flags(enabled=False, group='vnc')
5945+
self.flags(virt_type='kvm', group='libvirt')
5946+
self.flags(enabled=True,
5947+
agent_enabled=False,
5948+
image_compression='auto_lz',
5949+
jpeg_compression='never',
5950+
zlib_compression='always',
5951+
playback_compression=False,
5952+
streaming_mode='all',
5953+
server_listen='10.0.0.1',
5954+
group='spice')
5955+
self.flags(pointer_model='usbtablet')
5956+
5957+
cfg = self._get_guest_config_with_graphics()
5958+
5959+
self.assertEqual(len(cfg.devices), 9)
5960+
self.assertIsInstance(cfg.devices[0],
5961+
vconfig.LibvirtConfigGuestDisk)
5962+
self.assertIsInstance(cfg.devices[1],
5963+
vconfig.LibvirtConfigGuestDisk)
5964+
self.assertIsInstance(cfg.devices[2],
5965+
vconfig.LibvirtConfigGuestSerial)
5966+
self.assertIsInstance(cfg.devices[3],
5967+
vconfig.LibvirtConfigGuestGraphics)
5968+
self.assertIsInstance(cfg.devices[4],
5969+
vconfig.LibvirtConfigGuestVideo)
5970+
self.assertIsInstance(cfg.devices[5],
5971+
vconfig.LibvirtConfigGuestInput)
5972+
self.assertIsInstance(cfg.devices[6],
5973+
vconfig.LibvirtConfigGuestRng)
5974+
self.assertIsInstance(cfg.devices[7],
5975+
vconfig.LibvirtConfigGuestUSBHostController)
5976+
self.assertIsInstance(cfg.devices[8],
5977+
vconfig.LibvirtConfigMemoryBalloon)
5978+
5979+
self.assertEqual(cfg.devices[3].type, 'spice')
5980+
self.assertEqual(cfg.devices[3].listen, '10.0.0.1')
5981+
self.assertEqual(cfg.devices[3].image_compression, 'auto_lz')
5982+
self.assertEqual(cfg.devices[3].jpeg_compression, 'never')
5983+
self.assertEqual(cfg.devices[3].zlib_compression, 'always')
5984+
self.assertFalse(cfg.devices[3].playback_compression)
5985+
self.assertEqual(cfg.devices[3].streaming_mode, 'all')
5986+
59235987
@mock.patch.object(host.Host, 'get_guest')
59245988
@mock.patch.object(libvirt_driver.LibvirtDriver,
59255989
'_get_serial_ports_from_guest')

nova/virt/libvirt/config.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,12 @@ def __init__(self, **kwargs):
20472047
self.keymap = None
20482048
self.listen = None
20492049

2050+
self.image_compression = None
2051+
self.jpeg_compression = None
2052+
self.zlib_compression = None
2053+
self.playback_compression = None
2054+
self.streaming_mode = None
2055+
20502056
def format_dom(self):
20512057
dev = super(LibvirtConfigGuestGraphics, self).format_dom()
20522058

@@ -2057,6 +2063,24 @@ def format_dom(self):
20572063
if self.listen:
20582064
dev.set("listen", self.listen)
20592065

2066+
if self.type == "spice":
2067+
if self.image_compression is not None:
2068+
dev.append(etree.Element(
2069+
'image', compression=self.image_compression))
2070+
if self.jpeg_compression is not None:
2071+
dev.append(etree.Element(
2072+
'jpeg', compression=self.jpeg_compression))
2073+
if self.zlib_compression is not None:
2074+
dev.append(etree.Element(
2075+
'zlib', compression=self.zlib_compression))
2076+
if self.playback_compression is not None:
2077+
dev.append(etree.Element(
2078+
'playback', compression=self.get_on_off_str(
2079+
self.playback_compression)))
2080+
if self.streaming_mode is not None:
2081+
dev.append(etree.Element(
2082+
'streaming', mode=self.streaming_mode))
2083+
20602084
return dev
20612085

20622086

nova/virt/libvirt/driver.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7302,6 +7302,11 @@ def _guest_add_video_device(guest):
73027302
graphics = vconfig.LibvirtConfigGuestGraphics()
73037303
graphics.type = "spice"
73047304
graphics.listen = CONF.spice.server_listen
7305+
graphics.image_compression = CONF.spice.image_compression
7306+
graphics.jpeg_compression = CONF.spice.jpeg_compression
7307+
graphics.zlib_compression = CONF.spice.zlib_compression
7308+
graphics.playback_compression = CONF.spice.playback_compression
7309+
graphics.streaming_mode = CONF.spice.streaming_mode
73057310
guest.add_device(graphics)
73067311
add_video_driver = True
73077312

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
features:
3+
- |
4+
The following SPICE-related options are added to the ``spice``
5+
configuration group of a Nova configuration:
6+
7+
- ``image_compression``
8+
- ``jpeg_compression``
9+
- ``zlib_compression``
10+
- ``playback_compression``
11+
- ``streaming_mode``
12+
13+
These configuration options can be used to enable and set the
14+
SPICE compression settings for libvirt (QEMU/KVM) provisioned
15+
instances. Each configuration option is optional and can be set
16+
explictly to configure the associated SPICE compression setting
17+
for libvirt. If all configuration options are not set, then none
18+
of the SPICE compression settings will be configured for libvirt,
19+
which corresponds to the behavior before this change. In this case,
20+
the built-in defaults from the libvirt backend (e.g. QEMU) are used.
21+
22+
Note that those options are only taken into account if SPICE support
23+
is enabled (and the VNC support is disabled).

0 commit comments

Comments
 (0)