API implementation (#712)

* initial v0 creator

* working json api for generic reports

* add require login

* move report swagger into plugin, and set new default layout of noop

* require proper role and also use new util func

* start to tidy authn

* some work on cleaning up web authn

* clean up the authN checks

* fix bug

* fix the auth for api

* fixes to json handling

* set swagger sort order

* enable most reports for api endpoints

* fix doc

* add paramters to reports

* add missed report

* allow api_parameters in reports config

* reorganise api

* add vlan search

* add port search

* make sure to enable layout processing

* add device search

* add v1 to api paths

* add Node Search

* support api_responses

* add device object search; fix spurious ports field in device result class

* handle some plugins just returning undef if search fails

* errors from api seamlessley

* fix error in date range default

* more sensible default for prefix

* change order of endpoints in swagger-ui

* all db row classes can now TO_JSON

* add device_port api endpoint

* add device ports endpoint

* do not expand docs

* add swagger ui json tree formatter

* add all relations from Device table

* add port relations

* add nodes retrieve on device or vlan

* rename to GetAPIKey

* update config for previous commit
This commit is contained in:
Oliver Gorwits
2020-04-15 21:15:52 +01:00
committed by GitHub
parent a8a77a2df1
commit dff26abc5c
78 changed files with 815 additions and 257 deletions

View File

@@ -0,0 +1,176 @@
package App::Netdisco::Web::API::Objects;
use Dancer ':syntax';
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Swagger;
use Dancer::Plugin::Auth::Extensible;
use Try::Tiny;
swagger_path {
tags => ['Objects'],
description => 'Returns a row from the device table',
parameters => [
ip => {
description => 'Canonical IP of the Device. Use Search methods to find this.',
required => 1,
in => 'path',
},
],
responses => { default => {} },
}, get '/api/v1/object/device/:ip' => require_role api => sub {
my $device = try { schema('netdisco')->resultset('Device')
->find( params->{ip} ) } or send_error('Bad Device', 404);
return to_json $device->TO_JSON;
};
foreach my $rel (qw/device_ips vlans ports modules port_vlans wireless_ports ssids powered_ports/) {
swagger_path {
tags => ['Objects'],
description => "Returns $rel rows for a given device",
parameters => [
ip => {
description => 'Canonical IP of the Device. Use Search methods to find this.',
required => 1,
in => 'path',
},
],
responses => { default => {} },
}, get "/api/v1/object/device/:ip/$rel" => require_role api => sub {
my $rows = try { schema('netdisco')->resultset('Device')
->find( params->{ip} )->$rel } or send_error('Bad Device', 404);
return to_json [ map {$_->TO_JSON} $rows->all ];
};
}
swagger_path {
tags => ['Objects'],
description => 'Returns a row from the device_port table',
path => '/api/v1/object/device/{ip}/port/{port}',
parameters => [
ip => {
description => 'Canonical IP of the Device. Use Search methods to find this.',
required => 1,
in => 'path',
},
port => {
description => 'Name of the port. Use the ".../device/{ip}/ports" method to find these.',
required => 1,
in => 'path',
},
],
responses => { default => {} },
}, get qr{/api/v1/object/device/(?<ip>[^/]+)/port/(?<port>[^/]+)$} => require_role api => sub {
my $params = captures;
my $port = try { schema('netdisco')->resultset('DevicePort')
->find( $$params{port}, $$params{ip} ) }
or send_error('Bad Device or Port', 404);
return to_json $port->TO_JSON;
};
foreach my $rel (qw/nodes active_nodes nodes_with_age active_nodes_with_age vlans logs/) {
swagger_path {
tags => ['Objects'],
description => "Returns $rel rows for a given port",
path => "/api/v1/object/device/{ip}/port/{port}/$rel",
parameters => [
ip => {
description => 'Canonical IP of the Device. Use Search methods to find this.',
required => 1,
in => 'path',
},
port => {
description => 'Name of the port. Use the ".../device/{ip}/ports" method to find these.',
required => 1,
in => 'path',
},
],
responses => { default => {} },
}, get qq{/api/v1/object/device/(?<ip>[^/]+)/port/(?<port>[^/]+)/$rel} => require_role api => sub {
my $params = captures;
my $rows = try { schema('netdisco')->resultset('DevicePort')
->find( $$params{port}, $$params{ip} )->$rel }
or send_error('Bad Device or Port', 404);
return to_json [ map {$_->TO_JSON} $rows->all ];
};
}
foreach my $rel (qw/power properties ssid wireless agg_master neighbor last_node/) {
swagger_path {
tags => ['Objects'],
description => "Returns the related $rel table entry for a given port",
path => "/api/v1/object/device/{ip}/port/{port}/$rel",
parameters => [
ip => {
description => 'Canonical IP of the Device. Use Search methods to find this.',
required => 1,
in => 'path',
},
port => {
description => 'Name of the port. Use the ".../device/{ip}/ports" method to find these.',
required => 1,
in => 'path',
},
],
responses => { default => {} },
}, get qq{/api/v1/object/device/(?<ip>[^/]+)/port/(?<port>[^/]+)/$rel} => require_role api => sub {
my $params = captures;
my $row = try { schema('netdisco')->resultset('DevicePort')
->find( $$params{port}, $$params{ip} )->$rel }
or send_error('Bad Device or Port', 404);
return to_json $row->TO_JSON;
};
}
swagger_path {
tags => ['Objects'],
description => "Returns the nodes found on a given Device",
parameters => [
ip => {
description => 'Canonical IP of the Device. Use Search methods to find this.',
required => 1,
in => 'path',
},
active_only => {
description => 'Restrict results to active Nodes only',
type => 'boolean',
default => 'true',
in => 'query',
},
],
responses => { default => {} },
}, get '/api/v1/object/device/:ip/nodes' => require_role api => sub {
my $active = (params->{active_only} and ('true' eq params->{active_only})) ? 1 : 0;
my $rows = try { schema('netdisco')->resultset('Node')
->search({ switch => params->{ip}, ($active ? (-bool => 'active') : ()) }) }
or send_error('Bad Device', 404);
return to_json [ map {$_->TO_JSON} $rows->all ];
};
swagger_path {
tags => ['Objects'],
description => "Returns the nodes found in a given VLAN",
parameters => [
vlan => {
description => 'VLAN number',
type => 'integer',
required => 1,
in => 'path',
},
active_only => {
description => 'Restrict results to active Nodes only',
type => 'boolean',
default => 'true',
in => 'query',
},
],
responses => { default => {} },
}, get '/api/v1/object/vlan/:vlan/nodes' => require_role api => sub {
my $active = (params->{active_only} and ('true' eq params->{active_only})) ? 1 : 0;
my $rows = try { schema('netdisco')->resultset('Node')
->search({ vlan => params->{vlan}, ($active ? (-bool => 'active') : ()) }) }
or send_error('Bad VLAN', 404);
return to_json [ map {$_->TO_JSON} $rows->all ];
};
true;