Add feature-complete /domain/clock support

Feature reference: https://libvirt.org/formatdomain.html#time-keeping
This commit is contained in:
Bart Kus
2023-01-25 22:33:20 -08:00
parent 6b907ab6e0
commit 78e46979e0
7 changed files with 68 additions and 9 deletions

View File

@@ -1046,9 +1046,18 @@ end
## Clock ## Clock
Clock offset can be specified via `libvirt.clock_offset`. (Default is utc) The clock can be configured using one of the following methods:
Additionally timers can be specified via `libvirt.clock_timer`. * Set nothing, and the clock will default to UTC.
* Set `libvirt.clock_offset` to 'utc' or 'localtime' by assigning the respective values.
* To set the clock to a different timezone, assign the timezone name to `libvirt.clock_timezone`.
* To set the clock to the same absolute time whenever the VM starts, set `libvirt.clock_absolute`.
The value format is that of an epoch timestamp.
* To set the clock at an arbitrary offset to realtime, use `libvirt.clock_adjustment`.
Specify the offset adjustment in seconds. By default, the clock offset is relative to UTC,
but this can be changed by setting `libvirt.clock_basis` to 'localtime'.
In addition to the above, timers can be specified via `libvirt.clock_timer`.
Available options for timers are: name, track, tickpolicy, frequency, mode, present Available options for timers are: name, track, tickpolicy, frequency, mode, present
```ruby ```ruby

View File

