kudu-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ale...@apache.org
Subject [kudu] branch master updated: [mini_chronyd] add reference NTP servers in config
Date Wed, 11 Sep 2019 18:27:02 GMT
This is an automated email from the ASF dual-hosted git repository.

alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/master by this push:
     new 50f9347  [mini_chronyd] add reference NTP servers in config
50f9347 is described below

commit 50f9347ceef2e09c56acb5b73b382a49285d6451
Author: Alexey Serbin <alexey@apache.org>
AuthorDate: Tue Sep 10 18:40:27 2019 -0700

    [mini_chronyd] add reference NTP servers in config
    
    This patch adds the ability to specify reference NTP servers in chronyd
    configuration via the mini_chronyd wrapper.  New tests to cover
    the newly introduced functionality are added as well.
    
    Change-Id: I6d517bab98afd20ae63f2ff18635c1f579c39adb
    Reviewed-on: http://gerrit.cloudera.org:8080/14211
    Reviewed-by: Adar Dembo <adar@cloudera.com>
    Tested-by: Kudu Jenkins
---
 src/kudu/clock/test/mini_chronyd-test.cc | 88 ++++++++++++++++++++++++++++++++
 src/kudu/clock/test/mini_chronyd.cc      | 73 ++++++++++++++++++++++----
 src/kudu/clock/test/mini_chronyd.h       | 80 +++++++++++++++++++++++++++++
 3 files changed, 230 insertions(+), 11 deletions(-)

diff --git a/src/kudu/clock/test/mini_chronyd-test.cc b/src/kudu/clock/test/mini_chronyd-test.cc
index 6cb01d2..8f6accf 100644
--- a/src/kudu/clock/test/mini_chronyd-test.cc
+++ b/src/kudu/clock/test/mini_chronyd-test.cc
@@ -43,6 +43,38 @@ namespace clock {
 class MiniChronydTest: public KuduTest {
 };
 
+// Run chronyd without any reference: neither local reference mode, nor
+// reference NTP server present. Such server cannot be a good NTP source
+// because its clock is unsynchronized.
+TEST_F(MiniChronydTest, UnsynchronizedServer) {
+  MiniChronydOptions options;
+  options.bindaddress = GetBindIpForDaemon(1, kDefaultBindMode);
+  options.port = 10123 + getpid() % 1000;
+  options.local = false;
+  MiniChronyd chrony(options);
+  ASSERT_OK(chrony.Start());
+
+  // No client has talked to the NTP server yet.
+  {
+    MiniChronyd::ServerStats stats;
+    ASSERT_OK(chrony.GetServerStats(&stats));
+    ASSERT_EQ(0, stats.ntp_packets_received);
+  }
+
+  auto s = MiniChronyd::CheckNtpSource(
+      { HostPort(chrony.options().bindaddress, chrony.options().port) });
+  ASSERT_TRUE(s.IsRuntimeError()) << s.ToString();
+  ASSERT_STR_CONTAINS(s.ToString(),
+                      "failed measure clock offset from reference NTP servers");
+
+  // Make sure the client has communicated with the server.
+  {
+    MiniChronyd::ServerStats stats;
+    ASSERT_OK(chrony.GetServerStats(&stats));
+    ASSERT_LT(0, stats.ntp_packets_received);
+  }
+}
+
 // This scenario verifies basic functionality of the mini-chronyd wrapper:
 // start, stop, manually setting the reference time, etc.
 TEST_F(MiniChronydTest, BasicSingleServerInstance) {
@@ -157,5 +189,61 @@ TEST_F(MiniChronydTest, BasicMultipleServerInstances) {
 #endif
 }
 
+// This scenario runs multi-tier set of chronyd servers: few servers of
+// stratum X and few more servers of stratum X+1, so the latter use the former
+// as the source for synchronisation. Both set of servers should be a good clock
+// source to serve NTP clients.
+TEST_F(MiniChronydTest, MultiTierBasic) {
+  const uint16_t base_port = 10123 + getpid() % 1000;
+
+  vector<unique_ptr<MiniChronyd>> servers_0;
+  vector<HostPort> ntp_endpoints_0;
+  for (auto idx = 0; idx < 3; ++idx) {
+    MiniChronydOptions options;
+    options.index = idx;
+    options.bindaddress = GetBindIpForDaemon(idx + 1, kDefaultBindMode);
+    options.port = base_port + idx * 10;
+    unique_ptr<MiniChronyd> chrony(new MiniChronyd(options));
+    ASSERT_OK(chrony->Start());
+    ntp_endpoints_0.emplace_back(chrony->options().bindaddress,
+                                 chrony->options().port);
+    servers_0.emplace_back(std::move(chrony));
+  }
+
+  vector<unique_ptr<MiniChronyd>> servers_1;
+  vector<HostPort> ntp_endpoints_1;
+  for (auto idx = 3; idx < 5; ++idx) {
+    MiniChronydOptions options;
+    options.index = idx;
+    options.bindaddress = GetBindIpForDaemon(idx + 1, kDefaultBindMode);
+    options.port = base_port + idx * 10;
+    options.local = false;
+    for (const auto& ref : servers_0) {
+      MiniChronydServerOptions server_options;
+      server_options.port = ref->options().port;
+      server_options.address = ref->options().bindaddress;
+      options.servers.emplace_back(std::move(server_options));
+    }
+    unique_ptr<MiniChronyd> chrony(new MiniChronyd(options));
+    ASSERT_OK(chrony->Start());
+    ntp_endpoints_1.emplace_back(chrony->options().bindaddress,
+                                 chrony->options().port);
+    servers_1.emplace_back(std::move(chrony));
+  }
+
+  {
+    // All chronyd servers that use the system clock as a reference lock should
+    // present themselves as a set of NTP servers suitable for synchronisation.
+    auto s = MiniChronyd::CheckNtpSource(ntp_endpoints_0);
+    ASSERT_TRUE(s.ok()) << s.ToString();
+  }
+  {
+    // All chronyd servers that use the above mentioned chronyd servers
+    // as reference should be a set of good NTP sources as well.
+    auto s = MiniChronyd::CheckNtpSource(ntp_endpoints_1);
+    ASSERT_TRUE(s.ok()) << s.ToString();
+  }
+}
+
 } // namespace clock
 } // namespace kudu
