1#!/usr/bin/perl -w 2# 3# MIT Public License 4# http://www.opensource.org/licenses/MIT 5# 6# Copyright (C) 2012-2014 Tieto Corporation. 7# 8# Permission is hereby granted, free of charge, to any person obtaining a copy 9# of this software and associated documentation files (the "Software"), to deal 10# in the Software without restriction, including without limitation the rights 11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12# copies of the Software, and to permit persons to whom the Software is 13# furnished to do so, subject to the following conditions: 14# 15# The above copyright notice and this permission notice shall be included in all 16# copies or substantial portions of the Software. 17# 18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24# THE SOFTWARE. 25 26use strict; 27#use lib "/srv/xmlrpc/perl-lib"; 28use LWP::UserAgent; 29use HTTP::Request::Common; 30eval { 31 require IO::Socket::SSL; 32 import IO::Socket::SSL; 33}; 34die "Info: Please install Net::SSLeay perl module\n yum install perl-Net-SSLeay\n apt-get install libnet-ssleay-perl\n" if $@; 35use Net::SSLeay; 36use MIME::Base64; 37use Getopt::Long; 38eval { 39 require JSON; 40 import JSON; 41}; 42die "Info: Please install JSON perl module\n yum install perl-JSON\n apt-get install libjson-perl\n" if $@; 43eval { 44 require Date::Parse; 45 import Date::Parse; 46}; 47die "Info: Please install Date::Parse perl module\n yum install perl-TimeDate\n apt-get install libtimedate-perl\n" if $@; 48 49my $verbose = 0; 50my %keys; 51my %remove; 52# Generate password string with "echo -n password | base64" 53my $servers = { 54 "test1" => { 55 url => "http://localhost", 56 username => "admin", 57 password => "YWRtaW4=", 58 }, 59 # "server2" => { 60 # url => "https://server2.acme.com:444", 61 # username => "admin", 62 # password => "YWRtaW4=", 63 # cert => "/var/cfengine/httpd/ssl/certs/server2.cert", 64 # }, 65 }; 66 67GetOptions('v|verbose' => \$verbose) || die "Usage: $0 [--verbose]\n"; 68 69########################################################################### 70# Setup server certificate 71# 72# This is required to make this script work with libnet-http-perl version > 6 73# Hostname is checked by devault in versions > 6 and we only use IP address 74$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0; 75 76for my $server (sort keys %$servers) { 77 print "Server: $server "; 78 79 # Set up server cert 80 if ( exists $servers->{$server}->{cert} ) { 81 eval { 82 IO::Socket::SSL::set_ctx_defaults( 83 verify_mode => Net::SSLeay->VERIFY_PEER(), 84 ca_file => "$servers->{$server}->{cert}", 85 ); 86 }; 87 } 88 89 my $query = '{ "query": "SELECT Hosts.HostKey AS \"Host key\", Hosts.HostName AS \"Host name\", Hosts.LastReportTimeStamp AS \"Last report time\", Hosts.FirstReportTimeStamp AS \"First report-time\", Hosts.IPAddress AS \"IP address\" FROM Hosts" }'; 90 91 my $ua = new LWP::UserAgent(agent => "CLEANUP/1.0"); 92 my $req = HTTP::Request->new(POST => "$servers->{$server}->{url}/api/query"); 93 94 $req->authorization_basic($servers->{$server}->{username}, decode_base64($servers->{$server}->{password})); 95 $req->content($query); 96 my $res = $ua->request($req); 97 unless ( $res->is_success ) { 98 print "Query failed\n" if $verbose; 99 next; 100 } 101 print "Query successful\n" if $verbose; 102 my $decoded_json = decode_json( $res->content ); 103 104 for my $row ( @{$decoded_json->{data}[0]->{rows}} ) { 105 my $ip_address = "Unknown"; 106 my $host_key = $row->[0]; 107 my $hostname = $row->[1]; 108 my $report_timestamp = str2time($row->[2]); 109 my $first_report = str2time($row->[3]); 110 $ip_address = $row->[4] if $row->[4]; 111 $first_report =~ s/\..*//; 112 $report_timestamp =~ s/\..*//; 113 # print "$host_key $hostname $first_report $report_timestamp $ip_address\n" if $verbose; 114 $keys{$host_key}->{$server}->{first_report} = $first_report; 115 $keys{$host_key}->{$server}->{hostname} = $hostname; 116 $keys{$host_key}->{$server}->{report_timestamp} = $report_timestamp; 117 $keys{$host_key}->{$server}->{ip_address} = $ip_address; 118 } 119} 120 121# Remove all hosts with report_timestamp older then 90 days 122for my $key ( sort keys %keys ) { 123 for my $server ( sort keys %{$keys{$key}} ) { 124 if ( $keys{$key}->{$server}->{report_timestamp} < time() - 60 * 60 * 24 * 90 ) { 125 print "Host key $key, hostname $keys{$key}->{$server}->{hostname} on server $server is older then 90 days\n" if $verbose; 126 $remove{$key}->{$server} = 1; 127 } 128 } 129} 130 131# Remove all duplicate keys if report_timestamp is 24 hours older then the newest one 132for my $key ( sort keys %keys ) { 133 my $newest = 0; 134 for my $server ( sort keys %{$keys{$key}} ) { 135 $newest = $keys{$key}->{$server}->{report_timestamp} if $keys{$key}->{$server}->{report_timestamp} > $newest; 136 } 137 for my $server ( sort keys %{$keys{$key}} ) { 138 if ( $keys{$key}->{$server}->{report_timestamp} < $newest - 60 * 60 * 24 ) { 139 print "Host key $key, hostname $keys{$key}->{$server}->{hostname} on server $server is a duplicate key and it is 24 hours older then the newest one\n"; 140 $remove{$key}->{$server} = 1; 141 } 142 } 143} 144 145# Remove all duplicate hostnames if report_timestamp is 24 hours older then the newest one 146my %hosts; 147for my $key ( sort keys %keys ) { 148 for my $server ( sort keys %{$keys{$key}} ) { 149 $hosts{$keys{$key}->{$server}->{hostname}}->{newest} = 0 unless exists $hosts{$keys{$key}->{$server}->{hostname}}; 150 $hosts{$keys{$key}->{$server}->{hostname}}->{server}->{$server}->{$key} = $keys{$key}->{$server}->{report_timestamp}; 151 $hosts{$keys{$key}->{$server}->{hostname}}->{newest} = $keys{$key}->{$server}->{report_timestamp} if $keys{$key}->{$server}->{report_timestamp} > $hosts{$keys{$key}->{$server}->{hostname}}->{newest}; 152 } 153} 154for my $hostname ( sort keys %hosts ) { 155 for my $server ( sort keys %{$hosts{$hostname}->{server}} ) { 156 for my $key ( sort keys %{$hosts{$hostname}->{server}->{$server}} ) { 157 if ( $hosts{$hostname}->{server}->{$server}->{$key} < $hosts{$hostname}->{newest} - 60 * 60 * 24 ) { 158 print "Host key $key, hostname $hostname on server $server is a duplicate hostname and it is 24 hours older then the newest one\n"; 159 $remove{$key}->{$server} = 1; 160 } 161 } 162 } 163} 164 165# Remove hosts 166for my $key ( sort keys %remove ) { 167 for my $server ( sort keys %{$remove{$key}} ) { 168 print "Delete key $key from server $server: " if $verbose; 169 170 # Set up server cert 171 if ( exists $servers->{$server}->{cert} ) { 172 eval { 173 IO::Socket::SSL::set_ctx_defaults( 174 verify_mode => Net::SSLeay->VERIFY_PEER(), 175 ca_file => "$servers->{$server}->{cert}", 176 ); 177 }; 178 } 179 180 my $ua = new LWP::UserAgent(agent => "CLEANUP/1.0"); 181 my $req = HTTP::Request->new(DELETE => "$servers->{$server}->{url}/api/host/$key"); 182 $req->authorization_basic($servers->{$server}->{username}, decode_base64($servers->{$server}->{password})); 183 my $res = $ua->request($req); 184 unless ( $res->is_success ) { 185 print "Failed\n" if $verbose; 186 exit 1; 187 } 188 print "Successful\n" if $verbose; 189 } 190} 191