source: trunk/ddt/ddt @ 359

Last change on this file since 359 was 359, checked in by g7moreau, 6 years ago
  • Initial version of dns check by ip range
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 118.1 KB
Line 
1#!/usr/bin/perl
2#
3# Copyright (C) 2006-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
4# License GNU GPL version 2 or later and Perl equivalent
5#
6# apt-get install perl-base perl-modules libyaml-syck-perl libnet-netmask-perl libreadonly-perl libfile-touch-perl libtext-table-perl libnetaddr-ip-perl
7
8package DDT::RE;
9
10use strict;
11#use warnings;
12
13use Readonly;
14
15Readonly our $MAC_ADDRESS  => qr{ (?: [0-9A-F]{2} :){5} [0-9A-F]{2} }xms;
16Readonly our $IPv4_ADDRESS => qr{ [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} }xms;
17
18
19package main;
20
21use strict;
22#use warnings;
23use version; our $VERSION = version->declare('0.11.8');
24
25use Getopt::Long qw(GetOptions);
26#use YAML;
27use YAML::Syck;
28use Net::Netmask;
29use File::Touch;
30use File::Copy;
31use Socket;
32use Text::Table;
33use NetAddr::IP;
34
35my $command = shift @ARGV || 'help';
36
37my %cmd_db = (
38   'add-alias'          => \&cmd_add_alias,
39   'add-dhcp'           => \&cmd_add_dhcp,
40   'add-float'          => \&cmd_add_float,
41   'add-static'         => \&cmd_add_static,
42   'add-virtual'        => \&cmd_add_virtual,
43   'change-comment'     => \&cmd_change_comment,
44   'change-sector'      => \&cmd_change_sector,
45   'change-host'        => \&cmd_change_host,
46   'change-ip'          => \&cmd_change_ip,
47   'change-mac'         => \&cmd_change_mac,
48   'change-tag'         => \&cmd_change_tag,
49   'check-dns'          => \&cmd_check_dns,
50   'create-sector'      => \&cmd_create_sector,
51   'create-pool'        => \&cmd_create_pool,
52   'create-pxe'         => \&cmd_create_pxe,
53   'create-tag'         => \&cmd_create_tag,
54   'del-pc'             => \&cmd_del_pc,
55   'del-float'          => \&cmd_del_float,
56   'disable-pc'         => \&cmd_disable_pc,
57   'disable-float'      => \&cmd_disable_float,
58   'disable-pxe'        => \&cmd_disable_pxe,
59   'enable-pc'          => \&cmd_enable_pc,
60   'enable-float'       => \&cmd_enable_float,
61   'enable-pxe'         => \&cmd_enable_pxe,
62   'gen-dhcp-file'      => \&cmd_generate_dhcp_file,
63   'gen-dns-file'       => \&cmd_generate_dns_file,
64   'help'               => \&cmd_help,
65   'load-database'      => \&cmd_load_database,
66   'remove-pxe'         => \&cmd_remove_pxe,
67   'remove-tag'         => \&cmd_remove_tag,
68   'search-mac'         => \&cmd_search_mac,
69   'sector-add-ip'      => \&cmd_sector_add_ip,
70   'show'               => \&cmd_show_host,
71   'show-sector'        => \&cmd_show_sector,
72   'show-pool'          => \&cmd_show_pool,
73   'show-pxe'           => \&cmd_show_pxe,
74   'show-tag'           => \&cmd_show_tag,
75   'upgrade-db'         => \&cmd_upgrade_db,
76   'version'            => \&cmd_version,
77   );
78
79#-------------------------------------------------------------------------------
80
81my $CONFIG;
82
83my $xdg_config_home = $ENV{'XDG_CONFIG_HOME'} || "$ENV{'HOME'}/.config";
84$CONFIG = config_load("$xdg_config_home/ddt/config.yml") if -e "$xdg_config_home/ddt/config.yml";
85
86my $COMPUTER_BASENAME   = $CONFIG->{'database'}{'basename'} || 'ddt';
87my $COMPUTER_EXT        = $CONFIG->{'database'}{'ext'}      || 'db';
88
89my $FOLDER_APP          = $CONFIG->{'database'}{'folder'}   || '/var/lib/ddt';
90my $FOLDER_BACKUP       = $CONFIG->{'database'}{'backup'}   || "$FOLDER_APP/backup";
91my $FOLDER_GEN_DHCP     = $CONFIG->{'generate'}{'dhcp'}     || "$FOLDER_APP/dhcp";
92my $FOLDER_GEN_DNS      = $CONFIG->{'generate'}{'dns'}      || "$FOLDER_APP/dns";
93my $SCRIPT_UPDATE       = $CONFIG->{'script'}{'update'}     || '/usr/share/ddt/update-dhcp-server';
94
95my $COMPUTER_YAML       = "$FOLDER_APP/$COMPUTER_BASENAME.$COMPUTER_EXT";
96
97#-------------------------------------------------------------------------------
98
99mkdir $FOLDER_APP, 0755      if not -d $FOLDER_APP;
100mkdir $FOLDER_BACKUP, 0755   if not -d $FOLDER_BACKUP;
101mkdir $FOLDER_GEN_DHCP, 0755 if not -d $FOLDER_GEN_DHCP;
102mkdir $FOLDER_GEN_DNS, 0755  if not -d $FOLDER_GEN_DNS;
103
104if (defined $cmd_db{$command}) {
105   $cmd_db{$command}->(@ARGV);
106   }
107else {
108   print {*STDERR} "ddt: command $command not found\n\n";
109   $cmd_db{'help'}->();
110   exit 1;
111   }
112
113exit;
114
115#--------------------------------------------------------------------------------
116# LOAD SAVE section
117#--------------------------------------------------------------------------------
118
119sub config_load {
120   my $config_file = shift;
121
122   my $configdb = YAML::Syck::LoadFile($config_file);
123
124   return $configdb;
125   }
126
127#---------------------------------------------------------------
128# Load computer database
129
130sub ipamdb_load {
131   my $database_yaml = shift;
132
133   touch $database_yaml if not -e $database_yaml;
134   my $computer_db = YAML::Syck::LoadFile($database_yaml);
135
136   # add database version if not exist
137   if (not exists $computer_db->{'version'}) {
138      $computer_db->{'version'} = 1;
139      }
140
141   return $computer_db;
142   }
143
144#---------------------------------------------------------------
145# Save computer database
146
147sub ipamdb_save {
148   my ($database_yaml, $computer_db) = @_;
149
150   my $dirdb = $database_yaml;
151      $dirdb =~ s{ / [^/]* $}{}xms;
152   mkdir "$dirdb", 0755 unless -d "$dirdb";
153   YAML::Syck::DumpFile($database_yaml, $computer_db);
154
155   return $computer_db;
156   }
157
158#--------------------------------------------------------------------------------
159# CONTROL section
160#--------------------------------------------------------------------------------
161
162sub control_exist_pool {
163   my ($computer_db, $pool) = @_;
164
165   return exists $computer_db->{'pool'}{$pool} ? 1 : 0;
166   }
167
168#-------------------------------------------------------------------------------
169#Nom: control_exist_sector
170#Description: controle l'existence d'un sector dans le fichier YAML
171#             return 0 (faux) ou 1 (vrai)
172
173sub control_exist_sector {
174   my ($computer_db, $sector) = @_;
175
176   return 1 if exists $computer_db->{$sector};
177
178   print {*STDERR} "Error: sector $sector not found\n";
179   return 0;
180   }
181
182#-------------------------------------------------------------------------------
183#Nom: control_exist_hostname
184#Description: controle l'existence d'un nom de machine dans le fichier YAML
185#             return 0 (si trouvé) ou 1 (si non trouvé)
186
187sub control_exist_hostname {
188   my ($computer_db, $sector, $hostname) = @_;
189
190   if ($computer_db->{$sector} eq '') {
191      return 1;
192      }
193
194   my @sectordb = @{$computer_db->{$sector}};
195
196   for my $computer (@sectordb) {
197      my ($mac_address, $attribute) = %{$computer};
198      return 0 if $attribute->{'hostname'} eq $hostname;
199      }
200   return 1;
201   }
202
203#-------------------------------------------------------------------------------
204#Nom: control_exist_mac
205#Description: controle l'existence d'une adresse MAC dans le fichier YAML
206#             return 0 (si trouvé) ou 1 (si non trouvé)
207
208sub control_exist_mac {
209   my ($computer_db, $mac) = @_;
210
211   for my $sector_current (keys %{$computer_db}) {
212      next if $sector_current eq 'dset';
213      next if $sector_current eq 'pool';
214      next if $sector_current eq 'pxe';
215      next if $sector_current eq 'tag';
216      next if $sector_current eq 'version';
217
218      my @sectordb = @{$computer_db->{$sector_current}};
219
220      LOOP_ON_COMPUTER:
221      for my $computer (@sectordb) {
222         my ($mac_address, $attribute) = %{$computer};
223         return 0 if $mac_address eq $mac;
224         }
225      }
226   return 1;
227   }
228
229#-------------------------------------------------------------------------------
230#Nom: control_exist_ip
231#Description: controle l'existence d'une adresse IP dans le fichier YAML
232#             return 0 (si trouvé) ou 1 (si non trouvé)
233
234sub control_exist_ip {
235   my ($computer_db, $ip) = @_;
236
237   for my $sector_current (keys %{$computer_db}) {
238      next if $sector_current eq 'dset';
239      next if $sector_current eq 'pool';
240      next if $sector_current eq 'pxe';
241      next if $sector_current eq 'tag';
242      next if $sector_current eq 'version';
243
244      LOOP_ON_COMPUTER:
245      for my $computer (@{$computer_db->{$sector_current}}) {
246         my ($mac_address, $attribute) = %{$computer};
247         #print "Erreur: cette adresse IP $ip existe déjà\n";
248         return 0 if $attribute->{'ip'} eq $ip;
249         }
250      }
251
252   for my $current_pool (keys %{$computer_db->{'pool'}}) {
253      #--- Cette partie pour tester les ip des pools est bonne ne plus la changer ---#
254      my @T_pool_ip = @{$computer_db->{'pool'}{$current_pool}{'ip'}};
255
256      for my $pool_ip (@T_pool_ip) {
257         #print "Erreur: cette adresse IP $ip existe déjà\n";
258         return 0 if $pool_ip eq $ip;
259         }
260      }
261
262   return 1;
263   }
264
265#-------------------------------------------------------------------------------
266
267sub control_ip_in_range {
268   my ($computer_db, $sector, $ip) = @_;
269
270   return 1 if not exists $computer_db->{'dset'}{$sector}{'ip_range'}; # No IP range defined for this sector
271
272   my $ip_addr = NetAddr::IP->new($ip);
273
274   LOOP_ON_IP_RANGE:
275   for my $ip_range_current (@{$computer_db->{'dset'}{$sector}{'ip_range'}}) {
276      my $range = NetAddr::IP->new($ip_range_current);
277      return 1 if $range->contains($ip_addr);
278      }
279
280   return 0;
281   }
282
283#-------------------------------------------------------------------------------------
284#Nom: control_syntaxe_mac
285#Description: controle la syntaxe d'une adresse MAC (juste la longueur pas les valeurs)
286#             return 0 (si trouvé) ou 1 (si non trouvé)
287
288sub control_syntax_mac_address {
289   my $mac = shift;
290
291   if (scalar(split /:/, $mac) == 6 and $mac =~ $DDT::RE::MAC_ADDRESS) {
292      return 1;
293      }
294
295   print {*STDERR} "Error: bad MAC syntax: $mac\n";
296   return 0;
297   }
298
299#-------------------------------------------------------------------------------------
300#Nom: control_syntax_ip
301#Description: controle la syntaxe d'une adresse IP (juste la longueur pas les valeurs)
302#             return 0 (si trouvé) ou 1 (si non trouvé)
303
304sub control_syntax_ip {
305   my $ip = shift;
306
307   return 1 if $ip ne 'pool';
308
309   return 0 if $ip !~ m{^(\d+\.){3}\d+$};
310   return 0 if not NetAddr::IP->new("$ip/32");
311   return 1;
312   }
313
314#-------------------------------------------------------------------------------------
315
316sub control_syntax_cidr {
317   my $cidr = shift;
318
319   return 0 if $cidr !~ m{^(\d+\.){3}\d+/\d+$};
320   return 0 if not NetAddr::IP->new($cidr);
321   return 1;
322   }
323
324#-------------------------------------------------------------------------------------
325
326sub control_syntax_comment {
327   my $comment = shift;
328
329   if ($comment !~ m{^20\d\d-\d\d-\d\d\s}) {
330      print {*STDERR} "Error: no date like 2014-01-10 at the beginning: $comment\n";
331      return 0;
332      }
333
334   if ($comment !~ m{\(\w+\)$}) {
335      print {*STDERR} "Error: no (SERVICE) at the end: $comment\n";
336      return 0;
337      }
338
339   if ($comment =~ m{\s\s}) {
340      print {*STDERR} "Error: double space: $comment\n";
341      return 0;
342      }
343   return 1;
344   }
345
346#--------------------------------------------------------------------------------
347# UTILITY section
348#--------------------------------------------------------------------------------
349
350sub get_cmd_name {
351   my ($pkg, $sub) = split /::/, (caller(1))[3];
352   $sub =~ s/^cmd_//;
353   $sub =~ s/_/-/g;
354   return $sub;
355   }
356
357#-------------------------------------------------------------------------------
358
359sub normalize_mac_address {
360   my $mac_address = shift;
361
362   # D07E-28D1-7AB8 or d07e28-d17ab8
363   if ($mac_address =~ m{^ (?: [0-9A-Fa-f]{4} -){2} [0-9A-Fa-f]{4} $}xms
364      or $mac_address =~ m{^ [0-9A-Fa-f]{6} - [0-9A-Fa-f]{6} $}xms) {
365      $mac_address =~ s/-//g;
366      return join q{:}, unpack('(A2)*', uc($mac_address));
367      }
368
369   return join q{:}, map { substr( uc("00$_"), -2) } split m/ [:-] /xms, $mac_address;
370   }
371
372#-------------------------------------------------------------------------------
373
374sub normalize_comment {
375   my $comment = shift;
376
377   $comment =~ s{^(20\d\d)/(\d\d)/(\d\d)\s(.*)$}{$1-$2-$3 $4};
378
379   return $comment;
380   }
381
382#--------------------------------------------------------------------------------
383
384sub get_mac_from_hostname {
385   my ($computer_db, $sector, $hostname, $mac) = @_;
386
387   return $mac if $mac ne '';
388   return ''   if $hostname eq '';
389
390   LOOP_ON_COMPUTER:
391   for my $computer (@{$computer_db->{$sector}}) {
392      my ($mac_address, $attribute) = %{$computer};
393
394      next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
395
396      return $mac_address;
397      }
398   }
399
400#--------------------------------------------------------------------------------
401
402sub get_mac_from_ip {
403   my ($computer_db, $sector, $ip, $mac) = @_;
404
405   return $mac if $mac ne '';
406   return ''   if $ip eq '';
407
408   LOOP_ON_COMPUTER:
409   for my $computer (@{$computer_db->{$sector}}) {
410      my ($mac_address, $attribute) = %{$computer};
411
412      next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
413      return $mac_address;
414      }
415   }
416
417#--------------------------------------------------------------------------------
418# return a tuple (hash computer, iostat)
419# iostat 0/ok, 1/not exist
420
421sub get_computer_from_mac {
422   my ($computer_db, $sector, $mac) = @_;
423
424   LOOP_ON_COMPUTER:
425   for my $computer (@{$computer_db->{$sector}}) {
426      my ($mac_address, $attribute) = %{$computer};
427
428      next LOOP_ON_COMPUTER if $mac_address ne $mac;
429
430      return $attribute, 0;
431      }
432   return {}, 1;
433   }
434
435#-------------------------------------------------------------------------------
436# ADD computer section
437#-------------------------------------------------------------------------------
438
439#-------------------------------------------------------------------------------
440#Nom: add_alias
441#Description: ajoute un alias pour une machine. Pour la fonctionnalité CNAME dans le DNS.
442
443sub add_alias {
444   my ($computer_db, $hostname, $sector, $alias) = @_;
445
446   control_exist_sector($computer_db, $sector) or exit;
447   control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n";
448
449   my @sectordb = @{$computer_db->{$sector}};
450
451   LOOP_ON_COMPUTER:
452   for my $computer (@sectordb) {
453      my ($mac_address, $attribute) = %{$computer};
454
455      next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
456
457      $alias .= ' ' . $attribute->{'alias'};
458      $attribute->{'alias'}       = $alias;
459      $attribute->{'modify_time'} = time;
460      ipamdb_save("$COMPUTER_YAML", $computer_db);
461      print "Info: update attribute alias to $alias for host $hostname [OK]\n";
462      exit;
463      }
464   }
465
466#-------------------------------------------------------------------------------
467#Nom: add_static
468#Description: ajoute une machine non dhcp (donc à adressage fixe dans le fichier YAML)
469
470sub add_static {
471   my ($computer_db, $hostname, $sector, $ip, $mac, $comment) = @_;
472
473   $mac = normalize_mac_address($mac);
474   $comment = normalize_comment($comment);
475   control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n";
476   control_syntax_mac_address($mac)                         or exit;
477   control_exist_mac($computer_db, $mac)                    or die "Error: physical MAC address already exists: $mac\n";
478   control_syntax_ip($ip)                                   or die "Error: bad IP syntax $ip\n";
479   control_exist_ip($computer_db, $ip)                      or die "Error: IP $ip address already exist in sector $sector\n";
480   control_ip_in_range($computer_db, $sector, $ip)          or die "Error: IP $ip is not in sector $sector IP range.\n";
481   control_syntax_comment($comment)                         or exit;
482   my $timestamp = time;
483   push @{$computer_db->{$sector}}, { $mac => {
484      'hostname'     => $hostname,
485      'ip'           => $ip,
486      'address_type' => 'static',
487      'enabled'      => 'yes',
488      'create_time'  => $timestamp,
489      'modify_time'  => $timestamp,
490      'comment'      => $comment,
491      'alias'        =>  '',
492      }};
493   print "Info: add the host: $hostname, IP: $ip, MAC: $mac, sector: $sector [OK]\n";
494
495   ipamdb_save("$COMPUTER_YAML", $computer_db);
496   }
497
498
499#-------------------------------------------------------------------------------
500#Nom: add_dhcp
501#Description: section à corriger pour prendre en compte l'ajout d'une machine dans un pool dhcp
502#--- usage: ddt add-dhcp -s legi-sector03 -h meolpacif -m 00:18:F3:03:6F:66 -i 194.254.66.165
503
504sub add_dhcp {
505   my ($computer_db, $hostname, $sector, $ip, $mac, $comment) = @_;
506
507   my $timestamp = time;
508   $mac = normalize_mac_address($mac);
509   $comment = normalize_comment($comment);
510   control_exist_sector($computer_db, $sector)              or exit;
511   control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n";
512   control_syntax_mac_address($mac)                         or exit;
513   control_exist_mac($computer_db, $mac)                    or die "Error: physical MAC address already exists: $mac\n";
514   control_syntax_ip($ip)                                   or die "Error: bad IP syntax $ip\n";
515   control_exist_ip($computer_db, $ip)                      or die "Error: IP address already exist in sector $sector: $ip.\n";
516   control_ip_in_range($computer_db, $sector, $ip)          or die "Error: IP $ip is not in sector $sector IP range.\n";
517   control_syntax_comment($comment)                         or exit;
518
519   push @{$computer_db->{$sector}}, { $mac => {
520      'hostname'     => $hostname,
521      'ip'           => $ip,
522      'address_type' => 'dhcp',
523      'enabled'      => 'yes',
524      'create_time'  => $timestamp,
525      'modify_time'  => $timestamp,
526      'comment'      => $comment,
527      'alias'        => '',
528      }};
529   print "Add the computer: $hostname, IP: $ip, MAC: $mac, sector: $sector\n";
530
531   ipamdb_save("$COMPUTER_YAML", $computer_db);
532   }
533
534#-------------------------------------------------------------------------------
535#--- usage: ddt add-float -s legi-sector03 -h meolpacif -m 00:18:F3:03:6F:66 -i 194.254.66.165
536
537sub add_float {
538   my ($computer_db, $pool, $sector, $mac, $comment) = @_;
539
540   my $timestamp = time;
541   $mac = normalize_mac_address($mac);
542   $comment = normalize_comment($comment);
543   control_exist_sector($computer_db, $sector)  or exit;
544   control_syntax_mac_address($mac)                   or exit;
545   control_exist_mac($computer_db, $mac)              or die "Error: physical MAC address already exists: $mac\n";
546   control_exist_pool($computer_db, $pool)            or die "Error: the pool doesn't exists: $pool\n";
547   control_syntax_comment($comment)                   or exit;
548   push @{$computer_db->{$sector}}, { $mac => {
549      'hostname'     => $pool,
550      'ip'           => $pool,
551      'address_type' => 'pool-dhcp',
552      'enabled'      => 'yes',
553      'create_time'  => $timestamp,
554      'modify_time'  => $timestamp,
555      'comment'      => $comment,
556      }};
557   print "Info: add the computer in pool MAC: $mac, sector: $sector, Pool: $pool [OK]\n";
558
559   ipamdb_save("$COMPUTER_YAML", $computer_db);
560   }
561
562#-------------------------------------------------------------------------------
563# ADD computer section
564#-------------------------------------------------------------------------------
565
566sub cmd_add_alias {
567   local @ARGV = @_;
568
569   my $help = get_cmd_name();
570   my ($hostname, $sector, $alias);
571
572   GetOptions(
573      'hostname|h=s'    => \$hostname,
574      'sector|s|d=s'    => \$sector,
575      'alias|a=s'       => \$alias,
576      );
577
578   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
579   exit_on_error_option($help)
580      if $hostname   eq ''
581      or $sector  eq ''
582      or $alias      eq '';
583
584   my $computer_db = ipamdb_load($COMPUTER_YAML);
585   add_alias($computer_db, $hostname, $sector, $alias);
586   }
587
588#-------------------------------------------------------------------------------
589
590sub cmd_add_dhcp {
591   local @ARGV = @_;
592
593   my $help = get_cmd_name();
594   my ($hostname, $sector, $ip, $mac, $comment);
595
596   GetOptions(
597      'hostname|h=s'    => \$hostname,
598      'sector|s|d=s'    => \$sector,
599      'ip|i=s'          => \$ip,
600      'mac|m=s'         => \$mac,
601      'comment|c=s'     => \$comment,
602      );
603
604   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
605   exit_on_error_option($help)
606      if $hostname   eq ''
607      or $sector  eq ''
608      or $ip         eq ''
609      or $mac        eq ''
610      or $comment    eq '';
611
612   my $computer_db = ipamdb_load($COMPUTER_YAML);
613   add_dhcp($computer_db, $hostname, $sector, $ip, $mac, $comment);
614   }
615
616#-------------------------------------------------------------------------------
617
618sub cmd_add_float {
619   local @ARGV = @_;
620
621   my $help = get_cmd_name();
622   my ($pool, $sector, $mac, $comment);
623
624   GetOptions(
625      'pool|p=s'        => \$pool,
626      'sector|s|d=s'    => \$sector,
627      'mac|m=s'         => \$mac,
628      'comment|c=s'     => \$comment,
629      );
630
631   ($pool, $sector) = split /\./, $pool, 2 if $pool =~ m/\./;
632   exit_on_error_option($help)
633      if $pool       eq ''
634      or $sector  eq ''
635      or $mac        eq ''
636      or $comment    eq '';
637
638   my $computer_db = ipamdb_load($COMPUTER_YAML);
639   add_float($computer_db, $pool, $sector, $mac, $comment);
640   }
641
642#-------------------------------------------------------------------------------
643
644sub cmd_add_static {
645   local @ARGV = @_;
646
647   my $help = get_cmd_name();
648   my ($hostname, $sector, $ip, $mac, $comment);
649
650   GetOptions(
651      'hostname|h=s'    => \$hostname,
652      'sector|s|d=s'    => \$sector,
653      'ip|i=s'          => \$ip,
654      'mac|m=s'         => \$mac,
655      'comment|c=s'     => \$comment,
656      );
657
658   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
659   exit_on_error_option($help)
660      if $hostname   eq ''
661      or $sector  eq ''
662      or $ip         eq ''
663      or $mac        eq ''
664      or $comment    eq '';
665
666   my $computer_db = ipamdb_load($COMPUTER_YAML);
667   add_static($computer_db, $hostname, $sector, $ip, $mac, $comment);
668   }
669
670#-------------------------------------------------------------------------------
671# No real computer, just an entry A in DNS with virtual MAC
672
673sub cmd_add_virtual {
674   local @ARGV = @_;
675
676   my $help = get_cmd_name();
677   my ($hostname, $sector, $ip, $comment);
678
679   GetOptions(
680      'hostname|h=s'    => \$hostname,
681      'sector|s|d=s'    => \$sector,
682      'ip|i=s'          => \$ip,
683      'comment|c=s'     => \$comment,
684      );
685
686   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
687   exit_on_error_option($help)
688      if $hostname   eq ''
689      or $sector  eq ''
690      or $ip         eq ''
691      or $comment    eq '';
692
693   my $computer_db = ipamdb_load($COMPUTER_YAML);
694
695   $comment = normalize_comment($comment);
696   my $timestamp = time;
697
698   control_exist_sector($computer_db, $sector)              or exit;
699   control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n";
700   control_syntax_ip($ip)                                   or die "Error: bad IP syntax $ip\n";
701   control_exist_ip($computer_db, $ip)                      or die "Error: IP address already exist in sector $sector: $ip.\n";
702   control_ip_in_range($computer_db, $sector, $ip)          or die "Error: IP $ip is not in sector $sector IP range.\n";
703   control_syntax_comment($comment)                         or exit;
704
705   my $mac = join ':', 'FF', 'FF', map({sprintf("%02X", $_)} split(/\./, $ip));
706   control_syntax_mac_address($mac)             or exit;
707   control_exist_mac($computer_db, $mac)         or die "Error: virtual physical MAC address already exists: $mac\n";
708
709   push @{$computer_db->{$sector}}, { $mac => {
710      'hostname'     => $hostname,
711      'ip'           => $ip,
712      'address_type' => 'static',
713      'enabled'      => 'yes',
714      'create_time'  => $timestamp,
715      'modify_time'  => $timestamp,
716      'comment'      => $comment,
717      }};
718   print "Add the virtual computer: $hostname, IP: $ip, sector: $sector\n";
719
720   ipamdb_save("$COMPUTER_YAML", $computer_db);
721   }
722
723#-------------------------------------------------------------------------------
724# CHANGE computer section
725#-------------------------------------------------------------------------------
726
727#-------------------------------------------------------------------------------
728#Nom: change_mac
729#Description: change la mac adresse d'une machine en saisissant soit l'ip
730#             soit le nom de la mahcine et spécifiant le domaine
731#--- usage: ddt change-mac -s legi-sector03 -h meolpacif -m 00:18:F3:03:6F:66
732#--- usage: ddt change-mac -s legi-sector03 -i 194.254.66.187 -m 00:18:F3:03:6F:66
733
734sub change_mac {
735   my ($hostname, $sector, $ip, $mac) = @_;
736
737   my $computer_db = ipamdb_load($COMPUTER_YAML);
738
739   $mac = normalize_mac_address($mac);
740   control_exist_sector($computer_db, $sector)  or exit;
741   control_syntax_mac_address($mac)                   or exit;
742   control_exist_mac($computer_db, $mac)              or die "Error: physical MAC address already exists: $mac\n";
743   if ($ip ne '') {
744      control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";
745      if ( control_exist_ip($computer_db, $ip) == 1 ) {
746         print "Error: unkown IP address: $ip\n";
747         exit;
748         }
749      my @sectordb = @{$computer_db->{$sector}};
750      LOOP_ON_COMPUTER:
751      for my $computer (@sectordb) {
752         my ($mac_address, $attribute) = %{$computer};
753         die "Error: physical MAC address $mac already exists in sector $sector\n" if $mac_address eq $mac;
754
755         next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
756
757         $attribute->{'modify_time'} = time;
758         $computer->{$mac} = $attribute;     # add new mac
759         delete $computer->{$mac_address};   # remove old mac
760
761         ipamdb_save("$COMPUTER_YAML", $computer_db);
762         print "Info: update host $attribute->{'hostname'}, sector $sector, MAC $mac, IP $attribute->{'ip'} [OK]\n";
763         exit;
764         }
765      }
766   elsif ($hostname ne '') {
767      if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
768         die "Error: unkown host $hostname, sector $sector\n";
769         }
770      my @sectordb = @{$computer_db->{$sector}};
771      LOOP_ON_COMPUTER:
772      for my $computer (@sectordb) {
773         my ($mac_address, $attribute) = %{$computer};
774         die "Error: physical MAC address $mac already exists in sector $sector\n" if $mac_address eq $mac;
775
776         next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
777
778         $attribute->{'modify_time'} = time;
779         $computer->{$mac} = $attribute;     # add new mac
780         delete $computer->{$mac_address};   # remove old mac
781
782         ipamdb_save("$COMPUTER_YAML", $computer_db);
783         print "Info: update host $attribute->{'hostname'}, sector $sector, MAC $mac, IP $attribute->{'ip'} [OK]\n";
784         exit;
785         }
786      }
787   }
788
789#-------------------------------------------------------------------------------
790#Nom: change_ip
791#Description: change l'adresse IP d'une machine en saisissant le nom de la machine
792#             et le domaine
793
794sub change_ip {
795   my ($hostname, $sector, $ip) = @_;
796
797   my $computer_db = ipamdb_load($COMPUTER_YAML);
798
799   control_exist_sector($computer_db, $sector) or exit;
800   if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
801      die "Error: unkown host: $hostname, in sector: $sector\n";
802      }
803   control_syntax_ip($ip)                          or die "Error: bad IP syntax $ip\n";
804   control_exist_ip($computer_db, $ip)             or die "Error: IP $ip address already exist in sector $sector\n";
805   control_ip_in_range($computer_db, $sector, $ip) or die "Error: IP $ip is not in sector $sector IP range.\n";
806
807   my @sectordb = @{$computer_db->{$sector}};
808
809   LOOP_ON_COMPUTER:
810   for my $computer (@sectordb) {
811      my ($mac_address, $attribute) = %{$computer};
812     
813      next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
814 
815      if ($attribute->{'address_type'} eq 'pool-dhcp') {
816         die "Error: host $hostname from sector $sector belongs to a a pool [FAILED]" .
817            " ... use 'del-float' command before";
818         }
819
820      $attribute->{'modify_time'} = time;
821      $attribute->{'ip'}          = $ip;
822      ipamdb_save("$COMPUTER_YAML", $computer_db);
823      print "Info: update host $hostname MAC: $mac_address IP: $ip [OK]\n";
824      exit;
825      }
826   }
827
828#-------------------------------------------------------------------------------
829#Nom: change_host
830#Description: change le computer hostname en saisissant l'IP et le domaine
831
832sub change_host {
833   my ($hostname, $sector, $ip) = @_;
834
835   my $computer_db = ipamdb_load($COMPUTER_YAML);
836
837   control_exist_sector($computer_db, $sector) or exit;
838   control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";
839   if ( control_exist_ip($computer_db, $ip) == 1 ) {
840      die "Error: unkown IP address: $ip\n";
841      }
842   control_exist_hostname($computer_db, $sector, $hostname) or die "Error: host already exist in sector $sector: $hostname\n";
843
844   my @sectordb = @{$computer_db->{$sector}};
845
846   LOOP_ON_COMPUTER:
847   for my $computer (@sectordb) {
848      my ($mac_address, $attribute) = %{$computer};
849
850      next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
851
852      $attribute->{'modify_time'} = time;
853      $attribute->{'hostname'}    = $hostname;
854      ipamdb_save("$COMPUTER_YAML", $computer_db);
855      print "Info: update host $hostname MAC: $mac_address IP: $ip [OK]\n";
856      exit;
857      }
858
859   die "Error: failed to update hostname $hostname [FAILED]\n" .
860      " ... no IP $ip belongs to the sector $sector\n";
861   }
862
863#--------------------------------------------------------------------------------
864
865sub cmd_change_mac {
866   local @ARGV = @_;
867
868   my $help = get_cmd_name();
869   my ($hostname, $sector, $ip, $mac);
870
871   GetOptions(
872      'hostname|h=s'    => \$hostname,
873      'sector|s|d=s'    => \$sector,
874      'ip|i=s'          => \$ip,
875      'mac|m=s'         => \$mac,
876      );
877
878   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
879   exit_on_error_option($help)
880      if $sector  eq ''
881      or $mac        eq '';
882   exit_on_error_option($help)
883      if $hostname   ne ''
884      and $ip        ne '';
885
886   change_mac($hostname, $sector, $ip, $mac);
887   }
888
889#--------------------------------------------------------------------------------
890
891sub cmd_change_ip {
892   local @ARGV = @_;
893
894   my $help = get_cmd_name();
895   my ($hostname, $sector, $ip);
896
897   GetOptions(
898      'hostname|h=s'    => \$hostname,
899      'sector|s|d=s'    => \$sector,
900      'ip|i=s'          => \$ip,
901      );
902
903   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
904   exit_on_error_option($help)
905      if $hostname   eq ''
906      or $sector  eq ''
907      or $ip         eq '';
908
909   change_ip($hostname, $sector, $ip);
910   }
911
912#--------------------------------------------------------------------------------
913
914sub cmd_change_host {
915   local @ARGV = @_;
916
917   my $help = get_cmd_name();
918   my ($hostname, $sector, $ip);
919
920   GetOptions(
921      'hostname|h=s'    => \$hostname,
922      'sector|s|d=s'    => \$sector,
923      'ip|i=s'          => \$ip,
924      );
925
926   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
927   exit_on_error_option($help)
928      if $hostname   eq ''
929      or $sector  eq ''
930      or $ip         eq '';
931
932   change_host($hostname, $sector, $ip);
933   }
934
935#--------------------------------------------------------------------------------
936
937sub cmd_change_comment {
938   local @ARGV = @_;
939
940   my $help = get_cmd_name();
941   my ($sector, $mac, $comment);
942
943   GetOptions(
944      'sector|s|d=s'    => \$sector,
945      'mac|m=s'         => \$mac,
946      'comment|c=s'     => \$comment,
947      );
948
949   exit_on_error_option($help)
950      if $sector  eq ''
951      or $mac        eq ''
952      or $comment    eq '';
953
954   $mac     = normalize_mac_address($mac);
955   $comment = normalize_comment($comment);
956
957   my $computer_db = ipamdb_load($COMPUTER_YAML);
958
959   control_exist_sector($computer_db, $sector)  or exit;
960   control_syntax_mac_address($mac)                   or exit;
961   control_syntax_comment($comment)                   or exit;
962
963   my @sectordb = @{$computer_db->{$sector}};
964
965   LOOP_ON_COMPUTER:
966   for my $computer (@sectordb) {
967      my ($mac_address, $attribute) = %{$computer};
968
969      next LOOP_ON_COMPUTER if $mac_address ne $mac;
970
971      $attribute->{'modify_time'} = time;
972      $attribute->{'comment'}     = $comment;
973      ipamdb_save("$COMPUTER_YAML", $computer_db);
974      exit;
975      }
976   die "Error : Host $mac comment [FAILED]\n" .
977      " ... No MAC: $mac belongs to the domaine set $sector.\n";
978   }
979
980#--------------------------------------------------------------------------------
981
982sub cmd_change_sector {
983   local @ARGV = @_;
984
985   my $help = get_cmd_name();
986   my ($sector, $ip, $mac);
987
988   GetOptions(
989      'sector|s|d=s'    => \$sector,
990      'ip|i=s'          => \$ip,
991      'mac|m=s'         => \$mac,
992      );
993
994   exit_on_error_option($help)
995      if $sector  eq ''
996      or $ip         eq ''
997      or $mac        eq '';
998
999   $mac = normalize_mac_address($mac);
1000
1001   my $computer_db = ipamdb_load($COMPUTER_YAML);
1002
1003   control_exist_sector($computer_db, $sector)  or exit;
1004   control_syntax_ip($ip)                       or die "Error: bad IP syntax $ip\n";
1005   control_syntax_mac_address($mac)             or exit;
1006
1007   LOOP_ON_SECTOR:
1008   for my $sector_current (keys %{$computer_db}) {
1009      next if $sector_current eq 'dset';
1010      next if $sector_current eq 'pool';
1011      next if $sector_current eq 'pxe';
1012      next if $sector_current eq 'tag';
1013      next if $sector_current eq 'version';
1014
1015      my @sectordb = @{$computer_db->{$sector_current}};
1016      my $computer_index = 0;
1017      LOOP_ON_COMPUTER:
1018      for my $computer (@sectordb) {
1019         my ($mac_address, $attribute) = %{$computer};
1020
1021         $computer_index++, next LOOP_ON_COMPUTER if $mac_address ne $mac;
1022         next LOOP_ON_SECTOR if $attribute->{'ip'} ne $ip;
1023
1024         $attribute->{'modify_time'} = time;
1025         splice(@{$computer_db->{$sector_current}}, $computer_index => 1);
1026         push @{$computer_db->{$sector}}, { $mac => $attribute };
1027
1028         ipamdb_save("$COMPUTER_YAML", $computer_db);
1029         exit;
1030         }
1031      }
1032   die "Error: update of sector $sector [FAILED]\n" .
1033      " ... MAC $mac and IP $ip don't exists in the database\n";
1034   }
1035
1036#--------------------------------------------------------------------------------
1037
1038sub cmd_change_tag {
1039   local @ARGV = @_;
1040
1041   my $help = get_cmd_name();
1042   my ($hostname, $sector, $ip, $mac, $tags);
1043
1044   GetOptions(
1045      'hostname|h=s'    => \$hostname,
1046      'sector|s|d=s'    => \$sector,
1047      'ip|i=s'          => \$ip,
1048      'mac|m=s'         => \$mac,
1049      'tag|t=s'         => \$tags,
1050      );
1051
1052   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
1053
1054   exit_on_error_option($help)
1055      if $sector  eq ''
1056      or $tags       eq '';
1057   exit_on_error_option($help)
1058      if $mac        eq ''
1059      and $hostname  eq ''
1060      and $ip        eq '';
1061
1062   $mac = normalize_mac_address($mac);
1063
1064   my $computer_db = ipamdb_load($COMPUTER_YAML);
1065
1066   if ($tags !~ m/^ (?:\w+,)* \w+ $/xms) {
1067      die "Error: bad format for tags (comma separated list): $tags\n";
1068      }
1069
1070   for my $tag (split/,/, $tags) {
1071      next if $tag eq 'universal';
1072      die "Error: TAG doesn't exist in the database. Create it before with create_tag: $tag\n" if not exists $computer_db->{'tag'}{$tag};
1073      }
1074
1075   control_exist_sector($computer_db, $sector) or exit;
1076
1077   $mac = get_mac_from_ip($computer_db, $sector, $ip, $mac)             if $ip ne '';
1078   $mac = get_mac_from_hostname($computer_db, $sector, $hostname, $mac) if $hostname ne '';
1079   control_syntax_mac_address($mac) or exit;
1080
1081   LOOP_ON_COMPUTER:
1082   for my $computer (@{$computer_db->{$sector}}) {
1083      my ($mac_address, $attribute) = %{$computer};
1084
1085      next LOOP_ON_COMPUTER if $mac_address ne $mac;
1086
1087      $attribute->{'tag'}         = $tags;
1088      $attribute->{'modify_time'} = time;
1089
1090      delete $attribute->{'tag'} if $tags eq 'universal';
1091      ipamdb_save("$COMPUTER_YAML", $computer_db);
1092      exit;
1093      }
1094   print "Mise à jour du commentaire de la machine [FAILED]\n";
1095   print "L'adresse MAC: $mac n'existe pas dans le domaine: $sector.\n";
1096   }
1097
1098#-------------------------------------------------------------------------------
1099# ACTIVATION section
1100#-------------------------------------------------------------------------------
1101
1102#-------------------------------------------------------------------------------
1103#Nom: disable_pc
1104#Description: désactive une machine (du DHCP ou en IP statique, et du DNS) (champs enabled=non)
1105
1106sub disable_pc {
1107   my ($hostname, $sector, $ip) = @_;
1108
1109   my $computer_db = ipamdb_load($COMPUTER_YAML);
1110
1111   if ($ip ne '') { # disable by IP
1112      control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";;
1113      if ( control_exist_ip($computer_db, $ip) == 1 ) {
1114         die "Error: unkown IP address: $ip [FAILED]\n";
1115         }
1116
1117      for my $sector_current (keys %{$computer_db}) {
1118         next if $sector_current eq 'dset';
1119         next if $sector_current eq 'pool';
1120         next if $sector_current eq 'pxe';
1121         next if $sector_current eq 'tag';
1122         next if $sector_current eq 'version';
1123
1124         my @sectordb = @{$computer_db->{$sector_current}};
1125         LOOP_ON_COMPUTER:
1126         for my $computer (@sectordb) {
1127            my ($mac_address, $attribute) = %{$computer};
1128
1129            next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
1130
1131            if ($attribute->{'enabled'} eq 'no') {
1132               print "Info: IP $ip from sector $sector_current is already disable [OK]" .
1133                  " ... Status: $attribute->{'enabled'}\n";
1134               exit;
1135               }
1136
1137            my $timestamp = time;
1138            $attribute->{'modify_time'} = $timestamp;
1139            $attribute->{'enabled'}     = 'no';
1140            ipamdb_save("$COMPUTER_YAML", $computer_db);
1141            print "Info: disabling IP $ip from sector $sector_current [OK]" .
1142               " ... Status: $attribute->{'enabled'}\n";
1143            exit;
1144            }
1145         }
1146      }
1147   else { # disable by Hostname
1148      control_exist_sector($computer_db, $sector);
1149      if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
1150         die "Error: unkown host: $hostname, in sector: $sector [FAILED]\n";
1151         }
1152
1153      LOOP_ON_COMPUTER:
1154      for my  $computer (@{$computer_db->{$sector}}) {
1155         my ($mac_address, $attribute) = %{$computer};
1156
1157         next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
1158
1159         if ($attribute->{'address_type'} eq 'pool-dhcp') {
1160            die "Error: host $hostname from sector $sector belongs to a a pool [FAILED]" .
1161               " ... use 'disable-float' command instead";
1162            }
1163
1164         if ($attribute->{'enabled'} eq 'no') {
1165            print "Info: host $hostname from sector $sector is already disable [OK]" .
1166               " ... Status: $attribute->{'enabled'}\n";
1167            exit;
1168            }
1169
1170         my $timestamp = time;
1171         $attribute->{'modify_time'} = $timestamp;
1172         $attribute->{'enabled'}     = 'no';
1173         ipamdb_save("$COMPUTER_YAML", $computer_db);
1174         print "Info: disabling host $hostname from sector $sector [OK]" .
1175            " ... Status: $attribute->{'enabled'}\n";
1176         exit;
1177         }
1178      }
1179   }
1180
1181#-------------------------------------------------------------------------------
1182
1183sub disable_float {
1184   my ($pool, $mac) = @_;
1185
1186   my $computer_db = ipamdb_load($COMPUTER_YAML);
1187
1188   if ( control_exist_mac($computer_db, $mac) == 1 ) {
1189      die "Error: unkown physical MAC address: $mac [FAILED]\n";
1190      }
1191
1192   for my $sector_current (keys %{$computer_db}) {
1193      next if $sector_current eq 'dset';
1194      next if $sector_current eq 'pool';
1195      next if $sector_current eq 'pxe';
1196      next if $sector_current eq 'tag';
1197      next if $sector_current eq 'version';
1198
1199      my @sectordb = @{$computer_db->{$sector_current}};
1200
1201      LOOP_ON_COMPUTER:
1202      for my $computer (@sectordb) {
1203         my ($mac_address, $attribute) = %{$computer};
1204         next LOOP_ON_COMPUTER if $mac_address ne $mac;
1205
1206         if ($attribute->{'ip'} eq $pool) {
1207            if ($attribute->{'enabled'} eq 'no') {
1208               print "Info: host $mac from pool $pool is already disable [OK]" .
1209                  " ... Status: $attribute->{'enabled'}\n";
1210               exit;
1211               }
1212            my $timestamp = time;
1213            $attribute->{'modify_time'} = $timestamp;
1214            $attribute->{'enabled'}     = 'no';
1215            ipamdb_save("$COMPUTER_YAML", $computer_db);
1216            print "Info: disabling host $mac from pool $pool [OK]" .
1217               " ... Status: $attribute->{'enabled'}\n";
1218            exit;
1219            }
1220         else {
1221            die "Error: host disable $mac [FAILED]" .
1222               " ... The host $mac does not belong to the $pool pool.\n";
1223            }
1224         }
1225      }
1226   }
1227
1228#-------------------------------------------------------------------------------
1229#Nom: enable_pc
1230#Description: active une machine désactivée(du DHCP ou en IP statique, et du DNS) (champs enabled=non)
1231
1232sub enable_pc {
1233   my ($hostname, $sector, $ip) = @_;
1234
1235   my $computer_db = ipamdb_load($COMPUTER_YAML);
1236
1237   control_exist_sector($computer_db, $sector) or exit;
1238
1239   if ($ip ne '') { # enable by IP
1240      control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";;
1241      if ( control_exist_ip($computer_db, $ip) == 1 ) {
1242         print "Error: unkown IP address: $ip\n";
1243         exit;
1244         }
1245
1246      for my $sector_current (keys %{$computer_db}) {
1247         next if $sector_current eq 'dset';
1248         next if $sector_current eq 'pool';
1249         next if $sector_current eq 'pxe';
1250         next if $sector_current eq 'tag';
1251         next if $sector_current eq 'version';
1252
1253         my @sectordb = @{$computer_db->{$sector_current}};
1254
1255         LOOP_ON_COMPUTER:
1256         for my $computer (@sectordb) {
1257            my ($mac_address, $attribute) = %{$computer};
1258            if ($attribute->{'ip'} eq $ip) {
1259
1260               if ($attribute->{'enabled'} eq 'yes') {
1261                  print "Info: IP $ip belongs to sector $sector is already enable [OK]" .
1262                     " ... Status: $attribute->{'enabled'}\n";
1263                  exit;
1264                  }
1265
1266               my $timestamp = time;
1267               $attribute->{'modify_time'} = $timestamp;
1268               $attribute->{'enabled'}     = 'yes';
1269               ipamdb_save("$COMPUTER_YAML", $computer_db);
1270               print "Info: IP $ip is now enable [OK]" .
1271                  " ... Status: $attribute->{'enabled'}\n";
1272               exit;
1273               }
1274            }
1275         }
1276      }
1277   else { # enable by Hostname
1278      if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
1279         die "Error: unkown host: $hostname, in sector: $sector\n";
1280         }
1281
1282      LOOP_ON_COMPUTER:
1283      for my $computer (@{$computer_db->{$sector}}) {
1284         my ($mac_address, $attribute) = %{$computer};
1285         next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
1286
1287         if ($attribute->{'address_type'} eq 'pool-dhcp') {
1288            die "Error: host $hostname from sector $sector belongs to a a pool [FAILED]" .
1289               " ... use 'enable-float' command instead";
1290            }
1291
1292         if ($attribute->{'enabled'} eq 'yes') {
1293            print "Info: host $hostname belongs to sector $sector is already enable [OK]" .
1294               " ... Status: $attribute->{'enabled'}\n";
1295            exit;
1296            }
1297
1298         my $timestamp = time;
1299         $attribute->{'modify_time'} = $timestamp;
1300         $attribute->{'enabled'}     = 'yes';
1301         ipamdb_save("$COMPUTER_YAML", $computer_db);
1302         print "Info: host $hostname is now enable [OK]" .
1303            " ... Status: $attribute->{'enabled'}\n";
1304         exit;
1305         }
1306      }
1307   }
1308
1309#-------------------------------------------------------------------------------
1310
1311sub enable_float {
1312   my ($pool, $mac) = @_;
1313
1314   my $computer_db = ipamdb_load($COMPUTER_YAML);
1315
1316   if ( control_exist_mac($computer_db, $mac) == 1 ) {
1317      die "Error: unkown physical MAC address: $mac [FAILED]\n";
1318      }
1319
1320   for my $sector_current (keys %{$computer_db}) {
1321      next if $sector_current eq 'dset';
1322      next if $sector_current eq 'pool';
1323      next if $sector_current eq 'pxe';
1324      next if $sector_current eq 'tag';
1325      next if $sector_current eq 'version';
1326
1327      my @sectordb = @{$computer_db->{$sector_current}};
1328
1329      LOOP_ON_COMPUTER:
1330      for my $computer (@sectordb) {
1331         my ($mac_address, $attribute) = %{$computer};
1332         next LOOP_ON_COMPUTER if $mac_address ne $mac;
1333
1334         if ($attribute->{'ip'} ne $pool) {
1335            die "Error: host enable $mac [FAILED]" .
1336               " ... The host $mac does not belong to the $pool pool.\n";
1337            }
1338
1339         if ($attribute->{'enabled'} eq 'yes') {
1340            print "Info: host $mac from pool $pool is already enable [OK]" .
1341               " ... Status: $attribute->{'enabled'}\n";
1342            exit;
1343            }
1344
1345         my $timestamp = time;
1346         $attribute->{'modify_time'} = $timestamp;
1347         $attribute->{'enabled'}     = 'yes';
1348         ipamdb_save("$COMPUTER_YAML", $computer_db);
1349         print "Info: enabling host $mac from pool $pool [OK]" .
1350            " ... Status: $attribute->{'enabled'}\n";
1351         exit;
1352         }
1353      }
1354   }
1355
1356#-------------------------------------------------------------------------------
1357
1358sub cmd_enable_pc {
1359   local @ARGV = @_;
1360
1361   my $help = get_cmd_name();
1362   my ($hostname, $sector, $ip);
1363
1364   GetOptions(
1365      'hostname|h=s'    => \$hostname,
1366      'sector|s|d=s'    => \$sector,
1367      'ip|i=s'          => \$ip,
1368      );
1369
1370   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
1371   exit_on_error_option($help)
1372      if $sector  eq '';
1373   exit_on_error_option($help)
1374      if $hostname   eq ''
1375      and $ip        eq '';
1376   exit_on_error_option($help)
1377      if $hostname   ne ''
1378      and $ip        ne '';
1379
1380   enable_pc($hostname, $sector, $ip);
1381   }
1382
1383#-------------------------------------------------------------------------------
1384
1385sub cmd_disable_pc {
1386   local @ARGV = @_;
1387
1388   my $help = get_cmd_name();
1389   my ($hostname, $sector, $ip);
1390
1391   GetOptions(
1392      'hostname|h=s'    => \$hostname,
1393      'sector|s|d=s'    => \$sector,
1394      'ip|i=s'          => \$ip,
1395      );
1396
1397   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
1398   exit_on_error_option($help)
1399      if $sector  eq '';
1400   exit_on_error_option($help)
1401      if $hostname   eq ''
1402      and $ip        eq '';
1403   exit_on_error_option($help)
1404      if $hostname   ne ''
1405      and $ip        ne '';
1406
1407   disable_pc($hostname, $sector, $ip);
1408   }
1409
1410#-------------------------------------------------------------------------------
1411
1412sub cmd_disable_float {
1413   local @ARGV = @_;
1414
1415   my $help = get_cmd_name();
1416   my ($pool, $mac);
1417
1418   GetOptions(
1419      'pool|p=s'  => \$pool,
1420      'mac|m=s'   => \$mac,
1421      );
1422
1423   ($pool) = split /\./, $pool, 2 if $pool =~ m/\./;
1424   exit_on_error_option($help)
1425      if $pool eq ''
1426      or $mac  eq '';
1427
1428   disable_float($pool, $mac);
1429   }
1430
1431#-------------------------------------------------------------------------------
1432
1433sub cmd_enable_float {
1434   local @ARGV = @_;
1435
1436   my $help = get_cmd_name();
1437   my ($pool, $mac);
1438
1439   GetOptions(
1440      'pool|p=s'  => \$pool,
1441      'mac|m=s'   => \$mac,
1442      );
1443
1444   ($pool) = split /\./, $pool, 2 if $pool =~ m/\./;
1445   exit_on_error_option($help)
1446      if $pool eq ''
1447      or $mac  eq '';
1448
1449   enable_float($pool, $mac);
1450   }
1451
1452#-------------------------------------------------------------------------------
1453# DELETE section
1454#-------------------------------------------------------------------------------
1455
1456#-------------------------------------------------------------------------------
1457#Nom: del_pc
1458#Description: supprime une machine en DHCP ou en IP statique.
1459
1460sub del_pc {
1461   my ($hostname, $sector, $ip) = @_;
1462
1463   my $computer_db = ipamdb_load($COMPUTER_YAML);
1464
1465   control_exist_sector($computer_db, $sector) or exit;
1466   if ($ip ne '') { # delete by IP
1467      if ( control_exist_ip($computer_db, $ip) == 1 ) {
1468         die "Error: unkown IP address: $ip\n";
1469         }
1470
1471      my $computer_index = 0;
1472
1473      LOOP_ON_COMPUTER:
1474      for my $computer (@{$computer_db->{$sector}}) {
1475         my ($mac_address, $attribute) = %{$computer};
1476
1477         $computer_index++, next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
1478         
1479         splice(@{$computer_db->{$sector}}, $computer_index => 1);
1480         ipamdb_save("$COMPUTER_YAML", $computer_db);
1481         print "Info: host $ip has been removed from the sector $sector [OK]\n";
1482         exit;
1483         }
1484      }
1485   else {
1486      if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
1487         die "Error: unkown host: $hostname, in sector: $sector\n";
1488         }
1489
1490      my $computer_index = 0;
1491
1492      LOOP_ON_COMPUTER:
1493      for my $computer (@{$computer_db->{$sector}}) {
1494         my ($mac_address, $attribute) = %{$computer};
1495
1496         $computer_index++, next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
1497
1498         if ($attribute->{'address_type'} eq 'pool-dhcp') {
1499            die "Error: host remove $hostname from the sector $sector [FAILED]" .
1500               " ... The host $hostname belongs to a DHCP pool.\n";
1501            }
1502
1503         splice(@{$computer_db->{$sector}}, $computer_index => 1);
1504         ipamdb_save("$COMPUTER_YAML", $computer_db);
1505         print "Info: host $hostname has been removed from the sector $sector [OK]\n";
1506         exit;
1507         }
1508      }
1509   }
1510
1511#-------------------------------------------------------------------------------
1512#Nom: del_float
1513#Description: supprime une machine d'un pool DHCP
1514
1515sub del_float {
1516   my ($pool, $mac) = @_;
1517
1518   my $computer_db = ipamdb_load($COMPUTER_YAML);
1519
1520   if ( control_exist_mac($computer_db, $mac) == 1 ) {
1521      print "Adresse MAC $mac non trouvée.\n";
1522      exit;
1523      }
1524
1525   for my $sector_current (keys %{$computer_db}) {
1526      next if $sector_current eq 'dset';
1527      next if $sector_current eq 'pool';
1528      next if $sector_current eq 'pxe';
1529      next if $sector_current eq 'tag';
1530      next if $sector_current eq 'version';
1531
1532      my @sectordb = @{$computer_db->{$sector_current}};
1533
1534      my $computer_index = 0;
1535
1536      LOOP_ON_COMPUTER:
1537      for my $computer (@sectordb) {
1538         my ($mac_address, $attribute) = %{$computer};
1539
1540         $computer_index++, next LOOP_ON_COMPUTER if $mac_address ne $mac;
1541
1542         if ($attribute->{'ip'} ne $pool) {
1543            die "Error: host remove $mac [FAILED]" .
1544               " ... The host $mac does not belong to the $pool pool.\n";
1545            }
1546
1547         splice(@{$computer_db->{$sector_current}}, $computer_index => 1);
1548         ipamdb_save("$COMPUTER_YAML", $computer_db);
1549         print "Info: remove host $mac from the pool $pool [OK]\n";
1550         exit;
1551         }
1552      }
1553   }
1554
1555#-------------------------------------------------------------------------------
1556
1557sub cmd_del_pc {
1558   local @ARGV = @_;
1559
1560   my $help = get_cmd_name();
1561   my ($hostname, $sector, $ip);
1562
1563   GetOptions(
1564      'hostname|h=s'    => \$hostname,
1565      'sector|s|d=s'    => \$sector,
1566      'ip|i=s'          => \$ip,
1567      );
1568
1569   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
1570   exit_on_error_option($help)
1571      if $sector  eq '';
1572   exit_on_error_option($help)
1573      if $hostname   eq ''
1574      and $ip        eq '';
1575   exit_on_error_option($help)
1576      if $hostname   ne ''
1577      and $ip        ne '';
1578
1579   del_pc($hostname, $sector, $ip);
1580   }
1581
1582#-------------------------------------------------------------------------------
1583
1584sub cmd_del_float {
1585   local @ARGV = @_;
1586
1587   my $help = get_cmd_name();
1588   my ($pool, $mac);
1589
1590   GetOptions(
1591      'pool|p=s'        => \$pool,
1592      'mac|m=s'         => \$mac,
1593      );
1594
1595   ($pool) = split /\./, $pool, 2 if $pool =~ m/\./;
1596   exit_on_error_option($help)
1597      if $pool eq ''
1598      or $mac  eq '';
1599
1600   del_float($pool, $mac);
1601   }
1602
1603#-------------------------------------------------------------------------------
1604# SECTOR section
1605#-------------------------------------------------------------------------------
1606
1607sub cmd_create_sector {
1608   local @ARGV = @_;
1609
1610   my $help = get_cmd_name();
1611   my ($sector, $dns_extension, $comment);
1612
1613   GetOptions(
1614      'sector|s|d=s'       => \$sector,
1615      'dns-extension|e=s'  => \$dns_extension,
1616      'comment|c=s'        => \$comment,
1617      );
1618
1619   exit_on_error_option($help)
1620      if $sector        eq ''
1621      or $dns_extension eq ''
1622      or $comment       eq '';
1623
1624   $sector =~ m{^[\w\d]}            or die "Error: sector $sector must begin by a letter or a digit\n";
1625   $sector =~ m{^[\w\d][\w\d-_]*$}  or die "Error: sector $sector must only use letter digit dash and underscore character\n";
1626
1627   $comment = normalize_comment($comment);
1628
1629   my $computer_db = ipamdb_load($COMPUTER_YAML);
1630
1631   $computer_db->{'dset'} ||= {};
1632   die "Error: sector already exists: $sector\n" if exists $computer_db->{'dset'}{$sector};
1633
1634   control_syntax_comment($comment)    or exit;
1635
1636   my $timestamp = time;
1637   $computer_db->{'dset'}{$sector} = {
1638      'dns_extension'   => $dns_extension,
1639      'comment'         => $comment,
1640      'create_time'     => $timestamp,
1641      'modify_time'     => $timestamp,
1642      };
1643   $computer_db->{$sector} ||= []; # Create empty sector computer list by default
1644   ipamdb_save("$COMPUTER_YAML", $computer_db);
1645   }
1646
1647#-------------------------------------------------------------------------------
1648
1649sub cmd_sector_add_ip {
1650   local @ARGV = @_;
1651
1652   my $help = get_cmd_name();
1653   my ($sector, $ip_range);
1654
1655   GetOptions(
1656      'sector|s|d=s' => \$sector,
1657      'ip-range|i=s' => \$ip_range,
1658      );
1659
1660   exit_on_error_option($help)
1661      if $sector     eq ''
1662      or $ip_range   eq '';
1663
1664   control_syntax_cidr($ip_range)   or die "Error: bad IP range $ip_range syntax (CIDR)\n";;
1665
1666   my $computer_db = ipamdb_load($COMPUTER_YAML);
1667   exists $computer_db->{'dset'}{$sector} or die "Error: sector not exists: $sector\n";
1668
1669   my $timestamp = time;
1670   $computer_db->{'dset'}{$sector}{'ip-range'} ||= [];
1671   LOOP_ON_CIDR:
1672   for my $cidr_current (@{$computer_db->{'dset'}{$sector}{'ip-range'}}) {
1673      next LOOP_ON_CIDR if $cidr_current ne $ip_range;
1674     
1675      die "Error: IP range $ip_range already in sector $sector\n";
1676      }
1677
1678   my $timestamp = time;
1679   push @{$computer_db->{'dset'}{$sector}{'ip-range'}}, $ip_range;
1680   $computer_db->{'dset'}{$sector}{'modify_time'} = $timestamp;
1681   ipamdb_save("$COMPUTER_YAML", $computer_db);
1682   }
1683
1684#-------------------------------------------------------------------------------
1685# POOL section
1686#-------------------------------------------------------------------------------
1687
1688#-------------------------------------------------------------------------------
1689#Nom: create_pool
1690#Description: crée un pool dans le fichier de données YAML et dans le DHCP.
1691#
1692#Commentaires: il y a un petit bug si jamais on rentre que des adresses ip qui existent déjà.
1693#              Le pool est créé mais sans adresses ip.
1694
1695sub cmd_create_pool {
1696   local @ARGV = @_;
1697
1698   my $help = get_cmd_name();
1699   my ($pool, $sector, $file_pool, $ipaddress_pool);
1700
1701   GetOptions(
1702      'pool|p=s'           => \$pool,
1703      'sector|s|d=s'      => \$sector,
1704      'file-pool|f=s'      => \$file_pool,
1705      'ipaddress-pool|i=s' => \$ipaddress_pool,
1706      );
1707
1708   exit_on_error_option($help)
1709      if $pool             eq ''
1710      or $sector        eq ''
1711      or $file_pool        eq ''
1712      or $ipaddress_pool   eq '';
1713
1714   my $computer_db = ipamdb_load($COMPUTER_YAML);
1715
1716   if ($computer_db->{'pool'}) {
1717      die "Error: pool already exists: $pool\n" if exists $computer_db->{'pool'}{$pool};
1718      }
1719
1720   #--- control if the domain's pool exist ---#
1721   control_exist_sector($computer_db, $sector) or exit;
1722
1723   my @ip_list = ();
1724   #---control if address exist ---#
1725   if ($ipaddress_pool =~ /,/) {
1726      LOOP_ON_IP:
1727      for my $ip (split /,/, $ipaddress_pool) {
1728         if ($ip =~ /-/) {
1729            my ($ip1, $ip2, $ip3, $range) = split /\./, $ip;
1730            my ($first, $last) = split /-/, $range;
1731            for (my $cpt = $first; $cpt <= $last; $cpt++) {
1732               my $ip_loc = "$ip1.$ip2.$ip3.$cpt";
1733               control_syntax_ip($ip_loc) or die "Error: bad IP syntax: $ip_loc\n";
1734               control_exist_ip($computer_db, $ip_loc) or die "Error: IP address already exists: $ip_loc\n";
1735               push @ip_list, $ip_loc;
1736               }
1737            }
1738         else {
1739            control_syntax_ip($ip) or next LOOP_ON_IP;
1740            if ( control_exist_ip($computer_db, $ip) == 0 ) {
1741               print "L'adresse IP $ip existe déjà\n";
1742               next;
1743               }
1744            push @ip_list, $ip;
1745            }
1746         }
1747      }
1748
1749   my $timestamp = time;
1750   $computer_db->{'pool'}{$pool} = {
1751      'ip'          => [@ip_list],
1752      'enabled'     => 'yes',
1753      'create_time' => $timestamp,
1754      'modify_time' => $timestamp,
1755      'file'        => $file_pool,
1756      'domain'      => $sector,
1757      };
1758   ipamdb_save("$COMPUTER_YAML", $computer_db);
1759   }
1760
1761#-------------------------------------------------------------------------------
1762
1763sub cmd_show_pool {
1764   local @ARGV = @_;
1765
1766   my ($no_header);
1767
1768   GetOptions(
1769      'no-header|H' => \$no_header,
1770      );
1771
1772   my $computer_db = ipamdb_load($COMPUTER_YAML);
1773
1774   printf "%-17s %-17s %s\n", 'Pool', 'File', 'DNS-Domain' if not $no_header;
1775   LOOP_ON_PXE:
1776   for my $pool ( keys %{$computer_db->{'pool'}} ) {
1777
1778      printf "%-17s %-17s %s\n",
1779         $pool,
1780         $computer_db->{'pool'}{$pool}{'file'},
1781         $computer_db->{'pool'}{$pool}{'domain'},
1782      }
1783   }
1784
1785#-------------------------------------------------------------------------------
1786# PXE section
1787#-------------------------------------------------------------------------------
1788
1789sub cmd_create_pxe {
1790   local @ARGV = @_;
1791
1792   my $help = get_cmd_name();
1793   my ($pxe_config, $ip_next_server, $filename, $comment);
1794
1795   GetOptions(
1796      'bootp|b=s'       => \$pxe_config,
1797      'next-server|n=s' => \$ip_next_server,
1798      'filename|f=s'    => \$filename,
1799      'comment|c=s'     => \$comment,
1800      );
1801
1802   exit_on_error_option($help)
1803      if $pxe_config       eq ''
1804      or $ip_next_server   eq ''
1805      or $filename         eq ''
1806      or $comment          eq '';
1807
1808   my $computer_db = ipamdb_load($COMPUTER_YAML);
1809
1810   $comment = normalize_comment($comment);
1811
1812   $computer_db->{'pxe'} ||= {};
1813   die "Error: PXE config already exists: $pxe_config\n" if exists $computer_db->{'pxe'}{$pxe_config};
1814
1815   control_syntax_ip($ip_next_server)  or die "Error: bad IP syntax: $ip_next_server\n";
1816   control_syntax_comment($comment)    or exit;
1817
1818   my $timestamp = time;
1819   $computer_db->{'pxe'}{$pxe_config} = {
1820      'ip_next_server'  => $ip_next_server,
1821      'filename'        => $filename,
1822      'comment'         => $comment,
1823      'create_time'     => $timestamp,
1824      'modify_time'     => $timestamp,
1825      };
1826   ipamdb_save("$COMPUTER_YAML", $computer_db);
1827   }
1828
1829#-------------------------------------------------------------------------------
1830
1831sub cmd_remove_pxe {
1832   local @ARGV = @_;
1833
1834   my $help = get_cmd_name();
1835   my ($pxe_config);
1836
1837   GetOptions(
1838      'bootp|b=s' => \$pxe_config,
1839      );
1840
1841   exit_on_error_option($help)
1842      if $pxe_config eq '';
1843
1844   my $computer_db = ipamdb_load($COMPUTER_YAML);
1845
1846   $computer_db->{'pxe'} ||= {};
1847   die "Error: PXE config does not exist: $pxe_config\n" if not exists $computer_db->{'pxe'}{$pxe_config};
1848
1849   # Test if some computer use this config
1850   LOOP_ON_SECTOR:
1851   for my $sector_current (keys %{$computer_db}) {
1852      next if $sector_current eq 'dset';
1853      next if $sector_current eq 'pool';
1854      next if $sector_current eq 'pxe';
1855      next if $sector_current eq 'tag';
1856      next if $sector_current eq 'version';
1857
1858      LOOP_ON_COMPUTER:
1859      for my $computer (@{$computer_db->{$sector_current}}) {
1860         my ($mac_address, $attribute) = %{$computer};
1861
1862         if (exists $attribute->{'pxe_config'}) {
1863            my $hostname = $attribute->{'hostname'};
1864            die "Error: computer still use this PXE config: $hostname.$sector_current $mac_address\n" if $pxe_config eq $attribute->{'pxe_config'};
1865            }
1866         }
1867      }
1868
1869   delete $computer_db->{'pxe'}{$pxe_config};
1870   ipamdb_save("$COMPUTER_YAML", $computer_db);
1871   }
1872
1873#--------------------------------------------------------------------------------
1874
1875sub cmd_show_pxe {
1876   local @ARGV = @_;
1877
1878   my ($no_header);
1879
1880   GetOptions(
1881      'no-header|H' => \$no_header,
1882      );
1883
1884   my $computer_db = ipamdb_load($COMPUTER_YAML);
1885
1886   printf "%-12s %-13s %-30s %s\n", 'PXE-Config', 'Next-Server', 'Filename', 'Comment' if not $no_header;
1887   LOOP_ON_PXE:
1888   for my $pxe_config ( keys %{$computer_db->{'pxe'}} ) {
1889      my $ip_next_server = $computer_db->{'pxe'}{$pxe_config}{'ip_next_server'};
1890      my $filename       = $computer_db->{'pxe'}{$pxe_config}{'filename'};
1891      my $comment        = $computer_db->{'pxe'}{$pxe_config}{'comment'};
1892
1893      printf "%-12s %-13s %-30s %s\n", $pxe_config, $ip_next_server, $filename, $comment;
1894      }
1895   }
1896
1897#-------------------------------------------------------------------------------
1898
1899sub cmd_enable_pxe {
1900   local @ARGV = @_;
1901
1902   my $help = get_cmd_name();
1903   my ($hostname, $sector, $ip, $pxe_config);
1904
1905   GetOptions(
1906      'hostname|h=s'    => \$hostname,
1907      'sector|s|d=s'    => \$sector,
1908      'ip|i=s'          => \$ip,
1909      'bootp|b=s'       => \$pxe_config,
1910      );
1911
1912   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
1913   exit_on_error_option($help)
1914      if $sector  eq ''
1915      or $pxe_config eq '';
1916   exit_on_error_option($help)
1917      if $hostname   eq ''
1918      and $ip        eq '';
1919   exit_on_error_option($help)
1920      if $hostname   ne ''
1921      and $ip        ne '';
1922
1923   my $computer_db = ipamdb_load($COMPUTER_YAML);
1924
1925   die "Error: PXE config not exists: $pxe_config\n" if not exists $computer_db->{'pxe'}{$pxe_config};
1926
1927   control_exist_sector($computer_db, $sector) or exit;
1928   if ($ip ne '') {
1929      control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";;
1930      if ( control_exist_ip($computer_db, $ip) == 1 ) {
1931         die "Error: unkown IP address: $ip\n";
1932         }
1933
1934      for my $sector_current (keys %{$computer_db}) {
1935         next if $sector_current eq 'dset';
1936         next if $sector_current eq 'pool';
1937         next if $sector_current eq 'pxe';
1938         next if $sector_current eq 'tag';
1939         next if $sector_current eq 'version';
1940
1941         LOOP_ON_COMPUTER:
1942         for my $computer (@{$computer_db->{$sector_current}}) {
1943            my ($mac_address, $attribute) = %{$computer};
1944            next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
1945
1946            $attribute->{'modify_time'} = time;
1947            $attribute->{'pxe_config'}  = $pxe_config;
1948            ipamdb_save("$COMPUTER_YAML", $computer_db);
1949            print "Info: host $attribute->{'hostname'} ($sector_current), IP $ip, PXE enabled: $pxe_config\n";
1950            exit;
1951            }
1952         }
1953      }
1954   else {
1955      if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
1956         die "Error: unkown host: $hostname, in sector: $sector\n";
1957         }
1958
1959      LOOP_ON_COMPUTER:
1960      for my $computer (@{$computer_db->{$sector}}) {
1961         my ($mac_address, $attribute) = %{$computer};
1962         next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
1963         
1964         if ($attribute->{'address_type'} eq 'pool-dhcp') {
1965            die "Error. Host $hostname ($sector) in a pool. No PXE possible [FAILED]\n";
1966            }
1967
1968         $attribute->{'modify_time'} = time;
1969         $attribute->{'pxe_config'}  = $pxe_config;
1970         ipamdb_save("$COMPUTER_YAML", $computer_db);
1971         print "Info: host $hostname ($sector), IP $attribute->{'ip'}, PXE enabled: $pxe_config [OK]\n";
1972         exit;
1973         }
1974      }
1975   }
1976
1977#-------------------------------------------------------------------------------
1978
1979sub cmd_disable_pxe {
1980   local @ARGV = @_;
1981
1982   my $help = get_cmd_name();
1983   my ($hostname, $sector, $ip);
1984
1985   GetOptions(
1986      'hostname|h=s'    => \$hostname,
1987      'sector|s|d=s'    => \$sector,
1988      'ip|i=s'          => \$ip,
1989      );
1990
1991   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
1992   exit_on_error_option($help)
1993      if $sector  eq '';
1994   exit_on_error_option($help)
1995      if $hostname   eq ''
1996      and $ip        eq '';
1997   exit_on_error_option($help)
1998      if $hostname   ne ''
1999      and $ip        ne '';
2000
2001   my $computer_db = ipamdb_load($COMPUTER_YAML);
2002
2003   control_exist_sector($computer_db, $sector) or exit;
2004   if ($ip ne '') {
2005      control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";;
2006      if ( control_exist_ip($computer_db, $ip) == 1 ) {
2007         die "Error: unkown IP address: $ip\n";
2008         }
2009
2010      for my $sector_current (keys %{$computer_db}) {
2011         next if $sector_current eq 'dset';
2012         next if $sector_current eq 'pool';
2013         next if $sector_current eq 'pxe';
2014         next if $sector_current eq 'tag';
2015         next if $sector_current eq 'version';
2016
2017         LOOP_ON_COMPUTER:
2018         for my $computer (@{$computer_db->{$sector_current}}) {
2019            my ($mac_address, $attribute) = %{$computer};
2020           
2021            next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
2022            next LOOP_ON_COMPUTER if not exists $attribute->{'pxe_config'};
2023
2024            my $pxe_config = $attribute->{'pxe_config'};
2025            $attribute->{'modify_time'} = time;
2026            delete $attribute->{'pxe_config'};
2027            ipamdb_save("$COMPUTER_YAML", $computer_db);
2028            print "Info: IP address: $ip, PXE disable from config: $pxe_config [OK]\n";
2029            exit;
2030            }
2031         }
2032      }
2033   else {
2034      if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
2035         die "Error: unkown host: $hostname, in sector: $sector\n";
2036         }
2037
2038      LOOP_ON_COMPUTER:
2039      for my $computer (@{$computer_db->{$sector}}) {
2040         my ($mac_address, $attribute) = %{$computer};
2041
2042         next LOOP_ON_COMPUTER if $attribute->{'hostname'} eq $hostname;
2043
2044         if ($attribute->{'address_type'} eq 'pool-dhcp') {
2045            die "Error: host $hostname ($sector) in a pool. No PXE possible [FAILED]\n";
2046            }
2047
2048         next LOOP_ON_COMPUTER if not exists $attribute->{'pxe_config'};
2049
2050         my $pxe_config = $attribute->{'pxe_config'};
2051         $attribute->{'modify_time'} = time;
2052         delete $attribute->{'pxe_config'};
2053         ipamdb_save("$COMPUTER_YAML", $computer_db);
2054         print "Info: host $hostname ($sector), PXE disable from config: $pxe_config [OK]\n";
2055         exit;
2056         }
2057      }
2058   }
2059
2060#-------------------------------------------------------------------------------
2061# TAG section
2062#-------------------------------------------------------------------------------
2063
2064sub cmd_create_tag {
2065   local @ARGV = @_;
2066
2067   my $help = get_cmd_name();
2068   my ($tag, $comment);
2069
2070   GetOptions(
2071      'tag|t=s'      => \$tag,
2072      'comment|c=s'  => \$comment,
2073      );
2074
2075   exit_on_error_option($help)
2076      if $tag     eq ''
2077      or $comment eq '';
2078
2079   my $computer_db = ipamdb_load($COMPUTER_YAML);
2080
2081   $comment = normalize_comment($comment);
2082
2083   $computer_db->{'tag'} ||= {};
2084   die "Error: TAG already exists: $tag\n" if exists $computer_db->{'tag'}{$tag};
2085
2086   die "Error: TAG 'universal' is intrinsic. It's not possible to create it.\n" if $tag eq 'universal';
2087
2088   if ($tag !~ m/^ \w+ $/xms) {
2089      die "Error: bad format for TAG (alphanumeric string): $tag\n";
2090      }
2091
2092   control_syntax_comment($comment) or exit;
2093
2094   my $timestamp = time;
2095   $computer_db->{'tag'}{$tag} = {
2096      'comment'         => $comment,
2097      'create_time'     => $timestamp,
2098      'modify_time'     => $timestamp,
2099      };
2100   ipamdb_save("$COMPUTER_YAML", $computer_db);
2101   }
2102
2103#-------------------------------------------------------------------------------
2104
2105sub cmd_remove_tag {
2106   local @ARGV = @_;
2107
2108   my $help = get_cmd_name();
2109   my ($tag);
2110
2111   GetOptions(
2112      'tag|t=s' => \$tag,
2113      );
2114
2115   exit_on_error_option($help)
2116      if $tag eq '';
2117
2118   my $computer_db = ipamdb_load($COMPUTER_YAML);
2119
2120   $computer_db->{'tag'} ||= {};
2121   die "Error: TAG does not exist: $tag\n" if not exists $computer_db->{'tag'}{$tag};
2122
2123   # Test if some computer use this config
2124   LOOP_ON_SECTOR:
2125   for my $sector_current (keys %{$computer_db}) {
2126      next if $sector_current eq 'dset';
2127      next if $sector_current eq 'pool';
2128      next if $sector_current eq 'pxe';
2129      next if $sector_current eq 'tag';
2130      next if $sector_current eq 'version';
2131
2132      LOOP_ON_COMPUTER:
2133      for my $computer (@{$computer_db->{$sector_current}}) {
2134         my ($mac_address, $attribute) = %{$computer};
2135
2136         if (exists $attribute->{'tag'}) {
2137            my $hostname = $attribute->{'hostname'};
2138            die "Error: computer still use this TAG: $hostname.$sector_current $mac_address\n" if $tag eq $attribute->{'tag'};
2139            }
2140         }
2141      }
2142
2143   delete $computer_db->{'tag'}{$tag};
2144   ipamdb_save("$COMPUTER_YAML", $computer_db);
2145   }
2146
2147#--------------------------------------------------------------------------------
2148
2149sub cmd_show_tag {
2150   local @ARGV = @_;
2151
2152   my ($no_header);
2153
2154   GetOptions(
2155      'no-header|H' => \$no_header,
2156      );
2157
2158   my $computer_db = ipamdb_load($COMPUTER_YAML);
2159
2160   printf "%-12s %s\n", 'TAG', 'Comment' if not $no_header;
2161   LOOP_ON_TAG:
2162   for my $tag ( keys %{$computer_db->{'tag'}} ) {
2163      my $comment = $computer_db->{'tag'}{$tag}{'comment'};
2164
2165      printf "%-12s %s\n", $tag, $comment;
2166      }
2167   }
2168
2169#--------------------------------------------------------------------------------
2170# GLOBAL section
2171#--------------------------------------------------------------------------------
2172
2173sub cmd_upgrade_db {
2174   my $flag_change;
2175
2176   my $computer_db = ipamdb_load($COMPUTER_YAML);
2177
2178   LOOP_ON_SECTOR:
2179   for my $sector_current (keys %{$computer_db}) {
2180      next if $sector_current eq 'dset';
2181      next if $sector_current eq 'pool';
2182      next if $sector_current eq 'pxe';
2183      next if $sector_current eq 'tag';
2184      next if $sector_current eq 'version';
2185
2186      my @sectordb = @{$computer_db->{$sector_current}};
2187
2188      LOOP_ON_COMPUTER:
2189      for my $computer (@sectordb) {
2190         my ($mac_address, $attribute) = %{$computer};
2191         my $new_mac = normalize_mac_address($mac_address);
2192         print "perl -pi -e 's/$mac_address:/$new_mac:/' $COMPUTER_YAML\n" if "$mac_address" ne "$new_mac";
2193
2194         my $comment = $attribute->{'comment'};
2195         $comment =~ s/\s\s+/ /g and $flag_change++;
2196         $comment =~ s/^\s+\S//  and $flag_change++;
2197         $comment =~ s/\S\s+$//  and $flag_change++;
2198         $comment =~ s{^(\d\d\d\d)\/O(\d\/\d\d)}{$1/0$2} and $flag_change++;
2199         $comment =~ s{^(\d\d\d\d\/\d\d\/)O(\d)}{$1/0$2} and $flag_change++;
2200         $comment =~ s{^(\d\d\d\d)\/(\d\d)\/(\d\d)}{$1-$2-$3} and $flag_change++;
2201         if ($comment !~ m/^\d\d\d\d-\d\d-\d\d/) {
2202            print "# no date at beginning of comment $mac_address\n";
2203            }
2204
2205         $attribute->{'comment'} = $comment;
2206         }
2207      }
2208   print "# FLAG :$flag_change\n";
2209
2210   ipamdb_save("$COMPUTER_YAML", $computer_db) if $flag_change;
2211   }
2212
2213#--------------------------------------------------------------------------------
2214
2215sub cmd_show_sector {
2216   local @ARGV = @_;
2217
2218   my ($no_header);
2219
2220   GetOptions(
2221      'no-header|H' => \$no_header,
2222      );
2223
2224   my $computer_db = ipamdb_load($COMPUTER_YAML);
2225
2226   my $tb_computer = Text::Table->new(
2227     {align  => 'left',   align_title => 'left',   title => 'Sector'},
2228     {is_sep => 1,        body        => '  '},
2229     {align  => 'left',   align_title => 'left',   title => 'DNS-Extension'},
2230     {is_sep => 1,        body        => '  '},
2231     {align  => 'left',   align_title => 'left',   title => 'IP-Range'},
2232     {align  => 'left',   align_title => 'left',   title => 'Date'},
2233     {align  => 'left',   align_title => 'left',   title => 'Comment'},
2234     {align  => 'left',   align_title => 'left',   title => 'Category'},
2235     );
2236
2237   LOOP_ON_SECTOR:
2238   for my $sector_current (sort keys %{$computer_db}) {
2239      next if $sector_current eq 'dset';
2240      next if $sector_current eq 'pool';
2241      next if $sector_current eq 'pxe';
2242      next if $sector_current eq 'tag';
2243      next if $sector_current eq 'version';
2244
2245      $tb_computer->add($sector_current), next LOOP_ON_SECTOR if not exists $computer_db->{'dset'}{$sector_current};
2246
2247      my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $computer_db->{'dset'}{$sector_current}{'modify_time'};
2248      $year += 1900;
2249      $mon++;
2250      my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2251
2252      my $ip_range;
2253      $ip_range = join ',', @{$computer_db->{'dset'}{$sector_current}{'ip-range'}} if exists $computer_db->{'dset'}{$sector_current}{'ip-range'};
2254
2255      my $category;
2256      my $comment = $computer_db->{'dset'}{$sector_current}{'comment'};
2257      $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2258      $comment =~ s/\s+(\(\w+\))$// and $category = $1;
2259
2260      $tb_computer->add($sector_current,
2261         $computer_db->{'dset'}{$sector_current}{'dns_extension'},
2262         $ip_range,
2263         $date,
2264         $comment,
2265         $category,
2266         );
2267      }
2268
2269   print $tb_computer->title(),
2270         $tb_computer->rule('-') if not $no_header;
2271   print $tb_computer->body();
2272   }
2273
2274#--------------------------------------------------------------------------------
2275
2276sub cmd_search_mac {
2277   local @ARGV = @_;
2278
2279   my $help = get_cmd_name();
2280   my ($mac);
2281
2282   GetOptions(
2283      'mac|m=s' => \$mac,
2284      );
2285
2286   exit_on_error_option($help)
2287      if $mac eq '';
2288
2289   $mac = normalize_mac_address($mac);
2290
2291   my $computer_db = ipamdb_load($COMPUTER_YAML);
2292
2293   control_syntax_mac_address($mac) or exit;
2294
2295   LOOP_ON_SECTOR:
2296   for my $sector_current (keys %{$computer_db}) {
2297      next if $sector_current eq 'dset';
2298      next if $sector_current eq 'pool';
2299      next if $sector_current eq 'pxe';
2300      next if $sector_current eq 'tag';
2301      next if $sector_current eq 'version';
2302
2303      my @sectordb = @{$computer_db->{$sector_current}};
2304
2305      LOOP_ON_COMPUTER:
2306      for my $computer (@sectordb) {
2307         my ($mac_address, $attribute) = %{$computer};
2308
2309         next LOOP_ON_COMPUTER if $mac_address ne $mac;
2310
2311         my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $attribute->{'modify_time'};
2312         $year += 1900;
2313         $mon++;
2314         my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2315
2316         my $comment = $attribute->{'comment'};
2317         $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2318
2319         my $enable = $attribute->{'enabled'};
2320         if (exists $attribute->{'pxe_config'}) {
2321            $enable .= '/' . $attribute->{'pxe_config'};
2322            }
2323         if (exists $attribute->{'tag'}) {
2324            $enable .= ':' . $attribute->{'tag'};
2325            }
2326
2327         printf "%-30s  %-20s %17s %9s %3s %10s %s\n",
2328            $attribute->{'hostname'} . '.' . $sector_current,
2329            $attribute->{'ip'},
2330            $mac_address,
2331            $attribute->{'address_type'},
2332            $enable,
2333            $date,
2334            $comment;
2335         }
2336      }
2337   }
2338
2339#--------------------------------------------------------------------------------
2340#Nom: show
2341#Description: liste les machines à partir du fichier YAML par nom de domaine.
2342
2343sub cmd_show_host {
2344   my %ipdb = ();
2345
2346   my $computer_db = ipamdb_load($COMPUTER_YAML);
2347
2348   my $tb_computer = Text::Table->new(
2349     {align  => 'left',   align_title => 'left',   title => 'Hostname.Sector'},
2350     {is_sep => 1,        body        => '  '},
2351     {align  => 'left',   align_title => 'left',   title => 'IPv4-Address'},
2352     {is_sep => 1,        body        => '  '},
2353     {align  => 'center', align_title => 'center', title => 'MAC-Address'},
2354     {is_sep => 1,        body        => '  '},
2355     {align  => 'right',  align_title => 'right',  title => 'Type'},
2356     {align  => 'right',  align_title => 'right',  title => 'Status'},
2357     {is_sep => 1,        body        => '  '},
2358     {align  => 'left',   align_title => 'left',   title => 'Date'},
2359     {align  => 'left',   align_title => 'left',   title => 'Comment'},
2360     );
2361
2362  LOOP_ON_SECTOR:
2363   for my $sector_current (sort keys %{$computer_db}) {
2364      next if $sector_current eq 'dset';
2365      next if $sector_current eq 'pool';
2366      next if $sector_current eq 'pxe';
2367      next if $sector_current eq 'tag';
2368      next if $sector_current eq 'version';
2369
2370      my @sectordb = @{$computer_db->{$sector_current}};
2371
2372      LOOP_ON_COMPUTER:
2373      for my $computer (@sectordb) {
2374         my ($mac_address, $attribute) = %{$computer};
2375         my $ip = $attribute->{'ip'};
2376
2377         if ($ip =~ m/$DDT::RE::IPv4_ADDRESS/xms) {
2378            if ( not exists $ipdb{$ip} ) {
2379               $ipdb{$ip} = {
2380                  'mac_address'  => $mac_address,
2381                  %{$attribute},
2382                  'sector'    => $sector_current,
2383                  };
2384               }
2385            else {
2386               print {*STDERR} "# Warning: $ip already exists in the database with MAC $mac_address!\n";
2387               }
2388            next LOOP_ON_COMPUTER;
2389            }
2390
2391         my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $attribute->{'modify_time'};
2392         $year += 1900;
2393         $mon++;
2394         my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2395
2396         my $comment = normalize_comment($attribute->{'comment'});
2397         $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2398
2399         my $enable = $attribute->{'enabled'};
2400         if (exists $attribute->{'pxe_config'}) {
2401            $enable .= '/' . $attribute->{'pxe_config'};
2402            }
2403         if (exists $attribute->{'tag'}) {
2404            $enable .= ':' . $attribute->{'tag'};
2405            }
2406
2407         #printf "%-30s  %-20s %17s %9s %3s %10s %s\n",
2408         $tb_computer->add(
2409            $attribute->{'hostname'} . '.' . $sector_current,
2410            $ip,
2411            $mac_address,
2412            $attribute->{'address_type'},
2413            $enable,
2414            $date,
2415            $comment,
2416            );
2417         }
2418      #print "\n# *** List of pool computers in the sector: $sector_current ***\n";
2419      }
2420
2421   #print "\n# *** List of computers ordered by IP and sector ***\n";
2422   LOOP_ON_IP_ADDRESS:
2423   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %ipdb)) {
2424      my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $ipdb{$ip}->{'modify_time'};
2425      $year += 1900;
2426      $mon++;
2427      my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2428
2429      my $comment =$ipdb{$ip}->{'comment'};
2430      $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2431
2432      my $enable = $ipdb{$ip}->{'enabled'};
2433      if (exists $ipdb{$ip}->{'pxe_config'}) {
2434         $enable .= '/' . $ipdb{$ip}->{'pxe_config'};
2435         }
2436      if (exists $ipdb{$ip}->{'tag'}) {
2437         $enable .= ':' . $ipdb{$ip}->{'tag'};
2438         }
2439
2440      #printf "%-30s %-20s %17s %9s %3s %10s %s\n",
2441      $tb_computer->add(
2442         $ipdb{$ip}->{'hostname'} . '.' . $ipdb{$ip}->{'sector'},
2443         $ip,
2444         normalize_mac_address($ipdb{$ip}->{'mac_address'}),
2445         $ipdb{$ip}->{'address_type'},
2446         $enable,
2447         $date,
2448         $comment
2449         );
2450      }
2451
2452   print $tb_computer->title();
2453   print $tb_computer->rule('-');
2454   print $tb_computer->body();
2455   }
2456
2457#-------------------------------------------------------------------------------
2458#Nom: cmd_generate_dhcp_file
2459#Description: génère les fichiers de configuration des machines et des pools du dhcp
2460
2461sub cmd_generate_dhcp_file {
2462   backup_database();
2463
2464   my $computer_db = ipamdb_load($COMPUTER_YAML);
2465
2466   my %file_pool;
2467
2468   for my $sector_current (keys %{$computer_db}) {
2469      next if $sector_current eq 'dset';
2470      next if $sector_current eq 'pool';
2471      next if $sector_current eq 'pxe';
2472      next if $sector_current eq 'tag';
2473      next if $sector_current eq 'version';
2474
2475      open FILE_VLAN, '>', "$FOLDER_GEN_DHCP/$sector_current";
2476      my @sectordb = @{$computer_db->{$sector_current}};
2477      for my $value (@sectordb) {
2478         ALL_MAC_ADDRESS:
2479         for my $mac_addres (keys %{$value}) {
2480            #host pcdavoust {  deny-unknown-clients;
2481            #hardware ethernet 0:6:5b:b8:13:d1;
2482            #fixed-address 194.254.66.72;
2483            #}
2484
2485            my $hostname     = $value->{$mac_addres}{'hostname'};
2486            my $ip           = $value->{$mac_addres}{'ip'};
2487            my $comment      = $value->{$mac_addres}{'comment'};
2488            my $address_type = $value->{$mac_addres}{'address_type'};
2489            my $enabled      = $value->{$mac_addres}{'enabled'};
2490            my $tags         = $value->{$mac_addres}{'tag'} || 'universal';
2491
2492            my $buffer;
2493            if ($address_type eq 'dhcp') {
2494               if ($enabled eq 'yes') {
2495                  $buffer  = "host $hostname {\n"; # deny-unknown-clients;
2496                  $buffer .= "   hardware ethernet $mac_addres;\n";
2497                  $buffer .= "   fixed-address $ip;\n";
2498
2499                  if (exists $value->{$mac_addres}{'pxe_config'}) {
2500                     my $pxe_config     = $value->{$mac_addres}{'pxe_config'};
2501                     my $ip_next_server = $computer_db->{'pxe'}{$pxe_config}{'ip_next_server'};
2502                     my $filename       = $computer_db->{'pxe'}{$pxe_config}{'filename'};
2503                     $buffer .= "   next-server $ip_next_server;\n";
2504                     $buffer .= "   filename \"$filename\";\n";
2505                     }
2506                  $buffer .= "   #comment: $comment\n";
2507                  $buffer .= "   }\n";
2508                  $buffer .= "\n";
2509
2510                  for my $tag (split/,/, $tags) {
2511                     $file_pool{"tag-$tag"} ||= [];
2512                     push @{$file_pool{"tag-$tag"}}, "subclass \"tag-$tag\" 1:$mac_addres; # $comment\n";
2513                     }
2514                  }
2515               else {
2516                  $buffer  = "#host $hostname {\n"; # deny-unknown-clients;
2517                  $buffer .= "#   hardware ethernet $mac_addres;\n";
2518                  $buffer .= "#   fixed-address $ip;\n";
2519                  $buffer .= "#   comment: $comment \n";
2520                  $buffer .= "#   }\n";
2521                  $buffer .= "\n";
2522                  }
2523               print FILE_VLAN $buffer;
2524               }
2525            elsif ($address_type eq 'pool-dhcp') {
2526               #--- Génère les fichiers pool dhcp ---#
2527               for my $current_pool (keys %{$computer_db->{'pool'}}) {
2528                  next if $current_pool ne $ip;
2529
2530                  if ($enabled eq 'yes') {
2531                     $buffer = "subclass \"$current_pool\" 1:$mac_addres; # $comment\n";
2532
2533                     for my $tag (split/,/, $tags) {
2534                        $file_pool{"tag-$tag"} ||= [];
2535                        push @{$file_pool{"tag-$tag"}}, "subclass \"tag-$tag\" 1:$mac_addres; # $comment\n";
2536                        }
2537                     }
2538                  else {
2539                     $buffer = "#subclass \"$current_pool\" 1:$mac_addres; # $comment\n";
2540                     }
2541
2542                  my $current_pool_file_name = $computer_db->{'pool'}{$current_pool}{'file'};
2543
2544                  $file_pool{$current_pool_file_name} ||= [];
2545                  push @{$file_pool{$current_pool_file_name}}, $buffer;
2546                  }
2547               }
2548            }
2549         }
2550
2551      close FILE_VLAN;
2552
2553      for my $file_name (keys %file_pool) {
2554         open FILE_POOL, '>', "$FOLDER_GEN_DHCP/$file_name";
2555         print FILE_POOL @{$file_pool{$file_name}};
2556         close FILE_POOL;
2557         }
2558      }
2559      print "Copy DHCP files from $FOLDER_GEN_DHCP to /etc/dhcp/include/\n";
2560      exec $SCRIPT_UPDATE;
2561   }
2562
2563#-------------------------------------------------------------------------------
2564#Nom: cmd_generate_dns_file
2565#Description: génère les fichiers d'enregistrements DNS
2566
2567sub cmd_generate_dns_file {
2568   local @ARGV = @_;
2569
2570   my $help = get_cmd_name();
2571   my ($verbose);
2572
2573   GetOptions(
2574      'verbose|v' => \$verbose,
2575      );
2576
2577   my $buffer_fwd;
2578   my $buffer_rev;
2579   my $pool_domain;
2580
2581   my $computer_db = ipamdb_load($COMPUTER_YAML);
2582
2583   for my $sector_current (keys %{$computer_db}) {
2584      next if $sector_current eq 'dset';
2585      next if $sector_current eq 'pool';
2586      next if $sector_current eq 'pxe';
2587      next if $sector_current eq 'tag';
2588      next if $sector_current eq 'version';
2589
2590      if ($sector_current eq 'pool') {
2591         LOOP_ON_COMPUTER:
2592         for my $computer (@{$computer_db->{$sector_current}}) {
2593            for my $pool_name (keys %{$computer}) {
2594               $pool_domain = $computer->{$pool_name}->{'domain'}."\n";
2595               #print $computer->{$pool_name}->{'file'};
2596               chomp $pool_domain;
2597               open FILE_FORWARD_DNS, '>>', "$FOLDER_GEN_DNS/db.$pool_domain.fwd";
2598               open FILE_REVERSE_DNS, '>>', "$FOLDER_GEN_DNS/db.$pool_domain.rev";
2599               my @T_pool_ip = @{$computer->{$pool_name}->{'ip'}};
2600               for my $pool_ip (@T_pool_ip) {
2601                  my @T_split = split(/\./ , $pool_ip);
2602                  $buffer_fwd = sprintf "%-24s IN  A  %-15s ;\n", "$pool_name$T_split[3]", $pool_ip;
2603                  $buffer_rev = "$T_split[3]   IN PTR   $pool_name$T_split[3].$pool_domain.\n";
2604                  print FILE_FORWARD_DNS $buffer_fwd;
2605                  print FILE_REVERSE_DNS $buffer_rev;
2606                  }
2607               close FILE_FORWARD_DNS;
2608               close FILE_REVERSE_DNS;
2609               }
2610            }
2611         }
2612
2613      else {
2614         #--- Création du fichier non-reverse ---#
2615         open FILE_FORWARD_DNS, ">> $FOLDER_GEN_DNS/db.$sector_current.fwd";
2616         open FILE_REVERSE_DNS, ">> $FOLDER_GEN_DNS/db.$sector_current.rev";
2617
2618         my @sectordb = @{$computer_db->{$sector_current}};
2619
2620         LOOP_ON_COMPUTER:
2621         for my $computer (@sectordb) {
2622            my ($mac_address, $attribute) = %{$computer};
2623
2624            #host pcdavoust {  deny-unknown-clients;
2625            #hardware ethernet 0:6:5b:b8:13:d1;
2626            #fixed-address 194.254.66.72;
2627            #}
2628
2629            my $hostname     = $attribute->{'hostname'};
2630            my $ip           = $attribute->{'ip'};
2631            my $comment      = $attribute->{'comment'};
2632            my $address_type = $attribute->{'address_type'};
2633            my $enabled      = $attribute->{'enabled'};
2634
2635            next LOOP_ON_COMPUTER if not (($address_type eq 'dhcp') or ($address_type eq 'static'));
2636
2637            my $dns_domain = $sector_current;
2638            if (exists $computer_db->{'dset'}{$sector_current}) {
2639               $dns_domain = $computer_db->{'dset'}{$sector_current}{'dns_extension'};
2640               }
2641
2642            my @ip_split = split /\./, $ip;
2643            if ($enabled eq 'yes') {
2644               if (exists $attribute->{'dns_extension'}
2645                     and "$attribute->{'dns_extension'}" != "$dns_domain") {
2646                  print "A FAIRE\n";
2647                  }
2648               $buffer_fwd = sprintf "%-24s  IN A   %-15s ; %s\n", $hostname, $ip, $comment;
2649               $buffer_rev = sprintf "%3i    IN PTR %-15s\n", $ip_split[3], "$hostname.$dns_domain.";
2650               }
2651
2652            else {
2653               $buffer_fwd = sprintf ";%-24s IN A   %-15s ; %s\n", $hostname, $ip, $comment;
2654               $buffer_rev = sprintf ";%3i   IN PTR %-15s\n", $ip_split[3], "$hostname.$dns_domain.";
2655               }
2656            print FILE_REVERSE_DNS $buffer_rev;
2657            print FILE_FORWARD_DNS $buffer_fwd;
2658            }
2659         close FILE_REVERSE_DNS;
2660         close FILE_FORWARD_DNS;
2661         print "- DNS: db.$sector_current.fwd db.$sector_current.rev [CREATE].\n" if $verbose;
2662         print "  Ex : sort -k 4n -t . $FOLDER_GEN_DNS/db.$sector_current.fwd\n"     if $verbose;
2663         }
2664      }
2665   }
2666
2667#--------------------------------------------------------------------------------
2668
2669sub shell_command {
2670   my $cmd = shift;
2671
2672   require FileHandle;
2673   my $fh     = new FileHandle;
2674   my @result = ();
2675   open $fh, q{-|}, "LANG=C $cmd" or die "Can't exec $cmd\n";
2676   @result = <$fh>;
2677   close $fh;
2678   chomp @result;
2679   return @result;
2680   }
2681
2682#--------------------------------------------------------------------------------
2683
2684sub cmd_check_dns {
2685   local @ARGV = @_;
2686
2687   my $help = get_cmd_name();
2688   my ($opt_direct, $opt_reverse, $opt_byip);
2689
2690   GetOptions(
2691      'direct|d'  => \$opt_direct,
2692      'reverse|r' => \$opt_reverse,
2693      'by-ip|b'   => \$opt_byip,
2694      );
2695
2696   my $computer_db = ipamdb_load($COMPUTER_YAML);
2697
2698   if ($opt_direct or not ($opt_reverse or $opt_byip)) { # DDT to DNS check
2699      LOOP_ON_SECTOR:
2700      for my $sector_current (keys %{$computer_db}) {
2701         next if $sector_current eq 'dset';
2702         next if $sector_current eq 'pool';
2703         next if $sector_current eq 'pxe';
2704         next if $sector_current eq 'tag';
2705         next if $sector_current eq 'version';
2706
2707         my @sectordb = @{$computer_db->{$sector_current}};
2708
2709         LOOP_ON_COMPUTER:
2710         for my $computer (@sectordb) {
2711            my ($mac_address, $attribute) = %{$computer};
2712            #my $new_mac = normalize_mac_address($mac_address);
2713            my $ip = $attribute->{'ip'};
2714            next LOOP_ON_COMPUTER if not $ip =~ m/$DDT::RE::IPv4_ADDRESS/xms;
2715            next LOOP_ON_COMPUTER if $attribute->{'enabled'} eq 'no';
2716
2717            my $dns_hostname_fq = scalar gethostbyaddr(inet_aton($ip), AF_INET);
2718            my ($dns_hostname) = split /\./, $dns_hostname_fq;
2719
2720            if ($attribute->{'hostname'} ne $dns_hostname) {
2721               print "$mac_address ($sector_current) $ip - $dns_hostname / $attribute->{'hostname'} # $attribute->{'comment'}\n";
2722               next LOOP_ON_COMPUTER;
2723               }
2724
2725            my $packed_ip = scalar gethostbyname($dns_hostname_fq);
2726            if (defined $packed_ip) {
2727               my $ip_address = inet_ntoa($packed_ip);
2728               if ($ip ne $ip_address) {
2729                  print "Error: bad IP for reverse DNS on $dns_hostname_fq / $ip\n";
2730                  next LOOP_ON_COMPUTER;
2731                  }
2732               }
2733            }
2734         }
2735      }
2736
2737   if ($opt_reverse) {  # DNS to DDT check
2738      my %saw; # count for unique member
2739      my @dns_domain_list = sort grep !$saw{$_}++,
2740         map $computer_db->{'dset'}{$_}{'dns_extension'},
2741         grep exists($computer_db->{'dset'}{$_}{'dns_extension'}),
2742         keys $computer_db->{'dset'};
2743      LOOP_ON_DNS:
2744      for my $dns (@dns_domain_list) {
2745         LOOP_ON_IP:
2746         for (shell_command("host -t A -l $dns")) {
2747            # smtp2.legi.grenoble-inp.fr has address 194.254.67.37
2748            next if not m/has address/;
2749            next if not m/^(\w[\w-_\.]+\w)\s+has\saddress\s+(\d[\d\.]+\d)$/;
2750            my ($hostname_fq, $ip) = ($1, $2);
2751            control_syntax_ip($ip) or next LOOP_ON_IP;
2752            if (control_exist_ip($computer_db, $ip) == 1) {
2753               printf "Unkown IP: %-15s / %s\n", $ip, $hostname_fq;
2754               next LOOP_ON_IP;
2755               }
2756            }
2757         }
2758      }
2759
2760   if ($opt_byip) {  # IP Range DDT check
2761      my @ip_check;
2762      LOOP_ON_SECTOR:
2763      for my $sector_current (@{$computer_db->{'dset'}}) {
2764         next LOOP_ON_SECTOR if not exists $computer_db->{'dset'}{'ip_range'};
2765
2766         LOOP_ON_CIDR:
2767         for my $ip_range (@{$computer_db->{'dset'}{'ip_range'}}) {
2768
2769            LOOP_ON_IP:
2770            for my $ip (NetAddr::IP->new($ip_range)->hostenum()) {
2771               print "$ip\n";
2772               }
2773            }
2774         }
2775      }
2776   }
2777
2778#-------------------------------------------------------------------------------
2779#Nom: load_data_dhcp
2780#Description: permet de charger le fichier de données YAML via les fichiers de configuration
2781#             machines.
2782#            ATTENTION: LES COMMENTAIRES DU FICHIER DISPARAITRONT.
2783
2784sub load_data_dhcp {
2785   my ($sector, $input_file) = @_;
2786
2787   my $computer_db = ipamdb_load($COMPUTER_YAML);
2788
2789   my @T_mac;
2790   my @T_host;
2791   my @T_ip;
2792   my $cpt;
2793   open (FILE, "<$input_file");
2794   my @buffer = <FILE>;
2795   close(FILE);
2796
2797   LINE:
2798   for my $ligne (@buffer) {
2799      #--
2800      $ligne =~ s/#.*$//;
2801      $ligne =~ s/\s+/ /;
2802      $ligne =~ s/^\s+//;
2803      next if $ligne eq '';
2804
2805      if ($ligne =~ /^host /) {
2806         $cpt=0;
2807         my @T_split = split(/host\s+/, $ligne);
2808         @T_host = split(/ /, $T_split[1]);
2809         chomp($T_host[0]);
2810
2811         $cpt++;
2812         }
2813
2814      if ($ligne =~ /^*ethernet /) {
2815         $ligne =~ s/;//g;
2816         @T_mac = split(/ethernet\s+/, $ligne);
2817         chomp($T_mac[1]);
2818         $cpt++;
2819         }
2820
2821      if ($ligne =~ /^*address /) {
2822         $ligne =~ s/;//g;
2823         @T_ip = split(/address\s+/, $ligne);
2824         chomp($T_ip[1]);
2825
2826         $cpt++;
2827         }
2828
2829      if ($cpt == 3) {
2830         #   print "MAC $T_mac[1] HOST $T_host[0] IP $T_ip[1].\n";
2831         my $mac = $T_mac[1];
2832         my $hostname = $T_host[0];
2833         my $ip = $T_ip[1];
2834         $cpt = 0;
2835
2836         if ( control_exist_hostname($computer_db, $sector, $hostname) == 0 ) {
2837            print "Error: host already exist in sector $sector: $hostname\n";
2838            next LINE;
2839            }
2840         control_syntax_mac_address($mac) or next LINE;
2841         if ( control_exist_mac($computer_db, $mac) == 0) {
2842            print "Error: physical MAC address already exists: $mac\n";
2843            next LINE;
2844            }
2845
2846         control_syntax_ip($ip) or next LINE;
2847         if ( control_exist_ip($computer_db, $ip) == 0 ) {
2848            print "Error: IP address already exists: $ip\n";
2849            next LINE;
2850            }
2851         my $timestamp = time;
2852         push @{$computer_db->{$sector}}, { $mac => {
2853            'hostname'     => $hostname,
2854            'ip'           => $ip,
2855            'address_type' => 'dhcp',
2856            'enabled'      => 'yes',
2857            'create_time'  => $timestamp,
2858            'modify_time'  => $timestamp,
2859            'alias'        =>  '',
2860            }};
2861         }
2862      }
2863   }
2864
2865#-------------------------------------------------------------------------------
2866#Nom: load_data_pool
2867#Description: permet de charger le fichier YAML via les fichiers de conf 'pool' du dhcp.
2868
2869sub load_data_pool {
2870   my ($sector, $input_file) = @_;
2871
2872   my @T_mac;
2873
2874   open (FILE, "<$input_file");
2875   my @buffer = <FILE>;
2876   close(FILE);
2877
2878   my $computer_db = ipamdb_load($COMPUTER_YAML);
2879
2880   for my $ligne (@buffer) {
2881      #--
2882      $ligne =~ s/#.*$//;
2883      $ligne =~ s/\s+/ /;
2884      $ligne =~ s/^\s+//;
2885      $ligne =~ s/;//g;
2886      $ligne =~ s/"//g;
2887      next if $ligne eq '';
2888
2889      if (($ligne =~ /^subclass/)) {
2890         my @T_split = split(/ / ,$ligne);
2891         my $pool = $T_split[1];
2892
2893         @T_mac = split(/:/ , $T_split[2]);
2894         my $mac = $T_mac[1].":".$T_mac[2].":".$T_mac[3].":".$T_mac[4].":".$T_mac[5].":".$T_mac[6];
2895         control_syntax_mac_address($mac) or next;
2896         if (control_exist_mac($computer_db, $mac) == 0) {
2897            print "Error: physical MAC address already exists: $mac\n";
2898            next;
2899            }
2900
2901         #--- cette partie teste si le pool existe.
2902         if (not exists $computer_db->{'pool'}{$pool}) {
2903            print "Error: create pool with create_pool command before load database: $pool\n";
2904            exit;
2905            }
2906
2907         if ($computer_db->{'pool'}{'domain'} eq $sector) {
2908            my $timestamp = time;
2909            push @{$computer_db->{$sector}}, { $mac => {
2910               'hostname'     => $pool,
2911               'ip'           => $pool,
2912               'address_type' => 'pool-dhcp',
2913               'enabled'      => 'yes',
2914               'create_time'  => $timestamp,
2915               'modify_time'  => $timestamp,
2916               }};
2917            }
2918         else {
2919            print "Ajout de la machine $mac [FAILED]\n";
2920            print "Error: the pool doesn't exists: $pool, for the domain: $sector\n";
2921            }
2922         }
2923      }
2924   }
2925
2926#-------------------------------------------------------------------------------
2927
2928sub load_data_file {
2929   my ($sector, $input_file, $type_file) = @_;
2930
2931   my $computer_db = ipamdb_load($COMPUTER_YAML);
2932
2933   #$computer_db
2934   if ($type_file eq 'dhcp') {
2935      load_data_dhcp($sector, $input_file);
2936      }
2937
2938   elsif ($type_file eq 'pool-dhcp') {
2939      load_data_pool($sector, $input_file);
2940      }
2941
2942   ipamdb_save("$COMPUTER_YAML", $computer_db);
2943   }
2944
2945#-------------------------------------------------------------------------------
2946
2947sub cmd_load_database {
2948   local @ARGV = @_;
2949
2950   my $help = get_cmd_name();
2951   my ($sector, $input_file, $type_file);
2952
2953   GetOptions(
2954      'sector|s|d=s'    => \$sector,
2955      'filename|f=s'    => \$input_file,
2956      'kind|k=s'        => \$type_file,
2957      );
2958
2959   exit_on_error_option($help)
2960      if $sector  eq ''
2961      or $input_file eq ''
2962      or $type_file  eq '';
2963
2964   load_data_file($sector, $input_file, $type_file);
2965   }
2966
2967#-------------------------------------------------------------------------------
2968#Nom: backup_database
2969#Description: sauvegarde et réinitialise les fichiers d'enregistrements DHCP.
2970
2971sub backup_database {
2972   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime time;
2973   $year += 1900;
2974   $mon++;
2975   my $date = sprintf '%04i-%02i-%02i-%02i-%02i-%02i', $year, $mon, $mday, $hour, $min, $sec;
2976
2977   copy($COMPUTER_YAML, "$FOLDER_BACKUP/$COMPUTER_BASENAME-$date.conf") or die "Error: database copy backup failed: $!\n";
2978   }
2979
2980#-------------------------------------------------------------------------------
2981# HELP section
2982#-------------------------------------------------------------------------------
2983
2984#-------------------------------------------------------------------------------
2985#Nom: exit_on_error_option
2986#Description: messages d'aide des options pour les différentes commandes
2987
2988sub exit_on_error_option {
2989  my ($command) = @_;
2990
2991   if ($command eq 'add-dhcp') {
2992      print "List of options for command: $command\n";
2993      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
2994      print " -h : computer hostname (mandatory if option -i != 'pool'). Example: -h info8pc154\n";
2995      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A\n";
2996      print " -i : internet IP address (mandatory). Possible value: classical IP address or the keyword 'pool'\n";
2997      print " -p : name of the DHCP pool to which the machine belongs (mandatory if option -i == 'pool')\n";
2998      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
2999      print "Example:\n";
3000      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";
3001      }
3002
3003   elsif ($command eq 'add-float') {
3004      print "List of options for command: $command\n";
3005      print " -s : sector attachment (mandatory)\n";
3006      print " -p : name of the DHCP pool to which the machine belongs (mandatory)\n";
3007      print " -m : physical MAC address (mandatory)\n";
3008      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
3009      print "Example:\n";
3010      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";
3011      }
3012
3013   elsif ($command eq 'add-static') {
3014      print "List of options for command: $command\n";
3015      print " -s : sector attachment (mandatory)\n";
3016      print " -i : internet IP address (mandatory)\n";
3017      print " -h : computer hostname (mandatory)\n";
3018      print " -m : physical MAC address (mandatory)\n";
3019      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
3020      print "Example:\n";
3021      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";
3022      }
3023
3024   elsif ($command eq 'add-virtual') {
3025      print "List of options for command: $command\n";
3026      print " -s : sector attachment (mandatory)\n";
3027      print " -i : internet IP address (mandatory)\n";
3028      print " -h : computer hostname (mandatory)\n";
3029      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
3030      print "Example:\n";
3031      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";
3032      }
3033
3034   elsif ($command eq 'add-alias') {
3035      print "List of options for command: $command\n";
3036      print " -s : sector attachment (mandatory)\n";
3037      print " -h : computer hostname (mandatory)\n";
3038      print " -a : computer alias name (mandatory)\n";
3039      }
3040
3041   elsif ($command eq 'create-sector') {
3042      print "List of options for command: $command\n";
3043      print " -s : new sector (mandatory)\n";
3044      print " -e : DNS domain name extension( mandatory). Example legi.grenoble-inp.fr\n";
3045      print " -c : comment (mandatory). Example: 2016-08-22 VLAN legi-261 (INFO)\n";
3046      print "Examples:\n";
3047      print " ddt create-sector -s legi-sector03 -e legi.grenoble-inp.fr -c '2016-08-22 VLAN legi-261 (INFO)'\n";
3048      }
3049
3050   elsif ($command eq 'create-pool') {
3051      print "List of options for command: $command\n";
3052      print " -p : name of the DHCP pool. Example: pool-legi-priv\n";
3053      print " -s : sector attachment for the pool. (sector attachment must exist in file $COMPUTER_BASENAME.conf). Example: legi-sector03\n";
3054      print " -f : configuration filename on the DHCP server for the pool\n";
3055      print " -i : adresse(s) IP ou plage d'IP. Séparateur d'adresses IP: ','. Séparateur de plage '-'\n";
3056      print "Examples:\n";
3057      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";
3058      print " ddt create-pool -p legi-pool2 -s legi-sector03 -f legi-pool-public  -i 192.168.10.1-192.168.10.4\n";
3059      }
3060
3061   elsif ($command eq 'create-pxe') {
3062      print "List of options for command: $command\n";
3063      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3064      print " -n : internet IP address for the DHCP next-server.\n";
3065      print " -f : filename on TFTP server to load at boot\n";
3066      print " -c : comment (mandatory). Example: 2014-04-07 PXE Boot for CentOS (MOST)\n";
3067      }
3068
3069   elsif ($command eq 'remove-pxe') {
3070      print "List of options for command: $command\n";
3071      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3072      }
3073
3074   elsif ($command eq 'enable-pxe') {
3075      print "List of options for command: $command\n";
3076      print " -h : computer hostname (mandatory unless option -i)\n";
3077      print " -i : internet IP address (mandatory unless option -h)\n";
3078      print " -s : sector attachment (mandatory if option -h)\n";
3079      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3080      }
3081
3082   elsif ($command eq 'disable-pxe') {
3083      print "List of options for command: $command\n";
3084      print " -h : computer hostname (mandatory unless option -i)\n";
3085      print " -i : internet IP address (mandatory unless option -h)\n";
3086      print " -s : sector attachment (mandatory if option -h)\n";
3087      }
3088
3089   elsif ($command eq 'create-tag') {
3090      print "List of options for command: $command\n";
3091      print " -t : name of the TAG (mandatory). Example: restricted\n";
3092      print " -c : comment (mandatory). Example: 2014-04-07 tag restricted (INFO)\n";
3093      print "tag 'universal' is intrinsic\n";
3094      }
3095
3096   elsif ($command eq 'remove-tag') {
3097      print "List of options for command: $command\n";
3098      print " -b : name of the TAG. Example: restricted\n";
3099      }
3100
3101   elsif ($command eq 'change-mac') {
3102      print "List of options for command: $command\n";
3103      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3104      print " -h : computer hostname (mandatory unless option -i)\n";
3105      print " -i : internet IP address (mandatory unless option -h). Possible value: classical IP address or the keyword 'pool'\n";
3106      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3107      }
3108
3109   elsif ($command eq 'change-ip') {
3110      print "List of options for command: $command\n";
3111      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3112      print " -h : computer hostname (mandatory)\n";
3113      print " -i : new internet IP address (mandatory). Possible value: classical IP address\n";
3114      }
3115
3116   elsif ($command eq 'change-host') {
3117      print "List of options for command: $command\n";
3118      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3119      print " -i : internet IP address (mandatory). Possible value: classical IP address\n";
3120      print " -h : new computer hostname (mandatory)\n";
3121      print "It's not possible to change hostname for computer that belongs to a pool\n";
3122      }
3123
3124   elsif ($command eq 'change-comment') {
3125      print "List of options for command: $command\n";
3126      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3127      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3128      print " -c : new comment (mandatory)\n";
3129      }
3130
3131   elsif ($command eq 'change-sector') {
3132      print "List of options for command: $command\n";
3133      print " -s : new sector attachment (mandatory). Example: -s legi-sector03\n";
3134      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3135      print " -i : internet IP address (mandatory)\n";
3136      }
3137
3138   elsif ($command eq 'change-tag') {
3139      print "List of options for command: $command\n";
3140      print " -h : computer hostname (mandatory unless option -i or -m)\n";
3141      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3142      print " -i : internet IP address (mandatory unless option -h or -m)\n";
3143      print " -m : physical MAC address (mandatory unless option -h or -i, priority). Example: -m 0F:58:AB:2A:22:11\n";
3144      print " -t : list of tags separated by comma (mandatory). Example: -t internal,windows\n";
3145      }
3146
3147   elsif ($command eq 'load-database') {
3148      print "List of options for command: $command\n";
3149      print " -s : sector attachment\n";
3150      print " -f : input file in DHCP format\n";
3151      print " -k : possible cases (kind): dhcp, pool-dhcp, fix-address\n";
3152      }
3153
3154   elsif ($command eq 'enable-pc') {
3155      print "List of options for command: $command\n";
3156      print " -h : computer hostname (mandatory unless option -i)\n";
3157      print " -i : internet IP address (mandatory unless option -h)\n";
3158      print " -s : sector attachment (mandatory if option -h)\n";
3159      print "Examples:\n";
3160      print " ddt enable-pc -i 192.168.10.1\n";
3161      print " ddt enable-pc -s legi-sector03 -h kevinpc\n";
3162      }
3163
3164   elsif ($command eq 'enable-float') {
3165      print "List of options for command: $command\n";
3166      print " -m : physical MAC address (mandatory)\n";
3167      print " -p : name of the DHCP pool (mandatory)\n";
3168      }
3169
3170   elsif ($command eq 'disable-float') {
3171      print "List of options for command: $command\n";
3172      print " -m : physical MAC address (mandatory)\n";
3173      print " -p : name of the DHCP pool (mandatory)\n";
3174      }
3175
3176   elsif ($command eq 'disable-pc') {
3177      print "List of options for command: $command\n";
3178      print " -h : computer hostname (mandatory unless option -i)\n";
3179      print " -i : internet IP address (mandatory unless option -h)\n";
3180      print " -s : sector attachment (mandatory if option -h)\n";
3181      print "Examples:\n";
3182      print " ddt disable-pc -i 192.168.10.1\n";
3183      print " ddt disable-pc -s legi-sector03 -h kevinpc\n";
3184      }
3185
3186   elsif ($command eq 'del-pc') {
3187      print "List of options for command: $command\n";
3188      print " -s : sector attachment (mandatory)\n";
3189      print " -h : computer hostname (mandatory unless option -i)\n";
3190      print " -i : internet IP address (mandatory unless option -h)\n";
3191      }
3192
3193   elsif ($command eq 'del-float') {
3194      print "List of options for command: $command\n";
3195      print " -m : physical MAC address (mandatory)l\n";
3196      print " -p : name of the DHCP pool\n";
3197      }
3198
3199   elsif ($command eq 'search-mac') {
3200      print "List of options for command: $command\n";
3201      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3202      }
3203
3204   elsif ($command eq 'sector-add-ip') {
3205      print "List of options for command: $command\n";
3206      print " -s : sector attachment (mandatory)\n";
3207      print " -i : internet IP range address in CIDR notation (mandatory)\n";
3208      }
3209
3210   else {
3211      print "No help for command: $command\n";
3212      }
3213   exit;
3214   }
3215
3216#-------------------------------------------------------------------------------
3217
3218sub cmd_version {
3219
3220   print <<'END';
3221ddt - management of computer names and IP addresses
3222Copyright (C) 2006-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
3223Main author Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>
3224License GNU GPL version 2 or later and Perl equivalent
3225END
3226
3227   print "Database Version 1\n";
3228   print "Version $VERSION\n\n";
3229   print ' $Id: ddt 359 2018-09-14 18:44:13Z g7moreau $'."\n";
3230   return;
3231   }
3232
3233#-------------------------------------------------------------------------------
3234#Nom: usage
3235#Description: message d'aide sur les commandes du script
3236
3237sub cmd_help {
3238   print <<END;
3239ddt - management of computer names and IP addresses
3240
3241 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3242 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3243 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3244 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3245 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3246 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3247 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3248 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3249 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3250 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3251 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3252 ddt check-dns [--direct] [--reverse]
3253 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3254 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3255 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3256 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3257 ddt del-float [--pool|-p pool] [--mac|-m mac]
3258 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3259 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3260 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3261 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3262 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3263 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3264 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3265 ddt gen-dhcp-file
3266 ddt gen-dns-file [--verbose]
3267 ddt help
3268 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3269 ddt remove-pxe [--bootp|-b pxe_config]
3270 ddt remove-tag [--tag|-t tag]
3271 ddt search-mac [--mac|-m mac]
3272 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3273 ddt show-sector [--no-header|-H]
3274 ddt show
3275 ddt show-pool [--no-header|-H]
3276 ddt show-pxe [--no-header|-H]
3277 ddt show-tag [--no-header|-H]
3278 ddt version
3279
3280COMMANDS
3281
3282 * add-alias         : add an alias for a computer (like CNAME for the DNS)
3283 * add-dhcp          : add a computer with a fix DHCP IP or in a DHCP pool
3284 * add-float         : add a computer with an IP in a DHCP pool
3285 * add-static        : add a computer with a static IP
3286 * add-virtual       : add a virtual computer with a static IP but a virtual MAC (useful to declare float computer in DNS)
3287 * change-comment    : change the computer comment
3288 * change-sector     : change the sector attachment for a computer
3289 * change-host       : change the computer hostname
3290 * change-ip         : change the computer IP address
3291 * change-mac        : change the computer physical MAC address
3292 * change-tag        : change the list of TAGs associated to a computer
3293 * check-dns         : check the DNS table for base IPs
3294 * create-sector     : create a new sector
3295 * create-pool       : create a new pool for DHCP records
3296 * create-pxe        : create a new PXE/BOOTP configuration
3297 * create-tag        : create a new TAG
3298 * del-float         : remove a computer from a DHCP pool
3299 * del-pc            : remove a computer (DHCP or static IP) from the YAML database
3300 * disable-pc        : disable a computer (DHCP and/or DNS) (but keep it in the database)
3301 * disable-float     : disable a computer from a DHCP pool (but keep it in the database)
3302 * disable-pxe       : remove PXE/BOOTP configuration on a computer
3303 * enable-float      : enable a previous disable computer (DHCP and/or DNS)
3304 * enable-pc         : enable a previous disable computer (DHCP and/or DNS)
3305 * enable-pxe        : enable PXE/BOOTP configuration on a computer
3306 * gen-dhcp-file     : generate DHCP files for the isc DHCP server
3307 * gen-dns-file      : generate DNS files for the bind domain server
3308 * help              : this help
3309 * load-database     : load the YAML database (be careful)
3310 * remove-pxe        : remove a PXE/BOOTP configuration
3311 * remove-tag        : remove a TAG
3312 * search-mac        : search physical MAC address computer
3313 * ddt sector-add-ip : add IP range check on a sector
3314 * show-sector       : list all sector group of computer
3315 * show              : list all computers
3316 * show-pool         : list all pool
3317 * show-pxe          : list PXE/BOOTP configuration
3318 * show-tag          : list all TAGs
3319 * version           : return program version
3320END
3321   return;
3322   }
3323
3324################################################################
3325# documentation
3326################################################################
3327
3328__END__
3329
3330=head1 NAME
3331
3332ddt - management of computer names and IP addresses
3333
3334
3335=head1 USAGE
3336
3337 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3338 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3339 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3340 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3341 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3342 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3343 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3344 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3345 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3346 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3347 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3348 ddt check-dns [--direct] [--reverse]
3349 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3350 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3351 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3352 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3353 ddt del-float [--pool|-p pool] [--mac|-m mac]
3354 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3355 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3356 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3357 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3358 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3359 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3360 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3361 ddt gen-dhcp-file
3362 ddt gen-dns-file [--verbose]
3363 ddt help
3364 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3365 ddt remove-pxe [--bootp|-b pxe_config]
3366 ddt remove-tag [--tag|-t tag]
3367 ddt search-mac [--mac|-m mac]
3368 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3369 ddt show-sector [--no-header|-H]
3370 ddt show
3371 ddt show-pool [--no-header|-H]
3372 ddt show-pxe [--no-header|-H]
3373 ddt show-tag [--no-header|-H]
3374 ddt version
3375
3376
3377=head1 DESCRIPTION
3378
3379DDT is an acronym for DHCP-DNS-Tools.
3380The previous command name was not C<ddt> but just C<dhcp-dns-tools>...
3381In practise, DDT is an IP Address Management (IPAM) service.
3382It has been used in the LEGI laboratory for over 10 years.
3383
3384The tool is quite effective and tries to keep things simple
3385but easily configurable for your site like a swiss army knife.
3386Everything is saved in a YAML database
3387and entries could be added, deleted, or modified by the command line.
3388
3389
3390=head1 COMMANDS
3391
3392=head2 add-alias
3393
3394 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3395
3396=head2 add-dhcp
3397
3398 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3399
3400=head2 add-float
3401
3402 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3403
3404=head2 add-static
3405
3406 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3407
3408=head2 add-virtual
3409
3410 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3411
3412=head2 change-comment
3413
3414 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3415
3416=head2 change-sector
3417
3418 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3419
3420=head2 change-host
3421
3422 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3423
3424=head2 change-ip
3425
3426 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3427
3428=head2 change-mac
3429
3430 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3431
3432=head2 change-tag
3433
3434 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3435
3436=head2 check-dns
3437
3438 ddt check-dns [--direct] [--reverse]
3439
3440=head2 create-sector
3441
3442 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3443
3444=head2 create-pool
3445
3446 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3447
3448=head2 create-pxe
3449
3450 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3451
3452=head2 create-tag
3453
3454 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3455
3456=head2 del-float
3457
3458 ddt del-float [--pool|-p pool] [--mac|-m mac]
3459
3460=head2 del-pc
3461
3462 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3463
3464=head2 disable-pc
3465
3466 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3467
3468=head2 disable-float
3469
3470 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3471
3472=head2 disable-pxe
3473
3474 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3475
3476=head2 enable-float
3477
3478 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3479
3480=head2 enable-pc
3481
3482 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3483
3484=head2 enable-pxe
3485
3486 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3487
3488=head2 gen-dhcp-file
3489
3490 ddt gen-dhcp-file
3491
3492=head2 gen-dns-file
3493
3494 ddt gen-dns-file [--verbose]
3495
3496=head2 help
3497
3498 ddt help
3499
3500=head2 load-database
3501
3502 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3503
3504=head2 remove-pxe
3505
3506 ddt remove-pxe [--bootp|-b pxe_config]
3507
3508=head2 remove-tag
3509
3510 ddt remove-tag [--tag|-t tag]
3511
3512=head2 search-mac
3513
3514 ddt search-mac [--mac|-m mac]
3515
3516=head2 sector-add-ip
3517
3518 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3519
3520=head2 show-sector
3521
3522 ddt show-sector [--no-header|-H]
3523
3524=head2 show
3525
3526 ddt show
3527
3528=head2 show-pool
3529
3530 ddt show-pool [--no-header|-H]
3531
3532=head2 show-pxe
3533
3534 ddt show-pxe [--no-header|-H]
3535
3536=head2 show-tag
3537
3538 ddt show-tag [--no-header|-H]
3539
3540=head2 version
3541
3542 ddt version
3543
3544
3545=head1 AUTHORS
3546
3547Written by Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>, Kevin Reverchon, Olivier De-Marchi - Grenoble - France
3548
3549
3550=head1 LICENSE AND COPYRIGHT
3551
3552License GNU GPL version 2 or later and Perl equivalent
3553
3554Copyright (C) 2006-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
Note: See TracBrowser for help on using the repository browser.