stip package name from sub
[pxelator] / lib / PXElator / client.pm
index 1c062f5..8950cb1 100644 (file)
@@ -4,8 +4,37 @@ use warnings;
 use strict;
 use autodie;
 
-use server;
 use File::Slurp;
+use Net::Ping;
+use Carp qw/confess/;
+
+use server;
+use format;
+
+our $debug = $server::debug;
+
+sub mkbasedir {
+       my $path = shift;
+       $path =~ s{(^.*)/[^/]+$}{$1};
+       mkdir $path unless -d $path;
+       return $path;
+}
+
+sub mac_path { $server::conf . '/mac/' . $_[0] }
+sub  ip_path { $server::conf . '/ip/'  . join('/', @_) }
+sub conf_value {
+       my $path = shift;
+       my $value;
+       if ( -l $path ) {
+               $value = readlink $path;
+               $value =~ s{.*/([^/]+)$}{$1};
+       } elsif ( -f $path ) {
+               $value = read_file $path;
+       } else {
+               confess "$path not file or symlink";
+       }
+       return $value;
+}
 
 sub conf {
        my $ip  = shift;
@@ -17,26 +46,92 @@ sub conf {
                $default = $_[1]
        }
 
-       my $path ="$server::conf/ip/$ip";
+       my $path = ip_path $ip;
        mkdir $path unless -d $path;
        $path .= '/' . $name;
 
        if ( defined $value ) {
+               mkbasedir  $path;
                write_file $path, $value;
                warn "update $path = $value";
        } elsif ( ! -e $path && defined $default ) {
+               mkbasedir  $path;
                write_file $path, $default;
                warn "default $path = $default";
                $value = $default;
-       } elsif ( -e $path ) {
-               if ( -l $path ) {
-                       $value = readlink $path;
-                       $value =~ s{.*/([^/]+)$}{$1};
-               } else {
-                       $value = read_file $path;
-               }
+       } elsif ( -f $path ) {
+               $value = read_file $path;
+       } else {
+               warn "# $name missing $path\n" if $debug;
        }
        return $value;
 }
 
+sub next_ip($) {
+       my $mac = shift;
+
+       my $p = Net::Ping->new;
+
+       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 ) ) {
+               $ip = $prefix . $addr++;
+               die "all addresses allocated!" if $addr == $server::ip_to;
+               warn "skip $ip\n";
+       }
+
+       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;
+
+       return $ip;
+
+}
+
+sub ip_from_mac($) {
+       my $mac = shift;
+
+       $mac = lc $mac;
+       $mac =~ s{:}{}g;
+
+       my $mac_path = mac_path $mac;
+       return unless -e $mac_path;
+
+       my $ip;
+
+       if ( -f $mac_path ) {
+               $ip = read_file $mac_path;
+               unlink $mac_path;
+               symlink ip_path($ip), $mac_path;
+               warn "I: upgrade to mac symlink $mac_path\n";
+       } elsif ( -l $mac_path ) {
+               $ip = conf_value $mac_path;
+       } else {
+               die "$mac_path not file or symlink";
+       }
+
+       return $ip;
+}
+
+sub mac_from_ip($) {
+       my $ip = shift;
+       conf_value ip_path($ip, 'mac');
+}
+
+sub change_ip($$) {
+       my ($old, $new) = @_;
+       my $mac = mac_from_ip($old);
+       rename ip_path($old), ip_path($new);
+       unlink mac_path($mac);
+       symlink ip_path($new), mac_path($mac);
+}
+
 1;