skip directories in all_conf
[pxelator] / lib / PXElator / client.pm
index 8950cb1..89c3498 100644 (file)
@@ -5,11 +5,14 @@ use strict;
 use autodie;
 
 use File::Slurp;
-use Net::Ping;
-use Carp qw/confess/;
+use Data::Dump qw/dump/;
+use File::Path;
 
 use server;
 use format;
+use ip;
+use ping;
+use kvm;
 
 our $debug = $server::debug;
 
@@ -31,7 +34,7 @@ sub conf_value {
        } elsif ( -f $path ) {
                $value = read_file $path;
        } else {
-               confess "$path not file or symlink";
+               warn "W: $path not file or symlink\n";
        }
        return $value;
 }
@@ -47,7 +50,8 @@ sub conf {
        }
 
        my $path = ip_path $ip;
-       mkdir $path unless -d $path;
+       mkdir $path unless -e $path;
+       warn "WARNING: $path not directory" unless -d $path;
        $path .= '/' . $name;
 
        if ( defined $value ) {
@@ -59,25 +63,49 @@ sub conf {
                write_file $path, $default;
                warn "default $path = $default";
                $value = $default;
+       } elsif ( -l $path ) {
+               $value = readlink $path;
        } elsif ( -f $path ) {
                $value = read_file $path;
+               chomp $value;
        } else {
                warn "# $name missing $path\n" if $debug;
        }
        return $value;
 }
 
+sub all_conf {
+       my $ip = shift;
+       my $path = ip_path $ip || return;
+       my $conf;
+       foreach my $file ( glob("$path/*"), glob("$path/*/*") ) {
+               my $name = $file;
+               $name =~ s{^$path/+}{} || die "can't remove $path from $name";
+               next if -d $file;
+               $conf->{ $name } =
+                       -l $file ? readlink  $file :
+                       -f $file ? read_file $file :
+                       '?';
+       }
+       return $conf;
+}
 sub next_ip($) {
        my $mac = shift;
+       $mac = format::mac($mac);
 
-       my $p = Net::Ping->new;
+       if ( $server::new_clients > 0 ) {
+               warn "# clients left: ", --$server::new_clients;
+       } else {
+               warn "W: no new clients accepted";
+               return '0.0.0.0';
+       }
 
        my $prefix = $server::ip;
        $prefix =~ s{\.\d+$}{.};
        my $addr = $server::ip_from || die;
        my $ip = $prefix . $addr;
 
-       while ( -e ip_path($ip) || $p->ping( $ip, 0.7 ) ) {
+       while ( -e ip_path($ip) || ping::host($ip) ) {
                $ip = $prefix . $addr++;
                die "all addresses allocated!" if $addr == $server::ip_to;
                warn "skip $ip\n";
@@ -85,22 +113,27 @@ sub next_ip($) {
 
        warn "next_ip $ip\n";
 
-       mkdir ip_path($ip);
-
-       my $mac_path = mac_path($mac);
-       unlink $mac_path if -e $mac_path;       # XXX audit?
-       symlink ip_path($ip), $mac_path;
-       write_file ip_path($ip,'mac'), $mac;
+       save_ip_mac( $ip, $mac );
 
        return $ip;
+}
+
+sub save_ip_mac {
+       my ($ip,$mac) = @_;
+       $mac = format::mac($mac);
+       return if $mac eq '00:00:00:00:00:00' || $ip eq '0.0.0.0';
 
+       mkdir ip_path($ip) unless -e ip_path($ip);
+
+       my $mac_path = mac_path($mac);
+       unlink $mac_path if -l $mac_path;       # XXX audit?
+       symlink ip_path($ip), $mac_path;
+       write_file( ip_path($ip,'mac'), $mac );
 }
 
 sub ip_from_mac($) {
        my $mac = shift;
-
-       $mac = lc $mac;
-       $mac =~ s{:}{}g;
+       $mac = format::mac($mac);
 
        my $mac_path = mac_path $mac;
        return unless -e $mac_path;
@@ -128,10 +161,68 @@ sub mac_from_ip($) {
 
 sub change_ip($$) {
        my ($old, $new) = @_;
-       my $mac = mac_from_ip($old);
+       return if $old eq $new;
+       my $mac = mac_from_ip($old) || die "no mac for $old";
        rename ip_path($old), ip_path($new);
        unlink mac_path($mac);
        symlink ip_path($new), mac_path($mac);
+       return $new;
+}
+
+sub all_ips {
+       sort { ip::to_int($a) cmp ip::to_int($b) }
+       map {
+               my $ip = $_;
+               $ip =~ s{^.+/ip/}{};
+               autocreate_params( $ip );
+               $ip;
+       } glob("$server::conf/ip/*") 
+}
+
+sub remove {
+       my $ip = shift;
+       if ( my $mac = mac_from_ip $ip ) {
+               unlink "$server::conf/mac/$mac";
+       }
+       rmtree "$server::conf/ip/$ip";
+}
+
+sub arp_mac_dev {
+       my $arp = {
+               map {
+                       my @c = split(/\s+/,$_);
+                       if ( $#c == 5 ) {
+                               client::save_ip_mac( $c[0], $c[3] );
+                               ( uc $c[3] => $c[5] )
+                       } else {
+                       }
+               } read_file('/proc/net/arp')
+       };
+
+       warn "# arp ",dump( $arp );
+       return $arp;
+}
+
+sub rebuild_mac_links {
+       warn "# rebuild mac links";
+       foreach my $ip ( all_ips ) {
+               my $mac = ip_path $ip, 'mac';
+               if ( -e $mac ) {
+                       $mac = read_file $mac;
+                       chomp $mac;
+                       save_ip_mac( $ip, $mac );
+                       warn "## $ip $mac\n";
+               }
+       }
+}
+
+sub autocreate_params {
+       my $ip = shift;
+       my $mac = mac_from_ip $ip;
+       if ( $mac =~ m{^AC:DE:48:00:00} && ! defined conf( $ip, 'kvm' ) ) {
+               conf( $ip, 'kvm', default => kvm::nr_from_mac( $mac ) );
+               warn "# create kvm for $ip";
+       }
 }
 
 1;