[augeas-devel] [PATCH] Add a lens for keepalived.conf and associated test
raphink at gmail.com
raphink at gmail.com
Wed Sep 22 09:05:52 UTC 2010
From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= <raphink at gmail.com>
---
lenses/keepalived.aug | 249 ++++++++++++++++++++++++++++++++++++++
lenses/tests/test_keepalived.aug | 232 +++++++++++++++++++++++++++++++++++
2 files changed, 481 insertions(+), 0 deletions(-)
create mode 100644 lenses/keepalived.aug
create mode 100644 lenses/tests/test_keepalived.aug
diff --git a/lenses/keepalived.aug b/lenses/keepalived.aug
new file mode 100644
index 0000000..b661590
--- /dev/null
+++ b/lenses/keepalived.aug
@@ -0,0 +1,249 @@
+(*
+Module: Keepalived
+ Parses /etc/keepalived/keepalived.conf
+
+Author: Raphael Pinson <raphink at gmail.com>
+
+About: Reference
+ This lens tries to keep as close as possible to `man 5 keepalived.conf` where possible.
+
+About: License
+ This file is licenced under the LGPLv2+, like the rest of Augeas.
+
+About: Lens Usage
+ To be documented
+
+About: Configuration files
+ This lens applies to /etc/keepalived/keepalived.conf. See <filter>.
+*)
+
+
+module Keepalived =
+ autoload xfm
+
+(************************************************************************
+ * Group: USEFUL PRIMITIVES
+ *************************************************************************)
+
+(* Group: Comments and empty lines *)
+
+(* View: indent *)
+let indent = Util.indent
+
+(* View: eol *)
+let eol = Util.eol
+
+(* View: sep_spc *)
+let sep_spc = del /[ \t]+/ " "
+
+(* View: lbracket *)
+let lbracket = Util.del_str "{"
+
+(* View: rbracket *)
+let rbracket = Util.del_str "}"
+
+(* View: comment
+Map comments in "#comment" nodes *)
+let comment =
+ [ indent . label "#comment" . del /[#!][ \t]*/ "# "
+ . store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ . eol ]
+
+(* View: eol_comment
+And end-of-line comment
+with a space in front of # by default *)
+let eol_comment =
+ [ label "#comment" . del /[ \t]*[#!][ \t]*/ " # "
+ . store /([^ \t\n].*[^ \t\n]|[^ \t\n])/ . eol ]
+
+(* View: empty
+Map empty lines *)
+let empty = Util.empty
+
+(* View: sto_email_addr *)
+let sto_email_addr = store /[A-Za-z0-9_\+\.-]+@[A-Za-z0-9_\.-]+/
+
+(* Variable: word *)
+let word = /[A-Za-z0-9_\.-]+/
+
+(* Variable: word_slash *)
+let word_slash = /[A-Za-z0-9_\.\/-]+/
+
+(* View: sto_word *)
+let sto_word = store word
+
+(* View: sto_num *)
+let sto_num = store /[0-9]+/
+
+(* View: sto_to_eol
+Should not be necessary once static_ipaddress_field uses fields *)
+let sto_to_eol = store /[^}!# \t\n][^}!#\n]*[^}!# \t\n]|[^}!# \t\n]/
+
+
+(* View: field *)
+let field (kw:string) (sto:lens) = [ indent . key kw . sep_spc . sto . (eol_comment|eol) ]
+
+(* View: flag
+A single word *)
+let flag (kw:regexp) = [ indent . key kw ]
+
+(* View: lens_block
+A generic block with a title lens *)
+let lens_block (title:lens) (sto:lens) = [ indent . title . sep_spc . lbracket . eol
+ . (sto | empty | comment)+
+ . indent . rbracket . eol ]
+
+(* View: block
+A simple block with just a block title *)
+let block (kw:string) (sto:lens) = lens_block (key kw) sto
+
+(* View: named_block
+A block with a block title and name *)
+let named_block (kw:string) (sto:lens) = lens_block (key kw . sep_spc . sto_word) sto
+
+(* View: named_block_arg_title
+A title lens for named_block_arg *)
+let named_block_arg_title (kw:string) (name:string) (arg:string) =
+ key kw . sep_spc
+ . [ label name . sto_word ]
+ . sep_spc
+ . [ label arg . sto_word ]
+
+(* View: named_block_arg
+A block with a block title, a name and an argument *)
+let named_block_arg (kw:string) (name:string) (arg:string) (sto:lens) =
+ lens_block (named_block_arg_title kw name arg) sto
+
+
+(************************************************************************
+ * Group: GLOBAL CONFIGURATION
+ *************************************************************************)
+
+(* View: email
+A simple email address entry *)
+let email = [ indent . label "email" . sto_email_addr . (eol_comment|eol) ]
+
+(* View: global_defs_field
+Possible fields in the global_defs block *)
+let global_defs_field = block "notification_email" email
+ | field "notification_email_from" sto_email_addr
+ | field "smtp_server" sto_word
+ | field "smtp_connect_timeout" sto_num
+ | field "lvs_id" sto_word
+ | field "router_id" sto_word
+
+(* View: global_defs
+A global_defs block *)
+let global_defs = block "global_defs" global_defs_field
+
+(* View: prefixlen
+A prefix for IP addresses *)
+let prefixlen = [ label "prefixlen" . Util.del_str "/" . sto_num ]
+
+(* View: ipdev
+A device for IP addresses *)
+let ipdev = [ key "dev" . sep_spc . sto_word ]
+
+(* View: static_ipaddress_field
+The whole string is fed to ip addr add.
+You can truncate the string anywhere you like and let ip addr add use defaults for the rest of the string.
+To be refined with fields according to `ip addr help`.
+*)
+let static_ipaddress_field = [ indent . label "ipaddr"
+ . store /[0-9\.]+/
+ . prefixlen?
+ . (sep_spc . ipdev)?
+ . (eol|eol_comment) ]
+
+(* View: static_routes_field
+src $SRC_IP to $DST_IP dev $SRC_DEVICE
+*)
+let static_routes_field = [ indent . label "route"
+ . [ key "src" . sto_word ] . sep_spc
+ . [ key "to" . sto_word ] . sep_spc
+ . [ key "dev" . sto_word ] . (eol|eol_comment) ]
+
+(* View: static_routes *)
+let static_routes = block "static_ipaddress" static_ipaddress_field
+ | block "static_routes" static_routes_field
+
+
+(* View: global_conf
+A global configuration entry *)
+let global_conf = global_defs | static_routes
+
+
+(************************************************************************
+ * Group: VRRP CONFIGURATION
+ *************************************************************************)
+
+(*View: vrrp_sync_group_field *)
+let vrrp_sync_group_field = block "group" [ indent . key word . (eol|eol_comment) ]
+
+(* View: vrrp_sync_group *)
+let vrrp_sync_group = named_block "vrrp_sync_group" vrrp_sync_group_field
+
+(* View: vrrp_instance_field *)
+let vrrp_instance_field = field "state" sto_word
+ | field "interface" sto_word
+ | field "lvs_sync_daemon_interface" sto_word
+ | field "virtual_router_id" sto_num
+ | field "priority" sto_num
+ | field "advert_int" sto_num
+ | flag "smtp_alert"
+ | flag "nopreempt"
+ | block "authentication" (
+ field "auth_type" sto_word
+ | field "auth_pass" sto_word
+ )
+ | block "virtual_ipaddress" static_ipaddress_field
+
+(* View: vrrp_instance *)
+let vrrp_instance = named_block "vrrp_instance" vrrp_instance_field
+
+
+(* View: vrrpd_conf
+contains subblocks of VRRP synchronization group(s) and VRRP instance(s) *)
+let vrrpd_conf = vrrp_sync_group | vrrp_instance
+
+
+(************************************************************************
+ * Group: LVS CONFIGURATION
+ *************************************************************************)
+
+(* View: virtual_server_group *)
+
+(* View: tcp_check_field *)
+let tcp_check_field = field "connect_timeout" sto_num
+ | field "connect_port" sto_num
+
+(* View: real_server_field *)
+let real_server_field = field "weight" sto_num
+ | block "TCP_CHECK" tcp_check_field
+
+(* View: virtual_server_field *)
+let virtual_server_field = field "delay_loop" sto_num
+ | field "lb_algo" sto_word
+ | field "lb_kind" sto_word
+ | field "nat_mask" sto_word
+ | field "protocol" sto_word
+ | named_block_arg "real_server" "ip" "port" real_server_field
+
+(* View: virtual_server *)
+let virtual_server = named_block_arg "virtual_server" "ip" "port" virtual_server_field
+
+(* View: lvs_conf
+contains subblocks of Virtual server group(s) and Virtual server(s) *)
+let lvs_conf = virtual_server
+
+
+(* View: lns
+ The keepalived lens
+*)
+let lns = ( empty | comment | global_conf | vrrpd_conf | lvs_conf )*
+
+(* Variable: filter *)
+let filter = incl "/etc/keepalived/keepalived.conf"
+ . Util.stdexcl
+
+let xfm = transform lns filter
+
diff --git a/lenses/tests/test_keepalived.aug b/lenses/tests/test_keepalived.aug
new file mode 100644
index 0000000..e2f208a
--- /dev/null
+++ b/lenses/tests/test_keepalived.aug
@@ -0,0 +1,232 @@
+(* Test for keepalived lens *)
+
+module Test_keepalived =
+
+ let conf = "! This is a comment
+! Configuration File for keepalived
+
+global_defs {
+ ! this is who emails will go to on alerts
+ notification_email {
+ admins at example.com
+ fakepager at example.com
+ ! add a few more email addresses here if you would like
+ }
+ notification_email_from admins at example.com
+
+ smtp_server 127.0.0.1 ! I use the local machine to relay mail
+ smtp_connect_timeout 30
+
+ ! each load balancer should have a different ID
+ ! this will be used in SMTP alerts, so you should make
+ ! each router easily identifiable
+ lvs_id LVS_EXAMPLE_01
+}
+
+vrrp_sync_group VG1 {
+ group {
+ inside_network # name of vrrp_instance (below)
+ outside_network # One for each moveable IP.
+ }
+}
+
+vrrp_instance VI_1 {
+ state MASTER
+ interface eth0
+
+ lvs_sync_daemon_interface eth0
+
+ ! each virtual router id must be unique per instance name!
+ virtual_router_id 51
+
+ ! MASTER and BACKUP state are determined by the priority
+ ! even if you specify MASTER as the state, the state will
+ ! be voted on by priority (so if your state is MASTER but your
+ ! priority is lower than the router with BACKUP, you will lose
+ ! the MASTER state)
+ ! I make it a habit to set priorities at least 50 points apart
+ ! note that a lower number is lesser priority - lower gets less vote
+ priority 150
+
+ ! how often should we vote, in seconds?
+ advert_int 1
+
+ ! send an alert when this instance changes state from MASTER to BACKUP
+ smtp_alert
+
+ ! this authentication is for syncing between failover servers
+ ! keepalived supports PASS, which is simple password
+ ! authentication
+ ! or AH, which is the IPSec authentication header.
+ ! I don't use AH
+ ! yet as many people have reported problems with it
+ authentication {
+ auth_type PASS
+ auth_pass example
+ }
+
+ ! these are the IP addresses that keepalived will setup on this
+ ! machine. Later in the config we will specify which real
+ ! servers are behind these IPs
+ ! without this block, keepalived will not setup and takedown the
+ ! any IP addresses
+
+ virtual_ipaddress {
+ 192.168.1.11
+ 10.234.66.146/32 dev vlan933 # parse it well
+ ! and more if you want them
+ }
+}
+
+virtual_server 192.168.1.11 22 {
+ delay_loop 6
+
+ ! use round-robin as a load balancing algorithm
+ lb_algo rr
+
+ ! we are doing NAT
+ lb_kind NAT
+ nat_mask 255.255.255.0
+
+ protocol TCP
+
+ ! there can be as many real_server blocks as you need
+
+ real_server 10.20.40.10 22 {
+
+ ! if we used weighted round-robin or a similar lb algo,
+ ! we include the weight of this server
+
+ weight 1
+
+ ! here is a health checker for this server.
+ ! we could use a custom script here (see the keepalived docs)
+ ! but we will just make sure we can do a vanilla tcp connect()
+ ! on port 22
+ ! if it fails, we will pull this realserver out of the pool
+ ! and send email about the removal
+ TCP_CHECK {
+ connect_timeout 3
+ connect_port 22
+ }
+ }
+}
+
+! that's all
+"
+
+
+ test Keepalived.lns get conf =
+ { "#comment" = "This is a comment" }
+ { "#comment" = "Configuration File for keepalived" }
+ {}
+ { "global_defs"
+ { "#comment" = "this is who emails will go to on alerts" }
+ { "notification_email"
+ { "email" = "admins at example.com" }
+ { "email" = "fakepager at example.com" }
+ { "#comment" = "add a few more email addresses here if you would like" } }
+ { "notification_email_from" = "admins at example.com" }
+ { }
+ { "smtp_server" = "127.0.0.1"
+ { "#comment" = "I use the local machine to relay mail" } }
+ { "smtp_connect_timeout" = "30" }
+ {}
+ { "#comment" = "each load balancer should have a different ID" }
+ { "#comment" = "this will be used in SMTP alerts, so you should make" }
+ { "#comment" = "each router easily identifiable" }
+ { "lvs_id" = "LVS_EXAMPLE_01" } }
+ {}
+ { "vrrp_sync_group" = "VG1"
+ { "group"
+ { "inside_network"
+ { "#comment" = "name of vrrp_instance (below)" } }
+ { "outside_network"
+ { "#comment" = "One for each moveable IP." } } } }
+ {}
+ { "vrrp_instance" = "VI_1"
+ { "state" = "MASTER" }
+ { "interface" = "eth0" }
+ { }
+ { "lvs_sync_daemon_interface" = "eth0" }
+ { }
+ { "#comment" = "each virtual router id must be unique per instance name!" }
+ { "virtual_router_id" = "51" }
+ { }
+ { "#comment" = "MASTER and BACKUP state are determined by the priority" }
+ { "#comment" = "even if you specify MASTER as the state, the state will" }
+ { "#comment" = "be voted on by priority (so if your state is MASTER but your" }
+ { "#comment" = "priority is lower than the router with BACKUP, you will lose" }
+ { "#comment" = "the MASTER state)" }
+ { "#comment" = "I make it a habit to set priorities at least 50 points apart" }
+ { "#comment" = "note that a lower number is lesser priority - lower gets less vote" }
+ { "priority" = "150" }
+ { }
+ { "#comment" = "how often should we vote, in seconds?" }
+ { "advert_int" = "1" }
+ { }
+ { "#comment" = "send an alert when this instance changes state from MASTER to BACKUP" }
+ { "smtp_alert" }
+ { }
+ { }
+ { "#comment" = "this authentication is for syncing between failover servers" }
+ { "#comment" = "keepalived supports PASS, which is simple password" }
+ { "#comment" = "authentication" }
+ { "#comment" = "or AH, which is the IPSec authentication header." }
+ { "#comment" = "I don't use AH" }
+ { "#comment" = "yet as many people have reported problems with it" }
+ { "authentication"
+ { "auth_type" = "PASS" }
+ { "auth_pass" = "example" } }
+ { }
+ { "#comment" = "these are the IP addresses that keepalived will setup on this" }
+ { "#comment" = "machine. Later in the config we will specify which real" }
+ { "#comment" = "servers are behind these IPs" }
+ { "#comment" = "without this block, keepalived will not setup and takedown the" }
+ { "#comment" = "any IP addresses" }
+ { }
+ { "virtual_ipaddress"
+ { "ipaddr" = "192.168.1.11" }
+ { "ipaddr" = "10.234.66.146"
+ { "prefixlen" = "32" }
+ { "dev" = "vlan933" }
+ { "#comment" = "parse it well" } }
+ { "#comment" = "and more if you want them" } } }
+ { }
+ { "virtual_server"
+ { "ip" = "192.168.1.11" }
+ { "port" = "22" }
+ { "delay_loop" = "6" }
+ { }
+ { "#comment" = "use round-robin as a load balancing algorithm" }
+ { "lb_algo" = "rr" }
+ { }
+ { "#comment" = "we are doing NAT" }
+ { "lb_kind" = "NAT" }
+ { "nat_mask" = "255.255.255.0" }
+ { }
+ { "protocol" = "TCP" }
+ { }
+ { "#comment" = "there can be as many real_server blocks as you need" }
+ { }
+ { "real_server"
+ { "ip" = "10.20.40.10" }
+ { "port" = "22" }
+ { }
+ { "#comment" = "if we used weighted round-robin or a similar lb algo," }
+ { "#comment" = "we include the weight of this server" }
+ { }
+ { "weight" = "1" }
+ { }
+ { "#comment" = "here is a health checker for this server." }
+ { "#comment" = "we could use a custom script here (see the keepalived docs)" }
+ { "#comment" = "but we will just make sure we can do a vanilla tcp connect()" }
+ { "#comment" = "on port 22" }
+ { "#comment" = "if it fails, we will pull this realserver out of the pool" }
+ { "#comment" = "and send email about the removal" }
+ { "TCP_CHECK"
+ { "connect_timeout" = "3" }
+ { "connect_port" = "22" } } } }
+ { }
+ { "#comment" = "that's all" }
+
--
1.7.0.4
More information about the augeas-devel
mailing list