Add basic support to control serial console settings (#1385)

Support limited user defined serial console settings to redirect boot
time messages to a log file.

Authored-by: Darragh Bailey <daragh.bailey@gmail.com>
Signed-off-by: Itxaka <igarcia@suse.com>
This commit is contained in:
Itxaka 2021-10-19 16:37:46 +02:00 committed by GitHub
parent d5971f894f
commit b771048f0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 101 additions and 5 deletions

View File

@ -49,6 +49,7 @@ can help a lot :-)
* [USB Redirector Devices](#usb-redirector-devices)
* [Filter for USB Redirector Devices](#filter-for-usb-redirector-devices)
* [Random number generator passthrough](#random-number-generator-passthrough)
* [Serial Console Devices](#serial-console-devices)
* [Watchdog device](#watchdog-device)
* [Smartcard device](#smartcard-device)
* [Hypervisor Features](#hypervisor-features)
@ -657,6 +658,9 @@ end
it is not possible to communicate with VM through `vagrant ssh` or run
provisioning. Setting to 'false' is only possible when VM doesn't use box.
Defaults set to 'true'.
* `serial` - [libvirt serial devices](https://libvirt.org/formatdomain.html#elementsConsole).
Configure a serial/console port to communicate with the guest. Can be used
to log to file boot time messages sent to ttyS0 console by the guest.
Specific domain settings can be set for each domain separately in multi-VM
environment. Example below shows a part of Vagrantfile, where specific options
@ -1252,6 +1256,26 @@ Vagrant.configure("2") do |config|
end
```
## Serial Console Devices
You can define settings to redirect output from the serial console of any VM brought up with libvirt to a file or other devices that are listening. [See libvirt documentation](https://libvirt.org/formatdomain.html#elementCharSerial).
Currently only redirecting to a file is supported.
* `type` - only value that has an effect is file, in the future support may be added for virtual console, pty, dev, pipe, tcp, udp, unix socket, spiceport & nmdm.
* `source` - options pertaining to how the connection attaches to the host, contains sub-settings dependent on `type`.
`source` options for type `file`
* `path` - file on host to connect to the serial port to record all output. May be created by qemu system user causing some permissions issues.
```ruby
Vagrant.configure("2") do |config|
config.vm.define :test do |test|
test.vm.provider :libvirt do |domain|
domain.serial :type => "file", :source => {:path => "/var/log/vm_consoles/test.log}
end
end
end
```
## Random number generator passthrough
You can pass through `/dev/random` to your VM by configuring the domain like this:

View File

@ -171,6 +171,20 @@ module VagrantPlugins
storage_prefix = get_disk_storage_prefix(env, @storage_pool_name)
end
@serials = config.serials
@serials.each do |serial|
next unless serial[:source] && serial[:source][:path]
dir = File.dirname(serial[:source][:path])
begin
FileUtils.mkdir_p(dir)
rescue ::Errno::EACCES
raise Errors::SerialCannotCreatePathError,
path: dir
end
end
@disks.each do |disk|
disk[:path] ||= _disk_name(@name, disk)
@ -379,6 +393,13 @@ module VagrantPlugins
env[:ui].info(" -- smartcard device: mode=#{@smartcard_dev[:mode]}, type=#{@smartcard_dev[:type]}")
end
@serials.each_with_index do |serial, port|
if serial[:source]
env[:ui].info(" -- SERIAL(COM#{port}: redirect to #{serial[:source][:path]}")
env[:ui].warn(I18n.t('vagrant_libvirt.warnings.creating_domain_console_access_disabled'))
end
end
unless @qemu_args.empty?
env[:ui].info(' -- Command line args: ')
@qemu_args.each do |arg|

View File

@ -196,6 +196,9 @@ module VagrantPlugins
# Use QEMU Agent to get ip address
attr_accessor :qemu_use_agent
# serial consoles
attr_accessor :serials
def initialize
@uri = UNSET_VALUE
@driver = UNSET_VALUE
@ -338,6 +341,8 @@ module VagrantPlugins
# Use Qemu agent to get ip address
@qemu_use_agent = UNSET_VALUE
@serials = []
end
def boot(device)
@ -705,6 +710,20 @@ module VagrantPlugins
@qemu_env.merge!(options)
end
def serial(options={})
options = {
:type => "pty",
:source => nil,
}.merge(options)
serial = {
:type => options[:type],
:source => options[:source],
}
@serials << serial
end
def _default_uri
# Determine if any settings except driver provided explicitly, if not
# and the LIBVIRT_DEFAULT_URI var is set, use that.
@ -946,6 +965,8 @@ module VagrantPlugins
@qemu_env = {} if @qemu_env == UNSET_VALUE
@qemu_use_agent = true if @qemu_use_agent != UNSET_VALUE
@serials = [{:type => 'pty', :source => nil}] if @serials == []
end
def validate(machine)
@ -976,6 +997,12 @@ module VagrantPlugins
end
end
machine.provider_config.serials.each do |serial|
if serial[:source] and serial[:source][:path].nil?
errors << "serial :source requires :path to be defined"
end
end
machine.config.vm.networks.each do |_type, opts|
if opts[:mac]
if opts[:mac] =~ /\A([0-9a-fA-F]{12})\z/
@ -1017,6 +1044,10 @@ module VagrantPlugins
c = qemu_env != UNSET_VALUE ? qemu_env.dup : {}
c.merge!(other.qemu_env) if other.qemu_env != UNSET_VALUE
result.qemu_env = c
s = serials.dup
s += other.serials
result.serials = s
end
end

View File

@ -181,6 +181,10 @@ module VagrantPlugins
class DeleteSnapshotError < VagrantLibvirtError
error_key(:delete_snapshot_error)
end
class SerialCannotCreatePathError < VagrantLibvirtError
error_key(:serial_cannot_create_path_error)
end
end
end
end

View File

@ -162,10 +162,19 @@
</disk>
<% end %>
<serial type='pty'>
<target port='0'/>
<% @serials.each_with_index do |serial, port| %>
<serial type='<%= serial[:type] %>'>
<% unless serial[:source].nil? %>
<source path='<%= serial[:source][:path] %>'/>
<% end %>
<target port='<%= port %>'/>
</serial>
<console type='pty'>
<% end %>
<% console_log = @serials.first %>
<console type='<%= console_log[:type] %>'>
<% unless console_log[:source].nil? %>
<source path='<%= console_log[:source][:path] %>'/>
<% end %>
<target port='0'/>
</console>

View File

@ -64,6 +64,8 @@ en:
the minimum box image size of '%{minimum}'.
forwarding_udp: |-
Forwarding UDP ports is not supported. Ignoring.
creating_domain_console_access_disabled: |-
Serial console is being redirected, access via virsh will be disabled.
errors:
call_chain_error: Invalid action chain, must ensure that '%{require_action}' is called prior to calling '%{current_action}'
@ -166,6 +168,8 @@ en:
management_network_required: |-
Management network can't be disabled when VM use box.
Please fix your configuration and run vagrant again.
serial_cannot_create_path_error: |-
Error creating path for serial port output log: %{path}
states:
paused: |-

View File

@ -81,10 +81,12 @@
<readonly/>
</disk>
<serial type='pty'>
<serial type='file'>
<source path='/var/log/vm_consoles/machine.log'/>
<target port='0'/>
</serial>
<console type='pty'>
<console type='file'>
<source path='/var/log/vm_consoles/machine.log'/>
<target port='0'/>
</console>

View File

@ -89,6 +89,7 @@ describe 'templates/domain' do
target_port: '4242',
source_path: '/tmp/foo')
domain.random(model: 'random')
domain.serial(:type => 'file', :source => {:path => '/var/log/vm_consoles/machine.log'})
domain.pci(bus: '0x06', slot: '0x12', function: '0x5')
domain.pci(domain: '0x0001', bus: '0x03', slot: '0x00', function: '0x0')
domain.usb_controller(model: 'nec-xhci', ports: '4')