use Dancer ':syntax';
use App::Netdisco::JobQueue 'jq_insert';
swagger_path {
tags => ['Objects'],
path => (setting('api_base') || '').'/object/device/{ip}',
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(vars->{'tenant'})->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'],
path => (setting('api_base') || '')."/object/device/{ip}/$rel",
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(vars->{'tenant'})->resultset('Device')
->find( params->{ip} )->$rel } or send_error('Bad Device', 404);
return to_json [ map {$_->TO_JSON} $rows->all ];
};
}
swagger_path {
tags => ['Objects'],
path => (setting('api_base') || '').'/object/device/{ip}/jobs',
description => 'Delete jobs and clear skiplist for a device, optionally filtered by fields',
parameters => [
ip => {
description => 'Canonical IP of the Device. Use Search methods to find this.',
required => 1,
in => 'path',
},
port => {
description => 'Port field of the Job',
},
action => {
description => 'Action field of the Job',
},
status => {
description => 'Status field of the Job',
},
username => {
description => 'Username of the Job submitter',
},
userip => {
description => 'IP address of the Job submitter',
},
backend => {
description => 'Backend instance assigned the Job',
},
],
responses => { default => {} },
}, del '/api/v1/object/device/:ip/jobs' => require_role api_admin => sub {
my $device = try { schema(vars->{'tenant'})->resultset('Device')
->find( params->{ip} ) } or send_error('Bad Device', 404);
my $gone = schema(vars->{'tenant'})->resultset('Admin')->search({
device => param('ip'),
( param('port') ? ( port => param('port') ) : () ),
( param('action') ? ( action => param('action') ) : () ),
( param('status') ? ( status => param('status') ) : () ),
( param('username') ? ( username => param('username') ) : () ),
( param('userip') ? ( userip => param('userip') ) : () ),
( param('backend') ? ( backend => param('backend') ) : () ),
})->delete;
schema(vars->{'tenant'})->resultset('DeviceSkip')->search({
device => param('ip'),
( param('action') ? ( actionset => { '&&' => \[ 'ARRAY[?]', param('action') ] } ) : () ),
( param('backend') ? ( backend => param('backend') ) : () ),
})->delete;
return to_json { deleted => ($gone || 0)};
};
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 => (setting('api_base') || '')."/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 qr{/api/v1/object/device/(?<ip>[^/]+)/port/(?<port>.+)/${rel}$} => require_role api => sub {
my $params = captures;
my $rows = try { schema(vars->{'tenant'})->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 => (setting('api_base') || '')."/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 qr{/api/v1/object/device/(?<ip>[^/]+)/port/(?<port>.+)/${rel}$} => require_role api => sub {
my $params = captures;
my $row = try { schema(vars->{'tenant'})->resultset('DevicePort')
->find( $$params{port}, $$params{ip} )->$rel }
or send_error('Bad Device or Port', 404);
return to_json $row->TO_JSON;
};
}
# must come after the port methods above, so the route matches later
swagger_path {
tags => ['Objects'],
description => 'Returns a row from the device_port table',
path => (setting('api_base') || '').'/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(vars->{'tenant'})->resultset('DevicePort')
->find( $$params{port}, $$params{ip} ) }
or send_error('Bad Device or Port', 404);
return to_json $port->TO_JSON;
};
swagger_path {
tags => ['Objects'],
path => (setting('api_base') || '').'/object/device/{ip}/nodes',
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(vars->{'tenant'})->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'],
path => (setting('api_base') || '').'/object/device/{ip}/nodes',
description => "Queue a job to store 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',
},
nodes => {
description => 'List of node tuples (port, VLAN, MAC)',
default => '[]',
schema => {
type => 'array',
items => {
type => 'object',
properties => {
port => {
type => 'string'
},
vlan => {
type => 'integer',
default => '1'
},
mac => {
type => 'string'
}
}
}
},
in => 'body',
},
],
responses => { default => {} },
}, put '/api/v1/object/device/:ip/nodes' => require_role setting('defanged_api_admin') => sub {
jq_insert([{
action => 'macsuck',
device => params->{ip},
subaction => request->body,
username => session('logged_in_user'),
userip => request->remote_address,
}]);
return to_json {};
};
swagger_path {
tags => ['Objects'],
path => (setting('api_base') || '').'/object/vlan/{vlan}/nodes',
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(vars->{'tenant'})->resultset('Node')
->search({ vlan => params->{vlan}, ($active ? (-bool => 'active') : ()) }) }
or send_error('Bad VLAN', 404);
return to_json [ map {$_->TO_JSON} $rows->all ];
};
swagger_path {
tags => ['Objects'],
path => (setting('api_base') || '').'/object/device/{ip}/arps',
description => "Queue a job to store the ARP entries found on a given Device",
parameters => [
ip => {
description => 'Canonical IP of the Device. Use Search methods to find this.',
required => 1,
in => 'path',
},
arps => {
description => 'List of arp tuples (MAC, IP, DNS?). IPs will be resolved to FQDN by Netdisco.',
default => '[]',
schema => {
type => 'array',
items => {
type => 'object',
properties => {
mac => {
type => 'string',
required => 1,
},
ip => {
type => 'string',
required => 1,
},
dns => {
type => 'string',
required => 0,
}
}
}
},
in => 'body',
},
],
responses => { default => {} },
}, put '/api/v1/object/device/:ip/arps' => require_role setting('defanged_api_admin') => sub {
jq_insert([{
action => 'arpnip',
device => params->{ip},
subaction => request->body,
username => session('logged_in_user'),
userip => request->remote_address,
}]);
return to_json {};
};
true;