From bf8893ba35004a7f6649a90b5995b0eba457c66f Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Mon, 2 Mar 2009 20:43:25 +0000 Subject: dahdi_genconf: configuration handling cleanup. * Parsing genconf_parameters is now in Dahdi::Config::Params All hard-coded defaults are there too (in the item() method). * Dahdi::Config::Genconf is gone (merged into Dahdi::Config::Gen) All semantic mapping is in the constructor. * dahdi_genconf is now lean and mean. * Add some implementation docs into these files. git-svn-id: http://svn.asterisk.org/svn/dahdi/tools/trunk@6075 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- xpp/dahdi_genconf | 226 +++++++------------------ xpp/perl_modules/Dahdi/Config/Gen.pm | 181 +++++++++++++++++++- xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm | 2 +- xpp/perl_modules/Dahdi/Config/Gen/System.pm | 2 +- xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm | 2 +- xpp/perl_modules/Dahdi/Config/Gen/Users.pm | 2 +- xpp/perl_modules/Dahdi/Config/Params.pm | 148 ++++++++++++++++ 7 files changed, 385 insertions(+), 178 deletions(-) create mode 100644 xpp/perl_modules/Dahdi/Config/Params.pm diff --git a/xpp/dahdi_genconf b/xpp/dahdi_genconf index cba1963..2988343 100755 --- a/xpp/dahdi_genconf +++ b/xpp/dahdi_genconf @@ -14,187 +14,52 @@ BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); } use Getopt::Std; use Dahdi; use Dahdi::Xpp; -use Dahdi::Config::GenconfDefaults; +use Dahdi::Config::Gen; +use Dahdi::Config::Params; my $version = '1'; # Functionality version (integer) my $revision = '$Revision$'; my %opts; -my $genconf_defaults; - -my %default_context = ( - FXO => 'from-pstn', - FXS => 'from-internal', - IN => 'astbank-input', - OUT => 'astbank-output', - BRI_TE => 'from-pstn', - BRI_NT => 'from-internal', - E1_TE => 'from-pstn', - T1_TE => 'from-pstn', - J1_TE => 'from-pstn', - E1_NT => 'from-internal', - T1_NT => 'from-internal', - J1_NT => 'from-internal', - ); - -my %default_group = ( - FXO => 0, - FXS => "5", - IN => '', - OUT => '', - BRI_TE => 0, - BRI_NT => 6, - E1_TE => 0, - T1_TE => 0, - J1_TE => 0, - E1_NT => 6, - T1_NT => 6, - J1_NT => 6, - ); - -my $fxs_default_start = 'ks'; - -my %default_dahdi_signalling = ( - FXO => 'fxsks', - FXS => "fxo{fxs_default_start}", - IN => "fxo{fxs_default_start}", - OUT => "fxo{fxs_default_start}", - ); - -my %default_chan_dahdi_signalling = ( - FXO => 'fxs_ks', - FXS => "fxo_{fxs_default_start}", - IN => "fxo_{fxs_default_start}", - OUT => "fxo_{fxs_default_start}", - ); - -my $lc_country = 'us'; -my $pri_termtype = 'SPAN/* TE'; -my $echo_can = 'mg2'; - -my %global_config = ( - 'genconf_file' => 'HARD-CODED-DEFAULT', # GenconfDefaults override - 'base_exten' => 4000, - 'freepbx' => 'no', # Better via -F command line - 'fxs_immediate' => 'no', - 'loadzone' => $lc_country, - 'defaultzone' => $lc_country, - 'context' => \%default_context, - 'group' => \%default_group, - 'bri_hardhdlc' => 'no', - 'bri_sig_style' => 'bri_ptmp', - 'r2_idle_bits' => '1101', - 'brint_overlap' => 'no', - 'pri_connection_type' => 'PRI', # PRI or R2 - 'dahdi_signalling' => \%default_dahdi_signalling, - 'chan_dahdi_signalling' => \%default_chan_dahdi_signalling, - ); - -my %dahdi_default_vars = ( - GENCONF_FILE => \$global_config{'genconf_file'}, - base_exten => \$global_config{'base_exten'}, - freepbx => \$global_config{'freepbx'}, - fxs_immediate => \$global_config{'fxs_immediate'}, - fxs_default_start => \$fxs_default_start, - lc_country => [ - \$global_config{'loadzone'}, - \$global_config{'defaultzone'}, - ], - context_lines => \$default_context{FXO}, - context_phones => \$default_context{FXS}, - context_input => \$default_context{IN}, - context_output => \$default_context{OUT}, - group_phones => [ - \$default_group{FXS}, - \$default_group{IN}, - \$default_group{OUT}, - ], - group_lines => \$default_group{FXO}, - bri_sig_style => \$global_config{'bri_sig_style'}, - brint_overlap => \$global_config{'brint_overlap'}, - pri_termtype => \$pri_termtype, - pri_connection_type => \$global_config{'pri_connection_type'}, - r2_idle_bits => \$global_config{'r2_idle_bits'}, - echo_can => \$echo_can, - bri_hardhdlc => \$global_config{'bri_hardhdlc'}, - ); - -sub map_dahdi_defaults { - my %defaults = @_; - foreach my $name (keys %defaults) { - my $val = $defaults{$name}; - my $ref = $dahdi_default_vars{$name}; - my $type = ref $ref; - my @vars = (); - # Some broken shells (msh) export even variables - # That where not defined. Work around that. - next unless defined $val && $val ne ''; - if($type eq 'SCALAR') { - @vars = ($ref); - } elsif($type eq 'ARRAY') { - @vars = @$ref; - } else { - die "$0: Don't know how to map '$name' (type=$type)\n"; - } - foreach my $v (@vars) { - $$v = $val; - #printf STDERR "%-20s %s\n", $v, $val; - } - } -} - -my @spans = Dahdi::spans(); sub set_defaults { - # Source default files my $default_file = $ENV{GENCONF_PARAMETERS} || "/etc/dahdi/genconf_parameters"; - $genconf_defaults = Dahdi::Config::GenconfDefaults->new($default_file); + my $params = Dahdi::Config::Params->new($default_file); + #$params->dump; if($opts{v}) { - print "Default parameters from ", $genconf_defaults->{GENCONF_FILE}, "\n"; + print "Default parameters from ", $params->{GENCONF_FILE}, "\n"; } - map_dahdi_defaults(%$genconf_defaults); + my $gconfig = Dahdi::Config::Gen->new($params); + #$gconfig->dump; + return $gconfig; +} + +sub spans_prep($@) { + my $gconfig = shift || die; + my @spans = @_; foreach my $span (@spans) { if($span->is_pri) { - $span->pri_set_fromconfig($genconf_defaults); + $span->pri_set_fromconfig($gconfig); } } - # Fixups - foreach my $val (values %default_dahdi_signalling, values %default_chan_dahdi_signalling) { - $val =~ s/{fxs_default_start}/$fxs_default_start/g; - } - #$genconf_defaults->dump; } -sub parse_args { - my @default_generators; +sub generator_list($) { + my $gconfig = shift || die; + my @genlist; if (@ARGV) { for my $gen (@ARGV) { - push @default_generators, $gen; + push @genlist, $gen; } } else { # No files given. Use the defaults. - @default_generators = ('system', 'chandahdi'); - if($global_config{'pri_connection_type'} eq 'R2') { - push @default_generators, 'unicall'; + @genlist = ('system', 'chandahdi'); + if($gconfig->{'pri_connection_type'} eq 'R2') { + push @genlist, 'unicall'; } } - return @default_generators; -} - -sub run_generator($$) { - my ($name, $genopts) = @_; - - if(defined $opts{'v'}) { - $genopts->{'verbose'} = $opts{v}; - } - my $module = "Dahdi::Config::Gen::$name"; - eval "use $module"; - if($@) { - die "Failed to load configuration generator for '$name'\n"; - } - my $cfg = new $module(\%global_config, $genopts); - $cfg->generate(@spans); + return @genlist; } sub parse_genopts($) { @@ -210,16 +75,21 @@ sub parse_genopts($) { return %genopts; } -sub generate_files(@) { - my @default_generators = @_; +sub generate_files($@) { + my $gconfig = shift || die; + my @spans = @_; + my @generators = generator_list($gconfig); - for my $gen (@default_generators) { + for my $gen (@generators) { my ($name, $optstr) = split(/=/, $gen, 2); die "Illegal name '$name'\n" unless $name =~ /^\w+$/; $name =~ s/(.)(.*)/\u$1\L$2/; my %genopts = parse_genopts($optstr); $genopts{'freepbx'} = 'yes' if $opts{'F'}; - run_generator($name, \%genopts); + if(defined $opts{'v'}) { + $genopts{'verbose'} = $opts{v}; + } + $gconfig->run_generator($name, \%genopts, @spans); } } @@ -232,9 +102,10 @@ if($opts{'V'}) { exit 0; } -my @default_generators = parse_args; -set_defaults; -generate_files @default_generators; +my $gconfig = set_defaults; +my @spans = Dahdi::spans(); +spans_prep($gconfig, @spans); +generate_files($gconfig, @spans); __END__ @@ -279,7 +150,7 @@ a comma separated list of options to the generator name. E.g: dahdi_genconf system chandahdi=verbose unicall -Global options: +=head1 Global options: =over 4 @@ -297,4 +168,29 @@ Freepbx -- sets the C<'freepbx'> option for all generators. Currently, chandahdi is affected. +=back + +=head1 Implementation notes: + +=over 4 + +=item * + +F parsing is done via C. +An object representing the parsed data is instanciated by: +Cnew()>. +The C method of this object contains all the hard coded +defaults of the configuration directives. + +=item * + +A configuration object is instanciated by Cnew($params)>. +The mapping of configuration directives into semantic configuration is +done in the constructor. + +=item * + +A single generator is run via the the C method of the +configuration object. + =back diff --git a/xpp/perl_modules/Dahdi/Config/Gen.pm b/xpp/perl_modules/Dahdi/Config/Gen.pm index 556e193..b68fa28 100644 --- a/xpp/perl_modules/Dahdi/Config/Gen.pm +++ b/xpp/perl_modules/Dahdi/Config/Gen.pm @@ -1,4 +1,46 @@ package Dahdi::Config::Gen; +# +# Written by Oron Peled +# Copyright (C) 2009, Xorcom +# This program is free software; you can redistribute and/or +# modify it under the same terms as Perl itself. +# +# $Id$ +# + +=head1 NAME + +Dahdi::Config::Gen -- Wrapper class for configuration generators. + +=head1 SYNOPSIS + + use Dahdi::Config::Gen qw(is_true); + my $params = Dahdi::Config::Params->new('the-config-file'); + my $gconfig = Dahdi::Config::Gen->new($params); + my $num = $gconfig->{'base_exten'}; + my $overlap = is_true($gconfig->{'brint_overlap'}); + $gconfig->dump; # For debugging + $gconfig->run_generator('system', {}, @spans); + +=head1 DESCRIPTION + +The constructor must be given an C object. +The returned object contains all data required for generation in the +form of a hash. + +The constructor maps the Cs from the parameter object into semantic +configuration keys. E.g: the C item is mapped to C and +C keys. + +The actual generation is done by delegation to one of the generators. +This is done via the C method which receive the +generator name, a generator specific options hash and a list of +span objects (from C) for which to generate configuration. + +This module contains few helper functions. E.g: C, C. + +=cut + require Exporter; @ISA = qw(Exporter); @@ -6,21 +48,15 @@ require Exporter; use strict; +# Parse values as true/false sub is_true($) { my $val = shift; return undef unless defined $val; return $val =~ /^(1|y|yes)$/i; } -sub show_gconfig($) { - my $gconfig = shift || die; - - print "Global configuration:\n"; - foreach my $key (sort keys %{$gconfig}) { - printf " %-20s %s\n", $key, $gconfig->{$key}; - } -} - +# Generate channel range strings from span objects +# E.g: "63-77,79-93" sub bchan_range($) { my $span = shift || die; my $first_chan = ($span->chans())[0]; @@ -46,4 +82,131 @@ sub bchan_range($) { return join(',', @range); } +sub new($) { + my $pack = shift || die "$0: Missing package argument"; + my $p = shift || die "$0: Missing parameters argument"; + + # Set defaults + my $fxs_default_start = $p->item('fxs_default_start'); + + my %default_context = ( + FXO => $p->item('context_lines'), + FXS => $p->item('context_phones'), + IN => $p->item('context_input'), + OUT => $p->item('context_output'), + BRI_TE => $p->item('context_lines'), + BRI_NT => $p->item('context_phones'), + E1_TE => $p->item('context_lines'), + T1_TE => $p->item('context_lines'), + J1_TE => $p->item('context_lines'), + E1_NT => $p->item('context_phones'), + T1_NT => $p->item('context_phones'), + J1_NT => $p->item('context_phones'), + ); + my %default_group = ( + FXO => $p->item('group_lines'), + FXS => $p->item('group_phones'), + IN => '', + OUT => '', + BRI_TE => 0, + BRI_NT => 6, + E1_TE => 0, + T1_TE => 0, + J1_TE => 0, + E1_NT => 6, + T1_NT => 6, + J1_NT => 6, + ); + my %default_dahdi_signalling = ( + FXO => 'fxsks', + FXS => "fxo$fxs_default_start", + IN => "fxo$fxs_default_start", + OUT => "fxo$fxs_default_start", + ); + my %default_chan_dahdi_signalling = ( + FXO => 'fxs_ks', + FXS => "fxo_$fxs_default_start", + IN => "fxo_$fxs_default_start", + OUT => "fxo_$fxs_default_start", + ); + + # First complex mapping + my $gconfig = { + PARAMETERS => $p, + 'loadzone' => $p->item('lc_country'), + 'defaultzone' => $p->item('lc_country'), + 'context' => \%default_context, + 'group' => \%default_group, + 'dahdi_signalling' => \%default_dahdi_signalling, + 'chan_dahdi_signalling' => \%default_chan_dahdi_signalling, + }; + # Now add trivial mappings + my @trivial = qw( + base_exten + freepbx + fxs_immediate + bri_hardhdlc + bri_sig_style + r2_idle_bits + echo_can + brint_overlap + pri_termtype + pri_connection_type + ); + foreach my $k (@trivial) { + $gconfig->{$k} = $p->item($k); + } + bless $gconfig,$pack; + + return $gconfig; +} + +sub run_generator($$@) { + my $gconfig = shift || die; + my $name = shift || die "$0: Missing generator name argument"; + my $genopts = shift || die "$0: Missing genopts argument"; + ref($genopts) eq 'HASH' or die "$0: Bad genopts argument"; + my @spans = @_; + + my $module = "Dahdi::Config::Gen::$name"; + #print STDERR "DEBUG: $module\n"; + eval "use $module"; + if($@) { + die "Failed to load configuration generator for '$name'\n"; + } + my $cfg = $module->new($gconfig, $genopts); + $cfg->generate(@spans); +} + +sub dump($) { + my $self = shift || die; + printf STDERR "%s dump:\n", ref $self; + my $width = 30; + foreach my $k (sort keys %$self) { + my $val = $self->{$k}; + my $ref = ref $val; + #print STDERR "DEBUG: '$k', '$ref', '$val'\n"; + if($ref eq '') { + printf STDERR "%-${width}s %s\n", $k, $val; + } elsif($ref eq 'SCALAR') { + printf STDERR "%-${width}s %s\n", $k, ${$val}; + } elsif($ref eq 'ARRAY') { + #printf STDERR "%s:\n", $k; + my $i = 0; + foreach my $v (@{$val}) { + printf STDERR "%-${width}s %s\n", "$k\->[$i]", $v; + $i++; + } + } elsif($ref eq 'HASH') { + #printf STDERR "%s:\n", $k; + foreach my $k1 (keys %{$val}) { + printf STDERR "%-${width}s %s\n", "$k\->\{$k1\}", ${$val}{$k1}; + } + } else { + printf STDERR "%-${width}s (-> %s)\n", $k, $ref; + } + } +} + + 1; diff --git a/xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm b/xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm index f48455d..1f39a7a 100644 --- a/xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm +++ b/xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm @@ -131,7 +131,7 @@ sub generate($) { my $file = $self->{FILE}; my $gconfig = $self->{GCONFIG}; my $genopts = $self->{GENOPTS}; - #Dahdi::Config::Gen::show_gconfig($gconfig); + #$gconfig->dump; my @spans = @_; warn "Empty configuration -- no spans\n" unless @spans; rename "$file", "$file.bak" diff --git a/xpp/perl_modules/Dahdi/Config/Gen/System.pm b/xpp/perl_modules/Dahdi/Config/Gen/System.pm index da60ec4..f805b65 100644 --- a/xpp/perl_modules/Dahdi/Config/Gen/System.pm +++ b/xpp/perl_modules/Dahdi/Config/Gen/System.pm @@ -107,7 +107,7 @@ sub generate($$$) { rename "$file", "$file.bak" or $! == 2 # ENOENT (No dependency on Errno.pm) or die "Failed to backup old config: $!\n"; - #Dahdi::Config::Gen::show_gconfig($gconfig); + #$gconfig->dump; print "Generating $file\n" if $genopts->{verbose}; open(F, ">$file") || die "$0: Failed to open $file: $!\n"; my $old = select F; diff --git a/xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm b/xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm index 526b62b..1a796f4 100644 --- a/xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm +++ b/xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm @@ -22,7 +22,7 @@ sub generate($) { my $file = $self->{FILE}; my $gconfig = $self->{GCONFIG}; my $genopts = $self->{GENOPTS}; - #Dahdi::Config::Gen::show_gconfig($gconfig); + #$gconfig->dump; my @spans = @_; warn "Empty configuration -- no spans\n" unless @spans; die "Only for R2" unless $gconfig->{'pri_connection_type'} eq 'R2'; diff --git a/xpp/perl_modules/Dahdi/Config/Gen/Users.pm b/xpp/perl_modules/Dahdi/Config/Gen/Users.pm index 36c2e65..e9d8ab9 100644 --- a/xpp/perl_modules/Dahdi/Config/Gen/Users.pm +++ b/xpp/perl_modules/Dahdi/Config/Gen/Users.pm @@ -73,7 +73,7 @@ sub generate($) { my $file = $self->{FILE}; my $gconfig = $self->{GCONFIG}; my $genopts = $self->{GENOPTS}; - #Dahdi::Config::Gen::show_gconfig($gconfig); + #$gconfig->dump; my @spans = @_; warn "Empty configuration -- no spans\n" unless @spans; rename "$file", "$file.bak" diff --git a/xpp/perl_modules/Dahdi/Config/Params.pm b/xpp/perl_modules/Dahdi/Config/Params.pm new file mode 100644 index 0000000..b6d9cdc --- /dev/null +++ b/xpp/perl_modules/Dahdi/Config/Params.pm @@ -0,0 +1,148 @@ +package Dahdi::Config::Params; +# +# Written by Oron Peled +# Copyright (C) 2009, Xorcom +# This program is free software; you can redistribute and/or +# modify it under the same terms as Perl itself. +# +# $Id$ +# +use strict; + +=head1 NAME + +Dahdi::Config::Params -- Object oriented representation of F file. + +=head1 SYNOPSIS + + use Dahdi::Config::Params; + my $params = Dahdi::Config::Params->new('the-config-file'); + print $params->item{'some-key'}; + $params->dump; # For debugging + +=head1 DESCRIPTION + +The constructor must be given a configuration file name: + +=over 4 + +=item * Missing file is B an error. + +=item * Other opening errors cause a C to be thrown. + +=item * The file name is saved as the value of C key. + +=back + +The access to config keys should only be done via the C method: + +=over 4 + +=item * It contains all hard-coded defaults. + +=item * All these values are overriden by directives in the config file. + +=back + +=cut + +sub new($$) { + my $pack = shift || die; + my $cfg_file = shift || die; + my $self = { + GENCONF_FILE => $cfg_file, + }; + bless $self, $pack; + if(!open(F, $cfg_file)) { + if(defined($!{ENOENT})) { + #print STDERR "No $cfg_file. Assume empty config\n"; + return $self; # Empty configuration + } + die "$pack: Failed to open '$cfg_file': $!\n"; + } + #print STDERR "$pack: $cfg_file\n"; + my $array_key; + while() { + my ($key, $val); + chomp; + s/#.*$//; + s/\s+$//; # trim tail whitespace + next unless /\S/; + if(defined $array_key && /^\s+/) { + s/^\s+//; # trim beginning whitespace + push(@{$self->{$array_key}}, $_); + next; + } + undef $array_key; + ($key, $val) = split(/\s+/, $_, 2); + $key = lc($key); + if(! defined $val) { + $array_key = $key; + next; + } + die "$cfg_file:$.: Duplicate key '$key'\n", if exists $self->{$key}; + $self->{$key} = $val; + } + close F; + return $self; +} + +sub item($$) { + my $self = shift || die; + my $key = shift || die; + my %defaults = ( + base_exten => '4000', + freepbx => 'no', # Better via -F command line + fxs_immediate => 'no', + fxs_default_start => 'ks', + lc_country => 'us', + context_lines => 'from-pstn', + context_phones => 'from-internal', + context_input => 'astbank-input', + context_output => 'astbank-output', + group_phones => '5', + group_lines => '0', + brint_overlap => 'no', + bri_sig_style => 'bri_ptmp', + echo_can => 'mg2', + bri_hardhdlc => 'no', + pri_connection_type => 'PRI', + r2_idle_bits => '1101', + 'pri_termtype' => [ 'SPAN/* TE' ], + ); + + return (exists($self->{$key})) ? $self->{$key} :$defaults{$key}; +} + +sub dump($) { + my $self = shift || die; + printf STDERR "%s dump:\n", ref $self; + my $width = 30; + foreach my $k (sort keys %$self) { + my $val = $self->{$k}; + my $ref = ref $val; + #print STDERR "DEBUG: '$k', '$ref', '$val'\n"; + if($ref eq '') { + printf STDERR "%-${width}s %s\n", $k, $val; + } elsif($ref eq 'SCALAR') { + printf STDERR "%-${width}s %s\n", $k, ${$val}; + } elsif($ref eq 'ARRAY') { + #printf STDERR "%s:\n", $k; + my $i = 0; + foreach my $v (@{$val}) { + printf STDERR "%-${width}s %s\n", "$k\->[$i]", $v; + $i++; + } + } elsif($ref eq 'HASH') { + #printf STDERR "%s:\n", $k; + foreach my $k1 (keys %{$val}) { + printf STDERR "%-${width}s %s\n", "$k\->\{$k1\}", ${$val}{$k1}; + } + } else { + printf STDERR "%-${width}s (-> %s)\n", $k, $ref; + } + } +} + +1; + -- cgit v1.2.3