#!/usr/bin/perl # # Copyright (C) 2006-2019, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France # License GNU GPL version 2 or later and Perl equivalent # # apt-get install perl-base perl-modules libyaml-syck-perl libnet-netmask-perl libreadonly-perl libfile-touch-perl libtext-table-perl libnetaddr-ip-perl package DDT::RE; use strict; #use warnings; use Readonly; Readonly our $MAC_ADDRESS => qr{ (?: [0-9A-F]{2} :){5} [0-9A-F]{2} }xms; Readonly our $IPv4_ADDRESS => qr{ [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} }xms; package main; use strict; #use warnings; use version; our $VERSION = version->declare('0.12.1'); use Getopt::Long qw(GetOptions); #use YAML; use YAML::Syck; use Net::Netmask; use File::Touch; use File::Copy; use Socket; use Text::Table; use NetAddr::IP; my $command = shift @ARGV || 'help'; my %cmd_db = ( 'add-alias' => \&cmd_add_alias, 'add-dhcp' => \&cmd_add_dhcp, 'add-float' => \&cmd_add_float, 'add-static' => \&cmd_add_static, 'add-virtual' => \&cmd_add_virtual, 'change-comment' => \&cmd_change_comment, 'change-sector' => \&cmd_change_sector, 'change-host' => \&cmd_change_host, 'change-ip' => \&cmd_change_ip, 'change-mac' => \&cmd_change_mac, 'change-tag' => \&cmd_change_tag, 'change-type' => \&cmd_change_type, 'check-dns' => \&cmd_check_dns, 'create-sector' => \&cmd_create_sector, 'create-pool' => \&cmd_create_pool, 'create-pxe' => \&cmd_create_pxe, 'create-tag' => \&cmd_create_tag, 'del-pc' => \&cmd_del_pc, 'del-float' => \&cmd_del_float, 'disable-pc' => \&cmd_disable_pc, 'disable-float' => \&cmd_disable_float, 'disable-pxe' => \&cmd_disable_pxe, 'enable-pc' => \&cmd_enable_pc, 'enable-float' => \&cmd_enable_float, 'enable-pxe' => \&cmd_enable_pxe, 'gen-dhcp-file' => \&cmd_generate_dhcp_file, 'gen-dns-file' => \&cmd_generate_dns_file, 'help' => \&cmd_help, 'load-database' => \&cmd_load_database, 'remove-pxe' => \&cmd_remove_pxe, 'remove-tag' => \&cmd_remove_tag, 'search-mac' => \&cmd_search_mac, 'sector-add-ip' => \&cmd_sector_add_ip, 'show' => \&cmd_show_host, 'show-sector' => \&cmd_show_sector, 'show-pool' => \&cmd_show_pool, 'show-pxe' => \&cmd_show_pxe, 'show-tag' => \&cmd_show_tag, 'upgrade-db' => \&cmd_upgrade_db, 'version' => \&cmd_version, ); #------------------------------------------------------------------------------- my $CONFIG; my $xdg_config_home = $ENV{'XDG_CONFIG_HOME'} || "$ENV{'HOME'}/.config"; $CONFIG = config_load("$xdg_config_home/ddt/config.yml") if -e "$xdg_config_home/ddt/config.yml"; my $COMPUTER_BASENAME = $CONFIG->{'database'}{'basename'} || 'ddt'; my $COMPUTER_EXT = $CONFIG->{'database'}{'ext'} || 'db'; my $FOLDER_APP = $CONFIG->{'database'}{'folder'} || '/var/lib/ddt'; my $FOLDER_BACKUP = $CONFIG->{'database'}{'backup'} || "$FOLDER_APP/backup"; my $FOLDER_GEN_DHCP = $CONFIG->{'generate'}{'dhcp'} || "$FOLDER_APP/dhcp"; my $FOLDER_GEN_DNS = $CONFIG->{'generate'}{'dns'} || "$FOLDER_APP/dns"; my $SCRIPT_UPDATE = $CONFIG->{'script'}{'update'} || '/usr/share/ddt/update-dhcp-server'; my $COMPUTER_YAML = "$FOLDER_APP/$COMPUTER_BASENAME.$COMPUTER_EXT"; #------------------------------------------------------------------------------- mkdir $FOLDER_APP, 0755 if not -d $FOLDER_APP; mkdir $FOLDER_BACKUP, 0755 if not -d $FOLDER_BACKUP; mkdir $FOLDER_GEN_DHCP, 0755 if not -d $FOLDER_GEN_DHCP; mkdir $FOLDER_GEN_DNS, 0755 if not -d $FOLDER_GEN_DNS; if (defined $cmd_db{$command}) { $cmd_db{$command}->(@ARGV); } else { print {*STDERR} "ddt: command $command not found\n\n"; $cmd_db{'help'}->(); exit 1; } exit; #-------------------------------------------------------------------------------- # LOAD SAVE section #-------------------------------------------------------------------------------- sub config_load { my $config_file = shift; my $configdb = YAML::Syck::LoadFile($config_file); return $configdb; } #--------------------------------------------------------------- # Load computer database sub ipamdb_load { my $database_yaml = shift; touch $database_yaml if not -e $database_yaml; my $computer_db = YAML::Syck::LoadFile($database_yaml); # add database version if not exist if (not exists $computer_db->{'version'}) { $computer_db->{'version'} = 1; } return $computer_db; } #--------------------------------------------------------------- # Save computer database sub ipamdb_save { my ($database_yaml, $computer_db) = @_; my $dirdb = $database_yaml; $dirdb =~ s{ / [^/]* $}{}xms; mkdir "$dirdb", 0755 unless -d "$dirdb"; YAML::Syck::DumpFile($database_yaml, $computer_db); return $computer_db; } #-------------------------------------------------------------------------------- # CONTROL section #-------------------------------------------------------------------------------- sub control_exist_pool { my ($computer_db, $pool) = @_; return exists $computer_db->{'pool'}{$pool} ? 1 : 0; } #------------------------------------------------------------------------------- #Nom: control_exist_sector #Description: controle l'existence d'un sector dans le fichier YAML # return 0 (faux) ou 1 (vrai) sub control_exist_sector { my ($computer_db, $sector) = @_; return 1 if exists $computer_db->{$sector}; print {*STDERR} "Error: sector $sector not found\n"; return 0; } #------------------------------------------------------------------------------- #Nom: control_exist_hostname #Description: controle l'existence d'un nom de machine dans le fichier YAML # return 0 (si trouvé) ou 1 (si non trouvé) sub control_exist_hostname { my ($computer_db, $sector, $hostname) = @_; if ($computer_db->{$sector} eq '') { return 1; } my @sectordb = @{$computer_db->{$sector}}; for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; return 0 if $attribute->{'hostname'} eq $hostname; } return 1; } #------------------------------------------------------------------------------- #Nom: control_exist_mac #Description: controle l'existence d'une adresse MAC dans le fichier YAML # return 0 (si trouvé) ou 1 (si non trouvé) sub control_exist_mac { my ($computer_db, $mac) = @_; for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; return 0 if $mac_address eq $mac; } } return 1; } #------------------------------------------------------------------------------- #Nom: control_exist_ip #Description: controle l'existence d'une adresse IP dans le fichier YAML # return 0 (si trouvé) ou 1 (si non trouvé) sub control_exist_ip { my ($computer_db, $ip) = @_; for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector_current}}) { my ($mac_address, $attribute) = %{$computer}; #print "Erreur: cette adresse IP $ip existe déjà\n"; return 0 if $attribute->{'ip'} eq $ip; } } for my $current_pool (keys %{$computer_db->{'pool'}}) { #--- Cette partie pour tester les ip des pools est bonne ne plus la changer ---# my @T_pool_ip = @{$computer_db->{'pool'}{$current_pool}{'ip'}}; for my $pool_ip (@T_pool_ip) { #print "Erreur: cette adresse IP $ip existe déjà\n"; return 0 if $pool_ip eq $ip; } } return 1; } #------------------------------------------------------------------------------- sub control_ip_in_range { my ($computer_db, $sector, $ip) = @_; return 1 if not exists $computer_db->{'dset'}{$sector}{'ip_range'}; # No IP range defined for this sector my $ip_addr = NetAddr::IP->new($ip); LOOP_ON_IP_RANGE: for my $ip_range_current (@{$computer_db->{'dset'}{$sector}{'ip_range'}}) { my $range = NetAddr::IP->new($ip_range_current); return 1 if $range->contains($ip_addr); } return 0; } #------------------------------------------------------------------------------------- #Nom: control_syntaxe_mac #Description: controle la syntaxe d'une adresse MAC (juste la longueur pas les valeurs) # return 0 (si trouvé) ou 1 (si non trouvé) sub control_syntax_mac_address { my $mac = shift; if (scalar(split /:/, $mac) == 6 and $mac =~ $DDT::RE::MAC_ADDRESS) { return 1; } print {*STDERR} "Error: bad MAC syntax: $mac\n"; return 0; } #------------------------------------------------------------------------------------- #Nom: control_syntax_ip #Description: controle la syntaxe d'une adresse IP (juste la longueur pas les valeurs) # return 0 (si trouvé) ou 1 (si non trouvé) sub control_syntax_ip { my $ip = shift; return 1 if $ip ne 'pool'; return 0 if $ip !~ m{^(\d+\.){3}\d+$}; return 0 if not NetAddr::IP->new("$ip/32"); return 1; } #------------------------------------------------------------------------------------- sub control_syntax_cidr { my $cidr = shift; return 0 if $cidr !~ m{^(\d+\.){3}\d+/\d+$}; return 0 if not NetAddr::IP->new($cidr); return 1; } #------------------------------------------------------------------------------------- sub control_syntax_comment { my $comment = shift; if ($comment !~ m{^20\d\d-\d\d-\d\d\s}) { print {*STDERR} "Error: no date like 2014-01-10 at the beginning: $comment\n"; return 0; } if ($comment !~ m{\(\w+\)$}) { print {*STDERR} "Error: no (SERVICE) at the end: $comment\n"; return 0; } if ($comment =~ m{\s\s}) { print {*STDERR} "Error: double space: $comment\n"; return 0; } return 1; } #-------------------------------------------------------------------------------- # UTILITY section #-------------------------------------------------------------------------------- sub get_cmd_name { my ($pkg, $sub) = split /::/, (caller(1))[3]; $sub =~ s/^cmd_//; $sub =~ s/_/-/g; return $sub; } #------------------------------------------------------------------------------- sub normalize_mac_address { my $mac_address = shift; # D07E-28D1-7AB8 or d07e28-d17ab8 or D07E.28D1.7AB8 if ($mac_address =~ m{^ (?: [0-9A-Fa-f]{4} -){2} [0-9A-Fa-f]{4} $}xms or $mac_address =~ m{^ [0-9A-Fa-f]{6} - [0-9A-Fa-f]{6} $}xms) { $mac_address =~ s/-//g; return join q{:}, unpack('(A2)*', uc($mac_address)); } if ($mac_address =~ m{^ (?: [0-9A-Fa-f]{4} \.){2} [0-9A-Fa-f]{4} $}xms) { $mac_address =~ s/\.//g; return join q{:}, unpack('(A2)*', uc($mac_address)); } return join q{:}, map { substr( uc("00$_"), -2) } split m/ [:-] /xms, $mac_address; } #------------------------------------------------------------------------------- sub normalize_comment { my $comment = shift; $comment =~ s{^(20\d\d)/(\d\d)/(\d\d)\s(.*)$}{$1-$2-$3 $4}; return $comment; } #-------------------------------------------------------------------------------- sub get_mac_from_hostname { my ($computer_db, $sector, $hostname, $mac) = @_; return $mac if $mac ne ''; return '' if $hostname eq ''; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; return $mac_address; } } #-------------------------------------------------------------------------------- sub get_mac_from_ip { my ($computer_db, $sector, $ip, $mac) = @_; return $mac if $mac ne ''; return '' if $ip eq ''; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip; return $mac_address; } } #-------------------------------------------------------------------------------- # return a tuple (hash computer, iostat) # iostat 0/ok, 1/not exist sub get_computer_from_mac { my ($computer_db, $sector, $mac) = @_; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $mac_address ne $mac; return $attribute, 0; } return {}, 1; } #------------------------------------------------------------------------------- # ADD computer section #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- #Nom: add_alias #Description: ajoute un alias pour une machine. Pour la fonctionnalité CNAME dans le DNS. # Seems not finish and not functional ! sub add_alias { my ($computer_db, $hostname, $sector, $alias) = @_; control_exist_sector($computer_db, $sector) or exit; control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n"; my @sectordb = @{$computer_db->{$sector}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; $alias .= ' ' . $attribute->{'alias'}; $attribute->{'alias'} = $alias; $attribute->{'modify_time'} = time; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: update attribute alias to $alias for host $hostname [OK]\n"; exit; } } #------------------------------------------------------------------------------- #Nom: add_static #Description: ajoute une machine non dhcp (donc à adressage fixe dans le fichier YAML) sub add_static { my ($computer_db, $hostname, $sector, $ip, $mac, $comment) = @_; $mac = normalize_mac_address($mac); $comment = normalize_comment($comment); control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n"; control_syntax_mac_address($mac) or exit; control_exist_mac($computer_db, $mac) or die "Error: physical MAC address already exists: $mac\n"; control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n"; control_exist_ip($computer_db, $ip) or die "Error: IP $ip address already exist in sector $sector\n"; control_ip_in_range($computer_db, $sector, $ip) or die "Error: IP $ip is not in sector $sector IP range.\n"; control_syntax_comment($comment) or exit; my $timestamp = time; push @{$computer_db->{$sector}}, { $mac => { 'hostname' => $hostname, 'ip' => $ip, 'address_type' => 'static', 'enabled' => 'yes', 'create_time' => $timestamp, 'modify_time' => $timestamp, 'comment' => $comment, 'alias' => '', }}; print "Info: add the host: $hostname, IP: $ip, MAC: $mac, sector: $sector [OK]\n"; ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- #Nom: add_dhcp #Description: section à corriger pour prendre en compte l'ajout d'une machine dans un pool dhcp #--- usage: ddt add-dhcp -s legi-sector03 -h meolpacif -m 00:18:F3:03:6F:66 -i 194.254.66.165 sub add_dhcp { my ($computer_db, $hostname, $sector, $ip, $mac, $comment) = @_; my $timestamp = time; $mac = normalize_mac_address($mac); $comment = normalize_comment($comment); control_exist_sector($computer_db, $sector) or exit; control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n"; control_syntax_mac_address($mac) or exit; control_exist_mac($computer_db, $mac) or die "Error: physical MAC address already exists: $mac\n"; control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n"; control_exist_ip($computer_db, $ip) or die "Error: IP address already exist in sector $sector: $ip.\n"; control_ip_in_range($computer_db, $sector, $ip) or die "Error: IP $ip is not in sector $sector IP range.\n"; control_syntax_comment($comment) or exit; push @{$computer_db->{$sector}}, { $mac => { 'hostname' => $hostname, 'ip' => $ip, 'address_type' => 'dhcp', 'enabled' => 'yes', 'create_time' => $timestamp, 'modify_time' => $timestamp, 'comment' => $comment, 'alias' => '', }}; print "Add the computer: $hostname, IP: $ip, MAC: $mac, sector: $sector\n"; ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- #--- usage: ddt add-float -s legi-sector03 -h meolpacif -m 00:18:F3:03:6F:66 -i 194.254.66.165 sub add_float { my ($computer_db, $pool, $sector, $mac, $comment) = @_; my $timestamp = time; $mac = normalize_mac_address($mac); $comment = normalize_comment($comment); control_exist_sector($computer_db, $sector) or exit; control_syntax_mac_address($mac) or exit; control_exist_mac($computer_db, $mac) or die "Error: physical MAC address already exists: $mac\n"; control_exist_pool($computer_db, $pool) or die "Error: the pool doesn't exists: $pool\n"; control_syntax_comment($comment) or exit; push @{$computer_db->{$sector}}, { $mac => { 'hostname' => $pool, 'ip' => $pool, 'address_type' => 'pool-dhcp', 'enabled' => 'yes', 'create_time' => $timestamp, 'modify_time' => $timestamp, 'comment' => $comment, }}; print "Info: add the computer in pool MAC: $mac, sector: $sector, Pool: $pool [OK]\n"; ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- # ADD computer section #------------------------------------------------------------------------------- sub cmd_add_alias { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $alias); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'alias|a=s' => \$alias, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $hostname eq '' or $sector eq '' or $alias eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); add_alias($computer_db, $hostname, $sector, $alias); } #------------------------------------------------------------------------------- sub cmd_add_dhcp { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip, $mac, $comment); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, 'mac|m=s' => \$mac, 'comment|c=s' => \$comment, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $hostname eq '' or $sector eq '' or $ip eq '' or $mac eq '' or $comment eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); add_dhcp($computer_db, $hostname, $sector, $ip, $mac, $comment); } #------------------------------------------------------------------------------- sub cmd_add_float { local @ARGV = @_; my $help = get_cmd_name(); my ($pool, $sector, $mac, $comment); GetOptions( 'pool|p=s' => \$pool, 'sector|s|d=s' => \$sector, 'mac|m=s' => \$mac, 'comment|c=s' => \$comment, ); ($pool, $sector) = split /\./, $pool, 2 if $pool =~ m/\./; exit_on_error_option($help) if $pool eq '' or $sector eq '' or $mac eq '' or $comment eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); add_float($computer_db, $pool, $sector, $mac, $comment); } #------------------------------------------------------------------------------- # No DHCP computer, just an entry A in DNS with a real MAC sub cmd_add_static { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip, $mac, $comment); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, 'mac|m=s' => \$mac, 'comment|c=s' => \$comment, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $hostname eq '' or $sector eq '' or $ip eq '' or $mac eq '' or $comment eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); add_static($computer_db, $hostname, $sector, $ip, $mac, $comment); } #------------------------------------------------------------------------------- # No real computer, just an entry A in DNS with virtual MAC sub cmd_add_virtual { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip, $comment); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, 'comment|c=s' => \$comment, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $hostname eq '' or $sector eq '' or $ip eq '' or $comment eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); $comment = normalize_comment($comment); my $timestamp = time; control_exist_sector($computer_db, $sector) or exit; control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n"; control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n"; control_exist_ip($computer_db, $ip) or die "Error: IP address already exist in sector $sector: $ip.\n"; control_ip_in_range($computer_db, $sector, $ip) or die "Error: IP $ip is not in sector $sector IP range.\n"; control_syntax_comment($comment) or exit; my $mac = join ':', 'FF', 'FF', map({sprintf("%02X", $_)} split(/\./, $ip)); control_syntax_mac_address($mac) or exit; control_exist_mac($computer_db, $mac) or die "Error: virtual physical MAC address already exists: $mac\n"; push @{$computer_db->{$sector}}, { $mac => { 'hostname' => $hostname, 'ip' => $ip, 'address_type' => 'static', 'enabled' => 'yes', 'create_time' => $timestamp, 'modify_time' => $timestamp, 'comment' => $comment, 'alias' => '', }}; print "Add the virtual computer: $hostname, IP: $ip, sector: $sector\n"; ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- # CHANGE computer section #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- #Nom: change_mac #Description: change la mac adresse d'une machine en saisissant soit l'ip # soit le nom de la mahcine et spécifiant le domaine #--- usage: ddt change-mac -s legi-sector03 -h meolpacif -m 00:18:F3:03:6F:66 #--- usage: ddt change-mac -s legi-sector03 -i 194.254.66.187 -m 00:18:F3:03:6F:66 sub change_mac { my ($hostname, $sector, $ip, $mac) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); $mac = normalize_mac_address($mac); control_exist_sector($computer_db, $sector) or exit; control_syntax_mac_address($mac) or exit; control_exist_mac($computer_db, $mac) or die "Error: physical MAC address already exists: $mac\n"; if ($ip ne '') { control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n"; if ( control_exist_ip($computer_db, $ip) == 1 ) { print "Error: unkown IP address: $ip\n"; exit; } my @sectordb = @{$computer_db->{$sector}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; die "Error: physical MAC address $mac already exists in sector $sector\n" if $mac_address eq $mac; next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip; $attribute->{'modify_time'} = time; $computer->{$mac} = $attribute; # add new mac delete $computer->{$mac_address}; # remove old mac ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: update host $attribute->{'hostname'}, sector $sector, MAC $mac, IP $attribute->{'ip'} [OK]\n"; exit; } } elsif ($hostname ne '') { if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) { die "Error: unkown host $hostname, sector $sector\n"; } my @sectordb = @{$computer_db->{$sector}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; die "Error: physical MAC address $mac already exists in sector $sector\n" if $mac_address eq $mac; next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; $attribute->{'modify_time'} = time; $computer->{$mac} = $attribute; # add new mac delete $computer->{$mac_address}; # remove old mac ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: update host $attribute->{'hostname'}, sector $sector, MAC $mac, IP $attribute->{'ip'} [OK]\n"; exit; } } } #------------------------------------------------------------------------------- #Nom: change_ip #Description: change l'adresse IP d'une machine en saisissant le nom de la machine # et le domaine sub change_ip { my ($hostname, $sector, $ip) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); control_exist_sector($computer_db, $sector) or exit; if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) { die "Error: unkown host: $hostname, in sector: $sector\n"; } control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n"; control_exist_ip($computer_db, $ip) or die "Error: IP $ip address already exist in sector $sector\n"; control_ip_in_range($computer_db, $sector, $ip) or die "Error: IP $ip is not in sector $sector IP range.\n"; my @sectordb = @{$computer_db->{$sector}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; if ($attribute->{'address_type'} eq 'pool-dhcp') { die "Error: host $hostname from sector $sector belongs to a a pool [FAILED]" . " ... use 'del-float' command before"; } $attribute->{'modify_time'} = time; $attribute->{'ip'} = $ip; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: update host $hostname MAC: $mac_address IP: $ip [OK]\n"; exit; } } #------------------------------------------------------------------------------- #Nom: change_host #Description: change le computer hostname en saisissant l'IP et le domaine sub change_host { my ($hostname, $sector, $ip) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); control_exist_sector($computer_db, $sector) or exit; control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n"; if ( control_exist_ip($computer_db, $ip) == 1 ) { die "Error: unkown IP address: $ip\n"; } control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n"; my @sectordb = @{$computer_db->{$sector}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip; $attribute->{'modify_time'} = time; $attribute->{'hostname'} = $hostname; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: update host $hostname MAC: $mac_address IP: $ip [OK]\n"; exit; } die "Error: failed to update hostname $hostname [FAILED]\n" . " ... no IP $ip belongs to the sector $sector\n"; } #-------------------------------------------------------------------------------- sub cmd_change_mac { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip, $mac); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, 'mac|m=s' => \$mac, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $sector eq '' or $mac eq ''; exit_on_error_option($help) if $hostname ne '' and $ip ne ''; change_mac($hostname, $sector, $ip, $mac); } #-------------------------------------------------------------------------------- sub cmd_change_ip { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $hostname eq '' or $sector eq '' or $ip eq ''; change_ip($hostname, $sector, $ip); } #-------------------------------------------------------------------------------- sub cmd_change_host { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $hostname eq '' or $sector eq '' or $ip eq ''; change_host($hostname, $sector, $ip); } #-------------------------------------------------------------------------------- sub cmd_change_comment { local @ARGV = @_; my $help = get_cmd_name(); my ($sector, $mac, $comment); GetOptions( 'sector|s|d=s' => \$sector, 'mac|m=s' => \$mac, 'comment|c=s' => \$comment, ); exit_on_error_option($help) if $sector eq '' or $mac eq '' or $comment eq ''; $mac = normalize_mac_address($mac); $comment = normalize_comment($comment); my $computer_db = ipamdb_load($COMPUTER_YAML); control_exist_sector($computer_db, $sector) or exit; control_syntax_mac_address($mac) or exit; control_syntax_comment($comment) or exit; my @sectordb = @{$computer_db->{$sector}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $mac_address ne $mac; $attribute->{'modify_time'} = time; $attribute->{'comment'} = $comment; ipamdb_save("$COMPUTER_YAML", $computer_db); exit; } die "Error : Host $mac comment [FAILED]\n" . " ... No MAC: $mac belongs to the domaine set $sector.\n"; } #-------------------------------------------------------------------------------- sub cmd_change_sector { local @ARGV = @_; my $help = get_cmd_name(); my ($sector, $ip, $mac); GetOptions( 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, 'mac|m=s' => \$mac, ); exit_on_error_option($help) if $sector eq '' or $ip eq '' or $mac eq ''; $mac = normalize_mac_address($mac); my $computer_db = ipamdb_load($COMPUTER_YAML); control_exist_sector($computer_db, $sector) or exit; control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n"; control_syntax_mac_address($mac) or exit; LOOP_ON_SECTOR: for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; my $computer_index = 0; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; $computer_index++, next LOOP_ON_COMPUTER if $mac_address ne $mac; next LOOP_ON_SECTOR if $attribute->{'ip'} ne $ip; $attribute->{'modify_time'} = time; splice(@{$computer_db->{$sector_current}}, $computer_index => 1); push @{$computer_db->{$sector}}, { $mac => $attribute }; ipamdb_save("$COMPUTER_YAML", $computer_db); exit; } } die "Error: update of sector $sector [FAILED]\n" . " ... MAC $mac and IP $ip don't exists in the database\n"; } #-------------------------------------------------------------------------------- sub cmd_change_tag { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip, $mac, $tags); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, 'mac|m=s' => \$mac, 'tag|t=s' => \$tags, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $sector eq '' or $tags eq ''; exit_on_error_option($help) if $mac eq '' and $hostname eq '' and $ip eq ''; $mac = normalize_mac_address($mac); my $computer_db = ipamdb_load($COMPUTER_YAML); if ($tags !~ m/^ (?:\w+,)* \w+ $/xms) { die "Error: bad format for tags (comma separated list): $tags [FAILED]\n"; } for my $tag (split/,/, $tags) { next if $tag eq 'universal'; die "Error: TAG $tag doesn't exist in the database. Create $tag with command create_tag [FAILED]\n" if not exists $computer_db->{'tag'}{$tag}; } control_exist_sector($computer_db, $sector) or exit; $mac = get_mac_from_ip($computer_db, $sector, $ip, $mac) if $ip ne ''; $mac = get_mac_from_hostname($computer_db, $sector, $hostname, $mac) if $hostname ne ''; control_syntax_mac_address($mac) or exit; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $mac_address ne $mac; $attribute->{'tag'} = $tags; $attribute->{'modify_time'} = time; delete $attribute->{'tag'} if $tags eq 'universal'; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: update host $hostname sector $sector tags $tags [OK]\n"; exit; } die "Error: no host $hostname in sector $sector has MAC $mac [FAILED]\n"; } #-------------------------------------------------------------------------------- sub cmd_change_type { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $type); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'type|t=s' => \$type, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $sector eq '' and $hostname eq '' and $type eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); if ($type !~ m/^ (dhcp|float|static) $/xms) { die "Error: bad type: $type\n"; } $type =~ s/^float$/pool-dhcp/; # No type virtual actually. See and write exactly type name and their property control_exist_sector($computer_db, $sector) or exit; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; die "Warning: host $hostname already of type $type [FAILED]\n" if $attribute->{'address_type'} eq $type; $attribute->{'address_type'} = $type; $attribute->{'modify_time'} = time; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: update host $hostname sector $sector type $type [OK]\n"; exit; } die "Error: change host $hostname type [FAILED]\n"; } #------------------------------------------------------------------------------- # ACTIVATION section #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- #Nom: disable_pc #Description: désactive une machine (du DHCP ou en IP statique, et du DNS) (champs enabled=non) sub disable_pc { my ($hostname, $sector, $ip) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); if ($ip ne '') { # disable by IP control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";; if ( control_exist_ip($computer_db, $ip) == 1 ) { die "Error: unkown IP address: $ip [FAILED]\n"; } for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip; if ($attribute->{'enabled'} eq 'no') { print "Info: IP $ip from sector $sector_current is already disable [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } my $timestamp = time; $attribute->{'modify_time'} = $timestamp; $attribute->{'enabled'} = 'no'; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: disabling IP $ip from sector $sector_current [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } } } else { # disable by Hostname control_exist_sector($computer_db, $sector); if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) { die "Error: unkown host: $hostname, in sector: $sector [FAILED]\n"; } LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; if ($attribute->{'address_type'} eq 'pool-dhcp') { die "Error: host $hostname from sector $sector belongs to a a pool [FAILED]" . " ... use 'disable-float' command instead"; } if ($attribute->{'enabled'} eq 'no') { print "Info: host $hostname from sector $sector is already disable [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } my $timestamp = time; $attribute->{'modify_time'} = $timestamp; $attribute->{'enabled'} = 'no'; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: disabling host $hostname from sector $sector [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } } } #------------------------------------------------------------------------------- sub disable_float { my ($pool, $mac) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); if ( control_exist_mac($computer_db, $mac) == 1 ) { die "Error: unkown physical MAC address: $mac [FAILED]\n"; } for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $mac_address ne $mac; if ($attribute->{'ip'} eq $pool) { if ($attribute->{'enabled'} eq 'no') { print "Info: host $mac from pool $pool is already disable [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } my $timestamp = time; $attribute->{'modify_time'} = $timestamp; $attribute->{'enabled'} = 'no'; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: disabling host $mac from pool $pool [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } else { die "Error: host disable $mac [FAILED]" . " ... The host $mac does not belong to the $pool pool.\n"; } } } } #------------------------------------------------------------------------------- #Nom: enable_pc #Description: active une machine désactivée(du DHCP ou en IP statique, et du DNS) (champs enabled=non) sub enable_pc { my ($hostname, $sector, $ip) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); control_exist_sector($computer_db, $sector) or exit; if ($ip ne '') { # enable by IP control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";; if ( control_exist_ip($computer_db, $ip) == 1 ) { print "Error: unkown IP address: $ip\n"; exit; } for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; if ($attribute->{'ip'} eq $ip) { if ($attribute->{'enabled'} eq 'yes') { print "Info: IP $ip belongs to sector $sector is already enable [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } my $timestamp = time; $attribute->{'modify_time'} = $timestamp; $attribute->{'enabled'} = 'yes'; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: IP $ip is now enable [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } } } } else { # enable by Hostname if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) { die "Error: unkown host: $hostname, in sector: $sector\n"; } LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; if ($attribute->{'address_type'} eq 'pool-dhcp') { die "Error: host $hostname from sector $sector belongs to a a pool [FAILED]" . " ... use 'enable-float' command instead"; } if ($attribute->{'enabled'} eq 'yes') { print "Info: host $hostname belongs to sector $sector is already enable [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } my $timestamp = time; $attribute->{'modify_time'} = $timestamp; $attribute->{'enabled'} = 'yes'; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: host $hostname is now enable [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } } } #------------------------------------------------------------------------------- sub enable_float { my ($pool, $mac) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); if ( control_exist_mac($computer_db, $mac) == 1 ) { die "Error: unkown physical MAC address: $mac [FAILED]\n"; } for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $mac_address ne $mac; if ($attribute->{'ip'} ne $pool) { die "Error: host enable $mac [FAILED]" . " ... The host $mac does not belong to the $pool pool.\n"; } if ($attribute->{'enabled'} eq 'yes') { print "Info: host $mac from pool $pool is already enable [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } my $timestamp = time; $attribute->{'modify_time'} = $timestamp; $attribute->{'enabled'} = 'yes'; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: enabling host $mac from pool $pool [OK]" . " ... Status: $attribute->{'enabled'}\n"; exit; } } } #------------------------------------------------------------------------------- sub cmd_enable_pc { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $sector eq ''; exit_on_error_option($help) if $hostname eq '' and $ip eq ''; exit_on_error_option($help) if $hostname ne '' and $ip ne ''; enable_pc($hostname, $sector, $ip); } #------------------------------------------------------------------------------- sub cmd_disable_pc { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $sector eq ''; exit_on_error_option($help) if $hostname eq '' and $ip eq ''; exit_on_error_option($help) if $hostname ne '' and $ip ne ''; disable_pc($hostname, $sector, $ip); } #------------------------------------------------------------------------------- sub cmd_disable_float { local @ARGV = @_; my $help = get_cmd_name(); my ($pool, $mac); GetOptions( 'pool|p=s' => \$pool, 'mac|m=s' => \$mac, ); ($pool) = split /\./, $pool, 2 if $pool =~ m/\./; exit_on_error_option($help) if $pool eq '' or $mac eq ''; disable_float($pool, $mac); } #------------------------------------------------------------------------------- sub cmd_enable_float { local @ARGV = @_; my $help = get_cmd_name(); my ($pool, $mac); GetOptions( 'pool|p=s' => \$pool, 'mac|m=s' => \$mac, ); ($pool) = split /\./, $pool, 2 if $pool =~ m/\./; exit_on_error_option($help) if $pool eq '' or $mac eq ''; enable_float($pool, $mac); } #------------------------------------------------------------------------------- # DELETE section #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- #Nom: del_pc #Description: supprime une machine en DHCP ou en IP statique. sub del_pc { my ($hostname, $sector, $ip) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); control_exist_sector($computer_db, $sector) or exit; if ($ip ne '') { # delete by IP if ( control_exist_ip($computer_db, $ip) == 1 ) { die "Error: unkown IP address: $ip\n"; } my $computer_index = 0; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; $computer_index++, next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip; splice(@{$computer_db->{$sector}}, $computer_index => 1); ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: host $ip has been removed from the sector $sector [OK]\n"; exit; } } else { if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) { die "Error: unkown host: $hostname, in sector: $sector\n"; } my $computer_index = 0; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; $computer_index++, next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; if ($attribute->{'address_type'} eq 'pool-dhcp') { die "Error: host remove $hostname from the sector $sector [FAILED]" . " ... The host $hostname belongs to a DHCP pool.\n"; } splice(@{$computer_db->{$sector}}, $computer_index => 1); ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: host $hostname has been removed from the sector $sector [OK]\n"; exit; } } } #------------------------------------------------------------------------------- #Nom: del_float #Description: supprime une machine d'un pool DHCP sub del_float { my ($pool, $mac) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); if ( control_exist_mac($computer_db, $mac) == 1 ) { print "Adresse MAC $mac non trouvée.\n"; exit; } for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; my $computer_index = 0; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; $computer_index++, next LOOP_ON_COMPUTER if $mac_address ne $mac; if ($attribute->{'ip'} ne $pool) { die "Error: host remove $mac [FAILED]" . " ... The host $mac does not belong to the $pool pool.\n"; } splice(@{$computer_db->{$sector_current}}, $computer_index => 1); ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: remove host $mac from the pool $pool [OK]\n"; exit; } } } #------------------------------------------------------------------------------- sub cmd_del_pc { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $sector eq ''; exit_on_error_option($help) if $hostname eq '' and $ip eq ''; exit_on_error_option($help) if $hostname ne '' and $ip ne ''; del_pc($hostname, $sector, $ip); } #------------------------------------------------------------------------------- sub cmd_del_float { local @ARGV = @_; my $help = get_cmd_name(); my ($pool, $mac); GetOptions( 'pool|p=s' => \$pool, 'mac|m=s' => \$mac, ); ($pool) = split /\./, $pool, 2 if $pool =~ m/\./; exit_on_error_option($help) if $pool eq '' or $mac eq ''; del_float($pool, $mac); } #------------------------------------------------------------------------------- # SECTOR section #------------------------------------------------------------------------------- sub cmd_create_sector { local @ARGV = @_; my $help = get_cmd_name(); my ($sector, $dns_extension, $comment); GetOptions( 'sector|s|d=s' => \$sector, 'dns-extension|e=s' => \$dns_extension, 'comment|c=s' => \$comment, ); exit_on_error_option($help) if $sector eq '' or $dns_extension eq '' or $comment eq ''; $sector =~ m{^[\w\d]} or die "Error: sector $sector must begin by a letter or a digit\n"; $sector =~ m{^[\w\d][\w\d-_]*$} or die "Error: sector $sector must only use letter digit dash and underscore character\n"; $comment = normalize_comment($comment); my $computer_db = ipamdb_load($COMPUTER_YAML); $computer_db->{'dset'} ||= {}; die "Error: sector already exists: $sector\n" if exists $computer_db->{'dset'}{$sector}; control_syntax_comment($comment) or exit; my $timestamp = time; $computer_db->{'dset'}{$sector} = { 'dns_extension' => $dns_extension, 'comment' => $comment, 'create_time' => $timestamp, 'modify_time' => $timestamp, }; $computer_db->{$sector} ||= []; # Create empty sector computer list by default ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- sub cmd_sector_add_ip { local @ARGV = @_; my $help = get_cmd_name(); my ($sector, $ip_range); GetOptions( 'sector|s|d=s' => \$sector, 'ip-range|i=s' => \$ip_range, ); exit_on_error_option($help) if $sector eq '' or $ip_range eq ''; control_syntax_cidr($ip_range) or die "Error: bad IP range $ip_range syntax (CIDR)\n";; my $computer_db = ipamdb_load($COMPUTER_YAML); exists $computer_db->{'dset'}{$sector} or die "Error: sector not exists: $sector\n"; my $timestamp = time; $computer_db->{'dset'}{$sector}{'ip_range'} ||= []; LOOP_ON_CIDR: for my $cidr_current (@{$computer_db->{'dset'}{$sector}{'ip_range'}}) { next LOOP_ON_CIDR if $cidr_current ne $ip_range; die "Error: IP range $ip_range already in sector $sector\n"; } my $timestamp = time; push @{$computer_db->{'dset'}{$sector}{'ip_range'}}, $ip_range; $computer_db->{'dset'}{$sector}{'modify_time'} = $timestamp; ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- # POOL section #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- #Nom: create_pool #Description: crée un pool dans le fichier de données YAML et dans le DHCP. # #Commentaires: il y a un petit bug si jamais on rentre que des adresses ip qui existent déjà. # Le pool est créé mais sans adresses ip. sub cmd_create_pool { local @ARGV = @_; my $help = get_cmd_name(); my ($pool, $sector, $file_pool, $ipaddress_pool); GetOptions( 'pool|p=s' => \$pool, 'sector|s|d=s' => \$sector, 'file-pool|f=s' => \$file_pool, 'ipaddress-pool|i=s' => \$ipaddress_pool, ); exit_on_error_option($help) if $pool eq '' or $sector eq '' or $file_pool eq '' or $ipaddress_pool eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); if ($computer_db->{'pool'}) { die "Error: pool already exists: $pool\n" if exists $computer_db->{'pool'}{$pool}; } #--- control if the domain's pool exist ---# control_exist_sector($computer_db, $sector) or exit; my @ip_list = (); #---control if address exist ---# if ($ipaddress_pool =~ /,/) { LOOP_ON_IP: for my $ip (split /,/, $ipaddress_pool) { if ($ip =~ /-/) { my ($ip1, $ip2, $ip3, $range) = split /\./, $ip; my ($first, $last) = split /-/, $range; for (my $cpt = $first; $cpt <= $last; $cpt++) { my $ip_loc = "$ip1.$ip2.$ip3.$cpt"; control_syntax_ip($ip_loc) or die "Error: bad IP syntax: $ip_loc\n"; control_exist_ip($computer_db, $ip_loc) or die "Error: IP address already exists: $ip_loc\n"; push @ip_list, $ip_loc; } } else { control_syntax_ip($ip) or next LOOP_ON_IP; if ( control_exist_ip($computer_db, $ip) == 0 ) { print "L'adresse IP $ip existe déjà\n"; next; } push @ip_list, $ip; } } } my $timestamp = time; $computer_db->{'pool'}{$pool} = { 'ip' => [@ip_list], 'enabled' => 'yes', 'create_time' => $timestamp, 'modify_time' => $timestamp, 'file' => $file_pool, 'domain' => $sector, }; ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- sub cmd_show_pool { local @ARGV = @_; my ($no_header); GetOptions( 'no-header|H' => \$no_header, ); my $computer_db = ipamdb_load($COMPUTER_YAML); printf "%-17s %-17s %s\n", 'Pool', 'File', 'DNS-Domain' if not $no_header; LOOP_ON_PXE: for my $pool ( keys %{$computer_db->{'pool'}} ) { printf "%-17s %-17s %s\n", $pool, $computer_db->{'pool'}{$pool}{'file'}, $computer_db->{'pool'}{$pool}{'domain'}, } } #------------------------------------------------------------------------------- # PXE section #------------------------------------------------------------------------------- sub cmd_create_pxe { local @ARGV = @_; my $help = get_cmd_name(); my ($pxe_config, $ip_next_server, $filename, $comment); GetOptions( 'bootp|b=s' => \$pxe_config, 'next-server|n=s' => \$ip_next_server, 'filename|f=s' => \$filename, 'comment|c=s' => \$comment, ); exit_on_error_option($help) if $pxe_config eq '' or $ip_next_server eq '' or $filename eq '' or $comment eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); $comment = normalize_comment($comment); $computer_db->{'pxe'} ||= {}; die "Error: PXE config already exists: $pxe_config\n" if exists $computer_db->{'pxe'}{$pxe_config}; control_syntax_ip($ip_next_server) or die "Error: bad IP syntax: $ip_next_server\n"; control_syntax_comment($comment) or exit; my $timestamp = time; $computer_db->{'pxe'}{$pxe_config} = { 'ip_next_server' => $ip_next_server, 'filename' => $filename, 'comment' => $comment, 'create_time' => $timestamp, 'modify_time' => $timestamp, }; ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- sub cmd_remove_pxe { local @ARGV = @_; my $help = get_cmd_name(); my ($pxe_config); GetOptions( 'bootp|b=s' => \$pxe_config, ); exit_on_error_option($help) if $pxe_config eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); $computer_db->{'pxe'} ||= {}; die "Error: PXE config does not exist: $pxe_config\n" if not exists $computer_db->{'pxe'}{$pxe_config}; # Test if some computer use this config LOOP_ON_SECTOR: for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector_current}}) { my ($mac_address, $attribute) = %{$computer}; if (exists $attribute->{'pxe_config'}) { my $hostname = $attribute->{'hostname'}; die "Error: computer still use this PXE config: $hostname.$sector_current $mac_address\n" if $pxe_config eq $attribute->{'pxe_config'}; } } } delete $computer_db->{'pxe'}{$pxe_config}; ipamdb_save("$COMPUTER_YAML", $computer_db); } #-------------------------------------------------------------------------------- sub cmd_show_pxe { local @ARGV = @_; my ($no_header); GetOptions( 'no-header|H' => \$no_header, ); my $computer_db = ipamdb_load($COMPUTER_YAML); printf "%-12s %-13s %-30s %s\n", 'PXE-Config', 'Next-Server', 'Filename', 'Comment' if not $no_header; LOOP_ON_PXE: for my $pxe_config ( keys %{$computer_db->{'pxe'}} ) { my $ip_next_server = $computer_db->{'pxe'}{$pxe_config}{'ip_next_server'}; my $filename = $computer_db->{'pxe'}{$pxe_config}{'filename'}; my $comment = $computer_db->{'pxe'}{$pxe_config}{'comment'}; printf "%-12s %-13s %-30s %s\n", $pxe_config, $ip_next_server, $filename, $comment; } } #------------------------------------------------------------------------------- sub cmd_enable_pxe { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip, $pxe_config); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, 'bootp|b=s' => \$pxe_config, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $sector eq '' or $pxe_config eq ''; exit_on_error_option($help) if $hostname eq '' and $ip eq ''; exit_on_error_option($help) if $hostname ne '' and $ip ne ''; my $computer_db = ipamdb_load($COMPUTER_YAML); die "Error: PXE config not exists: $pxe_config\n" if not exists $computer_db->{'pxe'}{$pxe_config}; control_exist_sector($computer_db, $sector) or exit; if ($ip ne '') { control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";; if ( control_exist_ip($computer_db, $ip) == 1 ) { die "Error: unkown IP address: $ip\n"; } for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector_current}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip; $attribute->{'modify_time'} = time; $attribute->{'pxe_config'} = $pxe_config; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: host $attribute->{'hostname'} ($sector_current), IP $ip, PXE enabled: $pxe_config\n"; exit; } } } else { if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) { die "Error: unkown host: $hostname, in sector: $sector\n"; } LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname; if ($attribute->{'address_type'} eq 'pool-dhcp') { die "Error. Host $hostname ($sector) in a pool. No PXE possible [FAILED]\n"; } $attribute->{'modify_time'} = time; $attribute->{'pxe_config'} = $pxe_config; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: host $hostname ($sector), IP $attribute->{'ip'}, PXE enabled: $pxe_config [OK]\n"; exit; } } } #------------------------------------------------------------------------------- sub cmd_disable_pxe { local @ARGV = @_; my $help = get_cmd_name(); my ($hostname, $sector, $ip); GetOptions( 'hostname|h=s' => \$hostname, 'sector|s|d=s' => \$sector, 'ip|i=s' => \$ip, ); ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./; exit_on_error_option($help) if $sector eq ''; exit_on_error_option($help) if $hostname eq '' and $ip eq ''; exit_on_error_option($help) if $hostname ne '' and $ip ne ''; my $computer_db = ipamdb_load($COMPUTER_YAML); control_exist_sector($computer_db, $sector) or exit; if ($ip ne '') { control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";; if ( control_exist_ip($computer_db, $ip) == 1 ) { die "Error: unkown IP address: $ip\n"; } for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector_current}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip; next LOOP_ON_COMPUTER if not exists $attribute->{'pxe_config'}; my $pxe_config = $attribute->{'pxe_config'}; $attribute->{'modify_time'} = time; delete $attribute->{'pxe_config'}; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: IP address: $ip, PXE disable from config: $pxe_config [OK]\n"; exit; } } } else { if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) { die "Error: unkown host: $hostname, in sector: $sector\n"; } LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'hostname'} eq $hostname; if ($attribute->{'address_type'} eq 'pool-dhcp') { die "Error: host $hostname ($sector) in a pool. No PXE possible [FAILED]\n"; } next LOOP_ON_COMPUTER if not exists $attribute->{'pxe_config'}; my $pxe_config = $attribute->{'pxe_config'}; $attribute->{'modify_time'} = time; delete $attribute->{'pxe_config'}; ipamdb_save("$COMPUTER_YAML", $computer_db); print "Info: host $hostname ($sector), PXE disable from config: $pxe_config [OK]\n"; exit; } } } #------------------------------------------------------------------------------- # TAG section #------------------------------------------------------------------------------- sub cmd_create_tag { local @ARGV = @_; my $help = get_cmd_name(); my ($tag, $comment); GetOptions( 'tag|t=s' => \$tag, 'comment|c=s' => \$comment, ); exit_on_error_option($help) if $tag eq '' or $comment eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); $comment = normalize_comment($comment); $computer_db->{'tag'} ||= {}; die "Error: TAG already exists: $tag\n" if exists $computer_db->{'tag'}{$tag}; die "Error: TAG 'universal' is intrinsic. It's not possible to create it.\n" if $tag eq 'universal'; if ($tag !~ m/^ \w+ $/xms) { die "Error: bad format for TAG (alphanumeric string): $tag\n"; } control_syntax_comment($comment) or exit; my $timestamp = time; $computer_db->{'tag'}{$tag} = { 'comment' => $comment, 'create_time' => $timestamp, 'modify_time' => $timestamp, }; ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- sub cmd_remove_tag { local @ARGV = @_; my $help = get_cmd_name(); my ($tag); GetOptions( 'tag|t=s' => \$tag, ); exit_on_error_option($help) if $tag eq ''; my $computer_db = ipamdb_load($COMPUTER_YAML); $computer_db->{'tag'} ||= {}; die "Error: TAG does not exist: $tag\n" if not exists $computer_db->{'tag'}{$tag}; # Test if some computer use this config LOOP_ON_SECTOR: for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector_current}}) { my ($mac_address, $attribute) = %{$computer}; if (exists $attribute->{'tag'}) { my $hostname = $attribute->{'hostname'}; die "Error: computer still use this TAG: $hostname.$sector_current $mac_address\n" if $tag eq $attribute->{'tag'}; } } } delete $computer_db->{'tag'}{$tag}; ipamdb_save("$COMPUTER_YAML", $computer_db); } #-------------------------------------------------------------------------------- sub cmd_show_tag { local @ARGV = @_; my ($no_header); GetOptions( 'no-header|H' => \$no_header, ); my $computer_db = ipamdb_load($COMPUTER_YAML); printf "%-12s %s\n", 'TAG', 'Comment' if not $no_header; LOOP_ON_TAG: for my $tag ( keys %{$computer_db->{'tag'}} ) { my $comment = $computer_db->{'tag'}{$tag}{'comment'}; printf "%-12s %s\n", $tag, $comment; } } #-------------------------------------------------------------------------------- # GLOBAL section #-------------------------------------------------------------------------------- sub cmd_upgrade_db { my $flag_change; my $computer_db = ipamdb_load($COMPUTER_YAML); LOOP_ON_SECTOR: for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; my $new_mac = normalize_mac_address($mac_address); print "perl -pi -e 's/$mac_address:/$new_mac:/' $COMPUTER_YAML\n" if "$mac_address" ne "$new_mac"; my $comment = $attribute->{'comment'}; $comment =~ s/\s\s+/ /g and $flag_change++; $comment =~ s/^\s+\S// and $flag_change++; $comment =~ s/\S\s+$// and $flag_change++; $comment =~ s{^(\d\d\d\d)\/O(\d\/\d\d)}{$1/0$2} and $flag_change++; $comment =~ s{^(\d\d\d\d\/\d\d\/)O(\d)}{$1/0$2} and $flag_change++; $comment =~ s{^(\d\d\d\d)\/(\d\d)\/(\d\d)}{$1-$2-$3} and $flag_change++; if ($comment !~ m/^\d\d\d\d-\d\d-\d\d/) { print "# no date at beginning of comment $mac_address\n"; } $attribute->{'comment'} = $comment; } } print "# FLAG :$flag_change\n"; ipamdb_save("$COMPUTER_YAML", $computer_db) if $flag_change; } #-------------------------------------------------------------------------------- sub cmd_show_sector { local @ARGV = @_; my ($no_header); GetOptions( 'no-header|H' => \$no_header, ); my $computer_db = ipamdb_load($COMPUTER_YAML); my $tb_computer = Text::Table->new( {align => 'left', align_title => 'left', title => 'Sector'}, {is_sep => 1, body => ' '}, {align => 'left', align_title => 'left', title => 'DNS-Extension'}, {is_sep => 1, body => ' '}, {align => 'left', align_title => 'left', title => 'IP-Range'}, {align => 'left', align_title => 'left', title => 'Date'}, {align => 'left', align_title => 'left', title => 'Comment'}, {align => 'left', align_title => 'left', title => 'Category'}, ); LOOP_ON_SECTOR: for my $sector_current (sort keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; $tb_computer->add($sector_current), next LOOP_ON_SECTOR if not exists $computer_db->{'dset'}{$sector_current}; my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $computer_db->{'dset'}{$sector_current}{'modify_time'}; $year += 1900; $mon++; my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday; my $ip_range; $ip_range = join ',', @{$computer_db->{'dset'}{$sector_current}{'ip_range'}} if exists $computer_db->{'dset'}{$sector_current}{'ip_range'}; my $category; my $comment = $computer_db->{'dset'}{$sector_current}{'comment'}; $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//; $comment =~ s/\s+(\(\w+\))$// and $category = $1; $tb_computer->add($sector_current, $computer_db->{'dset'}{$sector_current}{'dns_extension'}, $ip_range, $date, $comment, $category, ); } print $tb_computer->title(), $tb_computer->rule('-') if not $no_header; print $tb_computer->body(); } #-------------------------------------------------------------------------------- sub cmd_search_mac { local @ARGV = @_; my $help = get_cmd_name(); my ($mac); GetOptions( 'mac|m=s' => \$mac, ); exit_on_error_option($help) if $mac eq ''; $mac = normalize_mac_address($mac); my $computer_db = ipamdb_load($COMPUTER_YAML); control_syntax_mac_address($mac) or exit; LOOP_ON_SECTOR: for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $mac_address ne $mac; my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $attribute->{'modify_time'}; $year += 1900; $mon++; my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday; my $comment = $attribute->{'comment'}; $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//; my $enable = $attribute->{'enabled'}; if (exists $attribute->{'pxe_config'}) { $enable .= '/' . $attribute->{'pxe_config'}; } if (exists $attribute->{'tag'}) { $enable .= ':' . $attribute->{'tag'}; } printf "%-30s %-20s %17s %9s %3s %10s %s\n", $attribute->{'hostname'} . '.' . $sector_current, $attribute->{'ip'}, $mac_address, $attribute->{'address_type'}, $enable, $date, $comment; } } } #-------------------------------------------------------------------------------- #Nom: show #Description: liste les machines à partir du fichier YAML par nom de domaine. sub cmd_show_host { my %ipdb = (); my $computer_db = ipamdb_load($COMPUTER_YAML); my $tb_computer = Text::Table->new( {align => 'left', align_title => 'left', title => 'Hostname.Sector'}, {is_sep => 1, body => ' '}, {align => 'left', align_title => 'left', title => 'IPv4-Address'}, {is_sep => 1, body => ' '}, {align => 'center', align_title => 'center', title => 'MAC-Address'}, {is_sep => 1, body => ' '}, {align => 'right', align_title => 'right', title => 'Type'}, {align => 'right', align_title => 'right', title => 'Status'}, {is_sep => 1, body => ' '}, {align => 'left', align_title => 'left', title => 'Date'}, {align => 'left', align_title => 'left', title => 'Comment'}, ); LOOP_ON_SECTOR: for my $sector_current (sort keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; my $ip = $attribute->{'ip'}; if ($ip =~ m/$DDT::RE::IPv4_ADDRESS/xms) { if ( not exists $ipdb{$ip} ) { $ipdb{$ip} = { 'mac_address' => $mac_address, %{$attribute}, 'sector' => $sector_current, }; } else { print {*STDERR} "# Warning: $ip already exists in the database with MAC $mac_address!\n"; } next LOOP_ON_COMPUTER; } my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $attribute->{'modify_time'}; $year += 1900; $mon++; my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday; my $comment = normalize_comment($attribute->{'comment'}); $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//; my $enable = $attribute->{'enabled'}; if (exists $attribute->{'pxe_config'}) { $enable .= '/' . $attribute->{'pxe_config'}; } if (exists $attribute->{'tag'}) { $enable .= ':' . $attribute->{'tag'}; } #printf "%-30s %-20s %17s %9s %3s %10s %s\n", $tb_computer->add( $attribute->{'hostname'} . '.' . $sector_current, $ip, $mac_address, $attribute->{'address_type'}, $enable, $date, $comment, ); } #print "\n# *** List of pool computers in the sector: $sector_current ***\n"; } #print "\n# *** List of computers ordered by IP and sector ***\n"; LOOP_ON_IP_ADDRESS: foreach my $ip (Net::Netmask::sort_by_ip_address(keys %ipdb)) { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $ipdb{$ip}->{'modify_time'}; $year += 1900; $mon++; my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday; my $comment =$ipdb{$ip}->{'comment'}; $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//; my $enable = $ipdb{$ip}->{'enabled'}; if (exists $ipdb{$ip}->{'pxe_config'}) { $enable .= '/' . $ipdb{$ip}->{'pxe_config'}; } if (exists $ipdb{$ip}->{'tag'}) { $enable .= ':' . $ipdb{$ip}->{'tag'}; } #printf "%-30s %-20s %17s %9s %3s %10s %s\n", $tb_computer->add( $ipdb{$ip}->{'hostname'} . '.' . $ipdb{$ip}->{'sector'}, $ip, normalize_mac_address($ipdb{$ip}->{'mac_address'}), $ipdb{$ip}->{'address_type'}, $enable, $date, $comment ); } print $tb_computer->title(); print $tb_computer->rule('-'); print $tb_computer->body(); } #------------------------------------------------------------------------------- #Nom: cmd_generate_dhcp_file #Description: génère les fichiers de configuration des machines et des pools du dhcp sub cmd_generate_dhcp_file { backup_database(); my $computer_db = ipamdb_load($COMPUTER_YAML); my %file_pool; for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; open FILE_VLAN, '>', "$FOLDER_GEN_DHCP/$sector_current"; my @sectordb = @{$computer_db->{$sector_current}}; for my $value (@sectordb) { ALL_MAC_ADDRESS: for my $mac_addres (keys %{$value}) { #host pcdavoust { deny-unknown-clients; #hardware ethernet 0:6:5b:b8:13:d1; #fixed-address 194.254.66.72; #} my $hostname = $value->{$mac_addres}{'hostname'}; my $ip = $value->{$mac_addres}{'ip'}; my $comment = $value->{$mac_addres}{'comment'}; my $address_type = $value->{$mac_addres}{'address_type'}; my $enabled = $value->{$mac_addres}{'enabled'}; my $tags = $value->{$mac_addres}{'tag'} || 'universal'; my $buffer; if ($address_type eq 'dhcp') { if ($enabled eq 'yes') { $buffer = "host $hostname {\n"; # deny-unknown-clients; $buffer .= " hardware ethernet $mac_addres;\n"; $buffer .= " fixed-address $ip;\n"; if (exists $value->{$mac_addres}{'pxe_config'}) { my $pxe_config = $value->{$mac_addres}{'pxe_config'}; my $ip_next_server = $computer_db->{'pxe'}{$pxe_config}{'ip_next_server'}; my $filename = $computer_db->{'pxe'}{$pxe_config}{'filename'}; $buffer .= " next-server $ip_next_server;\n"; $buffer .= " filename \"$filename\";\n"; } $buffer .= " #comment: $comment\n"; $buffer .= " }\n"; $buffer .= "\n"; for my $tag (split/,/, $tags) { $file_pool{"tag-$tag"} ||= []; push @{$file_pool{"tag-$tag"}}, "subclass \"tag-$tag\" 1:$mac_addres; # $comment\n"; } } else { $buffer = "#host $hostname {\n"; # deny-unknown-clients; $buffer .= "# hardware ethernet $mac_addres;\n"; $buffer .= "# fixed-address $ip;\n"; $buffer .= "# comment: $comment \n"; $buffer .= "# }\n"; $buffer .= "\n"; } print FILE_VLAN $buffer; } elsif ($address_type eq 'pool-dhcp') { #--- Génère les fichiers pool dhcp ---# for my $current_pool (keys %{$computer_db->{'pool'}}) { next if $current_pool ne $ip; if ($enabled eq 'yes') { $buffer = "subclass \"$current_pool\" 1:$mac_addres; # $comment\n"; for my $tag (split/,/, $tags) { $file_pool{"tag-$tag"} ||= []; push @{$file_pool{"tag-$tag"}}, "subclass \"tag-$tag\" 1:$mac_addres; # $comment\n"; } } else { $buffer = "#subclass \"$current_pool\" 1:$mac_addres; # $comment\n"; } my $current_pool_file_name = $computer_db->{'pool'}{$current_pool}{'file'}; $file_pool{$current_pool_file_name} ||= []; push @{$file_pool{$current_pool_file_name}}, $buffer; } } } } close FILE_VLAN; for my $file_name (keys %file_pool) { open FILE_POOL, '>', "$FOLDER_GEN_DHCP/$file_name"; print FILE_POOL @{$file_pool{$file_name}}; close FILE_POOL; } } print "Copy DHCP files from $FOLDER_GEN_DHCP to /etc/dhcp/include/\n"; exec $SCRIPT_UPDATE; } #------------------------------------------------------------------------------- #Nom: cmd_generate_dns_file #Description: génère les fichiers d'enregistrements DNS sub cmd_generate_dns_file { local @ARGV = @_; my $help = get_cmd_name(); my ($verbose); GetOptions( 'verbose|v' => \$verbose, ); my $buffer_fwd; my $buffer_rev; my $pool_domain; my $computer_db = ipamdb_load($COMPUTER_YAML); for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; if ($sector_current eq 'pool') { LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector_current}}) { for my $pool_name (keys %{$computer}) { $pool_domain = $computer->{$pool_name}->{'domain'}."\n"; #print $computer->{$pool_name}->{'file'}; chomp $pool_domain; open FILE_FORWARD_DNS, '>>', "$FOLDER_GEN_DNS/db.$pool_domain.fwd"; open FILE_REVERSE_DNS, '>>', "$FOLDER_GEN_DNS/db.$pool_domain.rev"; my @T_pool_ip = @{$computer->{$pool_name}->{'ip'}}; for my $pool_ip (@T_pool_ip) { my @T_split = split(/\./ , $pool_ip); $buffer_fwd = sprintf "%-24s IN A %-15s ;\n", "$pool_name$T_split[3]", $pool_ip; $buffer_rev = "$T_split[3] IN PTR $pool_name$T_split[3].$pool_domain.\n"; print FILE_FORWARD_DNS $buffer_fwd; print FILE_REVERSE_DNS $buffer_rev; } close FILE_FORWARD_DNS; close FILE_REVERSE_DNS; } } } else { #--- Création du fichier non-reverse ---# open FILE_FORWARD_DNS, ">> $FOLDER_GEN_DNS/db.$sector_current.fwd"; open FILE_REVERSE_DNS, ">> $FOLDER_GEN_DNS/db.$sector_current.rev"; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; #host pcdavoust { deny-unknown-clients; #hardware ethernet 0:6:5b:b8:13:d1; #fixed-address 194.254.66.72; #} my $hostname = $attribute->{'hostname'}; my $ip = $attribute->{'ip'}; my $comment = $attribute->{'comment'}; my $address_type = $attribute->{'address_type'}; my $enabled = $attribute->{'enabled'}; next LOOP_ON_COMPUTER if not (($address_type eq 'dhcp') or ($address_type eq 'static')); my $dns_domain = $sector_current; if (exists $computer_db->{'dset'}{$sector_current}) { $dns_domain = $computer_db->{'dset'}{$sector_current}{'dns_extension'}; } my @ip_split = split /\./, $ip; if ($enabled eq 'yes') { if (exists $attribute->{'dns_extension'} and "$attribute->{'dns_extension'}" != "$dns_domain") { print "A FAIRE\n"; } $buffer_fwd = sprintf "%-24s IN A %-15s ; %s\n", $hostname, $ip, $comment; $buffer_rev = sprintf "%3i IN PTR %-15s\n", $ip_split[3], "$hostname.$dns_domain."; } else { $buffer_fwd = sprintf ";%-24s IN A %-15s ; %s\n", $hostname, $ip, $comment; $buffer_rev = sprintf ";%3i IN PTR %-15s\n", $ip_split[3], "$hostname.$dns_domain."; } print FILE_REVERSE_DNS $buffer_rev; print FILE_FORWARD_DNS $buffer_fwd; } close FILE_REVERSE_DNS; close FILE_FORWARD_DNS; print "- DNS: db.$sector_current.fwd db.$sector_current.rev [CREATE].\n" if $verbose; print " Ex : sort -k 4n -t . $FOLDER_GEN_DNS/db.$sector_current.fwd\n" if $verbose; } } } #-------------------------------------------------------------------------------- sub shell_command { my $cmd = shift; require FileHandle; my $fh = new FileHandle; my @result = (); open $fh, q{-|}, "LANG=C $cmd" or die "Can't exec $cmd\n"; @result = <$fh>; close $fh; chomp @result; return @result; } #-------------------------------------------------------------------------------- sub cmd_check_dns { local @ARGV = @_; my $help = get_cmd_name(); my ($opt_direct, $opt_reverse, $opt_byip); GetOptions( 'direct|d' => \$opt_direct, 'reverse|r' => \$opt_reverse, 'by-ip|b' => \$opt_byip, ); my $computer_db = ipamdb_load($COMPUTER_YAML); if ($opt_direct or not ($opt_reverse or $opt_byip)) { # DDT to DNS check LOOP_ON_SECTOR: for my $sector_current (keys %{$computer_db}) { next if $sector_current eq 'dset'; next if $sector_current eq 'pool'; next if $sector_current eq 'pxe'; next if $sector_current eq 'tag'; next if $sector_current eq 'version'; my @sectordb = @{$computer_db->{$sector_current}}; LOOP_ON_COMPUTER: for my $computer (@sectordb) { my ($mac_address, $attribute) = %{$computer}; #my $new_mac = normalize_mac_address($mac_address); my $ip = $attribute->{'ip'}; next LOOP_ON_COMPUTER if not $ip =~ m/$DDT::RE::IPv4_ADDRESS/xms; next LOOP_ON_COMPUTER if $attribute->{'enabled'} eq 'no'; my $dns_hostname_fq = scalar gethostbyaddr(inet_aton($ip), AF_INET); my ($dns_hostname) = split /\./, $dns_hostname_fq; if ($attribute->{'hostname'} ne $dns_hostname) { print "$mac_address ($sector_current) $ip - $dns_hostname / $attribute->{'hostname'} # $attribute->{'comment'}\n"; next LOOP_ON_COMPUTER; } my $packed_ip = scalar gethostbyname($dns_hostname_fq); if (defined $packed_ip) { my $ip_address = inet_ntoa($packed_ip); if ($ip ne $ip_address) { print "Error: bad IP $ip for reverse DNS on $dns_hostname_fq\n"; next LOOP_ON_COMPUTER; } } } } } if ($opt_reverse) { # DNS to DDT check my %saw; # count for unique member my @dns_domain_list = sort grep !$saw{$_}++, map $computer_db->{'dset'}{$_}{'dns_extension'}, grep exists($computer_db->{'dset'}{$_}{'dns_extension'}), keys $computer_db->{'dset'}; LOOP_ON_DNS: for my $dns (@dns_domain_list) { LOOP_ON_IP: for (shell_command("host -t A -l $dns")) { # smtp2.legi.grenoble-inp.fr has address 194.254.67.37 next if not m/has address/; next if not m/^(\w[\w-_\.]+\w)\s+has\saddress\s+(\d[\d\.]+\d)$/; my ($hostname_fq, $ip) = ($1, $2); control_syntax_ip($ip) or next LOOP_ON_IP; if (control_exist_ip($computer_db, $ip) == 1) { printf "Unkown IP: %-15s / %s\n", $ip, $hostname_fq; next LOOP_ON_IP; } } } } if ($opt_byip) { # IP Range DDT check my @ip_check; LOOP_ON_SECTOR: for my $sector_current (keys %{$computer_db->{'dset'}}) { next LOOP_ON_SECTOR if not exists $computer_db->{'dset'}{$sector_current}{'ip_range'}; LOOP_ON_CIDR: for my $ip_range (@{$computer_db->{'dset'}{$sector_current}{'ip_range'}}) { LOOP_ON_IP: for my $ip (NetAddr::IP->new($ip_range)->hostenum()) { $ip =~ s{/32$}{}; my $dns_hostname_fq = scalar gethostbyaddr(inet_aton($ip), AF_INET); my ($dns_hostname) = split /\./, $dns_hostname_fq; # Verify reverse return same IP my $packed_ip = scalar gethostbyname($dns_hostname_fq); if (defined $packed_ip) { my $ip_address = inet_ntoa($packed_ip); if ($ip ne $ip_address) { print "Error: bad IP $ip for reverse DNS on $dns_hostname_fq sector $sector_current\n"; } } # Verify direct return same hostname LOOP_ON_COMPUTER: for my $computer (@{$computer_db->{$sector_current}}) { my ($mac_address, $attribute) = %{$computer}; next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip; print "Error: bad DNS host $dns_hostname / DDT host $attribute->{'hostname'} in sector $sector_current with IP $ip\n" if $attribute->{'hostname'} ne $dns_hostname and $attribute->{'enabled'} ne 'no'; next LOOP_ON_IP; } # Declare in DNS but not in DDT print "Error: DNS host $dns_hostname in sector $sector_current with IP $ip not declare in DDT database\n" if $dns_hostname ne ''; } } } } } #------------------------------------------------------------------------------- #Nom: load_data_dhcp #Description: permet de charger le fichier de données YAML via les fichiers de configuration # machines. # ATTENTION: LES COMMENTAIRES DU FICHIER DISPARAITRONT. sub load_data_dhcp { my ($sector, $input_file) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); my @T_mac; my @T_host; my @T_ip; my $cpt; open (FILE, "<$input_file"); my @buffer = ; close(FILE); LINE: for my $ligne (@buffer) { #-- $ligne =~ s/#.*$//; $ligne =~ s/\s+/ /; $ligne =~ s/^\s+//; next if $ligne eq ''; if ($ligne =~ /^host /) { $cpt=0; my @T_split = split(/host\s+/, $ligne); @T_host = split(/ /, $T_split[1]); chomp($T_host[0]); $cpt++; } if ($ligne =~ /^*ethernet /) { $ligne =~ s/;//g; @T_mac = split(/ethernet\s+/, $ligne); chomp($T_mac[1]); $cpt++; } if ($ligne =~ /^*address /) { $ligne =~ s/;//g; @T_ip = split(/address\s+/, $ligne); chomp($T_ip[1]); $cpt++; } if ($cpt == 3) { # print "MAC $T_mac[1] HOST $T_host[0] IP $T_ip[1].\n"; my $mac = $T_mac[1]; my $hostname = $T_host[0]; my $ip = $T_ip[1]; $cpt = 0; if ( control_exist_hostname($computer_db, $sector, $hostname) == 0 ) { print "Error: host already exist in sector $sector: $hostname\n"; next LINE; } control_syntax_mac_address($mac) or next LINE; if ( control_exist_mac($computer_db, $mac) == 0) { print "Error: physical MAC address already exists: $mac\n"; next LINE; } control_syntax_ip($ip) or next LINE; if ( control_exist_ip($computer_db, $ip) == 0 ) { print "Error: IP address already exists: $ip\n"; next LINE; } my $timestamp = time; push @{$computer_db->{$sector}}, { $mac => { 'hostname' => $hostname, 'ip' => $ip, 'address_type' => 'dhcp', 'enabled' => 'yes', 'create_time' => $timestamp, 'modify_time' => $timestamp, 'alias' => '', }}; } } } #------------------------------------------------------------------------------- #Nom: load_data_pool #Description: permet de charger le fichier YAML via les fichiers de conf 'pool' du dhcp. sub load_data_pool { my ($sector, $input_file) = @_; my @T_mac; open (FILE, "<$input_file"); my @buffer = ; close(FILE); my $computer_db = ipamdb_load($COMPUTER_YAML); for my $ligne (@buffer) { #-- $ligne =~ s/#.*$//; $ligne =~ s/\s+/ /; $ligne =~ s/^\s+//; $ligne =~ s/;//g; $ligne =~ s/"//g; next if $ligne eq ''; if (($ligne =~ /^subclass/)) { my @T_split = split(/ / ,$ligne); my $pool = $T_split[1]; @T_mac = split(/:/ , $T_split[2]); my $mac = $T_mac[1].":".$T_mac[2].":".$T_mac[3].":".$T_mac[4].":".$T_mac[5].":".$T_mac[6]; control_syntax_mac_address($mac) or next; if (control_exist_mac($computer_db, $mac) == 0) { print "Error: physical MAC address already exists: $mac\n"; next; } #--- cette partie teste si le pool existe. if (not exists $computer_db->{'pool'}{$pool}) { print "Error: create pool with create_pool command before load database: $pool\n"; exit; } if ($computer_db->{'pool'}{'domain'} eq $sector) { my $timestamp = time; push @{$computer_db->{$sector}}, { $mac => { 'hostname' => $pool, 'ip' => $pool, 'address_type' => 'pool-dhcp', 'enabled' => 'yes', 'create_time' => $timestamp, 'modify_time' => $timestamp, }}; } else { print "Ajout de la machine $mac [FAILED]\n"; print "Error: the pool doesn't exists: $pool, for the domain: $sector\n"; } } } } #------------------------------------------------------------------------------- sub load_data_file { my ($sector, $input_file, $type_file) = @_; my $computer_db = ipamdb_load($COMPUTER_YAML); #$computer_db if ($type_file eq 'dhcp') { load_data_dhcp($sector, $input_file); } elsif ($type_file eq 'pool-dhcp') { load_data_pool($sector, $input_file); } ipamdb_save("$COMPUTER_YAML", $computer_db); } #------------------------------------------------------------------------------- sub cmd_load_database { local @ARGV = @_; my $help = get_cmd_name(); my ($sector, $input_file, $type_file); GetOptions( 'sector|s|d=s' => \$sector, 'filename|f=s' => \$input_file, 'kind|k=s' => \$type_file, ); exit_on_error_option($help) if $sector eq '' or $input_file eq '' or $type_file eq ''; load_data_file($sector, $input_file, $type_file); } #------------------------------------------------------------------------------- #Nom: backup_database #Description: sauvegarde et réinitialise les fichiers d'enregistrements DHCP. sub backup_database { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime time; $year += 1900; $mon++; my $date = sprintf '%04i-%02i-%02i-%02i-%02i-%02i', $year, $mon, $mday, $hour, $min, $sec; copy($COMPUTER_YAML, "$FOLDER_BACKUP/$COMPUTER_BASENAME-$date.conf") or die "Error: database copy backup failed: $!\n"; } #------------------------------------------------------------------------------- # HELP section #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- #Nom: exit_on_error_option #Description: messages d'aide des options pour les différentes commandes sub exit_on_error_option { my ($command) = @_; if ($command eq 'add-dhcp') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory). Example: -s legi-sector03\n"; print " -h : computer hostname (mandatory if option -i != 'pool'). Example: -h info8pc154\n"; print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A\n"; print " -i : internet IP address (mandatory). Possible value: classical IP address or the keyword 'pool'\n"; print " -p : name of the DHCP pool to which the machine belongs (mandatory if option -i == 'pool')\n"; print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n"; print "Example:\n"; print " ddt add-dhcp -h most1mc130 -s legi-sector03 -i 194.254.66.130 -m 00:17:F2:D3:2B:FF -c '2008-07-03 Mac Book Guillaume Balleyrac (MOST)\n"; } elsif ($command eq 'add-float') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory)\n"; print " -p : name of the DHCP pool to which the machine belongs (mandatory)\n"; print " -m : physical MAC address (mandatory)\n"; print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n"; print "Example:\n"; print " ddt add-float -p pool-stagiaire -s legi-pool -i 192.168.10.1 -m 00:AB:1B:CC:AA:2F -c '2013-09-25 Dell OptiPlex 745 - Eric Goncalves (NRJ)\n"; } elsif ($command eq 'add-static') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory)\n"; print " -i : internet IP address (mandatory)\n"; print " -h : computer hostname (mandatory)\n"; print " -m : physical MAC address (mandatory)\n"; print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n"; print "Example:\n"; print " ddt add-static -h legipc1 -s legi-sector03 -i 192.168.10.1 -m 00:AB:1B:CC:AA:2F -c '2013-09-25 Dell OptiPlex 745 - Eric Goncalves (NRJ)\n"; } elsif ($command eq 'add-virtual') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory)\n"; print " -i : internet IP address (mandatory)\n"; print " -h : computer hostname (mandatory)\n"; print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n"; print "Example:\n"; print " ddt add-virtual -h legipc1 -s legi-sector03 -i 192.168.10.1 -c '2013-09-25 Dell OptiPlex 745 - Eric Goncalves (NRJ)\n"; } elsif ($command eq 'add-alias') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory)\n"; print " -h : computer hostname (mandatory)\n"; print " -a : computer alias name (mandatory)\n"; } elsif ($command eq 'create-sector') { print "List of options for command: $command\n"; print " -s : new sector (mandatory)\n"; print " -e : DNS domain name extension( mandatory). Example legi.grenoble-inp.fr\n"; print " -c : comment (mandatory). Example: 2016-08-22 VLAN legi-261 (INFO)\n"; print "Examples:\n"; print " ddt create-sector -s legi-sector03 -e legi.grenoble-inp.fr -c '2016-08-22 VLAN legi-261 (INFO)'\n"; } elsif ($command eq 'create-pool') { print "List of options for command: $command\n"; print " -p : name of the DHCP pool. Example: pool-legi-priv\n"; print " -s : sector attachment for the pool. (sector attachment must exist in file $COMPUTER_BASENAME.conf). Example: legi-sector03\n"; print " -f : configuration filename on the DHCP server for the pool\n"; print " -i : adresse(s) IP ou plage d'IP. Séparateur d'adresses IP: ','. Séparateur de plage '-'\n"; print "Examples:\n"; print " ddt create-pool -p legi-pool1 -s legi-sector03 -f legi-pool-private -i 192.168.10.1,192.168.10.2,192.168.10.3\n"; print " ddt create-pool -p legi-pool2 -s legi-sector03 -f legi-pool-public -i 192.168.10.1-192.168.10.4\n"; } elsif ($command eq 'create-pxe') { print "List of options for command: $command\n"; print " -b : name of the PXE/BOOTP configuration. Example: most\n"; print " -n : internet IP address for the DHCP next-server.\n"; print " -f : filename on TFTP server to load at boot\n"; print " -c : comment (mandatory). Example: 2014-04-07 PXE Boot for CentOS (MOST)\n"; } elsif ($command eq 'remove-pxe') { print "List of options for command: $command\n"; print " -b : name of the PXE/BOOTP configuration. Example: most\n"; } elsif ($command eq 'enable-pxe') { print "List of options for command: $command\n"; print " -h : computer hostname (mandatory unless option -i)\n"; print " -i : internet IP address (mandatory unless option -h)\n"; print " -s : sector attachment (mandatory if option -h)\n"; print " -b : name of the PXE/BOOTP configuration. Example: most\n"; } elsif ($command eq 'disable-pxe') { print "List of options for command: $command\n"; print " -h : computer hostname (mandatory unless option -i)\n"; print " -i : internet IP address (mandatory unless option -h)\n"; print " -s : sector attachment (mandatory if option -h)\n"; } elsif ($command eq 'create-tag') { print "List of options for command: $command\n"; print " -t : name of the TAG (mandatory). Example: restricted\n"; print " -c : comment (mandatory). Example: 2014-04-07 tag restricted (INFO)\n"; print "tag 'universal' is intrinsic\n"; } elsif ($command eq 'remove-tag') { print "List of options for command: $command\n"; print " -b : name of the TAG. Example: restricted\n"; } elsif ($command eq 'change-mac') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory). Example: -s legi-sector03\n"; print " -h : computer hostname (mandatory unless option -i)\n"; print " -i : internet IP address (mandatory unless option -h). Possible value: classical IP address or the keyword 'pool'\n"; print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n"; } elsif ($command eq 'change-ip') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory). Example: -s legi-sector03\n"; print " -h : computer hostname (mandatory)\n"; print " -i : new internet IP address (mandatory). Possible value: classical IP address\n"; } elsif ($command eq 'change-host') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory). Example: -s legi-sector03\n"; print " -i : internet IP address (mandatory). Possible value: classical IP address\n"; print " -h : new computer hostname (mandatory)\n"; print "It's not possible to change hostname for computer that belongs to a pool\n"; } elsif ($command eq 'change-comment') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory). Example: -s legi-sector03\n"; print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n"; print " -c : new comment (mandatory)\n"; } elsif ($command eq 'change-sector') { print "List of options for command: $command\n"; print " -s : new sector attachment (mandatory). Example: -s legi-sector03\n"; print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n"; print " -i : internet IP address (mandatory)\n"; } elsif ($command eq 'change-tag') { print "List of options for command: $command\n"; print " -h : computer hostname (mandatory unless option -i or -m)\n"; print " -s : sector attachment (mandatory). Example: -s legi-sector03\n"; print " -i : internet IP address (mandatory unless option -h or -m)\n"; print " -m : physical MAC address (mandatory unless option -h or -i, priority). Example: -m 0F:58:AB:2A:22:11\n"; print " -t : list of tags separated by comma (mandatory). Example: -t internal,windows\n"; } elsif ($command eq 'change-type') { print "List of options for command: $command\n"; print " -h : computer hostname (mandatory)\n"; print " -s : sector attachment (mandatory)\n"; print " -t : new type). Example: -t static\n"; } elsif ($command eq 'load-database') { print "List of options for command: $command\n"; print " -s : sector attachment\n"; print " -f : input file in DHCP format\n"; print " -k : possible cases (kind): dhcp, pool-dhcp, fix-address\n"; } elsif ($command eq 'enable-pc') { print "List of options for command: $command\n"; print " -h : computer hostname (mandatory unless option -i)\n"; print " -i : internet IP address (mandatory unless option -h)\n"; print " -s : sector attachment (mandatory if option -h)\n"; print "Examples:\n"; print " ddt enable-pc -i 192.168.10.1\n"; print " ddt enable-pc -s legi-sector03 -h kevinpc\n"; } elsif ($command eq 'enable-float') { print "List of options for command: $command\n"; print " -m : physical MAC address (mandatory)\n"; print " -p : name of the DHCP pool (mandatory)\n"; } elsif ($command eq 'disable-float') { print "List of options for command: $command\n"; print " -m : physical MAC address (mandatory)\n"; print " -p : name of the DHCP pool (mandatory)\n"; } elsif ($command eq 'disable-pc') { print "List of options for command: $command\n"; print " -h : computer hostname (mandatory unless option -i)\n"; print " -i : internet IP address (mandatory unless option -h)\n"; print " -s : sector attachment (mandatory if option -h)\n"; print "Examples:\n"; print " ddt disable-pc -i 192.168.10.1\n"; print " ddt disable-pc -s legi-sector03 -h kevinpc\n"; } elsif ($command eq 'del-pc') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory)\n"; print " -h : computer hostname (mandatory unless option -i)\n"; print " -i : internet IP address (mandatory unless option -h)\n"; } elsif ($command eq 'del-float') { print "List of options for command: $command\n"; print " -m : physical MAC address (mandatory)l\n"; print " -p : name of the DHCP pool\n"; } elsif ($command eq 'search-mac') { print "List of options for command: $command\n"; print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n"; } elsif ($command eq 'sector-add-ip') { print "List of options for command: $command\n"; print " -s : sector attachment (mandatory)\n"; print " -i : internet IP range address in CIDR notation (mandatory)\n"; } else { print "No help for command: $command\n"; } exit; } #------------------------------------------------------------------------------- sub cmd_version { print <<'END'; ddt - management of computer names and IP addresses Copyright (C) 2006-2019, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France Main author Gabriel Moreau License GNU GPL version 2 or later and Perl equivalent END print "Database Version 1\n"; print "Version $VERSION\n\n"; print ' $Id: ddt 385 2019-04-24 14:26:08Z g7moreau $'."\n"; return; } #------------------------------------------------------------------------------- #Nom: usage #Description: message d'aide sur les commandes du script sub cmd_help { print < but just C... In practise, DDT is an IP Address Management (IPAM) service. It has been used in the LEGI laboratory for over 10 years. The tool is quite effective and tries to keep things simple but easily configurable for your site like a swiss army knife. Everything is saved in a YAML database and entries could be added, deleted, or modified by the command line. =head1 COMMANDS =head2 add-alias ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias] =head2 add-dhcp ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment] =head2 add-float ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment] =head2 add-static Add a static host in the database. No DHCP configuration will be generated, only DNS. ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment] =head2 add-virtual Add a static host in the database with a virtual MAC address beginning by C. No DHCP configuration will be generated, only DNS. ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment] =head2 change-comment ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment] =head2 change-sector ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] =head2 change-host ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] =head2 change-ip ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] =head2 change-mac ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] =head2 change-tag ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag] =head2 change-type ddt change-type [--hostname|-h hostname] [--sector|-s|-d sector] [--type|-t type] =head2 check-dns ddt check-dns [--direct] [--reverse] =head2 create-sector ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment] =head2 create-pool ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool] =head2 create-pxe ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment] =head2 create-tag ddt create-tag [--tag|-t tag] [--comment|-c comment] =head2 del-float ddt del-float [--pool|-p pool] [--mac|-m mac] =head2 del-pc ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] =head2 disable-pc ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] =head2 disable-float ddt disable-float [--pool|-p pool] [--mac|-m mac] =head2 disable-pxe ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] =head2 enable-float ddt enable-float [--pool|-p pool] [--mac|-m mac] =head2 enable-pc ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] =head2 enable-pxe ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config] =head2 gen-dhcp-file ddt gen-dhcp-file =head2 gen-dns-file ddt gen-dns-file [--verbose] =head2 help ddt help =head2 load-database ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind] =head2 remove-pxe ddt remove-pxe [--bootp|-b pxe_config] =head2 remove-tag ddt remove-tag [--tag|-t tag] =head2 search-mac ddt search-mac [--mac|-m mac] =head2 sector-add-ip ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr] =head2 show-sector ddt show-sector [--no-header|-H] =head2 show ddt show =head2 show-pool ddt show-pool [--no-header|-H] =head2 show-pxe ddt show-pxe [--no-header|-H] =head2 show-tag ddt show-tag [--no-header|-H] =head2 version ddt version =head1 AUTHORS Written by Gabriel Moreau , Kevin Reverchon, Olivier De-Marchi - Grenoble - France =head1 LICENSE AND COPYRIGHT License GNU GPL version 2 or later and Perl equivalent Copyright (C) 2006-2019, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France