efficient device delete which does not walk nodes
This commit is contained in:
		| @@ -130,7 +130,15 @@ sub _set_canonical_ip { | ||||
|             my $gone = $device->device_ips->delete; | ||||
|             debug sprintf ' [%s] device - removed %s aliases', | ||||
|               $oldip, $gone; | ||||
|             $device->delete; | ||||
|  | ||||
|             # our special delete which is more efficient | ||||
|             schema('netdisco')->resultset('Device') | ||||
|               ->search({ ip => $device->ip })->delete; | ||||
|  | ||||
|             # a new row object from the old one | ||||
|             $device = schema('netdisco')->resultset('Device') | ||||
|               ->new({ $device->get_columns }); | ||||
|  | ||||
|             debug sprintf ' [%s] device - deleted self', $oldip; | ||||
|           }); | ||||
|  | ||||
|   | ||||
| @@ -78,7 +78,6 @@ __PACKAGE__->add_columns( | ||||
| ); | ||||
| __PACKAGE__->set_primary_key("ip"); | ||||
|  | ||||
|  | ||||
| # Created by DBIx::Class::Schema::Loader v0.07015 @ 2012-01-07 14:20:02 | ||||
| # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:671/XuuvsO2aMB1+IRWFjg | ||||
|  | ||||
|   | ||||
| @@ -528,4 +528,44 @@ sub with_port_count { | ||||
|       }); | ||||
| } | ||||
|  | ||||
| =head1 SPECIAL METHODS | ||||
|  | ||||
| =head2 delete( \%options? ) | ||||
|  | ||||
| Overrides the built-in L<DBIx::Class> delete method to more efficiently | ||||
| handle the removal or archiving of nodes. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub delete { | ||||
|   my $self = shift; | ||||
|  | ||||
|   my $schema = $self->result_source->schema; | ||||
|   my $devices = $self->search(undef, { columns => 'ip' }); | ||||
|  | ||||
|   foreach my $set (qw/ | ||||
|     Community | ||||
|     DeviceIp | ||||
|     DeviceVlan | ||||
|     DevicePower | ||||
|     DeviceModule | ||||
|   /) { | ||||
|       $schema->resultset($set)->search( | ||||
|         { ip => { '-in' => $devices->as_query }}, | ||||
|       )->delete; | ||||
|   } | ||||
|  | ||||
|   $schema->resultset('Admin')->search({ | ||||
|     device => { '-in' => $devices->as_query }, | ||||
|     action => { '-like' => 'queued%' }, | ||||
|   })->delete; | ||||
|  | ||||
|   $schema->resultset('DevicePort')->search( | ||||
|     { ip => { '-in' => $devices->as_query }}, | ||||
|   )->delete(@_); | ||||
|  | ||||
|   # now let DBIC do its thing | ||||
|   return $self->next::method(); | ||||
| } | ||||
|  | ||||
| 1; | ||||
|   | ||||
| @@ -133,4 +133,39 @@ sub with_vlan_count { | ||||
|       }); | ||||
| } | ||||
|  | ||||
| =head1 SPECIAL METHODS | ||||
|  | ||||
| =head2 delete( \%options? ) | ||||
|  | ||||
| Overrides the built-in L<DBIx::Class> delete method to more efficiently | ||||
| handle the removal or archiving of nodes. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub delete { | ||||
|   my $self = shift; | ||||
|  | ||||
|   my $schema = $self->result_source->schema; | ||||
|   my $ports = $self->search(undef, { columns => 'ip' }); | ||||
|  | ||||
|   foreach my $set (qw/ | ||||
|     DevicePortPower | ||||
|     DevicePortVlan | ||||
|     DevicePortWireless | ||||
|     DevicePortSsid | ||||
|     DevicePortLog | ||||
|   /) { | ||||
|       $schema->resultset($set)->search( | ||||
|         { ip => { '-in' => $ports->as_query }}, | ||||
|       )->delete; | ||||
|   } | ||||
|  | ||||
|   $schema->resultset('Node')->search( | ||||
|     { switch => { '-in' => $ports->as_query }}, | ||||
|   )->delete(@_); | ||||
|  | ||||
|   # now let DBIC do its thing | ||||
|   return $self->next::method(); | ||||
| } | ||||
|  | ||||
| 1; | ||||
|   | ||||
| @@ -8,7 +8,9 @@ __PACKAGE__->load_components(qw/ | ||||
|   +App::Netdisco::DB::ExplicitLocking | ||||
| /); | ||||
|  | ||||
| =head1 search_by_mac( \%cond, \%attrs? ) | ||||
| =head1 ADDITIONAL METHODS | ||||
|  | ||||
| =head2 search_by_mac( \%cond, \%attrs? ) | ||||
|  | ||||
|  my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55', active => 1}); | ||||
|  | ||||
| @@ -63,4 +65,57 @@ sub search_by_mac { | ||||
|       ->search($cond, $attrs); | ||||
| } | ||||
|  | ||||
| =head1 SPECIAL METHODS | ||||
|  | ||||
| =head2 delete( \%options? ) | ||||
|  | ||||
| Overrides the built-in L<DBIx::Class> delete method to more efficiently | ||||
| handle the removal or archiving of nodes. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| sub delete { | ||||
|   my $self = shift; | ||||
|   my ($opts) = @_; | ||||
|  | ||||
|   my $schema = $self->result_source->schema; | ||||
|   my $nodes = $self->search(undef, { columns => 'mac' }); | ||||
|  | ||||
|   if (ref {} eq ref $opts | ||||
|       and exists $opts->{archive} and $opts->{archive}) { | ||||
|  | ||||
|       foreach my $set (qw/ | ||||
|         NodeIp | ||||
|         NodeNbt | ||||
|         NodeMonitor | ||||
|         Node | ||||
|       /) { | ||||
|           $schema->resultset($set)->search( | ||||
|             { mac => { '-in' => $nodes->as_query }}, | ||||
|           )->update({ active => \'false' }); | ||||
|       } | ||||
|  | ||||
|       $schema->resultset('NodeWireless') | ||||
|         ->search({ mac => { '-in' => $nodes->as_query }})->delete; | ||||
|  | ||||
|       # avoid letting DBIC delete nodes | ||||
|       return 0E0; | ||||
|   } | ||||
|   else { | ||||
|       foreach my $set (qw/ | ||||
|         NodeIp | ||||
|         NodeNbt | ||||
|         NodeMonitor | ||||
|         NodeWireless | ||||
|       /) { | ||||
|           $schema->resultset($set)->search( | ||||
|             { mac => { '-in' => $nodes->as_query }}, | ||||
|           )->delete; | ||||
|       } | ||||
|  | ||||
|       # now let DBIC do its thing | ||||
|       return $self->next::method(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| 1; | ||||
|   | ||||
| @@ -59,6 +59,22 @@ foreach my $jobtype (keys %jobs_all, keys %jobs) { | ||||
|     }; | ||||
| } | ||||
|  | ||||
| ajax '/ajax/control/admin/delete' => require_role admin => sub { | ||||
|     send_error('Missing device', 400) unless param('device'); | ||||
|  | ||||
|     my $device = NetAddr::IP::Lite->new(param('device')); | ||||
|     send_error('Bad device', 400) | ||||
|       if ! $device or $device->addr eq '0.0.0.0'; | ||||
|  | ||||
|     schema('netdisco')->txn_do(sub { | ||||
|       my $device = schema('netdisco')->resultset('Device') | ||||
|         ->search({ip => param('device')}); | ||||
|  | ||||
|       # will delete everything related too... | ||||
|       $device->delete; | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| get '/admin/*' => require_role admin => sub { | ||||
|     my ($tag) = splat; | ||||
|  | ||||
|   | ||||
| @@ -56,15 +56,7 @@ ajax '/ajax/control/admin/pseudodevice/add' => require_role admin => sub { | ||||
|  | ||||
| ajax '/ajax/control/admin/pseudodevice/del' => require_role admin => sub { | ||||
|     send_error('Bad Request', 400) unless _sanity_ok(); | ||||
|  | ||||
|     schema('netdisco')->txn_do(sub { | ||||
|       my $device = schema('netdisco')->resultset('Device') | ||||
|         ->find({ip => param('ip')}); | ||||
|  | ||||
|       $device->ports->delete; | ||||
|       $device->device_ips->delete; | ||||
|       $device->delete; | ||||
|     }); | ||||
|     forward '/ajax/control/admin/delete', { device => param('ip') }; | ||||
| }; | ||||
|  | ||||
| ajax '/ajax/control/admin/pseudodevice/update' => require_role admin => sub { | ||||
|   | ||||
| @@ -85,6 +85,11 @@ div.content > div.tab-content table.nd_floatinghead thead { | ||||
|   z-index: -1000; | ||||
| } | ||||
|  | ||||
| /* for when we pinch h4 styling but don't want bold */ | ||||
| .nd_unbolden { | ||||
|   font-weight: normal; | ||||
| } | ||||
|  | ||||
| /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ | ||||
| /* styles to adjust the hero box used for homepage + login */ | ||||
|  | ||||
|   | ||||
| @@ -4,8 +4,8 @@ var nd_save_ok = false; | ||||
| // user clicked or asked for port changes to be submitted via ajax | ||||
| function port_control (e) { | ||||
|   var td = $(e).closest('td'), | ||||
|       logmessage = $('#nd_portlog_log').val(); | ||||
|   $('#nd_portlog_log').val(''); | ||||
|       logmessage = $('#nd_portlog-log').val(); | ||||
|   $('#nd_portlog-log').val(''); | ||||
|  | ||||
|   if (nd_save_ok == false) { | ||||
|     td.find('.nd_editable-cell-content').text(td.data('default')); | ||||
| @@ -109,7 +109,7 @@ $(document).ready(function() { | ||||
|   }); | ||||
|  | ||||
|   // to tell whether bootstrap's modal had Submit button pressed :( | ||||
|   $('#ports_pane').on('click', '#nd_portlog_submit', function() { | ||||
|   $('#ports_pane').on('click', '#nd_portlog-submit', function() { | ||||
|     nd_save_ok = true; | ||||
|   }); | ||||
|  | ||||
|   | ||||
| @@ -35,10 +35,10 @@ | ||||
|           data-target="#nd_devdel-[% count %]" type="button"><i class="icon-trash text-error"></i></button> | ||||
|  | ||||
|         <div id="nd_devdel-[% count %]" class="nd_modal modal hide fade" tabindex="-1" | ||||
|           role="dialog" aria-labelledby="nd_devdel_label-[% count %]" aria-hidden="true"> | ||||
|           role="dialog" aria-labelledby="nd_devdel-label-[% count %]" aria-hidden="true"> | ||||
|           <div class="modal-header"> | ||||
|             <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> | ||||
|             <h3 id="nd_devdel_label-[% count %]">Are you sure?</h3> | ||||
|             <h3 id="nd_devdel-label-[% count %]">Are you sure?</h3> | ||||
|           </div> | ||||
|           <div class="modal-body"> | ||||
|             <blockquote> | ||||
|   | ||||
| @@ -54,10 +54,10 @@ | ||||
|           data-target="#nd_devdel-[% count %]" type="button"><i class="icon-trash text-error"></i></button> | ||||
|  | ||||
|         <div id="nd_devdel-[% count %]" class="nd_modal modal hide fade" tabindex="-1" | ||||
|           role="dialog" aria-labelledby="nd_devdel_label-[% count %]" aria-hidden="true"> | ||||
|           role="dialog" aria-labelledby="nd_devdel-label-[% count %]" aria-hidden="true"> | ||||
|           <div class="modal-header"> | ||||
|             <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> | ||||
|             <h3 id="nd_devdel_label-[% count %]">Are you sure?</h3> | ||||
|             <h3 id="nd_devdel-label-[% count %]">Are you sure?</h3> | ||||
|           </div> | ||||
|           <div class="modal-body"> | ||||
|             <blockquote> | ||||
|   | ||||
| @@ -53,10 +53,10 @@ | ||||
|           data-target="#nd_devdel-[% count %]" type="button"><i class="icon-trash text-error"></i></button> | ||||
|  | ||||
|         <div id="nd_devdel-[% count %]" class="nd_modal modal hide fade" tabindex="-1" | ||||
|           role="dialog" aria-labelledby="nd_devdel_label-[% count %]" aria-hidden="true"> | ||||
|           role="dialog" aria-labelledby="nd_devdel-label-[% count %]" aria-hidden="true"> | ||||
|           <div class="modal-header"> | ||||
|             <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> | ||||
|             <h3 id="nd_devdel_label-[% count %]">Are you sure?</h3> | ||||
|             <h3 id="nd_devdel-label-[% count %]">Are you sure?</h3> | ||||
|           </div> | ||||
|           <div class="modal-body"> | ||||
|             <blockquote> | ||||
|   | ||||
| @@ -109,25 +109,29 @@ | ||||
|           data-toggle="modal" data-target="#nd_devdel" type="button">Delete</button> | ||||
|  | ||||
|         <div id="nd_devdel" class="nd_modal modal hide fade" tabindex="-1" | ||||
|           role="dialog" aria-labelledby="nd_devdel_label" aria-hidden="true"> | ||||
|           role="dialog" aria-labelledby="nd_devdel-label" aria-hidden="true"> | ||||
|           <div class="modal-header"> | ||||
|             <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> | ||||
|             <h3 id="nd_devdel_label">Confirm Delete: [% d.dns || d.ip | html_entity %]</h3> | ||||
|             <h3 id="nd_devdel-label">Confirm Delete: [% d.dns || d.ip | html_entity %]</h3> | ||||
|           </div> | ||||
|           <div class="modal-body"> | ||||
|             <blockquote> | ||||
|               <ul> | ||||
|                 <li><p>This action is immediate and not reversible</p></li> | ||||
|                 <li><p>All associated Nodes will be removed from the database</p></li> | ||||
|                 <li><p>All associated Nodes may be removed from the database</p></li> | ||||
|               </ul> | ||||
|             </blockquote> | ||||
|             <textarea class="input-block-level" rows="2" data-form="delete" | ||||
|             <textarea id="nd_devdel-log" class="input-block-level" rows="2" data-form="delete" | ||||
|               placeholder="Enter a log message" name="log"></textarea> | ||||
|             <label class="checkbox"> | ||||
|               <input id="nd_devdel-archive" type="checkbox" data-form="delete" name="archive"> | ||||
|               <h4 class="nd_unbolden">Archive Nodes</h4> | ||||
|             </label> | ||||
|             <input type="hidden" data-form="delete" value="[% d.ip %]" name="device"/> | ||||
|           </div> | ||||
|           <div class="modal-footer"> | ||||
|             <button class="btn btn-success" data-dismiss="modal" aria-hidden="true">No !</button> | ||||
|             <button class="btn btn-danger nd_adminbutton" name="delete" data-dismiss="modal">Really Delete</button> | ||||
|             <button class="btn btn-success" data-dismiss="modal" aria-hidden="true">Cancel</button> | ||||
|             <button class="btn btn-danger nd_adminbutton" name="delete" data-dismiss="modal">Confirm</button> | ||||
|           </div> | ||||
|         </div> | ||||
|       </td> | ||||
|   | ||||
| @@ -278,12 +278,12 @@ | ||||
| <div id="nd_portlog" class="nd_modal nd_deep-horizon modal hide fade" tabindex="-1" | ||||
|     role="dialog" aria-hidden="true"> | ||||
|   <div class="modal-body"> | ||||
|     <textarea id="nd_portlog_log" class="input-block-level" rows="2" name="log" | ||||
|     <textarea id="nd_portlog-log" class="input-block-level" rows="2" name="log" | ||||
|       placeholder="Enter a log message"></textarea> | ||||
|   </div> | ||||
|   <div class="modal-footer"> | ||||
|     <button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button> | ||||
|     <button id="nd_portlog_submit" class="btn btn-info" data-dismiss="modal">Continue</button> | ||||
|     <button id="nd_portlog-submit" class="btn btn-info" data-dismiss="modal">Continue</button> | ||||
|   </div> | ||||
| </div> | ||||
| [% END %] | ||||
|   | ||||
| @@ -59,6 +59,7 @@ | ||||
|     </div> | ||||
|   </div> | ||||
|   [% ELSE %] | ||||
|   <div class="span4 alert alert-info">No devices found. Do you need to run a Discover?</div> | ||||
|   <div class="span4 alert alert-info">No devices found. Do you need to run a | ||||
|     <a href="[% uri_for('/') %]">Discover?</a></div> | ||||
|   [% END %] | ||||
| </div> | ||||
|   | ||||
| @@ -104,12 +104,12 @@ | ||||
|         ,url: uri_base + '/ajax/control/admin/' + mode | ||||
|         ,data: tr.find('input[data-form="' + mode + '"],textarea[data-form="' + mode + '"]').serializeArray() | ||||
|         ,success: function() { | ||||
|           toastr.info('Queued '+ mode +' for device '+ tr.data('for-device')); | ||||
|           toastr.info('Requested '+ mode +' for device '+ tr.data('for-device')); | ||||
|         } | ||||
|         // skip any error reporting for now | ||||
|         // TODO: fix sanity_ok in Netdisco Web | ||||
|         ,error: function() { | ||||
|           toastr.error('Failed to queue '+ mode +' for device '+ tr.data('for-device')); | ||||
|           toastr.error('Failed to '+ mode +' for device '+ tr.data('for-device')); | ||||
|         } | ||||
|       }); | ||||
|     }); | ||||
| @@ -122,4 +122,10 @@ | ||||
|     $('#ports_pane').on('hidden', '.nd_modal', function () { | ||||
|       $(this).toggleClass('nd_deep-horizon'); | ||||
|     }); | ||||
|  | ||||
|     // clear any values in the delete confirm dialog | ||||
|     $('#details_pane').on('hidden', '.nd_modal', function () { | ||||
|       $('#nd_devdel-log').val(''); | ||||
|       $('#nd_devdel-archive').attr('checked', false); | ||||
|     }); | ||||
|   }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user