1package App::Netdisco::Web::Plugin::AdminTask::Topology;
2
3use Dancer ':syntax';
4use Dancer::Plugin::Ajax;
5use Dancer::Plugin::DBIC;
6use Dancer::Plugin::Auth::Extensible;
7
8use App::Netdisco::Web::Plugin;
9use App::Netdisco::Util::Device 'get_device';
10
11use Try::Tiny;
12use NetAddr::IP::Lite ':lower';
13
14register_admin_task({
15  tag => 'topology',
16  label => 'Manual Device Topology',
17});
18
19sub _sanity_ok {
20    my $dev1 = NetAddr::IP::Lite->new(param('dev1'));
21    return 0 unless ($dev1 and $dev1->addr ne '0.0.0.0');
22
23    my $dev2 = NetAddr::IP::Lite->new(param('dev2'));
24    return 0 unless ($dev2 and $dev2->addr ne '0.0.0.0');
25
26    return 0 unless param('port1');
27    return 0 unless param('port2');
28
29    return 0 if
30      (($dev1->addr eq $dev2->addr) and (param('port1') eq param('port2')));
31
32    return 1;
33}
34
35ajax '/ajax/control/admin/topology/add' => require_any_role [qw(admin port_control)] => sub {
36    send_error('Bad Request', 400) unless _sanity_ok();
37
38    my $device = schema('netdisco')->resultset('Topology')
39      ->create({
40        dev1  => param('dev1'),
41        port1 => param('port1'),
42        dev2  => param('dev2'),
43        port2 => param('port2'),
44      });
45
46    # re-set remote device details in affected ports
47    # could fail for bad device or port names
48    try {
49        schema('netdisco')->txn_do(sub {
50          # only work on root_ips
51          my $left  = get_device(param('dev1'));
52          my $right = get_device(param('dev2'));
53
54          # skip bad entries
55          return unless ($left->in_storage and $right->in_storage);
56
57          $left->ports
58            ->search({port => param('port1')}, {for => 'update'})
59            ->single()
60            ->update({
61              remote_ip   => param('dev2'),
62              remote_port => param('port2'),
63              remote_type => undef,
64              remote_id   => undef,
65              is_uplink   => \"true",
66              manual_topo => \"true",
67            });
68
69          $right->ports
70            ->search({port => param('port2')}, {for => 'update'})
71            ->single()
72            ->update({
73              remote_ip   => param('dev1'),
74              remote_port => param('port1'),
75              remote_type => undef,
76              remote_id   => undef,
77              is_uplink   => \"true",
78              manual_topo => \"true",
79            });
80        });
81    };
82};
83
84ajax '/ajax/control/admin/topology/del' => require_any_role [qw(admin port_control)] => sub {
85    send_error('Bad Request', 400) unless _sanity_ok();
86
87    schema('netdisco')->txn_do(sub {
88      my $device = schema('netdisco')->resultset('Topology')
89        ->search({
90          dev1  => param('dev1'),
91          port1 => param('port1'),
92          dev2  => param('dev2'),
93          port2 => param('port2'),
94        })->delete;
95    });
96
97    # re-set remote device details in affected ports
98    # could fail for bad device or port names
99    try {
100        schema('netdisco')->txn_do(sub {
101          # only work on root_ips
102          my $left  = get_device(param('dev1'));
103          my $right = get_device(param('dev2'));
104
105          # skip bad entries
106          return unless ($left->in_storage and $right->in_storage);
107
108          $left->ports
109            ->search({port => param('port1')}, {for => 'update'})
110            ->single()
111            ->update({
112              remote_ip   => undef,
113              remote_port => undef,
114              remote_type => undef,
115              remote_id   => undef,
116              is_uplink   => \"false",
117              manual_topo => \"false",
118            });
119
120          $right->ports
121            ->search({port => param('port2')}, {for => 'update'})
122            ->single()
123            ->update({
124              remote_ip   => undef,
125              remote_port => undef,
126              remote_type => undef,
127              remote_id   => undef,
128              is_uplink   => \"false",
129              manual_topo => \"false",
130            });
131        });
132    };
133};
134
135ajax '/ajax/content/admin/topology' => require_any_role [qw(admin port_control)] => sub {
136    my $set = schema('netdisco')->resultset('Topology')
137      ->search({},{order_by => [qw/dev1 dev2 port1/]});
138
139    content_type('text/html');
140    template 'ajax/admintask/topology.tt', {
141      results => $set,
142    }, { layout => undef };
143};
144
145true;
146