diff --git a/manifests/migration/libvirt.pp b/manifests/migration/libvirt.pp index 2466ec29c..64bf9c264 100644 --- a/manifests/migration/libvirt.pp +++ b/manifests/migration/libvirt.pp @@ -4,9 +4,10 @@ # # === Parameters: # -# [*use_tls*] -# (optional) Use tls for remote connections to libvirt -# Defaults to false +# [*transport*] +# (optional) Transport to use for live-migration. +# Valid options are 'tcp', 'tls', and 'ssh'. +# Defaults to 'tcp' # # [*auth*] # (optional) Use this authentication scheme for remote libvirt connections. @@ -53,8 +54,29 @@ # (optional) Whether or not configure libvirt bits. # Defaults to true. # +# [*client_user*] +# (optional) Remote user to connect as. +# Only applies to ssh transport. +# Defaults to undef (root) +# +# [*client_port*] +# (optional) Remote port to connect to. +# Defaults to undef (default port for the transport) +# +# [*client_extraparams*] +# (optional) Hash of additional params to append to the live-migraition uri +# See https://libvirt.org/guide/html/Application_Development_Guide-Architecture-Remote_URIs.html +# Defaults to {} +# +# DEPRECATED PARAMETERS +# +# [*use_tls*] +# (optional) Use tls for remote connections to libvirt +# Defaults to false +# Deprecated by transport paramater. +# class nova::migration::libvirt( - $use_tls = false, + $transport = undef, $auth = 'none', $listen_address = undef, $live_migration_tunnelled = $::os_service_default, @@ -63,28 +85,70 @@ class nova::migration::libvirt( $override_uuid = false, $configure_libvirt = true, $configure_nova = true, + $client_user = undef, + $client_port = undef, + $client_extraparams = {}, + # DEPRECATED PARAMETERS + $use_tls = false, ){ include ::nova::deps + if $transport { + $transport_real = $transport + } elsif $use_tls { + warning( + 'The use_tls parameter is now deprecated and will be removed in the Queens cycle. Please set transport=tls instead.' + ) + $transport_real = 'tls' + } else { + $transport_real = 'tcp' + } + + validate_re($transport_real, ['^tcp$', '^tls$', '^ssh$'], 'Valid options for transport are tcp, tls, ssh.') validate_re($auth, [ '^sasl$', '^none$' ], 'Valid options for auth are none and sasl.') - if $use_tls { + if $transport_real == 'tls' { $listen_tls = '1' $listen_tcp = '0' - } else { + } elsif $transport_real == 'tcp' { $listen_tls = '0' $listen_tcp = '1' + } else { + $listen_tls = '0' + $listen_tcp = '0' } if $configure_nova { - if $use_tls { - nova_config { - 'libvirt/live_migration_uri': value => 'qemu+tls://%s/system'; + + if $transport_real == 'ssh' { + if $client_user { + $prefix = "${client_user}@" + } else { + $prefix = '' } + } else { + $prefix = '' } + if $client_port { + $postfix = ":${client_port}" + } else { + $postfix = '' + } + + if $client_extraparams != {} { + $extra_params_before_python_escape = join(uriescape(join_keys_to_values($client_extraparams, '=')), '&') + # Must escape % as nova interprets it incorrecly. + $extra_params = sprintf('?%s', regsubst($extra_params_before_python_escape, '%', '%%', 'G')) + } else { + $extra_params ='' + } + + $live_migration_uri = "qemu+${transport_real}://${prefix}%s${postfix}/system${extra_params}" + nova_config { + 'libvirt/live_migration_uri': value => $live_migration_uri; 'libvirt/live_migration_tunnelled': value => $live_migration_tunnelled; 'libvirt/live_migration_completion_timeout': value => $live_migration_completion_timeout; 'libvirt/live_migration_progress_timeout': value => $live_migration_progress_timeout; @@ -136,14 +200,14 @@ class nova::migration::libvirt( tag => 'libvirt-file_line', } - if $use_tls { + if $transport_real == 'tls' { file_line { '/etc/libvirt/libvirtd.conf auth_tls': path => '/etc/libvirt/libvirtd.conf', line => "auth_tls = \"${auth}\"", match => 'auth_tls =', tag => 'libvirt-file_line', } - } else { + } elsif $transport_real == 'tcp' { file_line { '/etc/libvirt/libvirtd.conf auth_tcp': path => '/etc/libvirt/libvirtd.conf', line => "auth_tcp = \"${auth}\"", @@ -161,11 +225,13 @@ class nova::migration::libvirt( } } - file_line { '/etc/sysconfig/libvirtd libvirtd args': - path => '/etc/sysconfig/libvirtd', - line => 'LIBVIRTD_ARGS="--listen"', - match => 'LIBVIRTD_ARGS=', - tag => 'libvirt-file_line', + if $transport_real != 'ssh' { + file_line { '/etc/sysconfig/libvirtd libvirtd args': + path => '/etc/sysconfig/libvirtd', + line => 'LIBVIRTD_ARGS="--listen"', + match => 'LIBVIRTD_ARGS=', + tag => 'libvirt-file_line', + } } } @@ -184,14 +250,14 @@ class nova::migration::libvirt( tag => 'libvirt-file_line', } - if $use_tls { + if $transport_real == 'tls' { file_line { '/etc/libvirt/libvirtd.conf auth_tls': path => '/etc/libvirt/libvirtd.conf', line => "auth_tls = \"${auth}\"", match => 'auth_tls =', tag => 'libvirt-file_line', } - } else { + } elsif $transport_real == 'tcp' { file_line { '/etc/libvirt/libvirtd.conf auth_tcp': path => '/etc/libvirt/libvirtd.conf', line => "auth_tcp = \"${auth}\"", @@ -209,19 +275,21 @@ class nova::migration::libvirt( } } - if $::operatingsystem == 'Ubuntu' and versioncmp($::operatingsystemmajrelease, '16') >= 0 { - # If systemd is being used then libvirtd is already being launched correctly and - # adding -d causes a second consecutive start to fail which causes puppet to fail. - $libvirtd_opts = 'libvirtd_opts="-l"' - } else { - $libvirtd_opts = 'libvirtd_opts="-d -l"' - } + if $transport_real != 'ssh' { + if $::operatingsystem == 'Ubuntu' and versioncmp($::operatingsystemmajrelease, '16') >= 0 { + # If systemd is being used then libvirtd is already being launched correctly and + # adding -d causes a second consecutive start to fail which causes puppet to fail. + $libvirtd_opts = 'libvirtd_opts="-l"' + } else { + $libvirtd_opts = 'libvirtd_opts="-d -l"' + } - file_line { "/etc/default/${::nova::compute::libvirt::libvirt_service_name} libvirtd opts": - path => "/etc/default/${::nova::compute::libvirt::libvirt_service_name}", - line => $libvirtd_opts, - match => 'libvirtd_opts=', - tag => 'libvirt-file_line', + file_line { "/etc/default/${::nova::compute::libvirt::libvirt_service_name} libvirtd opts": + path => "/etc/default/${::nova::compute::libvirt::libvirt_service_name}", + line => $libvirtd_opts, + match => 'libvirtd_opts=', + tag => 'libvirt-file_line', + } } } diff --git a/releasenotes/notes/live_migration_ssh-00596d9c92a76759.yaml b/releasenotes/notes/live_migration_ssh-00596d9c92a76759.yaml new file mode 100644 index 000000000..1eadf6c93 --- /dev/null +++ b/releasenotes/notes/live_migration_ssh-00596d9c92a76759.yaml @@ -0,0 +1,13 @@ +--- +features: + - | + Add support for libvirt live-migration over SSH including the ability to + override all libvirt options applicable to the SSH transport. + For more info see https://libvirt.org/remote.html#Remote_URI_reference. + Adds new parameter "nova::migration::libvirt::transport" + Adds new parameter "nova::migration::libvirt::client_user" + Adds new parameter "nova::migration::libvirt::client_port" + Adds new parameter "nova::migration::libvirt::client_extraparams" +deprecations: + - | + The "nova::migration::libvirt::use_tls" parameter is deprecated by the "nova::migration::libvirt::transport" parameter. diff --git a/spec/classes/nova_migration_libvirt_spec.rb b/spec/classes/nova_migration_libvirt_spec.rb index 8ee9d3c96..eef40a64e 100644 --- a/spec/classes/nova_migration_libvirt_spec.rb +++ b/spec/classes/nova_migration_libvirt_spec.rb @@ -47,6 +47,8 @@ describe 'nova::migration::libvirt' do it { is_expected.to contain_nova_config('libvirt/live_migration_tunnelled').with_value('') } it { is_expected.to contain_nova_config('libvirt/live_migration_completion_timeout').with_value('') } it { is_expected.to contain_nova_config('libvirt/live_migration_progress_timeout').with_value('') } + it { is_expected.to contain_nova_config('libvirt/live_migration_uri').with_value('qemu+tcp://%s/system') } + end context 'with override_uuid enabled' do @@ -66,7 +68,7 @@ describe 'nova::migration::libvirt' do }).that_requires('Package[libvirt]').that_notifies('Service[libvirt]') } end - context 'with tls enabled' do + context 'with tls enabled (legacy)' do let :params do { :use_tls => true, @@ -79,6 +81,19 @@ describe 'nova::migration::libvirt' do it { is_expected.to contain_nova_config('libvirt/live_migration_uri').with_value('qemu+tls://%s/system')} end + context 'with tls enabled' do + let :params do + { + :transport => 'tls', + } + end + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tls').with(:line => "listen_tls = 1") } + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tcp').with(:line => "listen_tcp = 0") } + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf auth_tls').with(:line => "auth_tls = \"none\"") } + it { is_expected.not_to contain_file_line('/etc/libvirt/libvirtd.conf auth_tcp')} + it { is_expected.to contain_nova_config('libvirt/live_migration_uri').with_value('qemu+tls://%s/system')} + end + context 'with migration flags set' do let :params do { @@ -106,7 +121,7 @@ describe 'nova::migration::libvirt' do let :params do { :auth => 'sasl', - :use_tls => true + :transport => 'tls' } end it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf auth_tls').with(:line => "auth_tls = \"sasl\"") } @@ -130,13 +145,14 @@ describe 'nova::migration::libvirt' do } end it { is_expected.not_to contain_file_line('/etc/libvirt/libvirtd.conf listen_tls') } + it { is_expected.not_to contain_file_line('/etc/libvirt/libvirtd.conf listen_tcp') } end context 'when not configuring nova and tls enabled' do let :params do { :configure_nova => false, - :use_tls => true, + :transport => 'tls', } end it { is_expected.not_to contain_nova_config('libvirt/live_migration_uri').with_value('qemu+tls://%s/system') } @@ -192,4 +208,54 @@ describe 'nova::migration::libvirt' do it { is_expected.to contain_file_line('/etc/sysconfig/libvirtd libvirtd args').with(:line => 'LIBVIRTD_ARGS="--listen"') } end + shared_examples_for 'ssh tunneling' do + + context 'with ssh transport' do + let :params do + { + :transport => 'ssh', + } + end + it { is_expected.to contain_nova_config('libvirt/live_migration_uri').with_value('qemu+ssh://%s/system')} + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tls').with(:line => "listen_tls = 0") } + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tcp').with(:line => "listen_tcp = 0") } + end + + context 'with ssh transport with user' do + let :params do + { + :transport => 'ssh', + :client_user => 'foobar' + } + end + it { is_expected.to contain_nova_config('libvirt/live_migration_uri').with_value('qemu+ssh://foobar@%s/system')} + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tls').with(:line => "listen_tls = 0") } + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tcp').with(:line => "listen_tcp = 0") } + end + + context 'with ssh transport with port' do + let :params do + { + :transport => 'ssh', + :client_port => 1234 + } + end + it { is_expected.to contain_nova_config('libvirt/live_migration_uri').with_value('qemu+ssh://%s:1234/system')} + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tls').with(:line => "listen_tls = 0") } + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tcp').with(:line => "listen_tcp = 0") } + end + + context 'with ssh transport with extraparams' do + let :params do + { + :transport => 'ssh', + :client_extraparams => {'foo' => '%', 'bar' => 'baz'} + } + end + it { is_expected.to contain_nova_config('libvirt/live_migration_uri').with_value('qemu+ssh://%s/system?foo=%%25&bar=baz')} + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tls').with(:line => "listen_tls = 0") } + it { is_expected.to contain_file_line('/etc/libvirt/libvirtd.conf listen_tcp').with(:line => "listen_tcp = 0") } + end + + end end