1(*
2Module: Keepalived
3  Parses /etc/keepalived/keepalived.conf
4
5Author: Raphael Pinson <raphink@gmail.com>
6
7About: Reference
8  This lens tries to keep as close as possible to `man 5 keepalived.conf` where possible.
9
10About: License
11   This file is licenced under the LGPL v2+, like the rest of Augeas.
12
13About: Lens Usage
14   To be documented
15
16About: Configuration files
17   This lens applies to /etc/keepalived/keepalived.conf. See <filter>.
18
19About: Examples
20   The <Test_Keepalived> file contains various examples and tests.
21*)
22
23
24module Keepalived =
25  autoload xfm
26
27(************************************************************************
28 * Group:                 USEFUL PRIMITIVES
29 *************************************************************************)
30
31(* Group: Comments and empty lines *)
32
33(* View: indent *)
34let indent = Util.indent
35
36(* View: eol *)
37let eol = Util.eol
38
39(* View: opt_eol *)
40let opt_eol = del /[ \t]*\n?/ " "
41
42(* View: sep_spc *)
43let sep_spc = Sep.space
44
45(* View: comment
46Map comments in "#comment" nodes *)
47let comment = Util.comment_generic /[ \t]*[#!][ \t]*/ "# "
48
49(* View: comment_eol
50Map comments at eol *)
51let comment_eol = Util.comment_generic /[ \t]*[#!][ \t]*/ " # "
52
53(* View: comment_or_eol
54A <comment_eol> or <eol> *)
55let comment_or_eol = comment_eol | (del /[ \t]*[#!]?\n/ "\n")
56
57(* View: empty
58Map empty lines *)
59let empty   = Util.empty
60
61(* View: sto_email_addr *)
62let sto_email_addr = store Rx.email_addr
63
64(* Variable: word *)
65let word = Rx.word
66
67(* Variable: word_slash *)
68let word_slash = word | "/"
69
70(* View: sto_word *)
71let sto_word = store word
72
73(* View: sto_num *)
74let sto_num = store Rx.relinteger
75
76(* View: sto_ipv6 *)
77let sto_ipv6 = store Rx.ipv6
78
79(* View: sto_to_eol *)
80let sto_to_eol = store /[^#! \t\n][^#!\n]*[^#! \t\n]|[^#! \t\n]/
81
82(* View: field *)
83let field (kw:regexp) (sto:lens) = indent . Build.key_value_line_comment kw sep_spc sto comment_eol
84
85(* View: flag
86A single word *)
87let flag (kw:regexp) = [ indent . key kw . comment_or_eol ]
88
89(* View: ip_port
90   An IP <space> port pair *)
91let ip_port = [ label "ip" . sto_word ] . sep_spc . [ label "port" . sto_num ]
92
93(* View: lens_block
94A generic block with a title lens.
95The definition is very similar to Build.block_newlines
96but uses a different type of <comment>. *)
97let lens_block (title:lens) (sto:lens) =
98   [ indent . title
99   . Build.block_newlines sto comment . eol ]
100
101(* View: block
102A simple block with just a block title *)
103let block (kw:regexp) (sto:lens) = lens_block (key kw) sto
104
105(* View: named_block
106A block with a block title and name *)
107let named_block (kw:string) (sto:lens) = lens_block (key kw . sep_spc . sto_word) sto
108
109(* View: named_block_arg_title
110A title lens for named_block_arg *)
111let named_block_arg_title (kw:string) (name:string) (arg:string) =
112                            key kw . sep_spc
113                          . [ label name . sto_word ]
114                          . sep_spc
115                          . [ label arg . sto_word ]
116
117(* View: named_block_arg
118A block with a block title, a name and an argument *)
119let named_block_arg (kw:string) (name:string) (arg:string) (sto:lens) =
120                           lens_block (named_block_arg_title kw name arg) sto
121
122
123(************************************************************************
124 * Group:                 GLOBAL CONFIGURATION
125 *************************************************************************)
126
127(* View: email
128A simple email address entry *)
129let email = [ indent . label "email" . sto_email_addr . comment_or_eol ]
130
131(* View: global_defs_field
132Possible fields in the global_defs block *)
133let global_defs_field =
134      let word_re = "smtp_server"|"lvs_id"|"router_id"|"vrrp_mcast_group4"
135   in let ipv6_re = "vrrp_mcast_group6"
136   in let num_re = "smtp_connect_timeout"
137   in block "notification_email" email
138    | field "notification_email_from" sto_email_addr
139    | field word_re sto_word
140    | field num_re sto_num
141    | field ipv6_re sto_ipv6
142
143(* View: global_defs
144A global_defs block *)
145let global_defs = block "global_defs" global_defs_field
146
147(* View: prefixlen
148A prefix for IP addresses *)
149let prefixlen = [ label "prefixlen" . Util.del_str "/" . sto_num ]
150
151(* View: ipaddr
152An IP address or range with an optional mask *)
153let ipaddr = label "ipaddr" . store /[0-9.-]+/ . prefixlen?
154
155(* View: ipdev
156A device for IP addresses *)
157let ipdev = [ key "dev" . sep_spc . sto_word ]
158
159(* View: static_ipaddress_field
160The whole string is fed to ip addr add.
161You can truncate the string anywhere you like and let ip addr add use defaults for the rest of the string.
162To be refined with fields according to `ip addr help`.
163*)
164let static_ipaddress_field = [ indent . ipaddr
165                             . (sep_spc . ipdev)?
166                             . comment_or_eol ]
167
168(* View: static_routes_field
169src $SRC_IP to $DST_IP dev $SRC_DEVICE
170*)
171let static_routes_field = [ indent . label "route"
172                          . [ key "src" . sto_word ] . sep_spc
173                          . [ key "to"  . sto_word ] . sep_spc
174                          . [ key "dev" . sto_word ] . comment_or_eol ]
175
176(* View: static_routes *)
177let static_routes = block "static_ipaddress" static_ipaddress_field
178                  | block "static_routes" static_routes_field
179
180
181(* View: global_conf
182A global configuration entry *)
183let global_conf = global_defs | static_routes
184
185
186(************************************************************************
187 * Group:                 VRRP CONFIGURATION
188 *************************************************************************)
189
190(*View: vrrp_sync_group_field *)
191let vrrp_sync_group_field =
192      let to_eol_re = /notify(_master|_backup|_fault)?/
193   in let flag_re = "smtp_alert"
194   in field to_eol_re sto_to_eol
195    | flag flag_re
196    | block "group" [ indent . key word . comment_or_eol ]
197
198(* View: vrrp_sync_group *)
199let vrrp_sync_group = named_block "vrrp_sync_group" vrrp_sync_group_field
200
201(* View: vrrp_instance_field *)
202let vrrp_instance_field =
203      let word_re = "state" | "interface" | "lvs_sync_daemon_interface"
204   in let num_re = "virtual_router_id" | "priority" | "advert_int" | /garp_master_(delay|repeat|refresh|refresh_repeat)/
205   in let to_eol_re = /notify(_master|_backup|_fault)?/ | /(mcast|unicast)_src_ip/
206   in let flag_re = "smtp_alert" | "nopreempt" | "ha_suspend" | "debug" | "use_vmac" | "vmac_xmit_base" | "native_ipv6" | "dont_track_primary" | "preempt_delay"
207   in field word_re sto_word
208    | field num_re sto_num
209    | field to_eol_re sto_to_eol
210    | flag flag_re
211    | block "authentication" (
212         field /auth_(type|pass)/ sto_word
213         )
214    | block "virtual_ipaddress" static_ipaddress_field
215    | block /track_(interface|script)/ ( flag word )
216    | block "unicast_peer" static_ipaddress_field
217
218(* View: vrrp_instance *)
219let vrrp_instance = named_block "vrrp_instance" vrrp_instance_field
220
221(* View: vrrp_script_field *)
222let vrrp_script_field =
223      let num_re = "interval" | "weight" | "fall" | "raise"
224   in let to_eol_re = "script"
225   in field to_eol_re sto_to_eol
226    | field num_re sto_num
227
228(* View: vrrp_script *)
229let vrrp_script = named_block "vrrp_script" vrrp_script_field
230
231
232(* View: vrrpd_conf
233contains subblocks of VRRP synchronization group(s) and VRRP instance(s) *)
234let vrrpd_conf = vrrp_sync_group | vrrp_instance | vrrp_script
235
236
237(************************************************************************
238 * Group:                 REAL SERVER CHECKS CONFIGURATION
239 *************************************************************************)
240
241(* View: tcp_check_field *)
242let tcp_check_field =
243      let word_re = "bindto"
244   in let num_re = /connect_(timeout|port)/
245   in field word_re sto_word
246    | field num_re sto_num
247
248(* View: misc_check_field *)
249let misc_check_field =
250      let flag_re = "misc_dynamic"
251   in let num_re = "misc_timeout"
252   in let to_eol_re = "misc_path"
253   in field num_re sto_num
254    | flag flag_re
255    | field to_eol_re sto_to_eol
256
257(* View: smtp_host_check_field *)
258let smtp_host_check_field =
259      let word_re = "connect_ip" | "bindto"
260   in let num_re = "connect_port"
261   in field word_re sto_word
262    | field num_re sto_num
263
264(* View: smtp_check_field *)
265let smtp_check_field =
266      let word_re = "connect_ip" | "bindto"
267   in let num_re = "connect_timeout" | "retry" | "delay_before_retry"
268   in let to_eol_re = "helo_name"
269   in field word_re sto_word
270    | field num_re sto_num
271    | field to_eol_re sto_to_eol
272    | block "host" smtp_host_check_field
273
274(* View: http_url_check_field *)
275let http_url_check_field =
276      let word_re = "digest"
277   in let num_re = "status_code"
278   in let to_eol_re = "path"
279   in field word_re sto_word
280    | field num_re sto_num
281    | field to_eol_re sto_to_eol
282
283(* View: http_check_field *)
284let http_check_field =
285      let num_re = /connect_(timeout|port)/ | "nb_get_retry" | "delay_before_retry"
286   in field num_re sto_num
287    | block "url" http_url_check_field
288
289(* View: real_server_field *)
290let real_server_field =
291      let num_re = "weight"
292   in let flag_re = "inhibit_on_failure"
293   in let to_eol_re = /notify_(up|down)/
294   in field num_re sto_num
295    | flag flag_re
296    | field to_eol_re sto_to_eol
297    | block "TCP_CHECK" tcp_check_field
298    | block "MISC_CHECK" misc_check_field
299    | block "SMTP_CHECK" smtp_check_field
300    | block /(HTTP|SSL)_GET/ http_check_field
301
302(************************************************************************
303 * Group:                 LVS CONFIGURATION
304 *************************************************************************)
305
306(* View: virtual_server_field *)
307let virtual_server_field =
308      let num_re = "delay_loop" | "persistence_timeout" | "quorum" | "hysteresis"
309   in let word_re = /lb_(algo|kind)/ | "nat_mask" | "protocol" | "persistence_granularity"
310                      | "virtualhost"
311   in let flag_re = "ops" | "ha_suspend" | "alpha" | "omega"
312   in let to_eol_re = /quorum_(up|down)/
313   in let ip_port_re = "sorry_server"
314   in field num_re sto_num
315    | field word_re sto_word
316    | flag flag_re
317    | field to_eol_re sto_to_eol
318    | field ip_port_re ip_port
319    | named_block_arg "real_server" "ip" "port" real_server_field
320
321(* View: virtual_server *)
322let virtual_server = named_block_arg "virtual_server" "ip" "port" virtual_server_field
323
324(* View: virtual_server_group_field *)
325let virtual_server_group_field = [ indent . label "vip"
326                               . [ ipaddr ]
327			       . sep_spc
328			       . [ label "port" . sto_num ]
329			       . comment_or_eol ]
330
331(* View: virtual_server_group *)
332let virtual_server_group = named_block "virtual_server_group" virtual_server_group_field
333
334(* View: lvs_conf
335contains subblocks of Virtual server group(s) and Virtual server(s) *)
336let lvs_conf = virtual_server | virtual_server_group
337
338
339(* View: lns
340     The keepalived lens
341*)
342let lns = ( empty | comment | global_conf | vrrpd_conf | lvs_conf )*
343
344(* Variable: filter *)
345let filter = incl "/etc/keepalived/keepalived.conf"
346
347let xfm = transform lns filter
348
349