(plugin) network::cisco::meraki::cloudcontroller::restapi - change cache system + add pagination (#3466)

This commit is contained in:
qgarnier 2022-02-07 14:18:57 +01:00 committed by GitHub
parent ecd1e325d0
commit 4dd19e3035
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 444 additions and 585 deletions

View File

@ -50,11 +50,8 @@ sub new {
'timeout:s' => { name => 'timeout' }, 'timeout:s' => { name => 'timeout' },
'reload-cache-time:s' => { name => 'reload_cache_time' }, 'reload-cache-time:s' => { name => 'reload_cache_time' },
'ignore-permission-errors' => { name => 'ignore_permission_errors' }, 'ignore-permission-errors' => { name => 'ignore_permission_errors' },
'use-extra-cache' => { name => 'use_extra_cache' }, 'timespan:s' => { name => 'timespan' },
'reload-extra-cache-time:s' => { name => 'reload_extra_cache_time' }, 'cache-use' => { name => 'cache_use' }
'trace-api:s' => { name => 'trace_api' },
'trace-api-response:s' => { name => 'trace_api_response' },
'api-requests-disabled' => { name => 'api_requests_disabled' }
}); });
} }
$options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1);
@ -62,17 +59,12 @@ sub new {
$self->{output} = $options{output}; $self->{output} = $options{output};
$self->{http} = centreon::plugins::http->new(%options); $self->{http} = centreon::plugins::http->new(%options);
$self->{cache} = centreon::plugins::statefile->new(%options); $self->{cache} = centreon::plugins::statefile->new(%options);
$self->{cache_checked} = 0;
$self->{cache_extra_checked} = 0; $self->{datas} = {
$self->{cached} = {
updated => 0,
uplink_statuses => {}, uplink_statuses => {},
uplinks_loss_latency => {}, uplinks_loss_latency => {}
devices_statuses => {},
devices_connection_stats => {},
devices_performance => {},
devices_clients => {}
}; };
$self->{devices_connection_stats} = {};
return $self; return $self;
} }
@ -96,6 +88,7 @@ sub check_options {
$self->{reload_cache_time} = (defined($self->{option_results}->{reload_cache_time})) ? $self->{option_results}->{reload_cache_time} : 180; $self->{reload_cache_time} = (defined($self->{option_results}->{reload_cache_time})) ? $self->{option_results}->{reload_cache_time} : 180;
$self->{reload_extra_cache_time} = (defined($self->{option_results}->{reload_extra_cache_time})) ? $self->{option_results}->{reload_extra_cache_time} : 10; $self->{reload_extra_cache_time} = (defined($self->{option_results}->{reload_extra_cache_time})) ? $self->{option_results}->{reload_extra_cache_time} : 10;
$self->{ignore_permission_errors} = (defined($self->{option_results}->{ignore_permission_errors})) ? 1 : 0; $self->{ignore_permission_errors} = (defined($self->{option_results}->{ignore_permission_errors})) ? 1 : 0;
$self->{timespan} = (defined($self->{option_results}->{timespan})) ? $self->{option_results}->{timespan} : 300;
if (!defined($self->{hostname}) || $self->{hostname} eq '') { if (!defined($self->{hostname}) || $self->{hostname} eq '') {
$self->{output}->add_option_msg(short_msg => "Need to specify --hostname option."); $self->{output}->add_option_msg(short_msg => "Need to specify --hostname option.");
@ -106,19 +99,8 @@ sub check_options {
$self->{output}->option_exit(); $self->{output}->option_exit();
} }
if (defined($self->{option_results}->{trace_api})) { # we force to use storable module
centreon::plugins::misc::mymodule_load( $self->{option_results}->{statefile_storable} = 1;
output => $self->{output},
module => 'Time::HiRes',
error_msg => "Cannot load module 'Time::HiRes'."
);
centreon::plugins::misc::mymodule_load(
output => $self->{output},
module => 'POSIX',
error_msg => "Cannot load module 'POSIX'."
);
}
$self->{cache}->check_options(option_results => $self->{option_results}); $self->{cache}->check_options(option_results => $self->{option_results});
return 0; return 0;
} }
@ -129,44 +111,21 @@ sub get_token {
return md5_hex($self->{api_token}); return md5_hex($self->{api_token});
} }
sub trace_api {
my ($self, %options) = @_;
my $trace_file = $self->{option_results}->{trace_api} ne '' ? $self->{option_results}->{trace_api} : '/tmp/cisco_meraki_plugins.trace';
open(FH, '>>', $trace_file) or return ;
my $date_start = POSIX::strftime('%Y%m%d %H:%M:%S', localtime($options{time_start}));
$date_start .= sprintf('.%03d', ($options{time_start} - int($options{time_start})) * 1000);
my $time_end = Time::HiRes::time();
my $date_end = POSIX::strftime('%Y%m%d %H:%M:%S', localtime($time_end));
$date_end .= sprintf('.%03d', ($time_end - int($time_end)) * 1000);
print FH "$date_start - $date_end - $$ - $self->{api_token} - $options{url} - $options{code}\n";
if (defined($self->{option_results}->{trace_api_response})) {
if ($self->{option_results}->{trace_api_response} =~ /(\d+)/ && length($options{response}) < $1) {
print FH $options{response} . "\n";
} else {
print FH $options{response} . "\n";
}
}
close FH;
}
sub get_shard_hostname { sub get_shard_hostname {
my ($self, %options) = @_; my ($self, %options) = @_;
my $organization_id = $options{organization_id}; my $organization_id = $options{organization_id};
my $network_id = $options{network_id}; my $network_id = $options{network_id};
if (defined($options{serial}) && defined($self->{cache_devices}->{ $options{serial} })) { if (defined($options{serial}) && defined($self->{datas}->{devices}->{ $options{serial} })) {
$network_id = $self->{cache_devices}->{ $options{serial} }->{networkId}; $network_id = $self->{datas}->{devices}->{ $options{serial} }->{networkId};
} }
if (defined($network_id) && defined($self->{cache_networks}->{$network_id})) { if (defined($network_id) && defined($self->{datas}->{networks}->{$network_id})) {
$organization_id = $self->{cache_networks}->{$network_id}->{organizationId}; $organization_id = $self->{datas}->{networks}->{$network_id}->{organizationId};
} }
if (defined($organization_id)) { if (defined($organization_id)) {
if (defined($self->{cache_organizations}->{$organization_id}) if (defined($self->{datas}->{orgs}->{$organization_id})
&& $self->{cache_organizations}->{$organization_id}->{url} =~ /^(?:http|https):\/\/(.*?)\//) { && $self->{datas}->{orgs}->{$organization_id}->{url} =~ /^(?:http|https):\/\/(.*?)\//) {
return $1; return $1;
} }
} }
@ -174,49 +133,6 @@ sub get_shard_hostname {
return undef; return undef;
} }
sub get_cache_organizations {
my ($self, %options) = @_;
$self->cache_meraki_entities();
return $self->{cache_organizations};
}
sub get_cache_networks {
my ($self, %options) = @_;
$self->cache_meraki_entities();
return $self->{cache_networks};
}
sub get_organization {
my ($self, %options) = @_;
$self->cache_meraki_entities();
my $organization_id;
if (defined($options{network_id})) {
$organization_id = $self->{cache_networks}->{ $options{network_id} }->{organizationId};
}
my $organization;
$organization = $self->{cache_organizations}->{$organization_id}
if (defined($organization_id) && defined($self->{cache_organizations}->{$organization_id}));
return $organization;
}
sub get_organization_id {
my ($self, %options) = @_;
$self->cache_meraki_entities();
return $self->{cache_networks}->{ $options{network_id} }->{organizationId};
}
sub get_cache_devices {
my ($self, %options) = @_;
$self->cache_meraki_entities();
return $self->{cache_devices};
}
sub build_options_for_httplib { sub build_options_for_httplib {
my ($self, %options) = @_; my ($self, %options) = @_;
@ -236,8 +152,6 @@ sub settings {
sub request_api { sub request_api {
my ($self, %options) = @_; my ($self, %options) = @_;
return undef if (defined($self->{option_results}->{api_requests_disabled}));
$self->settings(); $self->settings();
my $hostname = $self->{hostname}; my $hostname = $self->{hostname};
@ -249,20 +163,23 @@ sub request_api {
#403: Forbidden- You don't have permission to do that. #403: Forbidden- You don't have permission to do that.
#404: Not found- No such URL, or you don't have access to the API or organization at all. #404: Not found- No such URL, or you don't have access to the API or organization at all.
#429: Too Many Requests- You submitted more than 5 calls in 1 second to an Organization, triggering rate limiting. This also applies for API calls made across multiple organizations that triggers rate limiting for one of the organizations. #429: Too Many Requests- You submitted more than 5 calls in 1 second to an Organization, triggering rate limiting. This also applies for API calls made across multiple organizations that triggers rate limiting for one of the organizations.
my $time_start; my $results = [];
my ($full_url, $get_param);
if (defined($options{paginate})) {
$get_param = ['perPage=' . $options{paginate}];
}
while (1) { while (1) {
$time_start = Time::HiRes::time() if (defined($self->{option_results}->{trace_api}));
my $response = $self->{http}->request( my $response = $self->{http}->request(
full_url => $full_url,
hostname => $hostname, hostname => $hostname,
url_path => '/api/v1' . $options{endpoint}, url_path => '/api/v1' . $options{endpoint},
get_param => $get_param,
critical_status => '', critical_status => '',
warning_status => '', warning_status => '',
unknown_status => '' unknown_status => ''
); );
my $code = $self->{http}->get_code(); my $code = $self->{http}->get_code();
$self->trace_api(time_start => $time_start, url => $hostname . '/api/v1' . $options{endpoint}, code => $code, response => $response)
if (defined($self->{option_results}->{trace_api}));
return [] if ($code == 403 && $self->{ignore_permission_errors} == 1); return [] if ($code == 403 && $self->{ignore_permission_errors} == 1);
return undef if (defined($options{ignore_codes}) && defined($options{ignore_codes}->{$code})); return undef if (defined($options{ignore_codes}) && defined($options{ignore_codes}->{$code}));
@ -286,121 +203,288 @@ sub request_api {
$self->{output}->option_exit(); $self->{output}->option_exit();
} }
if (defined($options{paginate})) {
push @$results, @$content;
my ($link) = $self->{http}->get_header(name => 'Link');
return $results if (!defined($link) || $link !~ /,\s+<([^;]*?)>;\s+rel=next/);
$get_param = undef;
$full_url = $1;
next;
}
return ($content); return ($content);
} }
} }
sub cache_meraki_entities { sub write_cache_file {
my ($self, %options) = @_; my ($self, %options) = @_;
return if ($self->{cache_checked} == 1); $self->{cache}->read(statefile => 'cache_meraki_' . md5_hex($self->{api_token}));
$self->{cache}->write(data => {
update_time => time(),
response => $self->{datas}
});
}
$self->{cache_checked} = 1; sub get_cache_file_response {
my $has_cache_file = $self->{cache}->read(statefile => 'cache_cisco_meraki_' . $self->get_token()); my ($self, %options) = @_;
my $timestamp_cache = $self->{cache}->get(name => 'last_timestamp');
$self->{cache_organizations} = $self->{cache}->get(name => 'organizations');
$self->{cache_networks} = $self->{cache}->get(name => 'networks');
$self->{cache_devices} = $self->{cache}->get(name => 'devices');
if ($has_cache_file == 0 || !defined($timestamp_cache) || ((time() - $timestamp_cache) > (($self->{reload_cache_time}) * 60))) { $self->{cache}->read(statefile => 'cache_meraki_' . md5_hex($self->{api_token}));
$self->{cache_organizations} = $self->get_organizations( $self->{datas} = $self->{cache}->get(name => 'response');
disable_cache => 1 if (!defined($self->{datas})) {
); $self->{output}->add_option_msg(short_msg => 'Cache file missing');
$self->{cache_networks} = $self->get_networks( $self->{output}->option_exit();
organizations => [keys %{$self->{cache_organizations}}],
disable_cache => 1
);
$self->{cache_devices} = $self->get_devices(
organizations => [keys %{$self->{cache_organizations}}],
disable_cache => 1
);
$self->{cache}->write(data => {
last_timestamp => time(),
organizations => $self->{cache_organizations},
networks => $self->{cache_networks},
devices => $self->{cache_devices}
});
} }
return $self->{datas};
}
sub call_datas {
my ($self, %options) = @_;
$self->get_organizations();
$self->get_networks(orgs => [keys %{$self->{datas}->{orgs}}]);
if (!defined($options{skipDevices})) {
$self->get_devices(orgs => [keys %{$self->{datas}->{orgs}}]);
}
if (!defined($options{skipDevicesStatus})) {
$self->get_organization_device_statuses(orgs => [keys %{$self->{datas}->{orgs}}]);
}
if (defined($options{cache})) {
foreach my $orgId (keys %{$self->{datas}->{orgs}}) {
$self->get_network_device_uplink(orgId => $orgId);
}
foreach my $orgId (keys %{$self->{datas}->{orgs}}) {
$self->get_organization_uplink_loss_and_latency(orgId => $orgId);
}
}
}
sub cache_datas {
my ($self, %options) = @_;
$self->call_datas(cache => 1);
$self->write_cache_file();
return $self->{datas};
}
sub get_datas {
my ($self, %options) = @_;
return $self->get_cache_file_response() if (defined($self->{option_results}->{cache_use}));
$self->call_datas(%options);
return $self->{datas};
} }
sub get_organizations { sub get_organizations {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->cache_meraki_entities();
return $self->{cache_organizations} if (!defined($options{disable_cache}) || $options{disable_cache} == 0);
my $datas = $self->request_api(endpoint => '/organizations'); my $datas = $self->request_api(endpoint => '/organizations');
my $results = {}; $self->{datas}->{orgs} = {};
if (defined($datas)) { if (defined($datas)) {
$results->{$_->{id}} = $_ foreach (@$datas); foreach (@$datas) {
$self->{datas}->{orgs}->{ $_->{id} } = {
name => $_->{name},
url => $_->{url}
};
}
} }
return $results; return $self->{datas}->{orgs};
} }
sub get_networks { sub get_networks {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->cache_meraki_entities(); $self->{datas}->{networks} = {};
return $self->{cache_networks} if (!defined($options{disable_cache}) || $options{disable_cache} == 0); foreach my $id (@{$options{orgs}}) {
my $results = {};
foreach my $id (keys %{$self->{cache_organizations}}) {
my $datas = $self->request_api( my $datas = $self->request_api(
endpoint => '/organizations/' . $id . '/networks', endpoint => '/organizations/' . $id . '/networks',
hostname => $self->get_shard_hostname(organization_id => $id) hostname => $self->get_shard_hostname(organization_id => $id)
); );
if (defined($datas)) { if (defined($datas)) {
$results->{ $_->{id} } = $_ foreach (@$datas); foreach (@$datas) {
if (defined($options{extended})) {
$self->{datas}->{networks}->{ $_->{id} } = $_;
} else {
$self->{datas}->{networks}->{ $_->{id} } = {
name => $_->{name},
organizationId => $_->{organizationId}
};
}
}
} }
} }
return $results; return $self->{datas}->{networks};
} }
sub get_devices { sub get_devices {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->cache_meraki_entities(); $self->{datas}->{devices} = {};
return $self->{cache_devices} if (!defined($options{disable_cache}) || $options{disable_cache} == 0); foreach my $id (@{$options{orgs}}) {
my $results = {};
foreach my $id (keys %{$self->{cache_organizations}}) {
my $datas = $self->request_api( my $datas = $self->request_api(
endpoint => '/organizations/' . $id . '/devices', endpoint => '/organizations/' . $id . '/devices',
paginate => 1000,
hostname => $self->get_shard_hostname(organization_id => $id) hostname => $self->get_shard_hostname(organization_id => $id)
); );
if (defined($datas)) { if (defined($datas)) {
$results->{ $_->{serial} } = $_ foreach (@$datas); foreach (@$datas) {
if (defined($options{extended})) {
$self->{datas}->{devices}->{ $_->{serial} } = $_;
$self->{datas}->{devices}->{ $_->{serial} }->{orgId} = $id;
} else {
$self->{datas}->{devices}->{ $_->{serial} } = {
name => $_->{name},
networkId => $_->{networkId},
orgId => $id,
tags => $_->{tags},
model => $_->{model}
};
}
}
} }
} }
return $self->{datas}->{devices};
}
sub get_organization_device_statuses {
my ($self, %options) = @_;
$self->{datas}->{devices_status} = {};
foreach my $id (@{$options{orgs}}) {
my $datas = $self->request_api(
endpoint => '/organizations/' . $id . '/devices/statuses',
paginate => 1000,
hostname => $self->get_shard_hostname(organization_id => $id)
);
foreach (@$datas) {
if (defined($options{extended})) {
$self->{datas}->{devices_status}->{ $_->{serial} } = $_;
} else {
$self->{datas}->{devices_status}->{ $_->{serial} } = {
status => $_->{status}
};
}
}
}
return $self->{datas}->{devices_status};
}
sub get_network_device_uplink {
my ($self, %options) = @_;
if (!defined($self->{datas}->{uplink_statuses}->{ $options{orgId} })) {
$self->{datas}->{uplink_statuses}->{ $options{orgId} } = {};
my $datas = $self->request_api(
endpoint => '/organizations/' . $options{orgId} . '/uplinks/statuses',
paginate => 1000,
hostname => $self->get_shard_hostname(organization_id => $options{orgId})
);
foreach (@$datas) {
$self->{datas}->{uplink_statuses}->{ $options{orgId} }->{ $_->{serial} } = $_->{uplinks};
}
}
return defined($options{serial}) ?
$self->{datas}->{uplink_statuses}->{ $options{orgId} }->{ $options{serial} } :
$self->{datas}->{uplink_statuses}->{ $options{orgId} };
}
sub get_organization_uplink_loss_and_latency {
my ($self, %options) = @_;
if (!defined($self->{datas}->{uplinks_loss_latency}->{ $options{orgId} })) {
$self->{datas}->{uplinks_loss_latency}->{ $options{orgId} } = {};
my $datas = $self->request_api(
endpoint => '/organizations/' . $options{orgId} . '/devices/uplinksLossAndLatency?timespan=' . $self->{timespan},
paginate => 1000,
hostname => $self->get_shard_hostname(organization_id => $options{orgId})
);
foreach (@$datas) {
$self->{datas}->{uplinks_loss_latency}->{ $options{orgId} }->{ $_->{serial} } = {}
if (!defined($self->{datas}->{uplinks_loss_latency}->{ $options{orgId} }->{ $_->{serial} }));
$self->{datas}->{uplinks_loss_latency}->{ $options{orgId} }->{ $_->{serial} }->{ $_->{uplink} } = $_;
}
}
return defined($options{serial}) ?
$self->{datas}->{uplinks_loss_latency}->{ $options{orgId} }->{ $options{serial} } :
$self->{datas}->{uplinks_loss_latency}->{ $options{orgId} };
}
sub get_device_clients {
my ($self, %options) = @_;
return $self->request_api(
endpoint => '/devices/' . $options{serial} . '/clients?timespan=' . $self->{timespan},
hostname => $self->get_shard_hostname(serial => $options{serial})
)
}
sub get_device_switch_port_statuses {
my ($self, %options) = @_;
return $self->request_api(
endpoint => '/devices/' . $options{serial} . '/switchPortStatuses?timespan=' . $self->{timespan},
hostname => $self->get_shard_hostname(serial => $options{serial})
);
}
sub get_network_device_connection_stats {
my ($self, %options) = @_;
if (!defined($self->{devices_connection_stats}->{ $options{network_id} })) {
$self->{devices_connection_stats}->{ $options{network_id} } = {};
my $datas = $self->request_api(
endpoint => '/networks/' . $options{network_id} . '/wireless/devices/connectionStats?timespan=' . $self->{timespan},
hostname => $self->get_shard_hostname(network_id => $options{network_id})
);
foreach (@$datas) {
$self->{devices_connection_stats}->{ $options{network_id} }->{ $_->{serial} } = $_->{connectionStats};
}
}
return defined($options{serial}) ?
$self->{devices_connection_stats}->{ $options{network_id} }->{ $options{serial} } :
$self->{devices_connection_stats}->{ $options{network_id} };
}
sub get_network_device_performance {
my ($self, %options) = @_;
$self->request_api(
endpoint => '/devices/' . $options{serial} . '/appliance/performance',
hostname => $self->get_shard_hostname(network_id => $options{network_id}),
ignore_codes => { 400 => 1, 204 => 1 }
);
}
sub get_organization_api_requests_overview {
my ($self, %options) = @_;
my $results = {};
foreach my $id (@{$options{orgs}}) {
$results->{$id} = $self->request_api(
endpoint => '/organizations/' . $id . '/apiRequests/overview?timespan=' . $self->{timespan},
hostname => $self->get_shard_hostname(organization_id => $id)
);
}
return $results; return $results;
} }
sub filter_organizations {
my ($self, %options) = @_;
my $organization_ids = [];
foreach (values %{$self->{cache_organizations}}) {
if (!defined($options{filter_name}) || $options{filter_name} eq '') {
push @$organization_ids, $_->{id};
} elsif ($_->{name} =~ /$options{filter_name}/) {
push @$organization_ids, $_->{id};
}
}
return $organization_ids;
}
sub get_networks_connection_stats { sub get_networks_connection_stats {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->cache_meraki_entities();
my $timespan = defined($options{timespan}) ? $options{timespan} : 300;
$timespan = 1 if ($timespan <= 0);
return $self->request_api( return $self->request_api(
endpoint => '/networks/' . $options{network_id}, endpoint => '/networks/' . $options{network_id},
hostname => $self->get_shard_hostname(network_id => $options{network_id}), hostname => $self->get_shard_hostname(network_id => $options{network_id}),
@ -411,246 +495,13 @@ sub get_networks_connection_stats {
sub get_networks_clients { sub get_networks_clients {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->cache_meraki_entities();
my $timespan = defined($options{timespan}) ? $options{timespan} : 300;
$timespan = 1 if ($timespan <= 0);
return $self->request_api( return $self->request_api(
endpoint => '/networks/' . $options{network_id} . '/clients?timespan=' . $options{timespan}, endpoint => '/networks/' . $options{network_id} . '/clients?timespan=' . $self->{timespan},
hostname => $self->get_shard_hostname(network_id => $options{network_id}), hostname => $self->get_shard_hostname(network_id => $options{network_id}),
ignore_codes => { 400 => 1 } ignore_codes => { 400 => 1 }
); );
} }
sub get_organization_device_statuses {
my ($self, %options) = @_;
$self->cache_meraki_entities();
$self->load_extra_cache();
return $self->{cached}->{devices_statuses}->{data} if (defined($self->{cached}->{devices_statuses}->{data}));
$self->{cached}->{updated} = 1;
$self->{cached}->{devices_statuses} = {
update_time => time(),
data => {}
};
foreach my $id (keys %{$self->{cache_organizations}}) {
my $datas = $self->request_api(
endpoint => '/organizations/' . $id . '/devices/statuses',
hostname => $self->get_shard_hostname(organization_id => $id)
);
foreach (@$datas) {
$self->{cached}->{devices_statuses}->{data}->{ $_->{serial} } = $_;
$self->{cached}->{devices_statuses}->{data}->{organizationId} = $id;
}
}
return $self->{cached}->{devices_statuses}->{data};
}
sub get_organization_api_requests_overview {
my ($self, %options) = @_;
$self->cache_meraki_entities();
my $organization_ids = $self->filter_organizations(filter_name => $options{filter_name});
my $timespan = defined($options{timespan}) ? $options{timespan} : 300;
$timespan = 1 if ($timespan <= 0);
my $results = {};
foreach my $id (@$organization_ids) {
$results->{$id} = $self->request_api(
endpoint => '/organizations/' . $id . '/apiRequests/overview?timespan=' . $options{timespan},
hostname => $self->get_shard_hostname(organization_id => $id)
);
}
return $results;
}
sub get_network_device_connection_stats {
my ($self, %options) = @_;
$self->cache_meraki_entities();
$self->load_extra_cache();
my $timespan = defined($options{timespan}) ? $options{timespan} : 300;
$timespan = 1 if ($timespan <= 0);
if (!defined($self->{cached}->{devices_connection_stats}->{ $options{network_id} })) {
$self->{cached}->{updated} = 1;
$self->{cached}->{devices_connection_stats}->{ $options{network_id} } = {
update_time => time(),
data => $self->request_api(
endpoint => '/networks/' . $options{network_id} . '/wireless/devices/connectionStats?timespan=' . $options{timespan},
hostname => $self->get_shard_hostname(network_id => $options{network_id})
)
};
}
my $result;
foreach (@{$self->{cached}->{devices_connection_stats}->{ $options{network_id} }->{data}}) {
if ($_->{serial} eq $options{serial}) {
$result = $_->{connectionStats};
last;
}
}
return $result;
}
sub get_network_device_uplink {
my ($self, %options) = @_;
$self->cache_meraki_entities();
$self->load_extra_cache();
if (!defined($self->{cached}->{uplink_statuses}->{ $options{organization_id} })) {
$self->{cached}->{updated} = 1;
$self->{cached}->{uplink_statuses}->{ $options{organization_id} } = {
update_time => time(),
data => $self->request_api(
endpoint => '/organizations/' . $options{organization_id} . '/uplinks/statuses',
hostname => $self->get_shard_hostname(organization_id => $options{organization_id})
)
};
}
my $result;
foreach (@{$self->{cached}->{uplink_statuses}->{ $options{organization_id} }->{data}}) {
if ($_->{serial} eq $options{serial}) {
$result = $_->{uplinks};
last;
}
}
return $result;
}
sub get_device_clients {
my ($self, %options) = @_;
$self->cache_meraki_entities();
$self->load_extra_cache();
my $timespan = defined($options{timespan}) ? $options{timespan} : 300;
$timespan = 1 if ($timespan <= 0);
if (!defined($self->{cached}->{devices_clients}->{ $options{serial} })) {
$self->{cached}->{updated} = 1;
# 400 = feature not supported. 204 = no content
$self->{cached}->{devices_clients}->{ $options{serial} } = {
update_time => time(),
data => $self->request_api(
endpoint => '/devices/' . $options{serial} . '/clients?timespan=' . $options{timespan},
hostname => $self->get_shard_hostname(serial => $options{serial})
)
};
}
return $self->{cached}->{devices_clients}->{ $options{serial} }->{data};
}
sub get_device_switch_port_statuses {
my ($self, %options) = @_;
$self->cache_meraki_entities();
my $timespan = defined($options{timespan}) ? $options{timespan} : 300;
$timespan = 1 if ($timespan <= 0);
return $self->request_api(
endpoint => '/devices/' . $options{serial} . '/switchPortStatuses?timespan=' . $options{timespan},
hostname => $self->get_shard_hostname(serial => $options{serial})
);
}
sub get_network_device_performance {
my ($self, %options) = @_;
$self->cache_meraki_entities();
$self->load_extra_cache();
if (!defined($self->{cached}->{devices_performance}->{ $options{serial} })) {
$self->{cached}->{updated} = 1;
# 400 = feature not supported. 204 = no content
$self->{cached}->{devices_performance}->{ $options{serial} } = {
update_time => time(),
data => $self->request_api(
endpoint => '/devices/' . $options{serial} . '/appliance/performance',
hostname => $self->get_shard_hostname(network_id => $options{network_id}),
ignore_codes => { 400 => 1, 204 => 1 }
)
};
}
return $self->{cached}->{devices_performance}->{ $options{serial} }->{data};
}
sub get_organization_uplink_loss_and_latency {
my ($self, %options) = @_;
$self->cache_meraki_entities();
$self->load_extra_cache();
my $timespan = defined($options{timespan}) ? $options{timespan} : 300;
$timespan = 1 if ($timespan <= 0);
if (!defined($self->{cached}->{uplinks_loss_latency}->{ $options{organization_id} })) {
$self->{cached}->{updated} = 1;
$self->{cached}->{uplinks_loss_latency}->{ $options{organization_id} } = {
update_time => time(),
data => $self->request_api(
endpoint => '/organizations/' . $options{organization_id} . '/devices/uplinksLossAndLatency?timespan=' . $options{timespan},
hostname => $self->get_shard_hostname(organization_id => $options{organization_id})
)
};
}
my $result = {};
if (defined($self->{cached}->{uplinks_loss_latency}->{ $options{organization_id} }->{data})) {
foreach (@{$self->{cached}->{uplinks_loss_latency}->{ $options{organization_id} }->{data}}) {
if ($options{serial} eq $_->{serial}) {
$result->{ $_->{uplink} } = $_;
}
}
}
return $result;
}
sub load_extra_cache {
my ($self, %options) = @_;
return if (!defined($self->{option_results}->{use_extra_cache}));
return if ($self->{cache_extra_checked} == 1);
$self->{cache_extra_checked} = 1;
my $has_cache_file = $self->{cache}->read(statefile => 'cache_extra_cisco_meraki_' . $self->get_token());
my $cached = $self->{cache}->get(name => 'cached');
$self->{cached} = $cached if (defined($cached));
if (defined($self->{cached}->{devices_statuses}->{update_time}) && ((time() - $self->{cached}->{devices_statuses}->{update_time}) > ($self->{reload_extra_cache_time} * 60))) {
$self->{cached}->{devices_statuses} = {};
}
foreach my $entry (('uplink_statuses', 'uplinks_loss_latency', 'devices_connection_stats', 'devices_performance', 'devices_clients')) {
next if (!defined($self->{cached}->{$entry}));
foreach (keys %{$self->{cached}->{$entry}}) {
if ((time() - $self->{cached}->{$entry}->{$_}->{update_time}) > ($self->{reload_extra_cache_time} * 60)) {
delete $self->{cached}->{$entry}->{$_};
}
}
}
}
sub close_extra_cache {
my ($self, %options) = @_;
return if (!defined($self->{option_results}->{use_extra_cache}));
if ($self->{cached}->{updated} == 1) {
$self->{cached}->{updated} = 0;
$self->{cache}->write(data => { cached => $self->{cached} });
}
}
1; 1;
__END__ __END__
@ -687,14 +538,14 @@ Meraki api token.
Set HTTP timeout Set HTTP timeout
=item B<--reload-cache-time>
Time in minutes before reloading cache file (default: 180).
=item B<--ignore-permission-errors> =item B<--ignore-permission-errors>
Ignore permission errors (403 status code). Ignore permission errors (403 status code).
=item B<--cache-use>
Use the cache file (created with cache mode).
=back =back
=head1 DESCRIPTION =head1 DESCRIPTION

View File

@ -38,8 +38,7 @@ sub set_counters {
key_values => [ { name => 'requests_200' }, { name => 'display' } ], key_values => [ { name => 'requests_200' }, { name => 'display' } ],
output_template => 'code 200: %s', output_template => 'code 200: %s',
perfdatas => [ perfdatas => [
{ value => 'requests_200', { template => '%d', min => 0, label_extra_instance => 1, instance_use => 'display' }
template => '%d', min => 0, label_extra_instance => 1, instance_use => 'display' }
] ]
} }
}, },
@ -47,8 +46,7 @@ sub set_counters {
key_values => [ { name => 'requests_404' }, { name => 'display' } ], key_values => [ { name => 'requests_404' }, { name => 'display' } ],
output_template => 'code 404: %s', output_template => 'code 404: %s',
perfdatas => [ perfdatas => [
{ value => 'requests_404', { template => '%d', min => 0, label_extra_instance => 1, instance_use => 'display' }
template => '%d', min => 0, label_extra_instance => 1, instance_use => 'display' }
] ]
} }
}, },
@ -56,8 +54,7 @@ sub set_counters {
key_values => [ { name => 'requests_429' }, { name => 'display' } ], key_values => [ { name => 'requests_429' }, { name => 'display' } ],
output_template => 'code 429: %s', output_template => 'code 429: %s',
perfdatas => [ perfdatas => [
{ value => 'requests_429', { template => '%d', min => 0, label_extra_instance => 1, instance_use => 'display' }
template => '%d', min => 0, label_extra_instance => 1, instance_use => 'display' }
] ]
} }
} }
@ -72,7 +69,7 @@ sub prefix_organization_output {
sub new { sub new {
my ($class, %options) = @_; my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class; bless $self, $class;
$options{options}->add_options(arguments => { $options{options}->add_options(arguments => {
@ -85,23 +82,18 @@ sub new {
sub manage_selection { sub manage_selection {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->{cache_name} = 'meraki_' . $self->{mode} . '_' . $options{custom}->get_token() . '_' . my $orgs = $options{custom}->get_organizations();
(defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' .
(defined($self->{option_results}->{filter_organization_name}) ? md5_hex($self->{option_results}->{filter_organization_name}) : md5_hex('all'));
my $last_timestamp = $self->read_statefile_key(key => 'last_timestamp');
my $timespan = 300;
$timespan = time() - $last_timestamp if (defined($last_timestamp));
my $cache_organizations = $options{custom}->get_cache_organizations();
my $api_requests = $options{custom}->get_organization_api_requests_overview(timespan => $timespan, filter_name => $self->{option_results}->{filter_organization_name});
$self->{organizations} = {}; $self->{organizations} = {};
foreach my $id (keys %$api_requests) { foreach my $orgId (keys %$orgs) {
$self->{organizations}->{$id} = { next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' &&
display => $cache_organizations->{$id}->{name}, $orgs->{orgId}->{name} !~ /$self->{option_results}->{filter_organization_name}/);
requests_200 => defined($api_requests->{$id}->{responseCodeCounts}->{200}) ? $api_requests->{$id}->{responseCodeCounts}->{200} : 0, my $api_requests = $options{custom}->get_organization_api_requests_overview(orgs => [$orgId]);
requests_404 => defined($api_requests->{$id}->{responseCodeCounts}->{404}) ? $api_requests->{$id}->{responseCodeCounts}->{404} : 0, $self->{organizations}->{$orgId} = {
requests_429 => defined($api_requests->{$id}->{responseCodeCounts}->{429}) ? $api_requests->{$id}->{responseCodeCounts}->{429} : 0, display => $orgs->{$orgId}->{name},
requests_200 => defined($api_requests->{$orgId}->{responseCodeCounts}->{200}) ? $api_requests->{$orgId}->{responseCodeCounts}->{200} : 0,
requests_404 => defined($api_requests->{$orgId}->{responseCodeCounts}->{404}) ? $api_requests->{$orgId}->{responseCodeCounts}->{404} : 0,
requests_429 => defined($api_requests->{$orgId}->{responseCodeCounts}->{429}) ? $api_requests->{$orgId}->{responseCodeCounts}->{429} : 0
}; };
} }

View File

@ -0,0 +1,60 @@
#
# Copyright 2022 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package network::cisco::meraki::cloudcontroller::restapi::mode::cache;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$options{options}->add_options(arguments => {});
return $self;
}
sub manage_selection {
my ($self, %options) = @_;
$options{custom}->cache_datas();
$self->{output}->output_add(
severity => 'OK',
short_msg => 'Cache files created successfully'
);
}
1;
__END__
=head1 MODE
Create cache files (other modes could use it with --cache-use option).
=over 8
=back
=cut

View File

@ -312,7 +312,6 @@ sub add_connection_stats {
my ($self, %options) = @_; my ($self, %options) = @_;
my $connections = $options{custom}->get_network_device_connection_stats( my $connections = $options{custom}->get_network_device_connection_stats(
timespan => $options{timespan},
serial => $options{serial}, serial => $options{serial},
network_id => $options{network_id} network_id => $options{network_id}
); );
@ -330,7 +329,6 @@ sub add_clients {
my ($self, %options) = @_; my ($self, %options) = @_;
my $clients = $options{custom}->get_device_clients( my $clients = $options{custom}->get_device_clients(
timespan => $options{timespan},
serial => $options{serial} serial => $options{serial}
); );
@ -353,7 +351,7 @@ sub add_uplink {
my $links = $options{custom}->get_network_device_uplink( my $links = $options{custom}->get_network_device_uplink(
serial => $options{serial}, serial => $options{serial},
organization_id => $options{organization_id} orgId => $options{orgId}
); );
if (defined($links)) { if (defined($links)) {
@ -371,11 +369,9 @@ sub add_uplink {
sub add_uplink_loss_latency { sub add_uplink_loss_latency {
my ($self, %options) = @_; my ($self, %options) = @_;
# 5 minutes max timespan
my $links = $options{custom}->get_organization_uplink_loss_and_latency( my $links = $options{custom}->get_organization_uplink_loss_and_latency(
timespan => 300,
serial => $options{serial}, serial => $options{serial},
organization_id => $options{custom}->get_organization_id(network_id => $options{network_id}) orgId => $options{orgId}
); );
return if (!defined($links)); return if (!defined($links));
@ -422,7 +418,6 @@ sub add_switch_port_statuses {
my ($self, %options) = @_; my ($self, %options) = @_;
my $ports = $options{custom}->get_device_switch_port_statuses( my $ports = $options{custom}->get_device_switch_port_statuses(
timespan => $options{timespan},
serial => $options{serial} serial => $options{serial}
); );
@ -443,54 +438,14 @@ sub manage_selection {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->{cache_name} = 'meraki_' . $self->{mode} . '_' . $options{custom}->get_token() . '_' . $self->{cache_name} = 'meraki_' . $self->{mode} . '_' . $options{custom}->get_token() . '_' .
(defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . md5_hex(
(defined($self->{option_results}->{filter_device_name}) ? md5_hex($self->{option_results}->{filter_device_name}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_counters}) ? $self->{option_results}->{filter_counters} : 'all') . '_' .
(defined($self->{option_results}->{filter_network_id}) ? md5_hex($self->{option_results}->{filter_network_id}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_device_name}) ? $self->{option_results}->{filter_device_name} : 'all') . '_' .
(defined($self->{option_results}->{filter_organization_id}) ? md5_hex($self->{option_results}->{filter_organization_id}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_network_id}) ? $self->{option_results}->{filter_network_id} : 'all') . '_' .
(defined($self->{option_results}->{filter_organization_name}) ? md5_hex($self->{option_results}->{filter_organization_name}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_organization_id}) ? $self->{option_results}->{filter_organization_id} : 'all') . '_' .
(defined($self->{option_results}->{filter_tags}) ? md5_hex($self->{option_results}->{filter_tags}) : md5_hex('all')); (defined($self->{option_results}->{filter_organization_name}) ? $self->{option_results}->{filter_organization_name} : 'all') . '_' .
my $last_timestamp = $self->read_statefile_key(key => 'last_timestamp'); (defined($self->{option_results}->{filter_tags}) ? $self->{option_results}->{filter_tags} : 'all')
my $timespan = 300; );
$timespan = time() - $last_timestamp if (defined($last_timestamp));
my $cache_devices = $options{custom}->get_cache_devices();
my $devices = {};
foreach (values %$cache_devices) {
if (defined($self->{option_results}->{filter_device_name}) && $self->{option_results}->{filter_device_name} ne '' &&
$_->{name} !~ /$self->{option_results}->{filter_device_name}/) {
$self->{output}->output_add(long_msg => "skipping device '" . $_->{name} . "': no matching filter.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_network_id}) && $self->{option_results}->{filter_network_id} ne '' &&
$_->{networkId} !~ /$self->{option_results}->{filter_network_id}/) {
$self->{output}->output_add(long_msg => "skipping device '" . $_->{name} . "': no matching filter.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_tags}) && $self->{option_results}->{filter_tags} ne '') {
my $tags;
$tags = join(' ', @{$_->{tags}}) if (defined($_->{tags}));
if (!defined($tags) || $tags !~ /$self->{option_results}->{filter_tags}/) {
$self->{output}->output_add(long_msg => "skipping device '" . $_->{name} . "': no matching filter.", debug => 1);
next;
}
}
my $organization = $options{custom}->get_organization(network_id => $_->{networkId});
if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' &&
$organization->{id} !~ /$self->{option_results}->{filter_organization_id}/) {
$self->{output}->output_add(long_msg => "skipping device '" . $_->{name} . "': no matching filter.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' &&
$organization->{name} !~ /$self->{option_results}->{filter_organization_name}/) {
$self->{output}->output_add(long_msg => "skipping device '" . $_->{name} . "': no matching filter.", debug => 1);
next;
}
$devices->{ $_->{serial} } = { model => $_->{model}, organization_id => $organization->{id} };
}
my $device_statuses = $options{custom}->get_organization_device_statuses();
# | /clients | /connectionStats | /performance | /uplink | /uplinksLossAndLatency | /switchPortStatuses # | /clients | /connectionStats | /performance | /uplink | /uplinksLossAndLatency | /switchPortStatuses
#-------------------|----------|---------------------------------|---------|------------------------|----------------------- #-------------------|----------|---------------------------------|---------|------------------------|-----------------------
@ -500,73 +455,87 @@ sub manage_selection {
# MX [appliance] | X | | X | X | X | # MX [appliance] | X | | X | X | X |
# MR [wireless] | X | X | | X | | # MR [wireless] | X | X | | X | |
my $datas = $options{custom}->get_datas();
$self->{global} = { total => 0, online => 0, offline => 0, alerting => 0, offline_prct => 0, online_prct => 0 }; $self->{global} = { total => 0, online => 0, offline => 0, alerting => 0, offline_prct => 0, online_prct => 0 };
$self->{devices} = {}; $self->{devices} = {};
foreach my $serial (keys %$devices) { foreach my $serial (keys %{$datas->{devices}}) {
next if (defined($self->{option_results}->{filter_device_name}) && $self->{option_results}->{filter_device_name} ne '' &&
$datas->{devices}->{$serial}->{name} !~ /$self->{option_results}->{filter_device_name}/);
next if (defined($self->{option_results}->{filter_network_id}) && $self->{option_results}->{filter_network_id} ne '' &&
$datas->{devices}->{$serial}->{networkId} !~ /$self->{option_results}->{filter_network_id}/);
if (defined($self->{option_results}->{filter_tags}) && $self->{option_results}->{filter_tags} ne '') {
my $tags;
$tags = join(' ', @{$datas->{devices}->{$serial}->{tags}}) if (defined($datas->{devices}->{$serial}->{tags}));
if (!defined($tags) || $tags !~ /$self->{option_results}->{filter_tags}/) {
next;
}
}
next if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' &&
$datas->{devices}->{$serial}->{orgId} !~ /$self->{option_results}->{filter_organization_id}/);
next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' &&
$datas->{orgs}->{ $datas->{devices}->{$serial}->{orgId} }->{name} !~ /$self->{option_results}->{filter_organization_name}/);
$self->{devices}->{$serial} = { $self->{devices}->{$serial} = {
display => $cache_devices->{$serial}->{name}, display => $datas->{devices}->{$serial}->{name},
device_status => { device_status => {
display => $cache_devices->{$serial}->{name}, display => $datas->{devices}->{$serial}->{name},
status => $device_statuses->{$serial}->{status} status => $datas->{devices_status}->{$serial}->{status}
}, },
device_links => {}, device_links => {},
device_ports => {} device_ports => {}
}; };
if (!defined($self->{option_results}->{skip_connections}) && $devices->{$serial}->{model} =~ /^(?:MG|MR)/) { if (!defined($self->{option_results}->{skip_connections}) && $datas->{devices}->{$serial}->{model} =~ /^(?:MG|MR)/) {
$self->add_connection_stats( $self->add_connection_stats(
custom => $options{custom}, custom => $options{custom},
timespan => $timespan,
serial => $serial, serial => $serial,
name => $cache_devices->{$serial}->{name}, name => $datas->{devices}->{$serial}->{name},
network_id => $cache_devices->{$serial}->{networkId} network_id => $datas->{devices}->{$serial}->{networkId}
); );
} }
if (!defined($self->{option_results}->{skip_clients}) && $devices->{$serial}->{model} =~ /^(?:MS|MG|MR|MX)/) { if (!defined($self->{option_results}->{skip_clients}) && $datas->{devices}->{$serial}->{model} =~ /^(?:MS|MG|MR|MX)/) {
$self->add_clients( $self->add_clients(
custom => $options{custom}, custom => $options{custom},
timespan => $timespan,
serial => $serial, serial => $serial,
name => $cache_devices->{$serial}->{name} name => $datas->{devices}->{$serial}->{name}
); );
} }
if ($devices->{$serial}->{model} =~ /^(?:MV|MS|MG|MR|MX)/) { if ($datas->{devices}->{$serial}->{model} =~ /^(?:MV|MS|MG|MR|MX)/) {
$self->add_uplink( $self->add_uplink(
custom => $options{custom}, custom => $options{custom},
serial => $serial, serial => $serial,
name => $cache_devices->{$serial}->{name}, name => $datas->{devices}->{$serial}->{name},
organization_id => $devices->{$serial}->{organization_id} orgId => $datas->{devices}->{$serial}->{orgId}
); );
} }
if (defined($self->{option_results}->{add_switch_ports}) && $devices->{$serial} =~ /^MS/) { if (defined($self->{option_results}->{add_switch_ports}) && $datas->{devices}->{$serial}->{model} =~ /^MS/) {
$self->add_switch_port_statuses( $self->add_switch_port_statuses(
custom => $options{custom}, custom => $options{custom},
timespan => $timespan,
serial => $serial serial => $serial
); );
} }
if ($devices->{$serial}->{model} =~ /^MX/) { if ($datas->{devices}->{$serial}->{model} =~ /^MX/) {
$self->add_performance( $self->add_performance(
custom => $options{custom}, custom => $options{custom},
serial => $serial, serial => $serial,
name => $cache_devices->{$serial}->{name}, name => $datas->{devices}->{$serial}->{name},
network_id => $cache_devices->{$serial}->{networkId} network_id => $datas->{devices}->{$serial}->{networkId}
) if (!defined($self->{option_results}->{skip_performance})); ) if (!defined($self->{option_results}->{skip_performance}));
$self->add_uplink_loss_latency( $self->add_uplink_loss_latency(
custom => $options{custom}, custom => $options{custom},
timespan => $timespan,
serial => $serial, serial => $serial,
network_id => $cache_devices->{$serial}->{networkId} orgId => $datas->{devices}->{$serial}->{orgId}
); );
} }
$self->{global}->{total}++; $self->{global}->{total}++;
$self->{global}->{ lc($device_statuses->{$serial}->{status}) }++ $self->{global}->{ lc($datas->{devices_status}->{$serial}->{status}) }++
if (defined($self->{global}->{ lc($device_statuses->{$serial}->{status}) })); if (defined($self->{global}->{ lc($datas->{devices_status}->{$serial}->{status}) }));
} }
$options{custom}->close_extra_cache();
if (scalar(keys %{$self->{devices}}) <= 0) { if (scalar(keys %{$self->{devices}}) <= 0) {
$self->{output}->output_add(short_msg => 'no devices found'); $self->{output}->output_add(short_msg => 'no devices found');
} }

View File

@ -60,10 +60,13 @@ sub discovery_devices {
my ($self, %options) = @_; my ($self, %options) = @_;
my $devices = $options{custom}->get_devices( my $devices = $options{custom}->get_devices(
organizations => [keys %{$options{organizations}}], orgs => [keys %{$options{organizations}}],
disable_cache => 1 extended => 1
);
my $devices_statuses = $options{custom}->get_organization_device_statuses(
orgs => [keys %{$options{organizations}}],
extended => 1
); );
my $devices_statuses = $options{custom}->get_organization_device_statuses();
my @results; my @results;
foreach (values %$devices) { foreach (values %$devices) {
@ -72,9 +75,9 @@ sub discovery_devices {
next if (defined($self->{option_results}->{filter_tags}) && $self->{option_results}->{filter_tags} ne '' && next if (defined($self->{option_results}->{filter_tags}) && $self->{option_results}->{filter_tags} ne '' &&
(!defined($_->{tags}) || $_->{tags} !~ /$self->{option_results}->{filter_tags}/)); (!defined($_->{tags}) || $_->{tags} !~ /$self->{option_results}->{filter_tags}/));
next if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' && next if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' &&
$options{networks}->{ $_->{networkId} }->{organizationId} !~ /$self->{option_results}->{filter_organization_id}/); $_->{orgId} !~ /$self->{option_results}->{filter_organization_id}/);
next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' && next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' &&
$options{organizations}->{ $options{networks}->{ $_->{networkId} }->{organizationId} }->{name} !~ /$self->{option_results}->{filter_organization_name}/); $options{organizations}->{ $_->{orgId} }->{name} !~ /$self->{option_results}->{filter_organization_name}/);
my $node = { my $node = {
name => $_->{name}, name => $_->{name},
@ -93,7 +96,7 @@ sub discovery_devices {
lan_ip => $_->{lanIp}, lan_ip => $_->{lanIp},
network_id => $_->{networkId}, network_id => $_->{networkId},
network_name => $options{networks}->{ $_->{networkId} }->{name}, network_name => $options{networks}->{ $_->{networkId} }->{name},
organization_name => $options{organizations}->{ $options{networks}->{ $_->{networkId} }->{organizationId} }->{name}, organization_name => $options{organizations}->{ $_->{orgId} }->{name},
configuration_updated_at => $_->{configurationUpdatedAt}, configuration_updated_at => $_->{configurationUpdatedAt},
last_reported_at => $devices_statuses->{ $_->{serial} }->{lastReportedAt} last_reported_at => $devices_statuses->{ $_->{serial} }->{lastReportedAt}
}; };
@ -144,11 +147,10 @@ sub run {
$disco_stats->{start_time} = time(); $disco_stats->{start_time} = time();
my $organizations = $options{custom}->get_organizations(disable_cache => 1); my $organizations = $options{custom}->get_organizations();
my $networks = $options{custom}->get_networks( my $networks = $options{custom}->get_networks(
organizations => [keys %{$organizations}], orgs => [keys %{$organizations}],
disable_cache => 1 extended => 1
); );
if ($self->{option_results}->{resource_type} eq 'network') { if ($self->{option_results}->{resource_type} eq 'network') {

View File

@ -48,17 +48,20 @@ sub check_options {
sub manage_selection { sub manage_selection {
my ($self, %options) = @_; my ($self, %options) = @_;
my $organizations = $options{custom}->get_organizations(disable_cache => 1); my $organizations = $options{custom}->get_organizations();
my $networks = $options{custom}->get_networks( my $networks = $options{custom}->get_networks(
organizations => [keys %$organizations], orgs => [keys %$organizations],
disable_cache => 1 extended => 1
); );
my $devices = $options{custom}->get_devices( my $devices = $options{custom}->get_devices(
organizations => [keys %$organizations], orgs => [keys %$organizations],
disable_cache => 1 extended => 1
);
my $devices_statuses = $options{custom}->get_organization_device_statuses(
orgs => [keys %$organizations],
extended => 1
); );
my $devices_statuses = $options{custom}->get_organization_device_statuses();
my $results = {}; my $results = {};
foreach (keys %$devices) { foreach (keys %$devices) {
next if (defined($self->{option_results}->{filter_network_id}) && $self->{option_results}->{filter_network_id} ne '' && next if (defined($self->{option_results}->{filter_network_id}) && $self->{option_results}->{filter_network_id} ne '' &&
@ -69,14 +72,15 @@ sub manage_selection {
next if (!defined($tags) || $tags !~ /$self->{option_results}->{filter_tags}/); next if (!defined($tags) || $tags !~ /$self->{option_results}->{filter_tags}/);
} }
next if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' && next if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' &&
$networks->{ $devices->{$_}->{networkId} }->{organizationId} !~ /$self->{option_results}->{filter_organization_id}/); $devices->{$_}->{orgId} !~ /$self->{option_results}->{filter_organization_id}/);
my $organization_name = $organizations->{ $networks->{ $devices->{$_}->{networkId} }->{organizationId} }->{name}; my $organization_name = $organizations->{ $devices->{$_}->{orgId} }->{name};
next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' && next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' &&
$organization_name !~ /$self->{option_results}->{filter_organization_name}/); $organization_name !~ /$self->{option_results}->{filter_organization_name}/);
$results->{$_} = { $results->{$_} = {
%{$devices->{$_}}, name => $devices->{$_}->{name},
tags => $devices->{$_}->{tags},
status => $devices_statuses->{ $devices->{$_}->{serial} }->{status}, status => $devices_statuses->{ $devices->{$_}->{serial} }->{status},
public_ip => $devices_statuses->{ $devices->{$_}->{serial} }->{publicIp}, public_ip => $devices_statuses->{ $devices->{$_}->{serial} }->{publicIp},
network_name => $networks->{ $devices->{$_}->{networkId} }->{name}, network_name => $networks->{ $devices->{$_}->{networkId} }->{name},
@ -129,7 +133,7 @@ sub disco_show {
network_name => $_->{network_name}, network_name => $_->{network_name},
network_id => $_->{networkId}, network_id => $_->{networkId},
organization_name => $_->{organization_name}, organization_name => $_->{organization_name},
tags => defined($_->{tags}) ? $_->{tags} : '' tags => defined($_->{tags}) ? join(',', @{$_->{tags}}) : ''
); );
} }
} }

View File

@ -48,14 +48,12 @@ sub check_options {
sub manage_selection { sub manage_selection {
my ($self, %options) = @_; my ($self, %options) = @_;
my $organizations = $options{custom}->get_organizations(disable_cache => 1); my $organizations = $options{custom}->get_organizations();
my $networks = $options{custom}->get_networks( my $networks = $options{custom}->get_networks(
organizations => [keys %$organizations], orgs => [keys %$organizations]
disable_cache => 1
); );
my $devices = $options{custom}->get_devices( my $devices = $options{custom}->get_devices(
organizations => [keys %$organizations], orgs => [keys %$organizations]
disable_cache => 1
); );
my $results = {}; my $results = {};
@ -64,9 +62,9 @@ sub manage_selection {
next if (defined($self->{option_results}->{filter_network_id}) && $self->{option_results}->{filter_network_id} ne '' && next if (defined($self->{option_results}->{filter_network_id}) && $self->{option_results}->{filter_network_id} ne '' &&
$devices->{$_}->{networkId} !~ /$self->{option_results}->{filter_network_id}/); $devices->{$_}->{networkId} !~ /$self->{option_results}->{filter_network_id}/);
next if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' && next if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' &&
$networks->{ $devices->{$_}->{networkId} }->{organizationId} !~ /$self->{option_results}->{filter_organization_id}/); $devices->{$_}->{orgId} !~ /$self->{option_results}->{filter_organization_id}/);
my $organization_name = $organizations->{ $networks->{ $devices->{$_}->{networkId} }->{organizationId} }->{name}; my $organization_name = $organizations->{ $devices->{$_}->{orgId} }->{name};
next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' && next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' &&
$organization_name !~ /$self->{option_results}->{filter_organization_name}/); $organization_name !~ /$self->{option_results}->{filter_organization_name}/);

View File

@ -26,6 +26,12 @@ use strict;
use warnings; use warnings;
use Digest::MD5 qw(md5_hex); use Digest::MD5 qw(md5_hex);
sub prefix_network_output {
my ($self, %options) = @_;
return "Network '" . $options{instance_value}->{display} . "' ";
}
sub set_counters { sub set_counters {
my ($self, %options) = @_; my ($self, %options) = @_;
@ -95,12 +101,6 @@ sub set_counters {
]; ];
} }
sub prefix_network_output {
my ($self, %options) = @_;
return "Network '" . $options{instance_value}->{display} . "' ";
}
sub new { sub new {
my ($class, %options) = @_; my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1);
@ -119,47 +119,30 @@ sub manage_selection {
my ($self, %options) = @_; my ($self, %options) = @_;
$self->{cache_name} = 'meraki_' . $self->{mode} . '_' . $options{custom}->get_token() . '_' . $self->{cache_name} = 'meraki_' . $self->{mode} . '_' . $options{custom}->get_token() . '_' .
(defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . md5_hex(
(defined($self->{option_results}->{filter_network_name}) ? md5_hex($self->{option_results}->{filter_network_name}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_counters}) ? $self->{option_results}->{filter_counters} : 'all') . '_' .
(defined($self->{option_results}->{filter_organization_id}) ? md5_hex($self->{option_results}->{filter_organization_id}) : md5_hex('all')) . '_' . (defined($self->{option_results}->{filter_network_name}) ? $self->{option_results}->{filter_network_name} : 'all') . '_' .
(defined($self->{option_results}->{filter_organization_name}) ? md5_hex($self->{option_results}->{filter_organization_name}) : md5_hex('all')); (defined($self->{option_results}->{filter_organization_id}) ? $self->{option_results}->{filter_organization_id} : 'all') . '_' .
my $last_timestamp = $self->read_statefile_key(key => 'last_timestamp'); (defined($self->{option_results}->{filter_organization_name}) ? $self->{option_results}->{filter_organization_name} : 'all')
my $timespan = 300; );
$timespan = time() - $last_timestamp if (defined($last_timestamp));
my $datas = $options{custom}->get_datas(skipDevices => 1, skipDevicesStatus => 1);
$self->{networks} = {}; $self->{networks} = {};
foreach my $id (keys %{$datas->{networks}}) {
next if (defined($self->{option_results}->{filter_network_name}) && $self->{option_results}->{filter_network_name} ne '' &&
$datas->{networks}->{$id}->{name} !~ /$self->{option_results}->{filter_network_name}/);
my $cache_networks = $options{custom}->get_cache_networks(); next if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' &&
foreach (values %$cache_networks) { $datas->{networks}->{$id}->{organizationId} !~ /$self->{option_results}->{filter_organization_id}/);
if (defined($self->{option_results}->{filter_network_name}) && $self->{option_results}->{filter_network_name} ne '' && next if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' &&
$_->{name} !~ /$self->{option_results}->{filter_network_name}/) { $datas->{orgs}->{ $datas->{networks}->{$id}->{organizationId} }->{name} !~ /$self->{option_results}->{filter_organization_name}/);
$self->{output}->output_add(long_msg => "skipping network '" . $_->{name} . "': no matching filter.", debug => 1);
next;
}
my $organization = $options{custom}->get_organization(network_id => $_->{id});
if (defined($self->{option_results}->{filter_organization_id}) && $self->{option_results}->{filter_organization_id} ne '' &&
$organization->{id} !~ /$self->{option_results}->{filter_organization_id}/) {
$self->{output}->output_add(long_msg => "skipping device '" . $_->{name} . "': no matching filter.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_organization_name}) && $self->{option_results}->{filter_organization_name} ne '' &&
$organization->{name} !~ /$self->{option_results}->{filter_organization_name}/) {
$self->{output}->output_add(long_msg => "skipping device '" . $_->{name} . "': no matching filter.", debug => 1);
next;
}
my $connections = $options{custom}->get_networks_connection_stats( my $connections = $options{custom}->get_networks_connection_stats(network_id => $id);
timespan => $timespan, my $clients = $options{custom}->get_networks_clients(network_id => $id);
network_id => $_->{id}
);
my $clients = $options{custom}->get_networks_clients(
timespan => $timespan,
network_id => $_->{id}
);
$self->{networks}->{ $_->{id} } = { $self->{networks}->{$id} = {
display => $_->{name}, display => $datas->{networks}->{$id}->{name},
assoc => defined($connections->{assoc}) ? $connections->{assoc} : 0, assoc => defined($connections->{assoc}) ? $connections->{assoc} : 0,
auth => defined($connections->{auth}) ? $connections->{auth} : 0, auth => defined($connections->{auth}) ? $connections->{auth} : 0,
dhcp => defined($connections->{dhcp}) ? $connections->{dhcp} : 0, dhcp => defined($connections->{dhcp}) ? $connections->{dhcp} : 0,
@ -170,8 +153,8 @@ sub manage_selection {
if (defined($clients)) { if (defined($clients)) {
foreach my $client (@$clients) { foreach my $client (@$clients) {
$self->{networks}->{ $_->{id} }->{traffic_in} += $client->{usage}->{recv} * 8; $self->{networks}->{$id}->{traffic_in} += $client->{usage}->{recv} * 8;
$self->{networks}->{ $_->{id} }->{traffic_out} += $client->{usage}->{sent} * 8; $self->{networks}->{$id}->{traffic_out} += $client->{usage}->{sent} * 8;
} }
} }
} }

View File

@ -29,15 +29,15 @@ sub new {
my $self = $class->SUPER::new(package => __PACKAGE__, %options); my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class; bless $self, $class;
$self->{version} = '1.0'; $self->{modes} = {
%{$self->{modes}} = (
'api-requests' => 'network::cisco::meraki::cloudcontroller::restapi::mode::apirequests', 'api-requests' => 'network::cisco::meraki::cloudcontroller::restapi::mode::apirequests',
'cache' => 'network::cisco::meraki::cloudcontroller::restapi::mode::cache',
'devices' => 'network::cisco::meraki::cloudcontroller::restapi::mode::devices', 'devices' => 'network::cisco::meraki::cloudcontroller::restapi::mode::devices',
'discovery' => 'network::cisco::meraki::cloudcontroller::restapi::mode::discovery', 'discovery' => 'network::cisco::meraki::cloudcontroller::restapi::mode::discovery',
'list-devices' => 'network::cisco::meraki::cloudcontroller::restapi::mode::listdevices', 'list-devices' => 'network::cisco::meraki::cloudcontroller::restapi::mode::listdevices',
'list-tags' => 'network::cisco::meraki::cloudcontroller::restapi::mode::listtags', 'list-tags' => 'network::cisco::meraki::cloudcontroller::restapi::mode::listtags',
'networks' => 'network::cisco::meraki::cloudcontroller::restapi::mode::networks' 'networks' => 'network::cisco::meraki::cloudcontroller::restapi::mode::networks'
); };
$self->{custom_modes}->{api} = 'network::cisco::meraki::cloudcontroller::restapi::custom::api'; $self->{custom_modes}->{api} = 'network::cisco::meraki::cloudcontroller::restapi::custom::api';
return $self; return $self;