Skip to content

Commit

Permalink
Merge 91952ed into 3b0d5f8
Browse files Browse the repository at this point in the history
  • Loading branch information
jreidinger committed Oct 15, 2019
2 parents 3b0d5f8 + 91952ed commit f5db338
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 41 deletions.
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ require "yast/rake"
Yast::Tasks.configuration do |conf|
# lets ignore license check for now
conf.skip_license_check << /.*/
conf.install_locations["src/systemd/*"] =
Packaging::Configuration::DESTDIR + "/usr/lib/systemd/system/"
end
6 changes: 6 additions & 0 deletions package/yast2-ntp-client.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Mon Oct 14 18:20:17 UTC 2019 - Josef Reidinger <jreidinger@suse.com>

- switch from cron to systemd timers (jsc#SLE-9113)
- 4.2.5

-------------------------------------------------------------------
Wed Oct 2 11:42:34 UTC 2019 - Josef Reidinger <jreidinger@suse.com>

Expand Down
29 changes: 25 additions & 4 deletions package/yast2-ntp-client.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


Name: yast2-ntp-client
Version: 4.2.4
Version: 4.2.5
Release: 0
Summary: YaST2 - NTP Client Configuration
License: GPL-2.0-or-later
Expand All @@ -28,10 +28,11 @@ Source0: %{name}-%{version}.tar.bz2

BuildRequires: augeas-lenses
BuildRequires: autoyast2-installation
# Needed for /etc/cron.* ownership; those directories have special permission handling
BuildRequires: cron
BuildRequires: perl-XML-Writer
BuildRequires: update-desktop-files
# need as it own /usr/lib/systemd and for systemd macros
BuildRequires: systemd-rpm-macros
%{?systemd_requires}
# cwm/popup
BuildRequires: yast2 >= 4.1.15
BuildRequires: yast2-country-data
Expand Down Expand Up @@ -71,12 +72,32 @@ This package contains the YaST2 component for NTP client configuration.
%yast_metainfo

%post
%service_add_post yast-timesync.service

# upgrade old name and convert it to chrony (bsc#1079122)
if [ -f /etc/cron.d/novell.ntp-synchronize ]; then
mv /etc/cron.d/novell.ntp-synchronize /etc/cron.d/suse-ntp_synchronize
sed -i 's:\* \* \* \* root .*:* * * * root /usr/sbin/chronyd -q \&>/dev/null:' /etc/cron.d/suse-ntp_synchronize
fi

# and now update cron to systemd timer. We need to support upgrade from SLE12 and also SLE15 SP1.
# jsc#SLE-9113
if [ -f /etc/cron.d/suse-ntp_synchronize ]; then
/usr/bin/erb timeout=$(grep -o '[[:digit:]]\+' /etc/cron.d/suse-ntp_synchronize) /usr/share/YaST2/data/yast-timesync.timer.erb > /etc/systemd/system/yast-timesync.timer
/bin/systemctl enable yast-timesync.timer
/bin/systemctl start yast-timesync.timer
rm /etc/cron.d/suse-ntp_synchronize
fi

%pre
%service_add_pre yast-timesync.service

%postun
%service_del_postun yast-timesync.service

%preun
%service_del_preun yast-timesync.service

%files
%{yast_clientdir}
%{yast_libdir}
Expand All @@ -86,8 +107,8 @@ fi
%{yast_metainfodir}
%{yast_ydatadir}
%{yast_schemadir}
%ghost %{_sysconfdir}/cron.d/suse-ntp_synchronize
%{yast_icondir}
%{_unitdir}/yast-timesync.service
%license COPYING
%doc %{yast_docdir}

Expand Down
2 changes: 1 addition & 1 deletion src/clients/ntp-client_proposal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def AskUser
# Writes configuration for ntp client.
# @param ntp_servers [Array<String>] list of servers to configure as ntp sync sources
# @param ntp_server [String] fallback server that is used if `ntp_servers` param is empty.
# @param run_service [Boolean] define if synchronize with systemd services or via cron sync
# @param run_service [Boolean] define if synchronize with systemd services or via systemd timer
# @return true
def WriteNtpSettings(ntp_servers, ntp_server, run_service)
ntp_servers = deep_copy(ntp_servers)
Expand Down
7 changes: 7 additions & 0 deletions src/data/yast-timesync.timer.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Timer]
# first sync after boot
OnBootSec=1min
OnUnitActiveSec=<%= timeout %>min