diff --git a/src/kudu/clock/test/mini_chronyd.cc b/src/kudu/clock/test/mini_chronyd.cc
index 8f92c5f..183f2b2 100644
--- a/src/kudu/clock/test/mini_chronyd.cc
+++ b/src/kudu/clock/test/mini_chronyd.cc
@@ -57,13 +57,36 @@ using strings::Substitute;
 namespace kudu {
 namespace clock {
 
-string MiniChronydOptions::ToString() const {
+string MiniChronydServerOptions::ToString() const {
   return Substitute(
-      "{bindaddress: $0,"
+      "{address: $0,"
       " port: $1,"
-      " data_root: $2,"
-      " bindcmdaddress: $3}",
-      bindaddress, port, data_root, bindcmdaddress);
+      " minpoll: $2,"
+      " maxpoll: $3,"
+      " iburst: $4,"
+      " burst: $5,"
+      " offset: $6}",
+      address, port, minpoll, maxpoll, iburst, burst, offset);
+}
+
+string MiniChronydOptions::ToString() const {
+  string servers_str = "[";
+  for (const auto& s : servers) {
+    servers_str += " " + s.ToString() + ",";
+  }
+  servers_str += "]";
+  return Substitute(
+      "{index: $0,"
+      " data_root: $1,"
+      " bindcmdaddress: $2,"
+      " bindaddress: $3,"
+      " port: $4,"
+      " pidfile: $5,"
+      " local: $6,"
+      " local_stratum: $7,"
+      " servers: $8}",
+      index, data_root, bindcmdaddress, bindaddress, port, pidfile,
+      local, local_stratum, servers_str);
 }
 
 // Check that the specified servers are seen as good enough synchronisation
@@ -303,7 +326,7 @@ string MiniChronyd::config_file_path() const {
 // instances on the same node, so all the 'defaults' should be customized
 // to avoid conflicts.
 Status MiniChronyd::CreateConf() {
-  static const string kFileTemplate = R"(
+  static const string kFileTemplateCommon = R"(
 # Override the default user chronyd NTP server starts because the compiled-in
 # default 'root' is not suitable when running chronyd in the context of the Kudu
 # testing framework. It's also be possible to override this parameter in the
@@ -334,10 +357,6 @@ pidfile $4
 # is already enabled.
 cmdport 0
 
-# Using the local clock as the clock source (usually it's a high precision
-# oscillator or a NTP server).
-local
-
 # NTP clients from all addresses are allowed to access the NTP server that is
 # serving requests as specified by the 'bindaddress' and 'port' directives.
 allow all
@@ -345,6 +364,18 @@ allow all
 # Allow setting the time manually using the cronyc CLI utility.
 manual
 )";
+
+  static const string kFileTemplateLocal = R"(
+# Use the local clock as the clock source (usually it's a high precision
+# oscillator or a NTP server), and report the stratum as configured.
+local stratum $0
+)";
+
+  static const string kFileTemplateServers = R"(
+# The set of NTP servers to synchronize with.
+$0
+)";
+
   if (options_.bindcmdaddress.empty()) {
     // The path to Unix domain socket file cannot be longer than ~100 bytes,
     // so it's necessary to create a directory with shorter absolute path.
@@ -362,12 +393,32 @@ manual
   }
   string username;
   RETURN_NOT_OK(GetLoggedInUser(&username));
-  auto contents = Substitute(kFileTemplate,
+  auto contents = Substitute(kFileTemplateCommon,
                              username,
                              options_.bindaddress,
                              options_.bindcmdaddress,
                              options_.port,
                              options_.pidfile);
+  if (options_.local) {
+    contents += Substitute(kFileTemplateLocal, options_.local_stratum);
+  }
+  if (!options_.servers.empty()) {
+    string servers_str;
+    for (const auto& server : options_.servers) {
+      auto str = Substitute(
+          "server $0 port $1 minpoll $2 maxpoll $3 offset $4",
+          server.address, server.port, server.minpoll, server.maxpoll, server.offset);
+      if (server.iburst) {
+        str += " iburst";
+      }
+      if (server.burst) {
+        str += " burst";
+      }
+      str += "\n";
+      servers_str += str;
+    }
+    contents += Substitute(kFileTemplateServers, servers_str);
+  }
   return WriteStringToFile(Env::Default(), contents, config_file_path());
 }
 
diff --git a/src/kudu/clock/test/mini_chronyd.h b/src/kudu/clock/test/mini_chronyd.h
index fa1862b..5cc5e4f 100644
--- a/src/kudu/clock/test/mini_chronyd.h
+++ b/src/kudu/clock/test/mini_chronyd.h
@@ -34,6 +34,65 @@ class Subprocess;
 
 namespace clock {
 
+// This structure represents a set of properties for the 'server' configuration
+// directive in the chrony.conf file. All the fields of the structure except
+// for the 'address' directly map into corresponding options of the 'server'
+// configuration directive (see 'man chrony.conf' for details).
+//
+// NOTE: the default values for the most configuration options are different
+//       from the defaults used in chronyd's config file (chrony.conf)
+struct MiniChronydServerOptions {
+  // Hostname or IP address of the server.
+  //
+  // Default: ""
+  std::string address;
+
+  // Port number where server listens for NTP requests.
+  //
+  // Default: 123
+  uint16_t port = 123;
+
+  // The minimum interval between requests sent to the server as a power of 2
+  // in seconds.
+  //
+  // Default: -3
+  int8_t minpoll = -3;
+
+  // The maximum interval between requests sent to the server as a power of 2
+  // in seconds.
+  //
+  // Default: 2
+  int8_t maxpoll = 2;
+
+  // With this option enabled, the interval between the first four requests sent
+  // to the server is much less than interval specified by the 'minpoll' option,
+  // which allows chronyd to make the first update of the clock shortly after
+  // it has started.
+  //
+  // Default: true
+  bool iburst = true;
+
+  // With this option enabled, chronyd will shorten the interval between up to
+  // four requests to 2 seconds or less when it cannot get a good measurement
+  // from the server.
+  //
+  // Default: true
+  bool burst = true;
+
+  // This option specifies a correction (in seconds) which will be applied to
+  // offsets measured with this source. In test scenarios, this is useful for
+  // fine-tuning the true time offsets as seen by a client in NTP responses
+  // sent from the server. For example, if running multiple chronyd NTP servers
+  // that use the local clock as a reference clock, it's possible to get precise
+  // distribution of the true time offsets observed by a client.
+  //
+  // Default: 0.0
+  double offset = 0.0;
+
+  // Returns a string representation of the options suitable for debug printing.
+  std::string ToString() const;
+};
+
 // Options to run MiniChronyd with.
 struct MiniChronydOptions {
   // There might be multiple mini_chronyd run by the same test.
@@ -74,6 +133,27 @@ struct MiniChronydOptions {
   // The default may only be used from a gtest unit test.
   std::string pidfile;
 
+  // Whether to run in the 'local reference mode', using the local clock of the
+  // machine as a reference clock. With 'local' set to 'true', chronyd is able
+  // to operate as NTP server synchronised to real time (from the viewpoint of
+  // clients polling it), even if it was never synchronised or the last update
+  // of the clock happened a long time ago.
+  //
+  // Default: true
+  bool local = true;
+
+  // Stratum of the server to report when running in local reference mode.
+  // This directly maps to chronyd's 'stratum' option of the 'local'
+  // configuration directive.
+  //
+  // Default: 10, which is default when running in local reference mode
+  uint8_t local_stratum = 10;
+
+  // NTP servers to use as reference servers for chronyd instance.
+  //
+  // Default: {} (an empty container)
+  std::vector<MiniChronydServerOptions> servers;
+
   // Returns a string representation of the options suitable for debug printing.
   std::string ToString() const;
 };


Mime
View raw message