1package App::Netdisco::DB::ResultSet::Node; 2use base 'App::Netdisco::DB::ResultSet'; 3 4use strict; 5use warnings; 6 7__PACKAGE__->load_components(qw/ 8 +App::Netdisco::DB::ExplicitLocking 9/); 10 11=head1 ADDITIONAL METHODS 12 13=head2 search_by_mac( \%cond, \%attrs? ) 14 15 my $set = $rs->search_by_mac({mac => '00:11:22:33:44:55', active => 1}); 16 17Like C<search()>, this returns a ResultSet of matching rows from the Node 18table. 19 20=over 4 21 22=item * 23 24The C<cond> parameter must be a hashref containing a key C<mac> with 25the value to search for. 26 27=item * 28 29Results are ordered by time last seen. 30 31=item * 32 33Additional columns C<time_first_stamp> and C<time_last_stamp> provide 34preformatted timestamps of the C<time_first> and C<time_last> fields. 35 36=item * 37 38A JOIN is performed on the Device table and the Device C<dns> column 39prefetched. 40 41=back 42 43To limit results only to active nodes, set C<< {active => 1} >> in C<cond>. 44 45=cut 46 47sub search_by_mac { 48 my ($rs, $cond, $attrs) = @_; 49 50 die "mac address required for search_by_mac\n" 51 if ref {} ne ref $cond or !exists $cond->{mac}; 52 53 $cond->{'me.mac'} = delete $cond->{mac}; 54 55 return $rs 56 ->search_rs({}, { 57 order_by => {'-desc' => 'time_last'}, 58 '+columns' => [ 59 'device.dns', 60 { time_first_stamp => \"to_char(time_first, 'YYYY-MM-DD HH24:MI')" }, 61 { time_last_stamp => \"to_char(time_last, 'YYYY-MM-DD HH24:MI')" }, 62 ], 63 join => 'device', 64 }) 65 ->search($cond, $attrs); 66} 67 68=head1 SPECIAL METHODS 69 70=head2 delete( \%options? ) 71 72Overrides the built-in L<DBIx::Class> delete method to more efficiently 73handle the removal or archiving of nodes. 74 75=cut 76 77sub delete { 78 my $self = shift; 79 my ($opts) = @_; 80 $opts = {} if (ref {} ne ref $opts); 81 82 my $schema = $self->result_source->schema; 83 my $nodes = $self->search(undef, { columns => 'mac' }); 84 85 if (exists $opts->{archive_nodes} and $opts->{archive_nodes}) { 86 foreach my $set (qw/ 87 NodeIp 88 NodeNbt 89 NodeMonitor 90 Node 91 /) { 92 $schema->resultset($set)->search( 93 { mac => { '-in' => $nodes->as_query }}, 94 )->update({ active => \'false' }); 95 } 96 97 $schema->resultset('NodeWireless') 98 ->search({ mac => { '-in' => $nodes->as_query }})->delete; 99 100 # avoid letting DBIC delete nodes 101 return 0E0; 102 } 103 elsif (exists $opts->{only_nodes} and $opts->{only_nodes}) { 104 # now let DBIC do its thing 105 return $self->next::method(); 106 } 107 elsif (exists $opts->{keep_nodes} and $opts->{keep_nodes}) { 108 # avoid letting DBIC delete nodes 109 return 0E0; 110 } 111 else { 112 foreach my $set (qw/ 113 NodeMonitor 114 NodeWireless 115 NodeNbt 116 /) { 117 $schema->resultset($set)->search( 118 { mac => { '-in' => $nodes->as_query }}, 119 )->delete; 120 } 121 122 # for node_ip only delete if there are no longer 123 # any nodes referencing the IP. 124 125 my @mac_restrict_aq = @{${ $nodes->as_query }}; 126 my @macport_restrict_aq = @{${ $nodes->search(undef, { '+columns' => 'port' })->as_query }}; 127 my $mac_restrict = shift @mac_restrict_aq; 128 my $macport_restrict = shift @macport_restrict_aq; 129 130 my $deleted = $schema->storage->dbh_do(sub { 131 my ($storage, $dbh, @extra) = @_; 132 local $dbh->{TraceLevel} = 133 ($ENV{DBIC_TRACE} ? '1|SQL' : $dbh->{TraceLevel}); 134 $dbh->do(<<SQL 135DELETE FROM node_ip WHERE mac IN ( 136 SELECT mac FROM node_ip 137 LEFT OUTER JOIN ( 138 SELECT mac, port FROM node 139 EXCEPT ($macport_restrict)) exceptions 140 USING (mac) 141 WHERE node_ip.mac IN ($mac_restrict) 142 AND exceptions.port IS NULL) 143SQL 144 , undef, (map {$_->[1]} (@macport_restrict_aq, @mac_restrict_aq))); 145 }); 146 147 # now let DBIC do its thing 148 return $self->next::method(); 149 } 150} 151 1521; 153