From: =?UTF-8?q?Rapha=C3=ABl=20Pinson?= <[email protected]> --- 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 <[email protected]> + +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 { + [email protected] + [email protected] + ! add a few more email addresses here if you would like + } + notification_email_from [email protected] + + 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" = "[email protected]" } + { "email" = "[email protected]" } + { "#comment" = "add a few more email addresses here if you would like" } } + { "notification_email_from" = "[email protected]" } + { } + { "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 _______________________________________________ augeas-devel mailing list [email protected] https://www.redhat.com/mailman/listinfo/augeas-devel
