587 lines
14 KiB
Perl
587 lines
14 KiB
Perl
package ZabbixAPI;
|
|
use Data::Dumper;
|
|
use LWP;
|
|
use JSON::XS;
|
|
use MIME::Base64 qw(encode_base64);
|
|
|
|
my @no_auth_methods = ('user.login','apiinfo.version');
|
|
sub new {
|
|
my $class = shift;
|
|
my $args = shift;
|
|
|
|
my $api_url = $args->{api_url}
|
|
|| 'http://localhost/zabbix/api_jsonrpc.php';
|
|
my $username = $args->{username} || 'Admin';
|
|
my $password = $args->{password} || 'zabbix';
|
|
|
|
my $self = bless {
|
|
api_url => $api_url,
|
|
username => $username,
|
|
password => $password,
|
|
ua => LWP::UserAgent->new(),
|
|
auth => undef,
|
|
id => 1,
|
|
}, $class;
|
|
|
|
$self->{req} = HTTP::Request->new( POST => $self->{api_url} );
|
|
$self->{req}->content_type('application/json-rpc');
|
|
|
|
return $self;
|
|
}
|
|
sub id {
|
|
my $self = shift;
|
|
return $self->{id}++;
|
|
}
|
|
|
|
|
|
sub prepare_auth {
|
|
my $self = shift;
|
|
my $method = shift;
|
|
|
|
if (grep /$method/,@no_auth_methods) {
|
|
return undef;
|
|
}
|
|
else
|
|
{
|
|
return $self->{auth};
|
|
}
|
|
};
|
|
|
|
sub do {
|
|
|
|
my $self = shift;
|
|
my $method = shift;
|
|
my $params = shift;
|
|
|
|
my $json = JSON::XS->new->utf8->encode(
|
|
{
|
|
jsonrpc => '2.0',
|
|
method => $method,
|
|
params => $params,
|
|
id => $self->id,
|
|
auth => $self->prepare_auth($method)
|
|
}
|
|
);
|
|
|
|
|
|
|
|
$self->{req}->content($json);
|
|
|
|
# Pass request to the user agent and get a response back
|
|
my $res = $self->{ua}->request( $self->{req} );
|
|
|
|
# Check the outcome of the response
|
|
if ( $res->is_success ) {
|
|
|
|
my $return = JSON::XS->new->utf8->decode( $res->content );
|
|
die $return->{error}->{data}."\n" if $return->{error};
|
|
return $return->{result};
|
|
}
|
|
else {
|
|
die $res->status_line, "\n";
|
|
}
|
|
|
|
}
|
|
|
|
sub do_raw {
|
|
|
|
my $self = shift;
|
|
my $method = shift;
|
|
my $params = shift;
|
|
|
|
my $json = JSON::XS->new->utf8->encode(
|
|
{
|
|
jsonrpc => '2.0',
|
|
method => $method,
|
|
params => JSON::XS->new->utf8->decode($params),
|
|
id => $self->id,
|
|
auth => $self->prepare_auth($method)
|
|
}
|
|
);
|
|
|
|
|
|
$self->{req}->content($json);
|
|
|
|
# Pass request to the user agent and get a response back
|
|
my $res = $self->{ua}->request( $self->{req} );
|
|
|
|
# Check the outcome of the response
|
|
if ( $res->is_success ) {
|
|
my $return = JSON::XS->new->utf8->decode( $res->content );
|
|
die $return->{error}->{data}."\n" if $return->{error};
|
|
return $return->{result};
|
|
}
|
|
else {
|
|
die $res->status_line, "\n";
|
|
}
|
|
|
|
|
|
}
|
|
|
|
sub import_configuration_from_file {
|
|
my $self = shift;
|
|
my $file = shift;
|
|
my $configuration;
|
|
{
|
|
local $/ = undef;
|
|
open(my $fh,'<:encoding(UTF-8)', $file) or die "Error opening $file: $!";
|
|
|
|
$configuration = <$fh>;
|
|
close $fh;
|
|
}
|
|
|
|
my $json = <<'END_PARAMS';
|
|
{
|
|
"format": "xml",
|
|
"rules": {
|
|
"groups": {
|
|
"createMissing": true
|
|
},
|
|
"hosts": {
|
|
"createMissing": true,
|
|
"updateExisting": true
|
|
},
|
|
"templates": {
|
|
"createMissing": true,
|
|
"updateExisting": true
|
|
},
|
|
"templateLinkage": {
|
|
"createMissing": true
|
|
},
|
|
"templateScreens": {
|
|
"createMissing": true,
|
|
"updateExisting": true,
|
|
"deleteMissing": true
|
|
},
|
|
"applications": {
|
|
"createMissing": true,
|
|
"deleteMissing": true
|
|
},
|
|
"discoveryRules": {
|
|
"createMissing": true,
|
|
"updateExisting": true,
|
|
"deleteMissing": true
|
|
},
|
|
"items": {
|
|
"createMissing": true,
|
|
"updateExisting": true,
|
|
"deleteMissing": true
|
|
},
|
|
"triggers": {
|
|
"createMissing": true,
|
|
"updateExisting": true,
|
|
"deleteMissing": true
|
|
},
|
|
"graphs": {
|
|
"createMissing": true,
|
|
"updateExisting": true,
|
|
"deleteMissing": true
|
|
},
|
|
"screens": {
|
|
"createMissing": true,
|
|
"updateExisting": true
|
|
},
|
|
"maps": {
|
|
"createMissing": true,
|
|
"updateExisting": true
|
|
},
|
|
"images": {
|
|
"createMissing": true,
|
|
"updateExisting": true
|
|
},
|
|
"valueMaps": {
|
|
"createMissing": true,
|
|
"updateExisting": true
|
|
}
|
|
|
|
},
|
|
"source": ""
|
|
}
|
|
END_PARAMS
|
|
my $params = JSON::XS->new->utf8->decode($json);
|
|
$params->{source}=$configuration;
|
|
$self->do('configuration.import', $params);
|
|
|
|
|
|
|
|
}
|
|
|
|
sub login {
|
|
my $self = shift;
|
|
my $params = {
|
|
user => $self->{username},
|
|
password => $self->{password}
|
|
};
|
|
my $content = $self->do("user.login",$params);
|
|
$self->{auth}=$content;
|
|
|
|
}
|
|
|
|
sub logout {
|
|
my $self = shift;
|
|
$self->do( 'user.logout', {} );
|
|
}
|
|
|
|
|
|
sub create_or_update_mediatype {
|
|
|
|
my $self = shift;
|
|
my $params = shift;
|
|
my $result;
|
|
eval { #try to create JSON
|
|
$result = $self->do('mediatype.create', $params);
|
|
};
|
|
if ($@) {
|
|
if($@ =~ /already exists/) {
|
|
warn "WARN: $params->{description} already exists. Updating instead..."."\n";
|
|
#get mediatypeid
|
|
$json = { output => ['mediatypeid'], filter =>{description=>[$params->{description}]}};
|
|
my $id = $self->do('mediatype.get',$json);
|
|
$params->{mediatypeid}= $id->[0]->{mediatypeid};
|
|
#update instead of creating....
|
|
$result = $self->do('mediatype.update', $params);
|
|
return $result;
|
|
}
|
|
else {
|
|
|
|
die $@;
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
return $result;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
sub create_or_update_user {
|
|
|
|
my $self = shift;
|
|
my $params = shift;
|
|
my $result;
|
|
eval { #try to create JSON
|
|
$result = $self->do('user.create', $params);
|
|
};
|
|
if ($@) {
|
|
if($@ =~ /already exists/) {
|
|
warn "WARN: $params->{alias} already exists. Updating instead..."."\n";
|
|
#get mediatypeid
|
|
$json = { output => ['userid'], filter =>{alias=>[$params->{alias}]}};
|
|
my $id = $self->do('user.get',$json);
|
|
|
|
$params->{userid}= $id->[0]->{userid};
|
|
#update instead of creating....
|
|
my $medias = $params->{user_medias}->[0];
|
|
|
|
delete $params->{user_medias}; # remove user_medias, not possible in 'user.update' call
|
|
$result = $self->do('user.update', $params);
|
|
|
|
my $result_media = $self->do('user.updatemedia',{users => [ {userid=>$params->{userid}} ],
|
|
medias => $medias
|
|
});
|
|
|
|
return $result;
|
|
}
|
|
else {
|
|
|
|
die $@;
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
sub create_or_update_action {
|
|
|
|
my $self = shift;
|
|
my $params = shift;
|
|
my $result;
|
|
eval { #try to create JSON
|
|
$result = $self->do('action.create', $params);
|
|
};
|
|
if ($@) {
|
|
if($@ =~ /already exists/) {
|
|
warn "WARN: $params->{name} already exists. Updating instead..."."\n";
|
|
#get mediatypeid
|
|
$json = { output => ['actionid'], filter =>{name=>[$params->{name}]}};
|
|
my $id = $self->do('action.get',$json);
|
|
$params->{actionid}= $id->[0]->{actionid};
|
|
#update instead of creating....
|
|
delete $params->{eventsource}; #cannot be update, must be removed
|
|
$result = $self->do('action.update', $params);
|
|
return $result;
|
|
}
|
|
else {
|
|
|
|
die $@;
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
sub create_or_update_drule {
|
|
|
|
my $self = shift;
|
|
my $params = shift;
|
|
my $result;
|
|
eval { #try to create JSON
|
|
$result = $self->do('drule.create', $params);
|
|
};
|
|
if ($@) {
|
|
if($@ =~ /already exists/) {
|
|
warn "WARN: $params->{name} already exists. Updating instead..."."\n";
|
|
$json = { output => ['druleid'], filter =>{name=>[$params->{name}]}};
|
|
my $id = $self->do('drule.get',$json);
|
|
$params->{druleid}= $id->[0]->{druleid};
|
|
#update instead of creating....
|
|
$result = $self->do('drule.update', $params);
|
|
return $result;
|
|
}
|
|
else {
|
|
|
|
die $@;
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
sub get_template_id {
|
|
|
|
my $self = shift;
|
|
my $template_name = shift;
|
|
|
|
my $json = { output => ['host','templateid'], filter =>{host=>[$template_name]}};
|
|
my $result = $self->do('template.get',$json);
|
|
return $result->[0]->{templateid};
|
|
|
|
}
|
|
|
|
sub get_hostgroup_id {
|
|
|
|
my $self = shift;
|
|
my $hgroup_name = shift;
|
|
|
|
my $json = { output => ['groupid'], filter =>{name=>[$hgroup_name]}};
|
|
my $result = $self->do('hostgroup.get',$json);
|
|
return $result->[0]->{groupid};
|
|
|
|
}
|
|
|
|
|
|
sub get_host_id {
|
|
|
|
my $self = shift;
|
|
my $host_name = shift;
|
|
|
|
my $json = { output => ['hostid'], filter =>{host=>[$host_name]}};
|
|
my $result = $self->do('host.get',$json);
|
|
return $result->[0]->{hostid};
|
|
|
|
}
|
|
|
|
sub get_host_by_name {
|
|
|
|
my $self = shift;
|
|
my $host_name = shift;
|
|
|
|
my $json = {
|
|
output => ['hostid'],
|
|
filter =>{host=>[$host_name]},
|
|
selectGroups => ['groupid','name'],
|
|
selectParentTemplates => ['templateid','name'],
|
|
selectMacros => ['macro','value']
|
|
};
|
|
my $result = $self->do('host.get',$json);
|
|
return $result->[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
sub create_or_merge_host {
|
|
|
|
my $self = shift;
|
|
my $host_name = shift;
|
|
my $params = shift;
|
|
my $result;
|
|
|
|
my $hostid = $self->get_host_id($host_name);
|
|
|
|
if ($hostid) {
|
|
print "WARN: Cannot create host $host_name ... going to merge instead\n";
|
|
#print $hostid."\n";
|
|
#update (merge mode currently)
|
|
$params->{hostid}=$hostid;
|
|
|
|
my $host = $self->get_host_by_name($host_name);
|
|
if ($params->{templates}) {
|
|
#merge with already existed
|
|
my @templates;
|
|
foreach my $template (@{$params->{templates}}){
|
|
push @templates,$template->{templateid};
|
|
}
|
|
foreach my $template (@{$host->{parentTemplates}}){
|
|
push @templates,$template->{templateid};
|
|
}
|
|
my %seen = (); # see http://perldoc.perl.org/perlfaq4.html#How-can-I-remove-duplicate-elements-from-a-list-or-array%3f
|
|
|
|
@templates = grep { ! $seen{ $_ }++ } @templates;
|
|
|
|
my $i=0;
|
|
delete $params->{templates};
|
|
foreach my $templateid (@templates) {
|
|
$params->{templates}->[$i]->{templateid} = $templateid;
|
|
$i++;
|
|
}
|
|
|
|
}
|
|
|
|
if ($params->{groups}) {
|
|
#merge with already existed
|
|
my @groups;
|
|
foreach my $group (@{$params->{groups}}){
|
|
push @groups,$group->{groupid};
|
|
}
|
|
foreach my $group (@{$host->{groups}}){
|
|
push @groups,$group->{groupid};
|
|
}
|
|
my %seen = (); # see http://perldoc.perl.org/perlfaq4.html#How-can-I-remove-duplicate-elements-from-a-list-or-array%3f
|
|
|
|
@groups = grep { ! $seen{ $_ }++ } @groups;
|
|
|
|
my $i=0;
|
|
delete $params->{groups};
|
|
foreach my $groupid (@groups) {
|
|
$params->{groups}->[$i]->{groupid} = $groupid;
|
|
$i++;
|
|
}
|
|
|
|
}
|
|
|
|
if ($params->{macros}) {
|
|
#merge with already existed
|
|
my @macros;
|
|
foreach my $macro (@{$params->{macros}}){
|
|
push @macros,
|
|
{
|
|
macro => $macro->{macro},
|
|
value => $macro->{value}
|
|
};
|
|
}
|
|
foreach my $macro (@{$host->{macros}}){
|
|
push @macros,
|
|
{
|
|
macro => $macro->{macro},
|
|
value => $macro->{value}
|
|
};
|
|
}
|
|
my %seen = (); # see http://perldoc.perl.org/perlfaq4.html#How-can-I-remove-duplicate-elements-from-a-list-or-array%3f
|
|
@macros = grep { ! $seen{ $_->{macro} }++ } @macros;
|
|
|
|
my $i=0;
|
|
delete $params->{macros};
|
|
|
|
foreach my $macro (@macros) {
|
|
$params->{macros}->[$i] = $macro;
|
|
$i++;
|
|
}
|
|
|
|
}
|
|
|
|
if ($params->{interfaces}) {
|
|
#merge with already existed
|
|
#warn "WARN: host interfaces merge is not supported yet... skipping interfaces part\n";
|
|
delete $params->{interfaces};
|
|
}
|
|
|
|
#print Dumper $params;
|
|
$result = $self->do('host.update', $params);
|
|
|
|
}
|
|
else {
|
|
#create
|
|
$params->{host}=$host_name;
|
|
#print Dumper $params;
|
|
$result = $self->do('host.create', $params);
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
|
|
}
|
|
|
|
|
|
sub import_image_from_file {
|
|
my $self = shift;
|
|
my $file = shift;
|
|
my $imagename = shift || $file;
|
|
my $imagetype = shift || 1; # 1 - icon , 2 - background
|
|
my $image;
|
|
my $result;
|
|
my $json;
|
|
{
|
|
local $/ = undef;
|
|
open(my $fh,, $file) or die "Error opening $file: $!";
|
|
|
|
$image = <$fh>;
|
|
close $fh;
|
|
}
|
|
|
|
my $params = {name => $imagename, imagetype => 1, image => encode_base64($image)};
|
|
|
|
eval {#try to import image
|
|
$result = $self->do('image.create', $params);
|
|
};
|
|
if ($@) {
|
|
if($@ =~ /already exists/) {
|
|
warn "WARN: $params->{name} already exists. Updating instead..."."\n";
|
|
#get imageid and update instead
|
|
$json = { output => ['imageid'], filter =>{name=>[$params->{name}]}};
|
|
my $id = $self->do('image.get',$json);
|
|
$params->{imageid}= $id->[0]->{imageid};
|
|
delete($params->{imagetype});
|
|
#update instead of creating....
|
|
$result = $self->do('image.update', $params);
|
|
return $result;
|
|
}
|
|
else {
|
|
|
|
die $@;
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
return $result;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
1; |