[Install]
WantedBy=timers.target
51 changes: 34 additions & 17 deletions src/modules/NtpClient.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
require "cfa/chrony_conf"
require "yast2/target_file" # required to cfa work on changed scr
require "ui/text_helpers"
require "erb"
require "yast2/systemctl"

module Yast
class NtpClientClass < Module
include Logger
include ::UI::TextHelpers

# the default synchronization interval in minutes when running in the manual
# sync mode ("Synchronize without Daemon" option, ntp started from cron)
# sync mode ("Synchronize without Daemon" option, ntp started from systemd timer)
# Note: the UI field currently uses maximum of 60 minutes
DEFAULT_SYNC_INTERVAL = 5

Expand All @@ -33,8 +35,9 @@ class NtpClientClass < Module

NTP_FILE = "/etc/chrony.conf".freeze

# The cron file name for the synchronization.
CRON_FILE = "/etc/cron.d/suse-ntp_synchronize".freeze
TIMER_FILE = "yast-timesync.timer".freeze
# The file name of systemd timer for the synchronization.
TIMER_PATH = "/etc/systemd/system/#{TIMER_FILE}".freeze

UNSUPPORTED_AUTOYAST_OPTIONS = [
"configure_dhcp",
Expand Down Expand Up @@ -281,15 +284,14 @@ def ProcessNtpConf
# synchronize_time and sync_interval variables
# Return updated value of synchronize_time
def ReadSynchronization
crontab = SCR.Read(path(".cron"), CRON_FILE, "")
log.info("NTP Synchronization crontab entry: #{crontab}")
cron_entry = (crontab || []).fetch(0, {}).fetch("events", []).fetch(0, {})
@synchronize_time = cron_entry["active"] == "1"
return false unless ::File.exist?(TIMER_PATH)

sync_interval_entry = cron_entry.fetch("minute", "*/#{DEFAULT_SYNC_INTERVAL}")
log.info("MINUTE #{sync_interval_entry}")
timer_content = ::File.read(TIMER_PATH)
log.info("NTP Synchronization timer entry: #{timer_content}")
@synchronize_time = Yast2::Systemctl.execute("is-active #{TIMER_FILE}").exit.zero?

@sync_interval = sync_interval_entry.tr("^[0-9]", "").to_i
interval = timer_content[/^\s*OnUnitActiveSec\s*=\s*(\d+)m/, 1]
@sync_interval = interval.to_i if interval
log.info("SYNC_INTERVAL #{@sync_interval}")

@synchronize_time
Expand Down Expand Up @@ -365,7 +367,7 @@ def Write

check_service

update_cron_settings
update_timer_settings

return false if !go_next

Expand Down Expand Up @@ -839,19 +841,34 @@ def check_service
end
end

# If synchronize time has been enable it writes ntp cron entry for manual
# sync. If not it removes current cron entry if exists.
def update_cron_settings
def timer_content
erb_template = ::File.read(Directory.find_data_file("#{TIMER_FILE}.erb"))
content = ERB.new(erb_template)
timeout = @sync_interval
content.result(binding)
end

# If synchronize time has been enable it writes systemd timer entry for manual
# sync. If not it removes current systemd timer entry if exists.
def update_timer_settings
if @synchronize_time
SCR.Write(
path(".target.string"),
CRON_FILE,
"-*/#{@sync_interval} * * * * root /usr/sbin/chronyd -q &>/dev/null\n"
TIMER_PATH,
timer_content
)
res = Yast2::Systemctl.execute("enable #{TIMER_FILE}")
log.info "enable timer: #{res.inspect}"
res = Yast2::Systemctl.execute("start #{TIMER_FILE}")
log.info "start timer: #{res.inspect}"
else
res = Yast2::Systemctl.execute("disable #{TIMER_FILE}")
log.info "disable timer: #{res.inspect}"
res = Yast2::Systemctl.execute("stop #{TIMER_FILE}")
log.info "stop timer: #{res.inspect}"
SCR.Execute(
path(".target.bash"),
"rm -vf #{CRON_FILE}"
"rm -vf #{TIMER_PATH}"
)
end
end
Expand Down
13 changes: 13 additions & 0 deletions src/systemd/yast-timesync.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=One time sync configured by YaST
DefaultDependencies=no
# one time sync cannot be done if chrony server runs
Conflicts=chronyd.service
RefuseManualStart=false

[Service]
Type=oneshot
StandardError=tty
StandardOutput=tty
RemainAfterExit=no
ExecStart=/usr/bin/systemd-cat -t yast-timesync -- /usr/sbin/chronyd -q
53 changes: 34 additions & 19 deletions test/ntp_client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,8 @@
end
end

it "updates cron settings" do
expect(subject).to receive(:update_cron_settings)
it "updates systemd timer settings" do
expect(subject).to receive(:update_timer_settings)

subject.Write
end
Expand Down Expand Up @@ -437,23 +437,27 @@
end

describe "#ReadSynchronization" do
let(:cron_job_file) { "/etc/cron.d/suse-ntp_synchronize" }
let(:cron_entry) { [] }
let(:systemd_timer_file) { "/etc/systemd/system/yast-timesync.timer" }
let(:timer_content) { "" }

before do
allow(Yast::SCR).to receive(:Read)
.with(Yast::Path.new(".cron"), cron_job_file, "").and_return(cron_entry)
allow(::File).to receive(:exist?).and_call_original
allow(::File).to receive(:exist?).with("/etc/systemd/system/yast-timesync.timer")
.and_return(true)
allow(::File).to receive(:read).and_return(timer_content)
end

it "reads cron file" do
expect(Yast::SCR).to receive(:Read)
.with(Yast::Path.new(".cron"), cron_job_file, "")
it "reads systemd timer" do
expect(::File).to receive(:read).and_return(timer_content)

subject.ReadSynchronization
end

context "when cron file does not exist" do
let(:cron_entry) { nil }
context "when systemd timer file does not exist" do
before do
allow(::File).to receive(:exist?).with("/etc/systemd/system/yast-timesync.timer")
.and_return(true)
end

it "sets synchronize_time as false" do
subject.ReadSynchronization
Expand All @@ -468,29 +472,40 @@
end
end

context "when cron file exists" do
context "when there is no cron entry" do
context "when systemd timer file exists" do
let(:timer_content) do
subject.sync_interval = 10
subject.send(:timer_content)
end

context "when timer is not active" do
before do
allow(Yast::SCR).to receive(:Execute).and_return("exit" => 3)
end

it "sets synchronize_time as false" do
subject.ReadSynchronization

expect(subject.synchronize_time).to eql(false)
end

it "sets sync interval with default value" do
it "sets sync interval with value from timer" do
subject.ReadSynchronization

expect(subject.sync_interval).to eql(Yast::NtpClientClass::DEFAULT_SYNC_INTERVAL)
expect(subject.sync_interval).to eql(10)
end
end

context "when there is cron entry" do
let(:cron_entry) { [{ "events" => [{ "active" => "1", "minute" => "*/10" }] }] }
context "when timer is active" do
before do
allow(Yast::SCR).to receive(:Execute).and_return("exit" => 0)
end

it "sets synchronize time as true if first cron entry is valid" do
it "sets synchronize time as true" do
expect(subject.ReadSynchronization).to eql(true)
end

it "sets sync_interval with cron minute interval" do
it "sets sync_interval with value from timer" do
subject.ReadSynchronization

expect(subject.sync_interval).to eql(10)
Expand Down
4 changes: 4 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ENV["Y2DIR"] = File.expand_path("../src", __dir__)
ENV["LC_ALL"] = "en_US.utf8"

require "yast"
require "yast/rspec"
Expand All @@ -23,6 +24,9 @@ def stub_module(name)

# stub classes from other modules to speed up a build
stub_module("Lan")
stub_module("Language")
stub_module("Pkg")
stub_module("PackageCallbacks")

if ENV["COVERAGE"]
require "simplecov"
Expand Down

0 comments on commit f5db338

Please sign in to comment.