举个栗子

马辰龙De技术分享
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

keepalive配置文件转化JSON

Posted on 2016-07-09 14:05  ChenlongMa  阅读(524)  评论(0编辑  收藏  举报

无论在管理LVS配置中,对keepalive的配置文件管理是必不可少的,解析配置文件也是核心功能之一,现在把自己写的一些思路分享给大家~

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use JSON;
use re 'eval';
#将keepalived.conf 格式化为json数据
 
 
my $file = "/Users/machenlong/Downloads/keepalived.conf";
open FH, $file or die "$!";
#一次行读取整个文件
my $str = do { local $/; <FH> };
#定义树形中的键值对
my $treeKey = {
    vrrpKey => {
        state             => 1,
        interface         => 1,
        virtual_router_id => 1,
        priority          => 1,
        advert_int        => 1,
    },
    virtualKey => {
        delay_loop => 1,
        lb_algo    => 1,
        lb_kind    => 1,
        protocol   => 1
    },
    realKey => {
        realKey0 => { weight => 1, },
        realKey1 => {
 
            TCP_CHECK => 1,
            HTTP_GET  => 1
 
        },
        realKey2 => {
            connect_timeout    => 1,
            nb_get_retry       => 1,
            delay_before_retry => 1,
            connect_port       => 1,
 
        },
        realKey3 => {
            url         => 1,
            path        => 1,
            status_code => 1
        }
    }
};
my $hash;
my $re
    = qr/(.*)s+{(?{local $a=0})(?>(?:([^{}]+)(?{push @{$hash->{$1}},$2;})| 
#将匹配到得内容push到$hash
#固化分组,减少回朔。
{(?{$a++})|   
#遇到开括号$a+1
}(?(?{$a!=0})(?{$a--})|       
#如果$a不等于0则遇到闭括号$a-1
(?!)))*)(?(?{$a!=0})(?!))}/x;
 
# 否则继续匹配,如果继续遇到$a不等于0 继续匹配到行尾
 
#处理注释
$str =~ s/
#.*$//mg;
 
1 while ( $str =~ /$re/g );
my ( $formatHash, $vrrpFormat );
for my $key ( keys %$hash ) {
    for ( @{ $hash->{$key} } ) {
        vrrp_format( $key, $_, $treeKey );
    }
}
 
my $confFormat = real_format( $vrrpFormat, $treeKey );
 
print encode_json $confFormat;
 
sub vrrp_format {
    my ( $varrKey, $varrParam, $treeKey ) = @_;
    my ( $realIp, $realPort, $key3, @unParams );
    if ( $varrKey =~ /(global_defs)/ ) {
        my @params = split ' ', $varrParam;
        $vrrpFormat->{$1}->{ $params[0] } = $params[1];
    }
 
    
#vvrp 分解
    elsif ( $varrKey =~ /(vrrp.*?)s+(w+)/ ) {
        my ( $key, $value ) = ( $1, $2 );
        my @params = split ' ', $varrParam;
        my $ips;
        for ( 0 .. $
#params ) {
            my @v = splice @params, 0, 2;
            if (@v) {
                if ( $treeKey->{vrrpKey}->{ $v[0] } ) {
                    $vrrpFormat->{$key}->{$value}->{ $v[0] } = $v[1];
                }
                else {
 
                    for (@v) {
 
                        
#IP处理
                        if (/(d+.){3}d+/) {
                            push @{ $vrrpFormat->{$key}->{$value}
                                    ->{virtual_ipaddress} }, $_;
                        }
 
                        
#auth字段处理
                        elsif (/auth_/) {
                            $vrrpFormat->{$key}->{$value}->{authentication}
                                ->{ $v[0] } = $v[1];
                        }
 
                    }
                }
 
            }
        }
 
    }
 
    
#virtual_server处理
    elsif ( $varrKey =~ /(virtual_server)s+((?:d+.){3}d+)s+(d+)/ ) {
 
        
#键值名,IP,端口
        my ( $key, $ip, $port ) = ( $1, $2, $3 );
        my @params = split ' ', $varrParam;
        for ( 0 .. $
#params ) {
 
            
#切分数组前两个元素
            my @v = splice @params, 0, 2;
            if (@v) {
                if ( $treeKey->{virtualKey}->{ $v[0] } ) {
                    $vrrpFormat->{$key}->{$ip}->{$port}->{ $v[0] } = $v[1];
                }
                else {
                    
#不匹配定义的检测,重新写回@params
                    unshift @params, @v;
                }
            }
        }
 
        if (@params) {
 
            
#将剩余的params写回总hash,real_serverArr临时数组
            push @{ $vrrpFormat->{$key}->{$ip}->{$port}->{real_serverArr} },
                @params;
        }
    }
 
}
 
sub real_format {
    my ( $vrrpFormat, $treeKey ) = @_;
 
    for my $sIp ( keys %{ $vrrpFormat->{virtual_server} } ) {
        my $portHash = $vrrpFormat->{virtual_server}->{$sIp};
        for my $port ( keys %$portHash ) {
 
            my @realArr = @{ $portHash->{$port}->{real_serverArr} };
 
            
#realserver  IP、port  位置
            my ($realIp, $realPort, @pos);
             
 
            
#3级 4级 键值类型,数值
            my ( $key3, $key4, $value4, $key5 );
 
            
#查找IP的POS未知
            for ( 0 .. $
#realArr ) {
                if ( $realArr[$_] =~ /(?:d+.){3}d+/ ) {
                    push @pos, $_;
 
                }
            }
            my ( @realIp, @realPort );
            my $cPos = 0;
 
            
#根据位置,将IP端口放入数组
            for (@pos) {
                push @realIp,   splice @realArr, $_ - $cPos, 1;
                push @realPort, splice @realArr, $_ - $cPos, 1;
                $cPos += 2;
            }
 
            for my $realParam ( @realArr) {
 
                
#根据real_server未知确定IP、端口未知
                if ( $realParam eq "real_server" ) {
                    $realIp   = shift @realIp;
                    $realPort = shift @realPort;
                    next;
                }
                
#遇到TCP_CHECK HTTP_GET url作为分支,存入key3
                if ( $realParam =~ /(TCP_CHECK)/ ) {
                    $key3 = $1;
 
                }
                elsif ( $realParam =~ /(HTTP_GET)/ ) {
                    $key3 = $1;
                }
                elsif ( $realParam =~ /(url)/ ) {
                    $key5 = $1;
 
                }
                if ( !$key4 and $realParam !~ /HTTP_GET|TCP_CHECK/ ) {
                    $key4 = $realParam;
                }
                
#匹配为键值对逻辑
                if ( $key4 and !$value4 ) {
                    
#必须为数字
                    if ( $realParam =~ /^d+$/ ) {
                        $value4 = $realParam;
                    }
                    
#或者为url
                    elsif ( $realParam =~ /https?:/// ) {
                        $value4 = $realParam;
                    }
                }
 
                if ( $key4 and $value4 and $key3 ) {
 
                    
# print "$realIp,$key3,$key4,$value4n";
                    
#判断键值对是否在定义中存在
                    if ( $treeKey->{realKey}->{realKey0}->{$key4} ) {
 
                        $portHash->{$port}->{real_server}->{$realIp}
                            ->{$realPort}->{$key4} = $value4;
 
                    }
                    elsif ( $treeKey->{realKey}->{realKey2}->{$key4} ) {
                        $portHash->{$port}->{real_server}->{$realIp}
                            ->{$realPort}->{$key3}->{$key4} = $value4;
                    }
                    
#url判断
                    elsif ($key5) {
                        $portHash->{$port}->{real_server}->{$realIp}
                            ->{$realPort}->{$key3}->{$key5}->{$key4}
                            = $value4;
                    }
                    undef $key4;
                    undef $value4;
                }
                
#删除临时存储数组
                delete $portHash->{$port}->{real_serverArr};
            }
        }
    }
    return $vrrpFormat;
}