Blob Blame Raw
From f6d87cb468845c498e42e7285099d5b295ee936b Mon Sep 17 00:00:00 2001
From: Pat Riehecky <riehecky@fnal.gov>
Date: Wed, 12 Feb 2014 11:43:16 -0600
Subject: [PATCH] Added chrony lense

(cherry picked from commit 319e30fcbea54aadc97430809cea6fb7b398b4b6)
---
 doc/naturaldocs/conf/lenses/Menu.txt |   2 +
 lenses/chrony.aug                    | 266 +++++++++++++++++++++++++++++++++++
 lenses/tests/test_chrony.aug         | 143 +++++++++++++++++++
 tests/Makefile.am                    |   1 +
 4 files changed, 412 insertions(+)
 create mode 100644 lenses/chrony.aug
 create mode 100644 lenses/tests/test_chrony.aug

diff --git a/doc/naturaldocs/conf/lenses/Menu.txt b/doc/naturaldocs/conf/lenses/Menu.txt
index a6fa0f0..34e0bf6 100644
--- a/doc/naturaldocs/conf/lenses/Menu.txt
+++ b/doc/naturaldocs/conf/lenses/Menu.txt
@@ -74,6 +74,7 @@ Group: Specific Modules  {
    File: Cgconfig  (no auto-title, cgconfig.aug)
    File: Cgrules  (no auto-title, cgrules.aug)
    File: Channels  (channels.aug)
+   File: Chrony  (chrony.aug)
    File: Collectd  (collectd.aug)
    File: Cron  (cron.aug)
    File: Crypttab  (crypttab.aug)
@@ -191,6 +192,7 @@ Group: Tests and Examples  {
    File: Test_Build  (tests/test_build.aug)
    File: Test_Carbon  (tests/test_carbon.aug)
    File: Test_Channels  (tests/test_channels.aug)
+   File: Test_Chrony  (tests/test_chrony.aug)
    File: Test_Collectd  (tests/test_collectd.aug)
    File: Test_Cups  (tests/test_cups.aug)
    File: Test_Dovecot  (tests/test_dovecot.aug)
diff --git a/lenses/chrony.aug b/lenses/chrony.aug
new file mode 100644
index 0000000..ede2c94
--- /dev/null
+++ b/lenses/chrony.aug
@@ -0,0 +1,266 @@
+(*
+Module: Chrony
+  Parses the chrony config file
+
+Author: Pat Riehecky <riehecky@fnal.gov>
+
+About: Reference
+  This lens tries to keep as close as possible to chrony config syntax
+
+  See http://chrony.tuxfamily.org/manual.html#Configuration-file
+
+About: Limitations
+  Does not (currently) support
+    - include
+    - manual
+    - refclock
+    - tempcomp
+
+About: License
+  This file is licenced under the LGPL v2+, like the rest of Augeas.
+
+About: Lens Usage
+  To be documented
+
+About: Configuration files
+  This lens applies to /etc/chrony.conf
+
+  See <filter>.
+*)
+
+module Chrony =
+  autoload xfm
+
+(************************************************************************
+ * Group: Import provided expressions
+ ************************************************************************)
+    (* View: empty *)
+    let empty   = Util.empty
+
+    (* View: eol *)
+    let eol     = Util.eol
+
+    (* View: space *)
+    let space   = Sep.space
+
+    (* Variable: email_addr *)
+    let email_addr = Rx.email_addr
+
+    (* Variable: word *)
+    let word       = Rx.word
+
+    (* Variable: integer *)
+    let integer    = Rx.integer
+
+    (* Variable: decimal *)
+    let decimal    = Rx.decimal
+
+    (* Variable: ip *)
+    let ip         = Rx.ip
+
+(************************************************************************
+ * Group: Create required expressions
+ ************************************************************************)
+    (* Variable: number *)
+    let number = integer | decimal
+
+    (* Variable: address_re *)
+    let address_re = Rx.ip | Rx.hostname
+
+    (*
+       View: comment
+            from 4.2.1 of the upstream doc
+            Chrony comments start with: ! ; # or % and must be on their own line
+    *)
+    let comment = Util.comment_generic /[ \t]*[!;#%][ \t]*/ "# "
+
+    (* Variable: no_space
+         No spaces or comment characters
+    *)
+    let no_space   = /[^ \t\r\n!;#%]+/
+
+    (* Variable: cmd_options
+         Server/Peer options with values
+    *)
+    let cmd_options = "key"
+                    | /maxdelay((dev)?ratio)?/
+                    | /(min|max)poll/
+                    | "polltarget"
+                    | "port"
+                    | "presend"
+
+    (* Variable: cmd_flags
+         Server/Peer options without values
+    *)
+    let cmd_flags = "auto_offline"|"iburst"|"noselect"|"offline"|"prefer"
+
+    (* Variable: server_peer
+         Server/Peer key names
+    *)
+    let server_peer = "server"|"peer"
+
+    (* Variable: flags
+         Options without values
+    *)
+    let flags = "dumponexit"
+              | "generatecommandkey"
+              | "lock_all"
+              | "noclientlog"
+              | "rtconutc"
+              | "rtcsync"
+
+    (* Variable: log_flags
+        log has a specific options list
+    *)
+    let log_flags = /measurments|statistics|tracking|rtc|refclocks|tempcomp/
+
+    (* Variable: simple_keys
+         Options with single values
+    *)
+    let simple_keys = "acquisitionport" | "allow" | "bindaddress"
+                    | "bindcmdaddress" | "cmdallow" | "cmddeny"
+                    | "combinelimit" | "commandkey" | "cmdport"
+                    | "corrtimeratio" | "deny" | "driftfile"
+                    | "dumpdir" | "keyfile" | "leapsectz" | "linux_hz"
+                    | "linux_freq_scale" | "logbanner" | "logchange"
+                    | "logdir" | "maxclockerror" | "maxsamples"
+                    | "maxupdateskew" | "minsamples" | "clientloglimit"
+                    | "pidfile" | "port" | "reselectdist" | "rtcdevice"
+                    | "rtcfile" | "sched_priority" | "stratumweight" | "user"
+
+(************************************************************************
+ * Group: Make some sub-lenses for use in later lenses
+ ************************************************************************)
+    (* View: host_flags *)
+    let host_flags = [ space . key cmd_flags ]
+    (* View: host_options *)
+    let host_options = [ space . key cmd_options . space . store integer ]
+    (* View: log_flag_list *)
+    let log_flag_list = [ space . key log_flags ]
+    (* View: store_address *)
+    let store_address = [ label "address" . store address_re ]
+
+(************************************************************************
+ * Group: Lenses for parsing out sections
+ ************************************************************************)
+    (* View: all_flags
+        match all flags using Build.flag_line
+    *)
+    let all_flags = Build.flag_line flags
+
+    (* View: kv
+        options with only one arg can be directly mapped to key = value
+    *)
+    let kv = Build.key_value_line_comment simple_keys space (store no_space) comment
+
+    (* Property: Options with multiple values
+    
+      Each of these gets their own parsing block
+      - server|peer <address> <options>
+      - log <options>
+      - broadcast <interval> <address> <optional port>
+      - fallbackdrift <min> <max>
+      - initstepslew <threshold> <addr> <optional extra addrs>
+      - local stratum <int>
+      - mailonchange <emailaddress> <threshold>
+      - makestep <threshold> <limit>
+      - maxchange <threshold> <delay> <limit>
+    *)
+
+    (* View: host_list
+        Find all ntp servers/peers and their flags/options
+    *)
+    let host_list = [ Util.indent . key server_peer
+                         . space . store address_re
+                         . ( host_flags | host_options )*
+                         . eol ]
+
+    (* View: log_list
+        log has a specific options list
+    *)
+    let log_list = [ Util.indent . key "log" . log_flag_list+ . eol ]
+
+    (* View: bcast
+         broadcast has specific syntax
+    *)
+    let bcast = [ Util.indent . key "broadcast"
+                      . space . [ label "interval" . store integer ]
+                      . space . store_address
+                      . ( space . [ label "port" . store integer] | eol) ]
+
+    (* View: fdrift
+         fallbackdrift has specific syntax
+    *)
+    let fdrift = [ Util.indent . key "fallbackdrift"
+                      . space . [ label "min" . store integer ]
+                      . space . [ label "max" . store integer ]
+                      . eol ]
+
+    (* View: istepslew
+         initstepslew has specific syntax
+    *)
+    let istepslew = [ Util.indent . key "initstepslew" 
+                         . space . [ label "threshold" . store number ]
+                         . ( space . store_address )+
+                         . eol ]
+
+    (* View: local
+         local has specific syntax
+    *)
+    let local = [ Util.indent . key "local" . space
+                     . [ key "stratum" . space . store integer ]
+                     . eol ]
+
+    (* View: email
+         mailonchange has specific syntax
+    *)
+    let email = [ Util.indent . key "mailonchange" . space
+                     . [ label "emailaddress" . store email_addr ]
+                     . space
+                     . [ label "threshold" . store number ]
+                     . eol ]
+
+    (* View: makestep
+         makestep has specific syntax
+    *)
+    let makestep = [ Util.indent . key "makestep"
+                      . space
+                      . [ label "threshold" . store number ]
+                      . space
+                      . [ label "limit" . store integer ]
+                      . eol ]
+
+    (* View: maxchange
+         maxchange has specific syntax
+    *)
+    let maxchange = [ Util.indent . key "maxchange"
+                      . space
+                      . [ label "threshold" . store number ]
+                      . space
+                      . [ label "delay" . store integer ]
+                      . space
+                      . [ label "limit" . store integer ]
+                      . eol ]
+
+(************************************************************************
+ * Group: Final lense summary
+ ************************************************************************)
+(* View: settings
+ *   All supported chrony settings
+ *)
+let settings = host_list | log_list | bcast | fdrift | istepslew
+             | local | email | makestep | maxchange | kv | all_flags
+
+(*
+ * View: lns
+ *   The crony lens
+ *)
+let lns = ( empty | comment | settings )*
+
+(* View: filter
+ *   The files parsed by default
+ *)
+let filter = incl "/etc/chrony.conf"
+
+let xfm = transform lns filter
+
diff --git a/lenses/tests/test_chrony.aug b/lenses/tests/test_chrony.aug
new file mode 100644
index 0000000..4917358
--- /dev/null
+++ b/lenses/tests/test_chrony.aug
@@ -0,0 +1,143 @@
+(*
+Module: Test_Chrony
+  Provides unit tests and examples for the <Chrony> lens.
+*)
+
+module Test_Chrony =
+
+  let exampleconf = "# Comment
+#Comment
+! Comment
+!Comment
+; Comment
+;Comment
+% Comment
+%Comment
+
+server ntp1.example.com
+server ntp2.example.com iburst
+server ntp3.example.com presend 2
+server ntp4.example.com offline polltarget 4
+server ntp5.example.com maxdelay 2 offline
+server ntp6.example.com maxdelay 2 iburst presend 2
+server ntp7.example.com iburst presend 2 offline
+peer ntpc1.example.com
+stratumweight 0
+driftfile /var/lib/chrony/drift
+rtcsync
+makestep 10 3
+bindcmdaddress 127.0.0.1
+bindcmdaddress ::1
+local stratum 10
+keyfile /etc/chrony.keys
+commandkey 1
+generatecommandkey
+noclientlog
+logchange 0.5
+logdir /var/log/chrony
+log rtc
+leapsectz right/UTC
+broadcast 10 192.168.1.255
+broadcast 10 192.168.100.255 123
+fallbackdrift 16 19
+mailonchange root@localhost 0.5
+maxchange 1000 1 2
+initstepslew 30 foo.bar.com
+initstepslew 30 foo.bar.com baz.quz.com
+"
+
+  test Chrony.lns get exampleconf =
+    { "#comment" = "Comment" }
+  { "#comment" = "Comment" }
+  { "#comment" = "Comment" }
+  { "#comment" = "Comment" }
+  { "#comment" = "Comment" }
+  { "#comment" = "Comment" }
+  { "#comment" = "Comment" }
+  { "#comment" = "Comment" }
+  {  }
+  { "server" = "ntp1.example.com" }
+  { "server" = "ntp2.example.com"
+    { "iburst" }
+  }
+  { "server" = "ntp3.example.com"
+    { "presend" = "2" }
+  }
+  { "server" = "ntp4.example.com"
+    { "offline" }
+    { "polltarget" = "4" }
+  }
+  { "server" = "ntp5.example.com"
+    { "maxdelay" = "2" }
+    { "offline" }
+  }
+  { "server" = "ntp6.example.com"
+    { "maxdelay" = "2" }
+    { "iburst" }
+    { "presend" = "2" }
+  }
+  { "server" = "ntp7.example.com"
+    { "iburst" }
+    { "presend" = "2" }
+    { "offline" }
+  }
+  { "peer" = "ntpc1.example.com" }
+  { "stratumweight" = "0" }
+  { "driftfile" = "/var/lib/chrony/drift" }
+  { "rtcsync" }
+  { "makestep"
+    { "threshold" = "10" }
+    { "limit" = "3" }
+  }
+  { "bindcmdaddress" = "127.0.0.1" }
+  { "bindcmdaddress" = "::1" }
+  { "local"
+    { "stratum" = "10" }
+  }
+  { "keyfile" = "/etc/chrony.keys" }
+  { "commandkey" = "1" }
+  { "generatecommandkey" }
+  { "noclientlog" }
+  { "logchange" = "0.5" }
+  { "logdir" = "/var/log/chrony" }
+  { "log"
+    { "rtc" }
+  }
+  { "leapsectz" = "right/UTC" }
+  { "broadcast"
+    { "interval" = "10" }
+    { "address" = "192.168.1.255" }
+  }
+  { "broadcast"
+    { "interval" = "10" }
+    { "address" = "192.168.100.255" }
+    { "port" = "123" }
+  }
+  {  }
+  { "fallbackdrift"
+    { "min" = "16" }
+    { "max" = "19" }
+  }
+  { "mailonchange"
+    { "emailaddress" = "root@localhost" }
+    { "threshold" = "0.5" }
+  }
+  { "maxchange"
+    { "threshold" = "1000" }
+    { "delay" = "1" }
+    { "limit" = "2" }
+  }
+  { "initstepslew"
+    { "threshold" = "30" }
+    { "address" = "foo.bar.com" }
+  }
+  { "initstepslew"
+    { "threshold" = "30" }
+    { "address" = "foo.bar.com" }
+    { "address" = "baz.quz.com" }
+  }
+
+
+(* Local Variables: *)
+(* mode: caml       *)
+(* End:             *)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 180a19d..1b79629 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -41,6 +41,7 @@ lens_tests =			\
   lens-cgconfig.sh		\
   lens-cgrules.sh  		\
   lens-channels.sh  		\
+  lens-chrony.sh  		\
   lens-cobblersettings.sh	\
   lens-cobblermodules.sh	\
   lens-collectd.sh	\