@@ -36,7 +36,11 @@ module VagrantPlugins
@nodeset = config.nodeset @nodeset = config.nodeset
@features = config.features @features = config.features
@features_hyperv = config.features_hyperv @features_hyperv = config.features_hyperv
@clock_absolute = config.clock_absolute
@clock_adjustment = config.clock_adjustment
@clock_basis = config.clock_basis
@clock_offset = config.clock_offset @clock_offset = config.clock_offset
@clock_timezone = config.clock_timezone
@clock_timers = config.clock_timers @clock_timers = config.clock_timers
@launchsecurity_data = config.launchsecurity_data @launchsecurity_data = config.launchsecurity_data
@shares = config.shares @shares = config.shares
@@ -236,7 +240,15 @@ module VagrantPlugins
env[:ui].info(" -- Feature (HyperV): name=#{feature[:name]}, state=#{feature[:state]}") env[:ui].info(" -- Feature (HyperV): name=#{feature[:name]}, state=#{feature[:state]}")
end end
end end
env[:ui].info(" -- Clock offset: #{@clock_offset}") if not @clock_absolute.nil?
env[:ui].info(" -- Clock absolute: #{@clock_absolute}")
elsif not @clock_adjustment.nil?
env[:ui].info(" -- Clock adjustment: #{@clock_adjustment}")
elsif not @clock_timezone.nil?
env[:ui].info(" -- Clock timezone: #{@clock_timezone}")
else
env[:ui].info(" -- Clock offset: #{@clock_offset}")
end
@clock_timers.each do |timer| @clock_timers.each do |timer|
env[:ui].info(" -- Clock timer: #{timer.map { |k,v| "#{k}=#{v}"}.join(', ')}") env[:ui].info(" -- Clock timer: #{timer.map { |k,v| "#{k}=#{v}"}.join(', ')}")
end end

View File

@@ -166,12 +166,29 @@ module VagrantPlugins
xml_descr.delete_element('/domain/cpu') xml_descr.delete_element('/domain/cpu')
end end
# Clock # Clock - can change in complicated ways, so just build a new clock and compare
newclock = REXML::Element.new('newclock')
if not config.clock_absolute.nil?
newclock.add_attribute('offset', 'absolute')
newclock.add_attribute('start', config.clock_absolute)
elsif not config.clock_adjustment.nil?
newclock.add_attribute('offset', 'variable')
newclock.add_attribute('basis', config.clock_basis)
newclock.add_attribute('adjustment', config.clock_adjustment)
elsif not config.clock_timezone.nil?
newclock.add_attribute('offset', 'timezone')
newclock.add_attribute('timezone', config.clock_timezone)
else
newclock.add_attribute('offset', config.clock_offset)
end
clock = REXML::XPath.first(xml_descr, '/domain/clock') clock = REXML::XPath.first(xml_descr, '/domain/clock')
if clock.attributes['offset'] != config.clock_offset if clock.attributes != newclock.attributes
@logger.debug "clock offset changed" @logger.debug "clock definition changed"
descr_changed = true descr_changed = true
clock.attributes['offset'] = config.clock_offset clock.attributes.clear
newclock.attributes.each do |attr, value|
clock.add_attribute(attr, value)
end
end end
# clock timers - because timers can be added/removed, just rebuild and then compare # clock timers - because timers can be added/removed, just rebuild and then compare

View File

@@ -98,7 +98,11 @@ module VagrantPlugins
attr_accessor :shares attr_accessor :shares
attr_accessor :features attr_accessor :features
attr_accessor :features_hyperv attr_accessor :features_hyperv
attr_accessor :clock_absolute
attr_accessor :clock_adjustment
attr_accessor :clock_basis
attr_accessor :clock_offset attr_accessor :clock_offset
attr_accessor :clock_timezone
attr_accessor :clock_timers attr_accessor :clock_timers
attr_accessor :launchsecurity_data attr_accessor :launchsecurity_data
attr_accessor :numa_nodes attr_accessor :numa_nodes
@@ -278,7 +282,11 @@ module VagrantPlugins
@shares = UNSET_VALUE @shares = UNSET_VALUE
@features = UNSET_VALUE @features = UNSET_VALUE
@features_hyperv = UNSET_VALUE @features_hyperv = UNSET_VALUE
@clock_absolute = UNSET_VALUE
@clock_adjustment = UNSET_VALUE
@clock_basis = UNSET_VALUE
@clock_offset = UNSET_VALUE @clock_offset = UNSET_VALUE
@clock_timezone = UNSET_VALUE
@clock_timers = [] @clock_timers = []
@launchsecurity_data = UNSET_VALUE @launchsecurity_data = UNSET_VALUE
@numa_nodes = UNSET_VALUE @numa_nodes = UNSET_VALUE
@@ -1002,7 +1010,11 @@ module VagrantPlugins
@shares = nil if @shares == UNSET_VALUE @shares = nil if @shares == UNSET_VALUE
@features = ['acpi','apic','pae'] if @features == UNSET_VALUE @features = ['acpi','apic','pae'] if @features == UNSET_VALUE
@features_hyperv = [] if @features_hyperv == UNSET_VALUE @features_hyperv = [] if @features_hyperv == UNSET_VALUE
@clock_absolute = nil if @clock_absolute == UNSET_VALUE
@clock_adjustment = nil if @clock_adjustment == UNSET_VALUE
@clock_basis = 'utc' if @clock_basis == UNSET_VALUE
@clock_offset = 'utc' if @clock_offset == UNSET_VALUE @clock_offset = 'utc' if @clock_offset == UNSET_VALUE
@clock_timezone = nil if @clock_timezone == UNSET_VALUE
@clock_timers = [] if @clock_timers == UNSET_VALUE @clock_timers = [] if @clock_timers == UNSET_VALUE
@launchsecurity_data = nil if @launchsecurity_data == UNSET_VALUE @launchsecurity_data = nil if @launchsecurity_data == UNSET_VALUE
@numa_nodes = @numa_nodes == UNSET_VALUE ? nil : _generate_numa @numa_nodes = @numa_nodes == UNSET_VALUE ? nil : _generate_numa

View File

@@ -132,7 +132,15 @@
</hyperv> </hyperv>
<%- end -%> <%- end -%>
</features> </features>
<%- if not @clock_absolute.nil? -%>
<clock offset='absolute' start='<%= @clock_absolute %>'>
<%- elsif not @clock_adjustment.nil? -%>
<clock offset='variable' basis='<%= @clock_basis %>' adjustment='<%= @clock_adjustment %>'>
<%- elsif not @clock_timezone.nil? -%>
<clock offset='timezone' timezone='<%= @clock_timezone %>'>
<%- else -%>
<clock offset='<%= @clock_offset %>'> <clock offset='<%= @clock_offset %>'>
<%- end -%>
<%- @clock_timers.each do |clock_timer| -%> <%- @clock_timers.each do |clock_timer| -%>
<timer<% clock_timer.each do |attr, value| %> <%= attr %>='<%= value %>'<% end %>/> <timer<% clock_timer.each do |attr, value| %> <%= attr %>='<%= value %>'<% end %>/>
<%- end -%> <%- end -%>

View File

@@ -47,7 +47,7 @@
<spinlocks state='on' retries='4096' /> <spinlocks state='on' retries='4096' />
</hyperv> </hyperv>
</features> </features>
<clock offset='variable'> <clock offset='variable' basis='localtime' adjustment='-31536000'>
<timer name='t1'/> <timer name='t1'/>
<timer name='t2' track='b' tickpolicy='c' frequency='d' mode='e' present='yes'/> <timer name='t2' track='b' tickpolicy='c' frequency='d' mode='e' present='yes'/>
</clock> </clock>

View File

@@ -62,7 +62,8 @@ describe 'templates/domain' do
domain.cpu_mode = 'custom' domain.cpu_mode = 'custom'
domain.cpu_feature(name: 'AAA', policy: 'required') domain.cpu_feature(name: 'AAA', policy: 'required')
domain.hyperv_feature(name: 'BBB', state: 'on') domain.hyperv_feature(name: 'BBB', state: 'on')
domain.clock_offset = 'variable' domain.clock_adjustment = -(365 * 24 * 60 * 60)
domain.clock_basis = 'localtime'
domain.clock_timer(name: 't1') domain.clock_timer(name: 't1')
domain.clock_timer(name: 't2', track: 'b', tickpolicy: 'c', frequency: 'd', mode: 'e', present: 'yes') domain.clock_timer(name: 't2', track: 'b', tickpolicy: 'c', frequency: 'd', mode: 'e', present: 'yes')
domain.hyperv_feature(name: 'spinlocks', state: 'on', retries: '4096') domain.hyperv_feature(name: 'spinlocks', state: 'on', retries: '4096')