http://www.perlmonks.org?node_id=972686

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi dear monks. I'm trying to develop a simple tool for mass configuration activities. I need to parse a csv file and create a configuration file:

Input file:

GroupID; Members; Group Description; contact; IP GSBDTD1831";"nbSm3Bh";"App.-Server MAIN";"user@example.com";"10.100.0. +2" "GSBTD1832";"nbSm3haz";"Appl.-Server Aux";"user1@example.com";"10.100. +0.3" "GSTD1822";"denJdkep64";"Printserver";"user3@example.com";"192.168.91. +1" "GSTD1822";"denJdw0a22";"Printserver";"user4@example.com";"192.168.91. +2" "GSTD1822";"nbSwgP14a";"Printserver";"user5@example.com";"192.168.91.5 +" "GSTD1983";"nbgwgxOrO";"Server2";"user5@example.com";"10.1.1.22"

This how every block in cfg file must look like, first field (GroupID) is unique, if there are more strings with same GroupID in csv file:

define hostgroup{

hostgroup_name GSBDTD183

alias Appl.-Server MAIN

members nbSm3Bh

}

if there are more strings with same GroupID in csv file, members must be grouped like this:

define hostgroup{

hostgroup_name GSTD1822

alias Printservers

members denJdkep64,denJdw0a22,nbSwgP14a

}

Here is some code which working not quite correct:
#!/usr/bin/perl -w use warnings; use strict; my (@members,@GroupIDs); ### Start Global Configuration my $src_file = "Servers.csv"; my $icinga_root = "/usr/local/etc/icinga"; my $objects_root = "objects"; ### End Global Configuration my %counter = (); my %groups = (); my $i = 0; open( SRC, "<", $src_file ); while (<SRC>){ next if /^(\s)*$/; s/\"//g; my ($GroupID,$member,$Group_descr,$contact,$ip) = split /;/, $_; s/\;//g; push @GroupIDs, $GroupID; foreach (@GroupIDs) { my $prev_GroupID = $GroupID; $#members = -1; push @members, join(',', $member); } $groups{$GroupID} = @members; $counter{$GroupID}++; if ($counter{$GroupID} <= 1) { open (HOSTGROUPS,">>", "$icinga_root/test/hostgroups.cfg"); print HOSTGROUPS <<HOSTGROUPSTMPL; define hostgroup{ hostgroup_name $GroupID alias $Group_descr members @members; } HOSTGROUPSTMPL close (HOSTGROUPS); } else { push @members,join(',', $member); open (HOSTGROUPS,">>", "$icinga_root/test/hostgroups.cfg"); print HOSTGROUPS <<HOSTGROUPSTMPL; define hostgroup{ hostgroup_name $GroupID alias $Group_descr members @members; } HOSTGROUPSTMPL close (HOSTGROUPS); } } close (SRC);
I just can't figure out how to implement inclusion of multiple "members" to one "definegroup" block. Thanks, in advance.

Replies are listed 'Best First'.
Re: groups maker
by CountZero (Bishop) on May 27, 2012 at 12:55 UTC
    use Modern::Perl; use Text::CSV_XS; use Data::Dump qw/dump/; my $csv = Text::CSV_XS->new( { sep_char => ';' } ); my %data; while (<DATA>) { $csv->parse($_) or die 'Error in parsing'; my @columns = $csv->fields(); push @{ $data{ $columns[0] }{'members'} }, { 'name' => $columns[1], 'email' => $columns[3], 'ip' => $columns[4], }; $data{ $columns[0] }{'alias'} = $columns[2]; } say dump(%data); __DATA__ "GSBDTD1831";"nbSm3Bh";"App.-Server MAIN";"user@example.com";"10.100.0 +.2" "GSBTD1832";"nbSm3haz";"Appl.-Server Aux";"user1@example.com";"10.100. +0.3" "GSTD1822";"denJdkep64";"Printserver";"user3@example.com";"192.168.91. +1" "GSTD1822";"denJdw0a22";"Printserver";"user4@example.com";"192.168.91. +2" "GSTD1822";"nbSwgP14a";"Printserver";"user5@example.com";"192.168.91.5 +" "GSTD1983";"nbgwgxOrO";"Server2";"user5@example.com";"10.1.1.22"
    Pulling the individual data out of the datastructure is easy. Try it and if you are having problems, come back here again and we will help you some more.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics
Re: groups maker
by choroba (Cardinal) on May 27, 2012 at 12:47 UTC
    I do not understand your $#members = -1 code. But this works for me:
    #!/usr/bin/perl use warnings; use strict; use feature 'say'; open my $IN, '<', '1.csv' or die $!; my %groups; while (<$IN>) { chomp; s/"//g; my ($group_id, $member, $group_descr) = split /;/; if (exists $groups{$group_id}) { die 'Invalid group description: ' . "$group_descr != $groups{$group_id}{descr}\n" if $group_descr ne $groups{$group_id}{descr}; die "Duplicate member $member in $group_id\n" if exists $groups{$group_id}{$member}; } else { $groups{$group_id}{descr} = $group_descr; } undef $groups{$group_id}{member}{$member}; } for my $group_id (keys %groups) { my $group = $groups{$group_id}; say 'define hostgroup {'; say " hostgroup_name $group_id"; $group->{descr} .= 's' if keys %{ $group->{member} } > 1; say " alias $group->{descr}"; say ' members ', join ',', keys %{ $group->{member} }; say '}'; }
    Contact and IP are never used, so I removed them.
      Thank you very much for your reply, this example really helped, and even more. important for me, I understood how your code works :).
Re: groups maker
by ww (Archbishop) on May 27, 2012 at 21:34 UTC
    Please... code tags are for data, as well as code!

    And one can't message Anonymonk privately to suggest that you note the instruction below the data entry box... so this will have to do. And since you can't edit the OP, either, that's work for the janitors.

    So, two suggestions: 1) read all instructions; 2) register for enhanced access and capabilities.