I have written a test script to perform certain functions. Script works as expected. Currently,The arguments required to run the script are passed from the command line using Getopt::Long
.I would like to move the command line arguments to a json file. The Endpoint ip will still be passed as command line arg.
I want the endpoint ip to act as a key. For instance, if the endpoint is 1.1.1.1, I want to get the client_ip,client_interface_ip,originip,....,port that is listed under endpoint id 1.1.1.1 in the json config file mentioned below. How do i do that ?
current version of the script:
use Getopt::Long;
my ($self) = @_;
GetOptions (
"endpoint|e=s" => \$self->{'endpoint'},
"aggregator|a=s" => \$self->{'aggregator'},
"port|pt=s" => \$self->{'port'},
"client|c=s" => \$self->{'client'},
"client_interface|ci=s" => \$self->{'client_interface'},
"origin|o=s" => \$self->{'origin'},
"origin_interface|oi=s" => \$self->{'origin_interface'},
"interfacename|ot=s" => \$self->{'i1'},
"interfacename2|it=s" => \$self->{'i2'},
) || $self->abort( "Invalid command line options.
Valid options are endpoint,aggregator,port,client,client_interface,
origin,origin_interface,outertunnel,innertunnel,");
#Terminate the script execution if the reqd args are not passed
my @required_args = qw(endpoint aggregator port client client_interface origin origin_interface
);
for my $command_line_arguments (@required_args) {
unless ($self->{$command_line_arguments}) {
$self->abort('missing required argument ' . $command_line_arguments);
}
}
$self->{'tObj'} = QA::crypto::tunnels->new
('host'=> $self->{'endpoint'})
or $self->abort('[Could not create a QA::Crypto::tunnels object.]');
json file for arguments:
{
"Endpoints": [{
"endpoint": "1.1.1.1",
"client_ip": "3.4.5.6",
"client_interface_ip": "10.11.12.14",
"origin": "a.a.a.a",
"origin_interface": "15.16.17.18",
"interfacename": "name",
"interfacename2": "name1",
"sl": 19,
"port": 362
}, {
"endpoint": "2.2.2.2",
"client_ip": "19.20.21.22",
"client_interface_ip": "23.24.25.26",
"origin": "1.2.3.4",
"origin_interface": "5.6.7.8",
"interfacename": "interface name",
"interfacename2": "interfacename_2",
"sl": 19,
"port": 366
}]
}
#!/usr/bin/perl
use strict;
use warnings;
use JSON;
my $json;
{
open my $fh, "<", "cfg.txt"
or die("Can't open file \"cfg.json\": $!\n");
local $/;
$json = <$fh>;
}
my $data = decode_json($json);
$json = JSON->new->utf8->pretty->encode($data);
The first question is about a suitable design for the JSON file. Hashes can serve well here while the arrayref doesn't seem needed at all. The endpoint values can be the keys, with their values being hashrefs with key-related information. Keep the endpoint value in its hashref as well, if you wish.
The key "Endpoints"
in your JSON doesn't seem to do much as it stands. But if you do need it, perhaps since there will be other types of keys, then you could have for its value another hashref, which will contain the hashref with endpoint values as keys.
For example
{ "Endpoints": { "1.1.1.1": { "client_ip": "3.4.5.6", ... }, "2.2.2.2": { "client_ip": "19.20.21.22", ... }, ... }, "OtherKeys": { ... }, ... }
The last values should not end with commas. See JSON format.
When you bring this into Perl you'll have nested hashrefs, like
$data = {
Endpoints => {
1.1.1.1 => { client_ip => '3.4.5.6', ... },
2.2.2.2 => { client_ip => '19.20.21.22', ... },
},
OtherKeys => { ... },
};
Then the values are retrieved simply as
my $client_ip = $data->{Endpoints}{'1.1.1.1'}{client_ip};
For example, retreive all endpoints and list client_ip
for them
my @endpoints = keys %{$data->{Endpoints}};
foreach my $ip (@endpoints) {
say $data->{Endpoints}{$ip}{client_ip};
}
See Using References in perlref, and this post is entirely about it. Also see perlreftut and perldsc.
We can inspect (see) the whole data structure with Data::Dumper
use Data::Dumper;
my $data = decode_json($json);
print Dumper($data);
There is a number of other packages for working with nested data structures.
Note that the JSON package comes with encode_json
and related methods, so you can create that file programmatically. This may help in getting its format right and with maintenance in the future.