ACC SHELL
/**
* File: modules/NtpClient.ycp
* Package: Configuration of ntp-client
* Summary: Data for configuration of ntp-client, input and output functions.
* Authors: Jiri Srain <jsrain@suse.cz>
*
* $Id: NtpClient.ycp 61641 2010-04-09 16:07:40Z varkoly $
*
* Representation of the configuration of ntp-client.
* Input and output routines.
*/
{
module "NtpClient";
textdomain "ntp-client";
import "Directory";
import "FileUtils";
import "Language";
import "Message";
import "Mode";
import "NetworkInterfaces";
import "PackageSystem";
import "Popup";
import "Progress";
import "Report";
import "Service";
import "SLPAPI";
import "Stage";
import "String";
import "Summary";
import "SuSEFirewall";
import "FileChanges";
/**
* Abort function
* return boolean return true if abort
*/
global boolean() AbortFunction = nil;
/**
* Data was modified?
*/
global boolean modified = false;
/**
* Write only, used during autoinstallation.
* Don't run services and SuSEconfig, it's all done at one place.
*/
global boolean write_only = false;
/**
* Read all ntp-client settings
* @return true on success
*/
global list<map<string, any> > ntp_records = [];
global map <string, map <string,any> > restrict_map = $[];
/**
* Should the daemon be started when system boots?
*/
global boolean run_service = true;
/**
* Should the time synchronized periodicaly?
*/
global boolean synchronize_time = false;
/**
* The interval of synchronization in minutes.
*/
global integer sync_interval = 5;
/**
* The cron file name for the synchronization.
*/
global string cron_file = "/etc/cron.d/novell.ntp-synchronize";
/**
* Service name of the NTP daemon
*/
global string service_name = "ntp";
/**
* Should the daemon be started in chroot environment?
*/
global boolean run_chroot = false;
/**
* Netconfig policy: for merging and prioritizing static and DHCP config.
* FIXME get a public URL
* https://svn.suse.de/svn/sysconfig/branches/mt/dhcp6-netconfig/netconfig/doc/README
*/
global string ntp_policy = "auto";
/**
* Index of the currently sellected item
*/
global integer selected_index = -1;
/**
* The currently sellected item
*/
global map<string,any> selected_record = $[];
/**
* Active Directory controller
*/
global string ad_controller = "";
/**
* Should the firewall settings be changed?
*/
global boolean change_firewall = false;
/**
* Required packages
*/
global list required_packages = ["ntp"];
/**
* ports in firewall to open
*/
global list<string> firewall_services = ["service:ntp"];
/**
* List of known NTP servers
* server address -> information
* address: the key repeated
* country: CC (uppercase)
* location: for displaying
* ...: (others are unused)
*/
map<string,map<string,string> > ntp_servers = nil;
/**
* Mapping between country codes and country names ("CZ" -> "Czech Republic")
*/
map<string,string> country_names = nil;
global boolean simple_dialog = false;
global boolean config_has_been_read = false;
global boolean ntp_selected = false;
global boolean PolicyIsAuto() {
return ntp_policy == "auto" || ntp_policy == "STATIC *";
}
global boolean PolicyIsNomodify() {
return ntp_policy == "";
}
global boolean PolicyIsNonstatic() {
return ntp_policy != "" && ntp_policy != "STATIC";
}
/**
* Abort function
* @return blah blah lahjk
*/
define boolean Abort() ``{
if(NtpClient::AbortFunction != nil)
return NtpClient::AbortFunction() == true;
return false;
}
// for lazy loading
boolean countries_already_read = false;
map <string, string> known_countries = $[];
/**
* Reads and returns all known countries with their country codes
*
* @return map <string, string> of known contries
* @struct $[
* "CL" : "Chile",
* "FR" : "France",
* ...
* ]
*/
global define map <string, string> GetAllKnownCountries () {
//first point of dependence on yast2-country-data
if (!countries_already_read) {
known_countries = (map <string, string>) eval (SCR::Read (.target.ycp, Directory::datadir + "/country.ycp"));
countries_already_read = true;
if (known_countries == nil) known_countries = $[];
}
//workaround bug #241054: servers in United Kingdom are in domain .uk
// domain .gb does not exist - add UK to the list of known countries
if (haskey(known_countries, "GB")){
known_countries["UK"] = known_countries["GB"]:"";
known_countries = remove(known_countries,"GB");
}
return known_countries;
}
/**
* Read current language (RC_LANG from sysconfig)
* @return two-letter language code (cs_CZ.UTF-8 -> CZ)
*/
global define string GetCurrentLanguageCode ( ) {
string lang = (string)SCR::Read (.sysconfig.language.RC_LANG);
//second point of dependence on yast2-country-data
return Language::GetGivenLanguageCountry( lang );
}
map<string, string> MakePoolRecord (string CC, string location) {
return $[
"address" : tolower(CC) + ".pool.ntp.org",
"country" : CC,
"location": location,
];
}
/**
* Get the list of known NTP servers
* @return a list of known NTP servers
*/
global map<string, map<string,string> > GetNtpServers () {
if (ntp_servers == nil)
{
ntp_servers = $[];
list<map<string,string> > servers = (list<map<string,string> >)
SCR::Read (.target.ycp, Directory::datadir + "/ntp_servers.ycp");
if (servers == nil)
{
y2error ("Failed to read the list of NTP servers");
}
else
{
y2milestone ("%1 known NTP servers read", size (servers));
ntp_servers = listmap (map<string,string> s, servers, {
string server = s["address"]:"";
return $[ server : s ];
});
}
foreach (string short_country, string country_name, GetAllKnownCountries(), {
// just refactored existing code
map<string, string> p = MakePoolRecord(short_country, country_name);
ntp_servers[p["address"]:""] = p;
});
}
return ntp_servers;
}
/**
* Get the mapping between country codea and names ("CZ" -> "Czech Republic")
* @return a map the country codes and names mapping
*/
global map<string, string> GetCountryNames () {
if (country_names == nil)
{
country_names = (map<string,string>)
eval(SCR::Read(.target.yast2, "country.ycp"));
}
if (country_names == nil)
{
y2error ("Failed to read country names");
country_names = $[];
}
return country_names;
}
/**
* Get list of public NTP servers for a country
* @param country two-letter country code
* @param terse_output display additional data (location etc.)
* @return list of servers (usable as combo-box items)
*/
global list GetNtpServersByCountry ( string country, boolean terse_output ) {
map<string,string> country_names = $[];
map<string,map<string,string> > servers = GetNtpServers ();
if (country != "")
{
servers = filter (string s, map<string,string> o, servers, {
return o["country"]:"" == country;
});
// bnc#458917 add country, in case data/country.ycp does not have it
map<string,string> p = MakePoolRecord (country, "");
servers[p["address"]:""] = p;
}
else
{
country_names = GetCountryNames ();
}
list items = maplist (string s, map<string,string> o, servers, {
string label = o["location"]:"";
string l_country = o["country"]:"";
if (country != "")
l_country = "";
else
l_country = country_names[l_country]:l_country;
if (label != "" && l_country != "")
label = sformat ("%1 (%2, %3)", s, label, l_country);
else if (label == "" && l_country == "")
label = s;
else
label = sformat ("%1 (%2%3)", s, label, l_country);
if (terse_output)
return `item (`id(s), s);
else
return `item (`id (s), label);
});
return items;
}
/**
* Read and parse /etc.ntp.conf
* @return true on success
*/
global define boolean ProcessNtpConf() ``{
if (config_has_been_read)
{
y2milestone("Configuration has been read already, skipping.");
return false;
}
map conf = nil;
if (FileUtils::Exists("/etc/ntp.conf"))
conf = (map)SCR::Read (.etc.ntp_conf.all);
if (conf == nil )
{
y2error("Failed to read /etc/ntp.conf, either it doesn't exist or contains no data");
return false;
}
config_has_been_read = true;
list<map<string, any> > value = conf["value"]:[];
integer index = -1;
ntp_records = maplist (map<string, any> m, value, ``{
index = index + 1;
string type = m["name"]:"";
string address = m["value"]:"";
string options = "";
if (contains ([
"server", "peer", "broadcast", "broadcastclient", "manycast",
"manycastclient", "fudge", "restrict" ],
type))
{
list<string> l = splitstring (address, " \t");
l = (list<string>)filter (string s, l, ``(s != ""));
address = l[0]:"";
l[0] = "";
options = mergestring (l, " ");
}
map<string,any> entry = $[
"type" : type,
"address" : address,
"options" : options,
"comment" : m["comment"]:"",
];
return entry;
});
list<map<string, any> > fudge_records = filter (map<string,any> m, ntp_records, ``(
m["type"]:"" == "fudge"
));
map <string, map<string, any> > fudge_map = (map <string, map<string, any> >)listmap (map m, fudge_records,
``{
string key = m["address"]:"";
return $[key: m];
});
list<map<string, any> > restrict_records = filter (map<string,any> m, ntp_records, ``(
m["type"]:"" == "restrict"
));
restrict_map = (map <string, map <string,any> > )listmap (map m, restrict_records,
{
string key = m["address"]:"";
map value = $[];
list <string> opts = splitstring( String::CutBlanks( m["options"]:"" ), " \t");
if ( opts[0]:"" == "mask") {
value["mask"] = opts[1]:"";
opts[0] = ""; opts[1] = "";
}
else {
value["mask"] = "";
}
value["options"] = String::CutBlanks( mergestring(opts, " "));
value["comment"] = m["comment"]:"";
return $[key: value];
});
ntp_records = filter (map<string,any> m, ntp_records, ``(
m["type"]:"" != "fudge"
));
ntp_records = filter (map<string,any> m, ntp_records, ``(
m["type"]:"" != "restrict"
));
ntp_records = (list<map<string,any> >)maplist (map m, ntp_records, ``{
if (haskey (fudge_map, m["address"]:""))
{
m["fudge_options"] = fudge_map[m["address"]:"", "options"]:"";
m["fudge_comment"] = fudge_map[m["address"]:"", "comment"]:"";
}
return m;
});
// mark local clock to be local clock and not real servers
ntp_records = maplist (map<string,any> p, ntp_records, ``{
if (p["type"]:"" == "server"
&& regexpmatch (p["address"]:"", "^127\.127\.[0-9]+.[0-9]+$"))
{
p["type"] = "__clock";
}
return p;
});
return true;
}
/**
* Read all ntp-client settings
* @return true on success
*/
global define boolean Read() ``{
if (config_has_been_read)
return true;
/* NtpClient read dialog caption */
string caption = _("Initializing NTP Client Configuration");
integer steps = 2;
integer sl = 500;
boolean have_progress = (Mode::normal());
// We do not set help text here, because it was set outside
if ( have_progress )
{
Progress::New( caption, " ", steps, [
// progress stage
_("Read network configuration"),
// progress stage
_("Read NTP settings"),
], [
// progress step
_("Reading network configuration..."),
// progress step
_("Reading NTP settings..."),
// progress step
_("Finished")
],
""
);
}
// read network configuration
if(Abort()) return false;
if (have_progress) Progress::NextStage();
boolean progress_orig = Progress::set (false);
NetworkInterfaces::Read ();
Progress::set (progress_orig);
//SCR::Read may return nil (no such value in sysconfig, file not there etc. )
string policy = (string)SCR::Read (.sysconfig.network.config.NETCONFIG_NTP_POLICY);
//set if not nil, otherwise use 'auto' as safe fallback (#449362)
if (policy != nil)
ntp_policy = policy;
GetNtpServers ();
GetCountryNames ();
// read current settings
if(Abort()) return false;
if (have_progress) Progress::NextStage();
boolean failed = false;
if (! Mode::testsuite () && ! Mode::installation ()
&& ! PackageSystem::CheckAndInstallPackagesInteractive (["ntp"])
)
{
return false;
}
run_service = Service::Enabled (service_name);
//Poke to /var/lib/YaST if there is Active Directory controller address dumped in .ycp file
string ad_ntp_file = Directory::vardir + "/ad_ntp_data.ycp";
if(FileUtils::Exists(ad_ntp_file)) {
y2milestone("Reading %1", ad_ntp_file);
map <string, string> ad_ntp_data = (map <string, string>) SCR::Read(.target.ycp, ad_ntp_file);
ad_controller = ad_ntp_data["ads"]:"";
if(ad_controller != "") {
y2milestone("Got %1 for ntp sync, deleting %2, since it is no longer needed", ad_controller, ad_ntp_file);
SCR::Execute(.target.remove, ad_ntp_file);
}
}
// Stay away if the user may have made changes which we cannot parse.
// But bnc#456553, no pop-ups for CLI.
if (! Mode::commandline() && ! FileChanges::CheckFiles (["/etc/ntp.conf"]))
failed = true;
ProcessNtpConf();
list crontab = (list)SCR::Read(.cron, cron_file, "");
y2milestone("CRONTAB %1", crontab);
string tmp = (string) crontab[0,"events",0,"active"]:"0";
synchronize_time = tmp == "1";
tmp = (string) crontab[0,"events",0,"minute"]:"*/5";
y2milestone("MINUTE %1", tmp);
list pos = regexppos(tmp, "[0-9]+");
string tmp2 = substring(tmp,pos[0]:0,pos[1]:0);
sync_interval = tointeger(tmp2);
y2milestone("SYNC_INTERVAL %1", sync_interval);
string run_chroot_s = (string) SCR::Read (.sysconfig.ntp.NTPD_RUN_CHROOTED);
run_chroot = run_chroot_s == "yes";
if (run_chroot_s == nil)
{
failed = true;
y2error ("Failed reading .sysconfig.ntp.NTPD_RUN_CHROOTED");
}
if(failed)
{
// error report
Report::Error (Message::CannotReadCurrentSettings ());
}
if (! Mode::testsuite ())
{
boolean progress_orig = Progress::set (false);
SuSEFirewall::Read ();
Progress::set (progress_orig);
}
if(Abort()) return false;
if (have_progress)
{
Progress::NextStage ();
Progress::Title (_("Finished"));
}
sleep(sl);
if(Abort()) return false;
modified = false;
return true;
}
/**
* Function returns list of NTP servers used in the configuration.
*
* @return list <string> of servers
*/
global list <string> GetUsedNtpServers () {
list <string> used_servers = [];
foreach (map <string, any> record, ntp_records, {
if (record["type"]:"" == "server") used_servers = add (used_servers, record["address"]:"");
});
return used_servers;
}
/**
* List of servers defined by the pool.ntp.org to get random ntp servers
*
* @see: http://www.pool.ntp.org/
*/
global list <string> random_pool_servers = ["0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org"];
/**
* Checks whether all servers listed in the random_pool_servers list
* are used in the configuration.
*
* @return boolean true if enabled
*/
global boolean IsRandomServersServiceEnabled () {
// all servers needed by pool.ntp.org service, before checking false == not used
map <string, boolean> needed_servers = $[];
foreach (string server_name, random_pool_servers, {
needed_servers[server_name] = false;
});
foreach (string used_server, GetUsedNtpServers(), {
// if server is needed by pool.ntp.org and matches
if (needed_servers[used_server]:nil != nil) {
needed_servers[used_server] = true;
}
});
boolean ret = true;
foreach (string nserver_name, boolean ns_value, needed_servers, {
if (ns_value != true) ret = false;
});
return ret;
}
/**
* Removes all servers contained in the random_pool_servers list
* from the current configuration.
*/
global define void DeActivateRandomPoolServersFunction () {
foreach (string random_pool_server, random_pool_servers, {
ntp_records = filter (map <string, any> one_record, ntp_records, {
return (
// do not filter out not-servers
one_record["type"]:"" != "server"
// do not filter out serces that are not random_pool_servers
|| one_record["address"]:"" != random_pool_server
);
});
});
}
/**
* Add servers needed for random_pool_servers function
* into the current configuration.
*/
global define void ActivateRandomPoolServersFunction () {
// leave the current configuration if any
map <string, map <string, any> > store_current_options = $[];
foreach (map <string, any> one_record, ntp_records, {
if (one_record["type"]:"" == "server" && one_record["address"]:"" != "") {
string one_address = one_record["address"]:"";
store_current_options[one_address] = $[];
store_current_options[one_address, "options"] = one_record["options"]:"";
}
});
// remove all old ones
DeActivateRandomPoolServersFunction();
ntp_records = filter (map <string, any> one_record, ntp_records, {
return (
// filter out all servers
one_record["type"]:"" != "server"
);
});
foreach (string one_server, random_pool_servers, {
string one_options = "";
if (haskey(store_current_options, one_server)) {
one_options = store_current_options[one_server, "options"]:"";
y2milestone("Leaving current configuration for server '%1', options '%2'",
one_server, one_options);
}
ntp_records = add (ntp_records, $[
"address":one_server,
"comment":"\n# Random pool server, see http://www.pool.ntp.org/ for more information\n",
"options":one_options,
"type":"server"
]);
});
}
/**
* Write all ntp-client settings
* @return true on success
*/
global define boolean Write() ``{
//boolean update_dhcp = original_config_dhcp != config_dhcp;
/* NtpClient read dialog caption */
string caption = _("Saving NTP Client Configuration");
integer steps = 2;
integer sl = 0;
sleep(sl);
boolean have_progress = (Mode::normal());
// We do not set help text here, because it was set outside
if ( have_progress )
{
Progress::New(caption, " ", steps, [
// progress stage
_("Write NTP settings"),
// progress stage
_("Restart NTP daemon")
], [
// progress step
_("Writing the settings..."),
// progress step
_("Restarting NTP daemon..."),
// progress step
_("Finished")
],
""
);
}
// write settings
if(Abort()) return false;
if ( have_progress ) Progress::NextStage();
if (true) {
foreach (string key, map <string, any> m, restrict_map, {
map <string, any> ret = $[
"address" : key,
"comment" : m["comment"]:"",
"type" : "restrict",
"options": ((m["mask"]:"" != "") ? " mask " + m["mask"]:"" : "" ) + " " +
m["options"]:"",
];
ntp_records = add(ntp_records, ret);
});
y2milestone ("Writing settings %1", ntp_records);
list<map<string, any> > save2 = (list<map<string, any> >)flatten (maplist(
map<string, any> r, ntp_records,
{
map<string,any> s1 = $[
"comment" : r["comment"]:"",
"kind" : "value",
"name" : r["type"]:"",
"type" : 0,
"value" : r["address"]:"" + " " + r["options"]:"",
];
map<string,any> s2 = nil;
if (r["type"]:"" == "__clock")
{
s2 = $[
"comment" : r["fudge_comment"]:"",
"kind" : "value",
"name" : "fudge",
"type" : 0,
"value" : r["address"]:"" + " " + r["fudge_options"]:"",
];
s1["name"] = "server";
}
return [ s1, s2 ];
}));
save2 = filter (map<string, any> m, save2, ``(m != nil));
boolean failed = false;
map conf = (map)SCR::Read (.etc.ntp_conf.all);
if (conf == nil)
{
failed = true;
}
else
{
conf["value"] = save2;
if (! SCR::Write (.etc.ntp_conf.all, conf))
failed = true;
if (! SCR::Write (.etc.ntp_conf, nil))
failed = true;
}
FileChanges::StoreFileCheckSum ("/etc/ntp.conf");
if (failed)
Report::Error (Message::CannotWriteSettingsTo ("/etc/ntp.conf"));
}
// write policy and run netconfig command
SCR::Write(.sysconfig.network.config.NETCONFIG_NTP_POLICY, ntp_policy);
SCR::Write(.sysconfig.network.config, nil);
if (SCR::Execute(.target.bash, "/sbin/netconfig update") != 0) {
// error message
Report::Error(_("Cannot update the dynamic configuration policy."));
}
if (! (SCR::Write (.sysconfig.ntp.NTPD_RUN_CHROOTED, run_chroot
? "yes"
: "no")
&& SCR::Write (.sysconfig.ntp, nil)))
{
// error report
Report::Error (_("Cannot write sysconfig variables."));
}
sleep(sl);
// restart daemon
if(Abort()) return false;
if (have_progress) Progress::NextStage ();
// SuSEFirewall::Write checks on its own whether there are pending
// changes, so call it always. bnc#476951
if (true)
{
boolean progress_orig = Progress::set (false);
SuSEFirewall::Write ();
Progress::set (progress_orig);
}
if (! Service::Adjust (service_name,
run_service ? "enable" : "disable"))
{
// error report
Report::Error (Message::CannotAdjustService ("NTP"));
}
if (run_service && (! write_only)
&& 0 != Service::RunInitScript(service_name, "restart"))
{
// error report
Report::Error (_("Cannot restart the NTP daemon."));
}
if (! run_service)
{
Service::RunInitScript(service_name, "stop");
}
if (synchronize_time)
{
SCR::Write (.target.string,cron_file,"-*/"+sync_interval+" * * * * root /etc/init.d/ntp ntptimeset &>/dev/null");
}
else
{
SCR::Execute (.target.bash,"test -e "+cron_file+" && rm "+cron_file+";");
}
sleep(sl);
if(Abort()) return false;
if ( have_progress )
{
Progress::NextStage ();
Progress::Title (_("Finished"));
}
sleep(sl);
if(Abort()) return false;
return true;
}
/**
* Get all ntp-client settings from the first parameter
* (For use by autoinstallation.)
* @param settings The YCP structure to be imported.
* @return boolean True on success
*/
global define boolean Import (map settings) ``{
synchronize_time = settings["synchronize_time"]:false;
sync_interval = settings["sync_interval"]:5;
run_service = settings["start_at_boot"]:false;
run_chroot = settings["start_in_chroot"]:true;
// compatibility: configure_dhcp:true translates to ntp_policy:auto
boolean config_dhcp = settings["configure_dhcp"]:false;
ntp_policy = settings["ntp_policy"]:(config_dhcp? "auto": "");
ntp_records = settings["peers"]:[];
ntp_records = maplist(map<string, any> p, ntp_records, ``{
if (haskey(p, "key") && haskey(p, "value") )
{
p["type"] = p["key"]:"";
p["address"] = p["value"]:"";
if (haskey (p, "param"))
p["options"] = p["param"]:"";
return (p);
} else {
return (p);
}
});
modified = true;
return true;
}
/**
* Dump the ntp-client settings to a single map
* (For use by autoinstallation.)
* @return map Dumped settings (later acceptable by Import ())
*/
global define map Export () ``{
return $[
"synchronize_time" : synchronize_time,
"sync_interval" : sync_interval,
"start_at_boot" : run_service,
"start_in_chroot" : run_chroot,
"ntp_policy" : ntp_policy,
"peers" : ntp_records,
];
}
/**
* Create a textual summary and a list of unconfigured cards
* @return string summary of the current configuration
*/
global define string Summary() ``{
string summary = "";
if (run_service)
// summary string
summary = Summary::AddLine(summary, _("The NTP daemon starts when starting the system.") );
else
// summary string
summary = Summary::AddLine(summary, _("The NTP daemon does not start automatically.") );
map types = $[
// summary string, %1 is list of addresses
"server" : _("Servers: %1"),
// summary string, %1 is list of addresses
"__clock" : _("Radio Clocks: %1"),
// summary string, %1 is list of addresses
"peer" : _("Peers: %1"),
// summary string, %1 is list of addresses
"broadcast" : _("Broadcast time information to: %1"),
// summary string, %1 is list of addresses
"broadcastclient" : _("Accept broadcasted time information from: %1"),
];
/*
if (config_dhcp)
{
summary = Summary::AddLine (summary,
// summary string
_("Configure NTP daemon via DHCP."));
return summary;
}
*/
// netconfig policy
if (PolicyIsAuto ()) {
// summary string, FIXME
summary = Summary::AddLine(summary, _("Combine static and DHCP configuration."));
} else if (PolicyIsNomodify ()) {
// summary string, FIXME
summary = Summary::AddLine(summary, _("Static configuration only."));
}
else {
// summary string, FIXME
summary = Summary::AddLine(summary, _("Custom configuration policy.")); // FIXME too generic!
}
foreach (string t, ["server", "__clock", "peer", "broadcast", "broadcastclient" ],
``{
list<map<string,any> > l
= filter (map<string,any> p, ntp_records, ``(p["type"]:"" == t));
list<string> names
= maplist (map<string,any> i, l, ``(i["address"]:""));
names = filter (string n, names, ``(n != ""));
if (size (names) > 0)
{
summary = Summary::AddLine (summary, sformat (
types[t]:"", mergestring ((list<string>)names, ", ")
));
}
});
return summary;
}
/**
* Test if specified NTP server answers
* @param server string host name or IP address of the NTP server
* @param verbosity `no_ui: ..., `transient_popup: pop up while scanning,
* `result_popup: also final pop up about the result
* @return boolean true if NTP server answers properly
*/
global boolean TestNtpServer (string server, symbol verbosity) {
if (verbosity != `no_ui)
UI::OpenDialog(
// An informative popup label diring the NTP server testings
`Left(`Label(_("Testing the NTP server...")))
);
y2milestone ("Testing reachability of server %1", server);
// testing the server using IPv4 and then using IPv6 protocol
// bug #74076, Firewall could have been blocked IPv6
// -c 1 -d 15: delay 15s, only one try (bnc#442287)
integer ret_IPv4 = (integer) SCR::Execute (.target.bash, sformat (
"/usr/sbin/sntp -4 -c 1 -d 15 %1",
server
));
integer ret_IPv6 = 0;
if (ret_IPv4 != 0)
ret_IPv6 = (integer) SCR::Execute (.target.bash, sformat (
"/usr/sbin/sntp -6 -c 1 -d 15 %1",
server
));
if (verbosity != `no_ui) {
UI::CloseDialog();
}
boolean ok = (ret_IPv4 == 0 || ret_IPv6 == 0);
if (verbosity == `result_popup)
{
if (ok)
{
// message report - result of test of connection to NTP server
Popup::Notify (_("Server is reachable and responds properly."));
}
else
{
// error message - result of test of connection to NTP server
// report error instead of simple message (#306018)
Report::Error (_("Server is unreachable or does not respond properly."));
}
}
return ok;
}
/**
* Detect NTP servers present in the local network
* @param method symbol method of the detection (only `slp suported ATM)
* @return a list of found NTP servers
*/
global list<string> DetectNtpServers (symbol method) {
if (method == `slp)
{
string required_package = "yast2-slp";
// if package is not installed (in the inst-sys, it is: bnc#399659)
if ( !Stage::initial() && !PackageSystem::Installed(required_package) )
{
if ( !PackageSystem::CheckAndInstallPackages( [required_package] ) )
{
Report::Error( sformat(_("Cannot search for NTP server in local network
without having package %1 installed."), required_package) );
y2warning("Not searching for local NTP servers via SLP");
return [];
}
else
{
SCR::RegisterAgent(.slp, `ag_slp(`SlpAgent()));
}
}
list<map> servers = SLPAPI::FindSrvs ("service:ntp", "");
list<string> server_names = maplist (map m, servers, ``(
(string)(m["pcHost"]:"")
));
server_names = filter (string s, server_names, ``(s != ""));
return server_names;
}
y2error ("Unknown detection method: %1", method);
return [];
}
/**
* Get the list of synchronization-related records
* @return a list of maps with keys type (eg. "server"), address and index.
*/
global define list<map<string,any> >getSyncRecords () ``{
integer index = -1;
list<map<string,any> > ret = maplist (map m, ntp_records, ``{
index = index + 1;
string type = m["type"]:"";
if (! contains (["server", "peer", "broadcast",
"broadcastclient", "__clock"], type))
{
return nil;
}
return $[
"type" : type,
"index" : index,
"address" : m["address"]:"",
"device" : m["device"]:"",
];
});
ret = filter (map<string,any> m, ret, ``(m != nil));
return ret;
}
/**
* Select synchronization record
* @param index integer, -1 for creating a new record
* @return boolean true on success
*/
global define boolean selectSyncRecord (integer index) ``{
boolean ret = true;
if (index >= size (ntp_records) || index < -1)
{
y2error ("Record with index %1 doesn't exist, creating new", index);
index = -1;
ret = false;
}
if (index == -1)
selected_record = $[];
else
selected_record = ntp_records[index]:$[];
selected_index = index;
return ret;
}
/**
* Find index of synchronization record
* @param type string record type
* @param address string address
* @return integer index of the record if found, -1 otherwise
*/
global define integer findSyncRecord (string type, string address) ``{
integer index = -1;
integer ret = -1;
foreach (map<string,any> m, ntp_records, ``{
index = index + 1;
if (type == m["type"]:"" && address == m["address"]:"")
ret = index;
});
return ret;
}
/**
* Store currently sellected synchronization record
* @return boolean true on success
*/
global define boolean storeSyncRecord () ``{
if (selected_index == -1)
ntp_records = add (ntp_records, selected_record);
else
ntp_records[selected_index] = selected_record;
modified = true;
return true;
}
/**
* Delete specified synchronization record
* @param index integer index of record to delete
* @return boolean true on success
*/
global define boolean deleteSyncRecord (integer index) ``{
if (index >= size (ntp_records) || index <= -1)
{
y2error ("Record with index %1 doesn't exist", index);
return false;
}
ntp_records[index] = nil;
ntp_records = filter (map<string,any> r, ntp_records, ``(r != nil));
modified = true;
return true;
}
/**
* Ensure that selected_record["options"] contains the option.
* (A set operation in a string)
*/
global void enableOptionInSyncRecord (string option) {
// careful, "burst" != "iburst"
string old = selected_record["options"]:"";
list<string> old_l = splitstring (old, " \t");
if (!contains (old_l, option)) {
old_l = add (old_l, option);
}
selected_record["options"] = mergestring (old_l, " ");
}
/**
* Return required packages for auto-installation
* @return map of packages to be installed and to be removed
*/
global define map AutoPackages() ``{
return ($["install": required_packages, "remove": []]);
}
/* EOF */
}
ACC SHELL 2018