source: trunk/ddt/ddt @ 357

Last change on this file since 357 was 357, checked in by g7moreau, 6 years ago
  • Better control IP syntax
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 117.3 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.7');
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   $comment = normalize_comment($comment);
1625
1626   my $computer_db = ipamdb_load($COMPUTER_YAML);
1627
1628   $computer_db->{'dset'} ||= {};
1629   die "Error: sector already exists: $sector\n" if exists $computer_db->{'dset'}{$sector};
1630
1631   control_syntax_comment($comment)    or exit;
1632
1633   my $timestamp = time;
1634   $computer_db->{'dset'}{$sector} = {
1635      'dns_extension'   => $dns_extension,
1636      'comment'         => $comment,
1637      'create_time'     => $timestamp,
1638      'modify_time'     => $timestamp,
1639      };
1640   $computer_db->{$sector} ||= []; # Create empty sector computer list by default
1641   ipamdb_save("$COMPUTER_YAML", $computer_db);
1642   }
1643
1644#-------------------------------------------------------------------------------
1645
1646sub cmd_sector_add_ip {
1647   local @ARGV = @_;
1648
1649   my $help = get_cmd_name();
1650   my ($sector, $ip_range);
1651
1652   GetOptions(
1653      'sector|s|d=s' => \$sector,
1654      'ip-range|i=s' => \$ip_range,
1655      );
1656
1657   exit_on_error_option($help)
1658      if $sector     eq ''
1659      or $ip_range   eq '';
1660
1661   control_syntax_cidr($ip_range)   or die "Error: bad IP range $ip_range syntax (CIDR)\n";;
1662
1663   my $computer_db = ipamdb_load($COMPUTER_YAML);
1664   exists $computer_db->{'dset'}{$sector} or die "Error: sector not exists: $sector\n";
1665
1666   my $timestamp = time;
1667   $computer_db->{'dset'}{$sector}{'ip-range'} ||= [];
1668   LOOP_ON_CIDR:
1669   for my $cidr_current (@{$computer_db->{'dset'}{$sector}{'ip-range'}}) {
1670      next LOOP_ON_CIDR if $cidr_current ne $ip_range;
1671     
1672      die "Error: IP range $ip_range already in sector $sector\n";
1673      }
1674
1675   my $timestamp = time;
1676   push @{$computer_db->{'dset'}{$sector}{'ip-range'}}, $ip_range;
1677   $computer_db->{'dset'}{$sector}{'modify_time'} = $timestamp;
1678   ipamdb_save("$COMPUTER_YAML", $computer_db);
1679   }
1680
1681#-------------------------------------------------------------------------------
1682# POOL section
1683#-------------------------------------------------------------------------------
1684
1685#-------------------------------------------------------------------------------
1686#Nom: create_pool
1687#Description: crée un pool dans le fichier de données YAML et dans le DHCP.
1688#
1689#Commentaires: il y a un petit bug si jamais on rentre que des adresses ip qui existent déjà.
1690#              Le pool est créé mais sans adresses ip.
1691
1692sub cmd_create_pool {
1693   local @ARGV = @_;
1694
1695   my $help = get_cmd_name();
1696   my ($pool, $sector, $file_pool, $ipaddress_pool);
1697
1698   GetOptions(
1699      'pool|p=s'           => \$pool,
1700      'sector|s|d=s'      => \$sector,
1701      'file-pool|f=s'      => \$file_pool,
1702      'ipaddress-pool|i=s' => \$ipaddress_pool,
1703      );
1704
1705   exit_on_error_option($help)
1706      if $pool             eq ''
1707      or $sector        eq ''
1708      or $file_pool        eq ''
1709      or $ipaddress_pool   eq '';
1710
1711   my $computer_db = ipamdb_load($COMPUTER_YAML);
1712
1713   if ($computer_db->{'pool'}) {
1714      die "Error: pool already exists: $pool\n" if exists $computer_db->{'pool'}{$pool};
1715      }
1716
1717   #--- control if the domain's pool exist ---#
1718   control_exist_sector($computer_db, $sector) or exit;
1719
1720   my @ip_list = ();
1721   #---control if address exist ---#
1722   if ($ipaddress_pool =~ /,/) {
1723      LOOP_ON_IP:
1724      for my $ip (split /,/, $ipaddress_pool) {
1725         if ($ip =~ /-/) {
1726            my ($ip1, $ip2, $ip3, $range) = split /\./, $ip;
1727            my ($first, $last) = split /-/, $range;
1728            for (my $cpt = $first; $cpt <= $last; $cpt++) {
1729               my $ip_loc = "$ip1.$ip2.$ip3.$cpt";
1730               control_syntax_ip($ip_loc) or die "Error: bad IP syntax: $ip_loc\n";
1731               control_exist_ip($computer_db, $ip_loc) or die "Error: IP address already exists: $ip_loc\n";
1732               push @ip_list, $ip_loc;
1733               }
1734            }
1735         else {
1736            control_syntax_ip($ip) or next LOOP_ON_IP;
1737            if ( control_exist_ip($computer_db, $ip) == 0 ) {
1738               print "L'adresse IP $ip existe déjà\n";
1739               next;
1740               }
1741            push @ip_list, $ip;
1742            }
1743         }
1744      }
1745
1746   my $timestamp = time;
1747   $computer_db->{'pool'}{$pool} = {
1748      'ip'          => [@ip_list],
1749      'enabled'     => 'yes',
1750      'create_time' => $timestamp,
1751      'modify_time' => $timestamp,
1752      'file'        => $file_pool,
1753      'domain'      => $sector,
1754      };
1755   ipamdb_save("$COMPUTER_YAML", $computer_db);
1756   }
1757
1758#-------------------------------------------------------------------------------
1759
1760sub cmd_show_pool {
1761   local @ARGV = @_;
1762
1763   my ($no_header);
1764
1765   GetOptions(
1766      'no-header|H' => \$no_header,
1767      );
1768
1769   my $computer_db = ipamdb_load($COMPUTER_YAML);
1770
1771   printf "%-17s %-17s %s\n", 'Pool', 'File', 'DNS-Domain' if not $no_header;
1772   LOOP_ON_PXE:
1773   for my $pool ( keys %{$computer_db->{'pool'}} ) {
1774
1775      printf "%-17s %-17s %s\n",
1776         $pool,
1777         $computer_db->{'pool'}{$pool}{'file'},
1778         $computer_db->{'pool'}{$pool}{'domain'},
1779      }
1780   }
1781
1782#-------------------------------------------------------------------------------
1783# PXE section
1784#-------------------------------------------------------------------------------
1785
1786sub cmd_create_pxe {
1787   local @ARGV = @_;
1788
1789   my $help = get_cmd_name();
1790   my ($pxe_config, $ip_next_server, $filename, $comment);
1791
1792   GetOptions(
1793      'bootp|b=s'       => \$pxe_config,
1794      'next-server|n=s' => \$ip_next_server,
1795      'filename|f=s'    => \$filename,
1796      'comment|c=s'     => \$comment,
1797      );
1798
1799   exit_on_error_option($help)
1800      if $pxe_config       eq ''
1801      or $ip_next_server   eq ''
1802      or $filename         eq ''
1803      or $comment          eq '';
1804
1805   my $computer_db = ipamdb_load($COMPUTER_YAML);
1806
1807   $comment = normalize_comment($comment);
1808
1809   $computer_db->{'pxe'} ||= {};
1810   die "Error: PXE config already exists: $pxe_config\n" if exists $computer_db->{'pxe'}{$pxe_config};
1811
1812   control_syntax_ip($ip_next_server)  or die "Error: bad IP syntax: $ip_next_server\n";
1813   control_syntax_comment($comment)    or exit;
1814
1815   my $timestamp = time;
1816   $computer_db->{'pxe'}{$pxe_config} = {
1817      'ip_next_server'  => $ip_next_server,
1818      'filename'        => $filename,
1819      'comment'         => $comment,
1820      'create_time'     => $timestamp,
1821      'modify_time'     => $timestamp,
1822      };
1823   ipamdb_save("$COMPUTER_YAML", $computer_db);
1824   }
1825
1826#-------------------------------------------------------------------------------
1827
1828sub cmd_remove_pxe {
1829   local @ARGV = @_;
1830
1831   my $help = get_cmd_name();
1832   my ($pxe_config);
1833
1834   GetOptions(
1835      'bootp|b=s' => \$pxe_config,
1836      );
1837
1838   exit_on_error_option($help)
1839      if $pxe_config eq '';
1840
1841   my $computer_db = ipamdb_load($COMPUTER_YAML);
1842
1843   $computer_db->{'pxe'} ||= {};
1844   die "Error: PXE config does not exist: $pxe_config\n" if not exists $computer_db->{'pxe'}{$pxe_config};
1845
1846   # Test if some computer use this config
1847   LOOP_ON_SECTOR:
1848   for my $sector_current (keys %{$computer_db}) {
1849      next if $sector_current eq 'dset';
1850      next if $sector_current eq 'pool';
1851      next if $sector_current eq 'pxe';
1852      next if $sector_current eq 'tag';
1853      next if $sector_current eq 'version';
1854
1855      LOOP_ON_COMPUTER:
1856      for my $computer (@{$computer_db->{$sector_current}}) {
1857         my ($mac_address, $attribute) = %{$computer};
1858
1859         if (exists $attribute->{'pxe_config'}) {
1860            my $hostname = $attribute->{'hostname'};
1861            die "Error: computer still use this PXE config: $hostname.$sector_current $mac_address\n" if $pxe_config eq $attribute->{'pxe_config'};
1862            }
1863         }
1864      }
1865
1866   delete $computer_db->{'pxe'}{$pxe_config};
1867   ipamdb_save("$COMPUTER_YAML", $computer_db);
1868   }
1869
1870#--------------------------------------------------------------------------------
1871
1872sub cmd_show_pxe {
1873   local @ARGV = @_;
1874
1875   my ($no_header);
1876
1877   GetOptions(
1878      'no-header|H' => \$no_header,
1879      );
1880
1881   my $computer_db = ipamdb_load($COMPUTER_YAML);
1882
1883   printf "%-12s %-13s %-30s %s\n", 'PXE-Config', 'Next-Server', 'Filename', 'Comment' if not $no_header;
1884   LOOP_ON_PXE:
1885   for my $pxe_config ( keys %{$computer_db->{'pxe'}} ) {
1886      my $ip_next_server = $computer_db->{'pxe'}{$pxe_config}{'ip_next_server'};
1887      my $filename       = $computer_db->{'pxe'}{$pxe_config}{'filename'};
1888      my $comment        = $computer_db->{'pxe'}{$pxe_config}{'comment'};
1889
1890      printf "%-12s %-13s %-30s %s\n", $pxe_config, $ip_next_server, $filename, $comment;
1891      }
1892   }
1893
1894#-------------------------------------------------------------------------------
1895
1896sub cmd_enable_pxe {
1897   local @ARGV = @_;
1898
1899   my $help = get_cmd_name();
1900   my ($hostname, $sector, $ip, $pxe_config);
1901
1902   GetOptions(
1903      'hostname|h=s'    => \$hostname,
1904      'sector|s|d=s'    => \$sector,
1905      'ip|i=s'          => \$ip,
1906      'bootp|b=s'       => \$pxe_config,
1907      );
1908
1909   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
1910   exit_on_error_option($help)
1911      if $sector  eq ''
1912      or $pxe_config eq '';
1913   exit_on_error_option($help)
1914      if $hostname   eq ''
1915      and $ip        eq '';
1916   exit_on_error_option($help)
1917      if $hostname   ne ''
1918      and $ip        ne '';
1919
1920   my $computer_db = ipamdb_load($COMPUTER_YAML);
1921
1922   die "Error: PXE config not exists: $pxe_config\n" if not exists $computer_db->{'pxe'}{$pxe_config};
1923
1924   control_exist_sector($computer_db, $sector) or exit;
1925   if ($ip ne '') {
1926      control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";;
1927      if ( control_exist_ip($computer_db, $ip) == 1 ) {
1928         die "Error: unkown IP address: $ip\n";
1929         }
1930
1931      for my $sector_current (keys %{$computer_db}) {
1932         next if $sector_current eq 'dset';
1933         next if $sector_current eq 'pool';
1934         next if $sector_current eq 'pxe';
1935         next if $sector_current eq 'tag';
1936         next if $sector_current eq 'version';
1937
1938         LOOP_ON_COMPUTER:
1939         for my $computer (@{$computer_db->{$sector_current}}) {
1940            my ($mac_address, $attribute) = %{$computer};
1941            next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
1942
1943            $attribute->{'modify_time'} = time;
1944            $attribute->{'pxe_config'}  = $pxe_config;
1945            ipamdb_save("$COMPUTER_YAML", $computer_db);
1946            print "Info: host $attribute->{'hostname'} ($sector_current), IP $ip, PXE enabled: $pxe_config\n";
1947            exit;
1948            }
1949         }
1950      }
1951   else {
1952      if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
1953         die "Error: unkown host: $hostname, in sector: $sector\n";
1954         }
1955
1956      LOOP_ON_COMPUTER:
1957      for my $computer (@{$computer_db->{$sector}}) {
1958         my ($mac_address, $attribute) = %{$computer};
1959         next LOOP_ON_COMPUTER if $attribute->{'hostname'} ne $hostname;
1960         
1961         if ($attribute->{'address_type'} eq 'pool-dhcp') {
1962            die "Error. Host $hostname ($sector) in a pool. No PXE possible [FAILED]\n";
1963            }
1964
1965         $attribute->{'modify_time'} = time;
1966         $attribute->{'pxe_config'}  = $pxe_config;
1967         ipamdb_save("$COMPUTER_YAML", $computer_db);
1968         print "Info: host $hostname ($sector), IP $attribute->{'ip'}, PXE enabled: $pxe_config [OK]\n";
1969         exit;
1970         }
1971      }
1972   }
1973
1974#-------------------------------------------------------------------------------
1975
1976sub cmd_disable_pxe {
1977   local @ARGV = @_;
1978
1979   my $help = get_cmd_name();
1980   my ($hostname, $sector, $ip);
1981
1982   GetOptions(
1983      'hostname|h=s'    => \$hostname,
1984      'sector|s|d=s'    => \$sector,
1985      'ip|i=s'          => \$ip,
1986      );
1987
1988   ($hostname, $sector) = split /\./, $hostname, 2 if $hostname =~ m/\./;
1989   exit_on_error_option($help)
1990      if $sector  eq '';
1991   exit_on_error_option($help)
1992      if $hostname   eq ''
1993      and $ip        eq '';
1994   exit_on_error_option($help)
1995      if $hostname   ne ''
1996      and $ip        ne '';
1997
1998   my $computer_db = ipamdb_load($COMPUTER_YAML);
1999
2000   control_exist_sector($computer_db, $sector) or exit;
2001   if ($ip ne '') {
2002      control_syntax_ip($ip) or die "Error: bad IP syntax $ip\n";;
2003      if ( control_exist_ip($computer_db, $ip) == 1 ) {
2004         die "Error: unkown IP address: $ip\n";
2005         }
2006
2007      for my $sector_current (keys %{$computer_db}) {
2008         next if $sector_current eq 'dset';
2009         next if $sector_current eq 'pool';
2010         next if $sector_current eq 'pxe';
2011         next if $sector_current eq 'tag';
2012         next if $sector_current eq 'version';
2013
2014         LOOP_ON_COMPUTER:
2015         for my $computer (@{$computer_db->{$sector_current}}) {
2016            my ($mac_address, $attribute) = %{$computer};
2017           
2018            next LOOP_ON_COMPUTER if $attribute->{'ip'} ne $ip;
2019            next LOOP_ON_COMPUTER if not exists $attribute->{'pxe_config'};
2020
2021            my $pxe_config = $attribute->{'pxe_config'};
2022            $attribute->{'modify_time'} = time;
2023            delete $attribute->{'pxe_config'};
2024            ipamdb_save("$COMPUTER_YAML", $computer_db);
2025            print "Info: IP address: $ip, PXE disable from config: $pxe_config [OK]\n";
2026            exit;
2027            }
2028         }
2029      }
2030   else {
2031      if ( control_exist_hostname($computer_db, $sector, $hostname) == 1 ) {
2032         die "Error: unkown host: $hostname, in sector: $sector\n";
2033         }
2034
2035      LOOP_ON_COMPUTER:
2036      for my $computer (@{$computer_db->{$sector}}) {
2037         my ($mac_address, $attribute) = %{$computer};
2038
2039         next LOOP_ON_COMPUTER if $attribute->{'hostname'} eq $hostname;
2040
2041         if ($attribute->{'address_type'} eq 'pool-dhcp') {
2042            die "Error: host $hostname ($sector) in a pool. No PXE possible [FAILED]\n";
2043            }
2044
2045         next LOOP_ON_COMPUTER if not exists $attribute->{'pxe_config'};
2046
2047         my $pxe_config = $attribute->{'pxe_config'};
2048         $attribute->{'modify_time'} = time;
2049         delete $attribute->{'pxe_config'};
2050         ipamdb_save("$COMPUTER_YAML", $computer_db);
2051         print "Info: host $hostname ($sector), PXE disable from config: $pxe_config [OK]\n";
2052         exit;
2053         }
2054      }
2055   }
2056
2057#-------------------------------------------------------------------------------
2058# TAG section
2059#-------------------------------------------------------------------------------
2060
2061sub cmd_create_tag {
2062   local @ARGV = @_;
2063
2064   my $help = get_cmd_name();
2065   my ($tag, $comment);
2066
2067   GetOptions(
2068      'tag|t=s'      => \$tag,
2069      'comment|c=s'  => \$comment,
2070      );
2071
2072   exit_on_error_option($help)
2073      if $tag     eq ''
2074      or $comment eq '';
2075
2076   my $computer_db = ipamdb_load($COMPUTER_YAML);
2077
2078   $comment = normalize_comment($comment);
2079
2080   $computer_db->{'tag'} ||= {};
2081   die "Error: TAG already exists: $tag\n" if exists $computer_db->{'tag'}{$tag};
2082
2083   die "Error: TAG 'universal' is intrinsic. It's not possible to create it.\n" if $tag eq 'universal';
2084
2085   if ($tag !~ m/^ \w+ $/xms) {
2086      die "Error: bad format for TAG (alphanumeric string): $tag\n";
2087      }
2088
2089   control_syntax_comment($comment) or exit;
2090
2091   my $timestamp = time;
2092   $computer_db->{'tag'}{$tag} = {
2093      'comment'         => $comment,
2094      'create_time'     => $timestamp,
2095      'modify_time'     => $timestamp,
2096      };
2097   ipamdb_save("$COMPUTER_YAML", $computer_db);
2098   }
2099
2100#-------------------------------------------------------------------------------
2101
2102sub cmd_remove_tag {
2103   local @ARGV = @_;
2104
2105   my $help = get_cmd_name();
2106   my ($tag);
2107
2108   GetOptions(
2109      'tag|t=s' => \$tag,
2110      );
2111
2112   exit_on_error_option($help)
2113      if $tag eq '';
2114
2115   my $computer_db = ipamdb_load($COMPUTER_YAML);
2116
2117   $computer_db->{'tag'} ||= {};
2118   die "Error: TAG does not exist: $tag\n" if not exists $computer_db->{'tag'}{$tag};
2119
2120   # Test if some computer use this config
2121   LOOP_ON_SECTOR:
2122   for my $sector_current (keys %{$computer_db}) {
2123      next if $sector_current eq 'dset';
2124      next if $sector_current eq 'pool';
2125      next if $sector_current eq 'pxe';
2126      next if $sector_current eq 'tag';
2127      next if $sector_current eq 'version';
2128
2129      LOOP_ON_COMPUTER:
2130      for my $computer (@{$computer_db->{$sector_current}}) {
2131         my ($mac_address, $attribute) = %{$computer};
2132
2133         if (exists $attribute->{'tag'}) {
2134            my $hostname = $attribute->{'hostname'};
2135            die "Error: computer still use this TAG: $hostname.$sector_current $mac_address\n" if $tag eq $attribute->{'tag'};
2136            }
2137         }
2138      }
2139
2140   delete $computer_db->{'tag'}{$tag};
2141   ipamdb_save("$COMPUTER_YAML", $computer_db);
2142   }
2143
2144#--------------------------------------------------------------------------------
2145
2146sub cmd_show_tag {
2147   local @ARGV = @_;
2148
2149   my ($no_header);
2150
2151   GetOptions(
2152      'no-header|H' => \$no_header,
2153      );
2154
2155   my $computer_db = ipamdb_load($COMPUTER_YAML);
2156
2157   printf "%-12s %s\n", 'TAG', 'Comment' if not $no_header;
2158   LOOP_ON_TAG:
2159   for my $tag ( keys %{$computer_db->{'tag'}} ) {
2160      my $comment = $computer_db->{'tag'}{$tag}{'comment'};
2161
2162      printf "%-12s %s\n", $tag, $comment;
2163      }
2164   }
2165
2166#--------------------------------------------------------------------------------
2167# GLOBAL section
2168#--------------------------------------------------------------------------------
2169
2170sub cmd_upgrade_db {
2171   my $flag_change;
2172
2173   my $computer_db = ipamdb_load($COMPUTER_YAML);
2174
2175   LOOP_ON_SECTOR:
2176   for my $sector_current (keys %{$computer_db}) {
2177      next if $sector_current eq 'dset';
2178      next if $sector_current eq 'pool';
2179      next if $sector_current eq 'pxe';
2180      next if $sector_current eq 'tag';
2181      next if $sector_current eq 'version';
2182
2183      my @sectordb = @{$computer_db->{$sector_current}};
2184
2185      LOOP_ON_COMPUTER:
2186      for my $computer (@sectordb) {
2187         my ($mac_address, $attribute) = %{$computer};
2188         my $new_mac = normalize_mac_address($mac_address);
2189         print "perl -pi -e 's/$mac_address:/$new_mac:/' $COMPUTER_YAML\n" if "$mac_address" ne "$new_mac";
2190
2191         my $comment = $attribute->{'comment'};
2192         $comment =~ s/\s\s+/ /g and $flag_change++;
2193         $comment =~ s/^\s+\S//  and $flag_change++;
2194         $comment =~ s/\S\s+$//  and $flag_change++;
2195         $comment =~ s{^(\d\d\d\d)\/O(\d\/\d\d)}{$1/0$2} and $flag_change++;
2196         $comment =~ s{^(\d\d\d\d\/\d\d\/)O(\d)}{$1/0$2} and $flag_change++;
2197         $comment =~ s{^(\d\d\d\d)\/(\d\d)\/(\d\d)}{$1-$2-$3} and $flag_change++;
2198         if ($comment !~ m/^\d\d\d\d-\d\d-\d\d/) {
2199            print "# no date at beginning of comment $mac_address\n";
2200            }
2201
2202         $attribute->{'comment'} = $comment;
2203         }
2204      }
2205   print "# FLAG :$flag_change\n";
2206
2207   ipamdb_save("$COMPUTER_YAML", $computer_db) if $flag_change;
2208   }
2209
2210#--------------------------------------------------------------------------------
2211
2212sub cmd_show_sector {
2213   local @ARGV = @_;
2214
2215   my ($no_header);
2216
2217   GetOptions(
2218      'no-header|H' => \$no_header,
2219      );
2220
2221   my $computer_db = ipamdb_load($COMPUTER_YAML);
2222
2223   my $tb_computer = Text::Table->new(
2224     {align  => 'left',   align_title => 'left',   title => 'Sector'},
2225     {is_sep => 1,        body        => '  '},
2226     {align  => 'left',   align_title => 'left',   title => 'DNS-Extension'},
2227     {is_sep => 1,        body        => '  '},
2228     {align  => 'left',   align_title => 'left',   title => 'IP-Range'},
2229     {align  => 'left',   align_title => 'left',   title => 'Date'},
2230     {align  => 'left',   align_title => 'left',   title => 'Comment'},
2231     {align  => 'left',   align_title => 'left',   title => 'Category'},
2232     );
2233
2234   LOOP_ON_SECTOR:
2235   for my $sector_current (sort keys %{$computer_db}) {
2236      next if $sector_current eq 'dset';
2237      next if $sector_current eq 'pool';
2238      next if $sector_current eq 'pxe';
2239      next if $sector_current eq 'tag';
2240      next if $sector_current eq 'version';
2241
2242      $tb_computer->add($sector_current), next LOOP_ON_SECTOR if not exists $computer_db->{'dset'}{$sector_current};
2243
2244      my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $computer_db->{'dset'}{$sector_current}{'modify_time'};
2245      $year += 1900;
2246      $mon++;
2247      my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2248
2249      my $ip_range;
2250      $ip_range = join ',', @{$computer_db->{'dset'}{$sector_current}{'ip-range'}} if exists $computer_db->{'dset'}{$sector_current}{'ip-range'};
2251
2252      my $category;
2253      my $comment = $computer_db->{'dset'}{$sector_current}{'comment'};
2254      $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2255      $comment =~ s/\s+(\(\w+\))$// and $category = $1;
2256
2257      $tb_computer->add($sector_current,
2258         $computer_db->{'dset'}{$sector_current}{'dns_extension'},
2259         $ip_range,
2260         $date,
2261         $comment,
2262         $category,
2263         );
2264      }
2265
2266   print $tb_computer->title(),
2267         $tb_computer->rule('-') if not $no_header;
2268   print $tb_computer->body();
2269   }
2270
2271#--------------------------------------------------------------------------------
2272
2273sub cmd_search_mac {
2274   local @ARGV = @_;
2275
2276   my $help = get_cmd_name();
2277   my ($mac);
2278
2279   GetOptions(
2280      'mac|m=s' => \$mac,
2281      );
2282
2283   exit_on_error_option($help)
2284      if $mac eq '';
2285
2286   $mac = normalize_mac_address($mac);
2287
2288   my $computer_db = ipamdb_load($COMPUTER_YAML);
2289
2290   control_syntax_mac_address($mac) or exit;
2291
2292   LOOP_ON_SECTOR:
2293   for my $sector_current (keys %{$computer_db}) {
2294      next if $sector_current eq 'dset';
2295      next if $sector_current eq 'pool';
2296      next if $sector_current eq 'pxe';
2297      next if $sector_current eq 'tag';
2298      next if $sector_current eq 'version';
2299
2300      my @sectordb = @{$computer_db->{$sector_current}};
2301
2302      LOOP_ON_COMPUTER:
2303      for my $computer (@sectordb) {
2304         my ($mac_address, $attribute) = %{$computer};
2305
2306         next LOOP_ON_COMPUTER if $mac_address ne $mac;
2307
2308         my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $attribute->{'modify_time'};
2309         $year += 1900;
2310         $mon++;
2311         my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2312
2313         my $comment = $attribute->{'comment'};
2314         $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2315
2316         my $enable = $attribute->{'enabled'};
2317         if (exists $attribute->{'pxe_config'}) {
2318            $enable .= '/' . $attribute->{'pxe_config'};
2319            }
2320         if (exists $attribute->{'tag'}) {
2321            $enable .= ':' . $attribute->{'tag'};
2322            }
2323
2324         printf "%-30s  %-20s %17s %9s %3s %10s %s\n",
2325            $attribute->{'hostname'} . '.' . $sector_current,
2326            $attribute->{'ip'},
2327            $mac_address,
2328            $attribute->{'address_type'},
2329            $enable,
2330            $date,
2331            $comment;
2332         }
2333      }
2334   }
2335
2336#--------------------------------------------------------------------------------
2337#Nom: show
2338#Description: liste les machines à partir du fichier YAML par nom de domaine.
2339
2340sub cmd_show_host {
2341   my %ipdb = ();
2342
2343   my $computer_db = ipamdb_load($COMPUTER_YAML);
2344
2345   my $tb_computer = Text::Table->new(
2346     {align  => 'left',   align_title => 'left',   title => 'Hostname.Sector'},
2347     {is_sep => 1,        body        => '  '},
2348     {align  => 'left',   align_title => 'left',   title => 'IPv4-Address'},
2349     {is_sep => 1,        body        => '  '},
2350     {align  => 'center', align_title => 'center', title => 'MAC-Address'},
2351     {is_sep => 1,        body        => '  '},
2352     {align  => 'right',  align_title => 'right',  title => 'Type'},
2353     {align  => 'right',  align_title => 'right',  title => 'Status'},
2354     {is_sep => 1,        body        => '  '},
2355     {align  => 'left',   align_title => 'left',   title => 'Date'},
2356     {align  => 'left',   align_title => 'left',   title => 'Comment'},
2357     );
2358
2359  LOOP_ON_SECTOR:
2360   for my $sector_current (sort keys %{$computer_db}) {
2361      next if $sector_current eq 'dset';
2362      next if $sector_current eq 'pool';
2363      next if $sector_current eq 'pxe';
2364      next if $sector_current eq 'tag';
2365      next if $sector_current eq 'version';
2366
2367      my @sectordb = @{$computer_db->{$sector_current}};
2368
2369      LOOP_ON_COMPUTER:
2370      for my $computer (@sectordb) {
2371         my ($mac_address, $attribute) = %{$computer};
2372         my $ip = $attribute->{'ip'};
2373
2374         if ($ip =~ m/$DDT::RE::IPv4_ADDRESS/xms) {
2375            if ( not exists $ipdb{$ip} ) {
2376               $ipdb{$ip} = {
2377                  'mac_address'  => $mac_address,
2378                  %{$attribute},
2379                  'sector'    => $sector_current,
2380                  };
2381               }
2382            else {
2383               print {*STDERR} "# Warning: $ip already exists in the database with MAC $mac_address!\n";
2384               }
2385            next LOOP_ON_COMPUTER;
2386            }
2387
2388         my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $attribute->{'modify_time'};
2389         $year += 1900;
2390         $mon++;
2391         my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2392
2393         my $comment = normalize_comment($attribute->{'comment'});
2394         $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2395
2396         my $enable = $attribute->{'enabled'};
2397         if (exists $attribute->{'pxe_config'}) {
2398            $enable .= '/' . $attribute->{'pxe_config'};
2399            }
2400         if (exists $attribute->{'tag'}) {
2401            $enable .= ':' . $attribute->{'tag'};
2402            }
2403
2404         #printf "%-30s  %-20s %17s %9s %3s %10s %s\n",
2405         $tb_computer->add(
2406            $attribute->{'hostname'} . '.' . $sector_current,
2407            $ip,
2408            $mac_address,
2409            $attribute->{'address_type'},
2410            $enable,
2411            $date,
2412            $comment,
2413            );
2414         }
2415      #print "\n# *** List of pool computers in the sector: $sector_current ***\n";
2416      }
2417
2418   #print "\n# *** List of computers ordered by IP and sector ***\n";
2419   LOOP_ON_IP_ADDRESS:
2420   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %ipdb)) {
2421      my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $ipdb{$ip}->{'modify_time'};
2422      $year += 1900;
2423      $mon++;
2424      my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2425
2426      my $comment =$ipdb{$ip}->{'comment'};
2427      $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2428
2429      my $enable = $ipdb{$ip}->{'enabled'};
2430      if (exists $ipdb{$ip}->{'pxe_config'}) {
2431         $enable .= '/' . $ipdb{$ip}->{'pxe_config'};
2432         }
2433      if (exists $ipdb{$ip}->{'tag'}) {
2434         $enable .= ':' . $ipdb{$ip}->{'tag'};
2435         }
2436
2437      #printf "%-30s %-20s %17s %9s %3s %10s %s\n",
2438      $tb_computer->add(
2439         $ipdb{$ip}->{'hostname'} . '.' . $ipdb{$ip}->{'sector'},
2440         $ip,
2441         normalize_mac_address($ipdb{$ip}->{'mac_address'}),
2442         $ipdb{$ip}->{'address_type'},
2443         $enable,
2444         $date,
2445         $comment
2446         );
2447      }
2448
2449   print $tb_computer->title();
2450   print $tb_computer->rule('-');
2451   print $tb_computer->body();
2452   }
2453
2454#-------------------------------------------------------------------------------
2455#Nom: cmd_generate_dhcp_file
2456#Description: génère les fichiers de configuration des machines et des pools du dhcp
2457
2458sub cmd_generate_dhcp_file {
2459   backup_database();
2460
2461   my $computer_db = ipamdb_load($COMPUTER_YAML);
2462
2463   my %file_pool;
2464
2465   for my $sector_current (keys %{$computer_db}) {
2466      next if $sector_current eq 'dset';
2467      next if $sector_current eq 'pool';
2468      next if $sector_current eq 'pxe';
2469      next if $sector_current eq 'tag';
2470      next if $sector_current eq 'version';
2471
2472      open FILE_VLAN, '>', "$FOLDER_GEN_DHCP/$sector_current";
2473      my @sectordb = @{$computer_db->{$sector_current}};
2474      for my $value (@sectordb) {
2475         ALL_MAC_ADDRESS:
2476         for my $mac_addres (keys %{$value}) {
2477            #host pcdavoust {  deny-unknown-clients;
2478            #hardware ethernet 0:6:5b:b8:13:d1;
2479            #fixed-address 194.254.66.72;
2480            #}
2481
2482            my $hostname     = $value->{$mac_addres}{'hostname'};
2483            my $ip           = $value->{$mac_addres}{'ip'};
2484            my $comment      = $value->{$mac_addres}{'comment'};
2485            my $address_type = $value->{$mac_addres}{'address_type'};
2486            my $enabled      = $value->{$mac_addres}{'enabled'};
2487            my $tags         = $value->{$mac_addres}{'tag'} || 'universal';
2488
2489            my $buffer;
2490            if ($address_type eq 'dhcp') {
2491               if ($enabled eq 'yes') {
2492                  $buffer  = "host $hostname {\n"; # deny-unknown-clients;
2493                  $buffer .= "   hardware ethernet $mac_addres;\n";
2494                  $buffer .= "   fixed-address $ip;\n";
2495
2496                  if (exists $value->{$mac_addres}{'pxe_config'}) {
2497                     my $pxe_config     = $value->{$mac_addres}{'pxe_config'};
2498                     my $ip_next_server = $computer_db->{'pxe'}{$pxe_config}{'ip_next_server'};
2499                     my $filename       = $computer_db->{'pxe'}{$pxe_config}{'filename'};
2500                     $buffer .= "   next-server $ip_next_server;\n";
2501                     $buffer .= "   filename \"$filename\";\n";
2502                     }
2503                  $buffer .= "   #comment: $comment\n";
2504                  $buffer .= "   }\n";
2505                  $buffer .= "\n";
2506
2507                  for my $tag (split/,/, $tags) {
2508                     $file_pool{"tag-$tag"} ||= [];
2509                     push @{$file_pool{"tag-$tag"}}, "subclass \"tag-$tag\" 1:$mac_addres; # $comment\n";
2510                     }
2511                  }
2512               else {
2513                  $buffer  = "#host $hostname {\n"; # deny-unknown-clients;
2514                  $buffer .= "#   hardware ethernet $mac_addres;\n";
2515                  $buffer .= "#   fixed-address $ip;\n";
2516                  $buffer .= "#   comment: $comment \n";
2517                  $buffer .= "#   }\n";
2518                  $buffer .= "\n";
2519                  }
2520               print FILE_VLAN $buffer;
2521               }
2522            elsif ($address_type eq 'pool-dhcp') {
2523               #--- Génère les fichiers pool dhcp ---#
2524               for my $current_pool (keys %{$computer_db->{'pool'}}) {
2525                  next if $current_pool ne $ip;
2526
2527                  if ($enabled eq 'yes') {
2528                     $buffer = "subclass \"$current_pool\" 1:$mac_addres; # $comment\n";
2529
2530                     for my $tag (split/,/, $tags) {
2531                        $file_pool{"tag-$tag"} ||= [];
2532                        push @{$file_pool{"tag-$tag"}}, "subclass \"tag-$tag\" 1:$mac_addres; # $comment\n";
2533                        }
2534                     }
2535                  else {
2536                     $buffer = "#subclass \"$current_pool\" 1:$mac_addres; # $comment\n";
2537                     }
2538
2539                  my $current_pool_file_name = $computer_db->{'pool'}{$current_pool}{'file'};
2540
2541                  $file_pool{$current_pool_file_name} ||= [];
2542                  push @{$file_pool{$current_pool_file_name}}, $buffer;
2543                  }
2544               }
2545            }
2546         }
2547
2548      close FILE_VLAN;
2549
2550      for my $file_name (keys %file_pool) {
2551         open FILE_POOL, '>', "$FOLDER_GEN_DHCP/$file_name";
2552         print FILE_POOL @{$file_pool{$file_name}};
2553         close FILE_POOL;
2554         }
2555      }
2556      print "Copy DHCP files from $FOLDER_GEN_DHCP to /etc/dhcp/include/\n";
2557      exec $SCRIPT_UPDATE;
2558   }
2559
2560#-------------------------------------------------------------------------------
2561#Nom: cmd_generate_dns_file
2562#Description: génère les fichiers d'enregistrements DNS
2563
2564sub cmd_generate_dns_file {
2565   local @ARGV = @_;
2566
2567   my $help = get_cmd_name();
2568   my ($verbose);
2569
2570   GetOptions(
2571      'verbose|v' => \$verbose,
2572      );
2573
2574   my $buffer_fwd;
2575   my $buffer_rev;
2576   my $pool_domain;
2577
2578   my $computer_db = ipamdb_load($COMPUTER_YAML);
2579
2580   for my $sector_current (keys %{$computer_db}) {
2581      next if $sector_current eq 'dset';
2582      next if $sector_current eq 'pool';
2583      next if $sector_current eq 'pxe';
2584      next if $sector_current eq 'tag';
2585      next if $sector_current eq 'version';
2586
2587      if ($sector_current eq 'pool') {
2588         LOOP_ON_COMPUTER:
2589         for my $computer (@{$computer_db->{$sector_current}}) {
2590            for my $pool_name (keys %{$computer}) {
2591               $pool_domain = $computer->{$pool_name}->{'domain'}."\n";
2592               #print $computer->{$pool_name}->{'file'};
2593               chomp $pool_domain;
2594               open FILE_FORWARD_DNS, '>>', "$FOLDER_GEN_DNS/db.$pool_domain.fwd";
2595               open FILE_REVERSE_DNS, '>>', "$FOLDER_GEN_DNS/db.$pool_domain.rev";
2596               my @T_pool_ip = @{$computer->{$pool_name}->{'ip'}};
2597               for my $pool_ip (@T_pool_ip) {
2598                  my @T_split = split(/\./ , $pool_ip);
2599                  $buffer_fwd = sprintf "%-24s IN  A  %-15s ;\n", "$pool_name$T_split[3]", $pool_ip;
2600                  $buffer_rev = "$T_split[3]   IN PTR   $pool_name$T_split[3].$pool_domain.\n";
2601                  print FILE_FORWARD_DNS $buffer_fwd;
2602                  print FILE_REVERSE_DNS $buffer_rev;
2603                  }
2604               close FILE_FORWARD_DNS;
2605               close FILE_REVERSE_DNS;
2606               }
2607            }
2608         }
2609
2610      else {
2611         #--- Création du fichier non-reverse ---#
2612         open FILE_FORWARD_DNS, ">> $FOLDER_GEN_DNS/db.$sector_current.fwd";
2613         open FILE_REVERSE_DNS, ">> $FOLDER_GEN_DNS/db.$sector_current.rev";
2614
2615         my @sectordb = @{$computer_db->{$sector_current}};
2616
2617         LOOP_ON_COMPUTER:
2618         for my $computer (@sectordb) {
2619            my ($mac_address, $attribute) = %{$computer};
2620
2621            #host pcdavoust {  deny-unknown-clients;
2622            #hardware ethernet 0:6:5b:b8:13:d1;
2623            #fixed-address 194.254.66.72;
2624            #}
2625
2626            my $hostname     = $attribute->{'hostname'};
2627            my $ip           = $attribute->{'ip'};
2628            my $comment      = $attribute->{'comment'};
2629            my $address_type = $attribute->{'address_type'};
2630            my $enabled      = $attribute->{'enabled'};
2631
2632            next LOOP_ON_COMPUTER if not (($address_type eq 'dhcp') or ($address_type eq 'static'));
2633
2634            my $dns_domain = $sector_current;
2635            if (exists $computer_db->{'dset'}{$sector_current}) {
2636               $dns_domain = $computer_db->{'dset'}{$sector_current}{'dns_extension'};
2637               }
2638
2639            my @ip_split = split /\./, $ip;
2640            if ($enabled eq 'yes') {
2641               if (exists $attribute->{'dns_extension'}
2642                     and "$attribute->{'dns_extension'}" != "$dns_domain") {
2643                  print "A FAIRE\n";
2644                  }
2645               $buffer_fwd = sprintf "%-24s  IN A   %-15s ; %s\n", $hostname, $ip, $comment;
2646               $buffer_rev = sprintf "%3i    IN PTR %-15s\n", $ip_split[3], "$hostname.$dns_domain.";
2647               }
2648
2649            else {
2650               $buffer_fwd = sprintf ";%-24s IN A   %-15s ; %s\n", $hostname, $ip, $comment;
2651               $buffer_rev = sprintf ";%3i   IN PTR %-15s\n", $ip_split[3], "$hostname.$dns_domain.";
2652               }
2653            print FILE_REVERSE_DNS $buffer_rev;
2654            print FILE_FORWARD_DNS $buffer_fwd;
2655            }
2656         close FILE_REVERSE_DNS;
2657         close FILE_FORWARD_DNS;
2658         print "- DNS: db.$sector_current.fwd db.$sector_current.rev [CREATE].\n" if $verbose;
2659         print "  Ex : sort -k 4n -t . $FOLDER_GEN_DNS/db.$sector_current.fwd\n"     if $verbose;
2660         }
2661      }
2662   }
2663
2664#--------------------------------------------------------------------------------
2665
2666sub shell_command {
2667   my $cmd = shift;
2668
2669   require FileHandle;
2670   my $fh     = new FileHandle;
2671   my @result = ();
2672   open $fh, q{-|}, "LANG=C $cmd" or die "Can't exec $cmd\n";
2673   @result = <$fh>;
2674   close $fh;
2675   chomp @result;
2676   return @result;
2677   }
2678
2679#--------------------------------------------------------------------------------
2680
2681sub cmd_check_dns {
2682   local @ARGV = @_;
2683
2684   my $help = get_cmd_name();
2685   my ($opt_direct, $opt_reverse);
2686
2687   GetOptions(
2688      'direct|d'  => \$opt_direct,
2689      'reverse|r' => \$opt_reverse,
2690      );
2691
2692   my $computer_db = ipamdb_load($COMPUTER_YAML);
2693
2694   if ($opt_direct or not $opt_reverse) { # DDT to DNS check
2695      LOOP_ON_SECTOR:
2696      for my $sector_current (keys %{$computer_db}) {
2697         next if $sector_current eq 'dset';
2698         next if $sector_current eq 'pool';
2699         next if $sector_current eq 'pxe';
2700         next if $sector_current eq 'tag';
2701         next if $sector_current eq 'version';
2702
2703         my @sectordb = @{$computer_db->{$sector_current}};
2704
2705         LOOP_ON_COMPUTER:
2706         for my $computer (@sectordb) {
2707            my ($mac_address, $attribute) = %{$computer};
2708            #my $new_mac = normalize_mac_address($mac_address);
2709            my $ip = $attribute->{'ip'};
2710            next LOOP_ON_COMPUTER if not $ip =~ m/$DDT::RE::IPv4_ADDRESS/xms;
2711            next LOOP_ON_COMPUTER if $attribute->{'enabled'} eq 'no';
2712
2713            my $dns_hostname_fq = scalar gethostbyaddr(inet_aton($ip), AF_INET);
2714            my ($dns_hostname) = split /\./, $dns_hostname_fq;
2715
2716            if ($attribute->{'hostname'} ne $dns_hostname) {
2717               print "$mac_address ($sector_current) $ip - $dns_hostname / $attribute->{'hostname'} # $attribute->{'comment'}\n";
2718               next LOOP_ON_COMPUTER;
2719               }
2720
2721            my $packed_ip = scalar gethostbyname($dns_hostname_fq);
2722            if (defined $packed_ip) {
2723               my $ip_address = inet_ntoa($packed_ip);
2724               if ($ip ne $ip_address) {
2725                  print "Error: bad IP for reverse DNS on $dns_hostname_fq / $ip\n";
2726                  next LOOP_ON_COMPUTER;
2727                  }
2728               }
2729            }
2730         }
2731      }
2732
2733   if ($opt_reverse) {  # DNS to DDT check
2734      my %saw; # count for unique member
2735      my @dns_domain_list = sort grep !$saw{$_}++,
2736         map $computer_db->{'dset'}{$_}{'dns_extension'},
2737         grep exists($computer_db->{'dset'}{$_}{'dns_extension'}),
2738         keys $computer_db->{'dset'};
2739      LOOP_ON_DNS:
2740      for my $dns (@dns_domain_list) {
2741         LOOP_ON_IP:
2742         for (shell_command("host -t A -l $dns")) {
2743            # smtp2.legi.grenoble-inp.fr has address 194.254.67.37
2744            next if not m/has address/;
2745            next if not m/^(\w[\w-_\.]+\w)\s+has\saddress\s+(\d[\d\.]+\d)$/;
2746            my ($hostname_fq, $ip) = ($1, $2);
2747            control_syntax_ip($ip) or next LOOP_ON_IP;
2748            if (control_exist_ip($computer_db, $ip) == 1) {
2749               printf "Unkown IP: %-15s / %s\n", $ip, $hostname_fq;
2750               next LOOP_ON_IP;
2751               }
2752            }
2753         }
2754      }
2755   }
2756
2757#-------------------------------------------------------------------------------
2758#Nom: load_data_dhcp
2759#Description: permet de charger le fichier de données YAML via les fichiers de configuration
2760#             machines.
2761#            ATTENTION: LES COMMENTAIRES DU FICHIER DISPARAITRONT.
2762
2763sub load_data_dhcp {
2764   my ($sector, $input_file) = @_;
2765
2766   my $computer_db = ipamdb_load($COMPUTER_YAML);
2767
2768   my @T_mac;
2769   my @T_host;
2770   my @T_ip;
2771   my $cpt;
2772   open (FILE, "<$input_file");
2773   my @buffer = <FILE>;
2774   close(FILE);
2775
2776   LINE:
2777   for my $ligne (@buffer) {
2778      #--
2779      $ligne =~ s/#.*$//;
2780      $ligne =~ s/\s+/ /;
2781      $ligne =~ s/^\s+//;
2782      next if $ligne eq '';
2783
2784      if ($ligne =~ /^host /) {
2785         $cpt=0;
2786         my @T_split = split(/host\s+/, $ligne);
2787         @T_host = split(/ /, $T_split[1]);
2788         chomp($T_host[0]);
2789
2790         $cpt++;
2791         }
2792
2793      if ($ligne =~ /^*ethernet /) {
2794         $ligne =~ s/;//g;
2795         @T_mac = split(/ethernet\s+/, $ligne);
2796         chomp($T_mac[1]);
2797         $cpt++;
2798         }
2799
2800      if ($ligne =~ /^*address /) {
2801         $ligne =~ s/;//g;
2802         @T_ip = split(/address\s+/, $ligne);
2803         chomp($T_ip[1]);
2804
2805         $cpt++;
2806         }
2807
2808      if ($cpt == 3) {
2809         #   print "MAC $T_mac[1] HOST $T_host[0] IP $T_ip[1].\n";
2810         my $mac = $T_mac[1];
2811         my $hostname = $T_host[0];
2812         my $ip = $T_ip[1];
2813         $cpt = 0;
2814
2815         if ( control_exist_hostname($computer_db, $sector, $hostname) == 0 ) {
2816            print "Error: host already exist in sector $sector: $hostname\n";
2817            next LINE;
2818            }
2819         control_syntax_mac_address($mac) or next LINE;
2820         if ( control_exist_mac($computer_db, $mac) == 0) {
2821            print "Error: physical MAC address already exists: $mac\n";
2822            next LINE;
2823            }
2824
2825         control_syntax_ip($ip) or next LINE;
2826         if ( control_exist_ip($computer_db, $ip) == 0 ) {
2827            print "Error: IP address already exists: $ip\n";
2828            next LINE;
2829            }
2830         my $timestamp = time;
2831         push @{$computer_db->{$sector}}, { $mac => {
2832            'hostname'     => $hostname,
2833            'ip'           => $ip,
2834            'address_type' => 'dhcp',
2835            'enabled'      => 'yes',
2836            'create_time'  => $timestamp,
2837            'modify_time'  => $timestamp,
2838            'alias'        =>  '',
2839            }};
2840         }
2841      }
2842   }
2843
2844#-------------------------------------------------------------------------------
2845#Nom: load_data_pool
2846#Description: permet de charger le fichier YAML via les fichiers de conf 'pool' du dhcp.
2847
2848sub load_data_pool {
2849   my ($sector, $input_file) = @_;
2850
2851   my @T_mac;
2852
2853   open (FILE, "<$input_file");
2854   my @buffer = <FILE>;
2855   close(FILE);
2856
2857   my $computer_db = ipamdb_load($COMPUTER_YAML);
2858
2859   for my $ligne (@buffer) {
2860      #--
2861      $ligne =~ s/#.*$//;
2862      $ligne =~ s/\s+/ /;
2863      $ligne =~ s/^\s+//;
2864      $ligne =~ s/;//g;
2865      $ligne =~ s/"//g;
2866      next if $ligne eq '';
2867
2868      if (($ligne =~ /^subclass/)) {
2869         my @T_split = split(/ / ,$ligne);
2870         my $pool = $T_split[1];
2871
2872         @T_mac = split(/:/ , $T_split[2]);
2873         my $mac = $T_mac[1].":".$T_mac[2].":".$T_mac[3].":".$T_mac[4].":".$T_mac[5].":".$T_mac[6];
2874         control_syntax_mac_address($mac) or next;
2875         if (control_exist_mac($computer_db, $mac) == 0) {
2876            print "Error: physical MAC address already exists: $mac\n";
2877            next;
2878            }
2879
2880         #--- cette partie teste si le pool existe.
2881         if (not exists $computer_db->{'pool'}{$pool}) {
2882            print "Error: create pool with create_pool command before load database: $pool\n";
2883            exit;
2884            }
2885
2886         if ($computer_db->{'pool'}{'domain'} eq $sector) {
2887            my $timestamp = time;
2888            push @{$computer_db->{$sector}}, { $mac => {
2889               'hostname'     => $pool,
2890               'ip'           => $pool,
2891               'address_type' => 'pool-dhcp',
2892               'enabled'      => 'yes',
2893               'create_time'  => $timestamp,
2894               'modify_time'  => $timestamp,
2895               }};
2896            }
2897         else {
2898            print "Ajout de la machine $mac [FAILED]\n";
2899            print "Error: the pool doesn't exists: $pool, for the domain: $sector\n";
2900            }
2901         }
2902      }
2903   }
2904
2905#-------------------------------------------------------------------------------
2906
2907sub load_data_file {
2908   my ($sector, $input_file, $type_file) = @_;
2909
2910   my $computer_db = ipamdb_load($COMPUTER_YAML);
2911
2912   #$computer_db
2913   if ($type_file eq 'dhcp') {
2914      load_data_dhcp($sector, $input_file);
2915      }
2916
2917   elsif ($type_file eq 'pool-dhcp') {
2918      load_data_pool($sector, $input_file);
2919      }
2920
2921   ipamdb_save("$COMPUTER_YAML", $computer_db);
2922   }
2923
2924#-------------------------------------------------------------------------------
2925
2926sub cmd_load_database {
2927   local @ARGV = @_;
2928
2929   my $help = get_cmd_name();
2930   my ($sector, $input_file, $type_file);
2931
2932   GetOptions(
2933      'sector|s|d=s'    => \$sector,
2934      'filename|f=s'    => \$input_file,
2935      'kind|k=s'        => \$type_file,
2936      );
2937
2938   exit_on_error_option($help)
2939      if $sector  eq ''
2940      or $input_file eq ''
2941      or $type_file  eq '';
2942
2943   load_data_file($sector, $input_file, $type_file);
2944   }
2945
2946#-------------------------------------------------------------------------------
2947#Nom: backup_database
2948#Description: sauvegarde et réinitialise les fichiers d'enregistrements DHCP.
2949
2950sub backup_database {
2951   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime time;
2952   $year += 1900;
2953   $mon++;
2954   my $date = sprintf '%04i-%02i-%02i-%02i-%02i-%02i', $year, $mon, $mday, $hour, $min, $sec;
2955
2956   copy($COMPUTER_YAML, "$FOLDER_BACKUP/$COMPUTER_BASENAME-$date.conf") or die "Error: database copy backup failed: $!\n";
2957   }
2958
2959#-------------------------------------------------------------------------------
2960# HELP section
2961#-------------------------------------------------------------------------------
2962
2963#-------------------------------------------------------------------------------
2964#Nom: exit_on_error_option
2965#Description: messages d'aide des options pour les différentes commandes
2966
2967sub exit_on_error_option {
2968  my ($command) = @_;
2969
2970   if ($command eq 'add-dhcp') {
2971      print "List of options for command: $command\n";
2972      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
2973      print " -h : computer hostname (mandatory if option -i != 'pool'). Example: -h info8pc154\n";
2974      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A\n";
2975      print " -i : internet IP address (mandatory). Possible value: classical IP address or the keyword 'pool'\n";
2976      print " -p : name of the DHCP pool to which the machine belongs (mandatory if option -i == 'pool')\n";
2977      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
2978      print "Example:\n";
2979      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";
2980      }
2981
2982   elsif ($command eq 'add-float') {
2983      print "List of options for command: $command\n";
2984      print " -s : sector attachment (mandatory)\n";
2985      print " -p : name of the DHCP pool to which the machine belongs (mandatory)\n";
2986      print " -m : physical MAC address (mandatory)\n";
2987      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
2988      print "Example:\n";
2989      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";
2990      }
2991
2992   elsif ($command eq 'add-static') {
2993      print "List of options for command: $command\n";
2994      print " -s : sector attachment (mandatory)\n";
2995      print " -i : internet IP address (mandatory)\n";
2996      print " -h : computer hostname (mandatory)\n";
2997      print " -m : physical MAC address (mandatory)\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-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";
3001      }
3002
3003   elsif ($command eq 'add-virtual') {
3004      print "List of options for command: $command\n";
3005      print " -s : sector attachment (mandatory)\n";
3006      print " -i : internet IP address (mandatory)\n";
3007      print " -h : computer hostname (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-virtual -h legipc1 -s legi-sector03 -i 192.168.10.1 -c '2013-09-25 Dell OptiPlex 745 - Eric Goncalves (NRJ)\n";
3011      }
3012
3013   elsif ($command eq 'add-alias') {
3014      print "List of options for command: $command\n";
3015      print " -s : sector attachment (mandatory)\n";
3016      print " -h : computer hostname (mandatory)\n";
3017      print " -a : computer alias name (mandatory)\n";
3018      }
3019
3020   elsif ($command eq 'create-sector') {
3021      print "List of options for command: $command\n";
3022      print " -s : new sector (mandatory)\n";
3023      print " -e : DNS domain name extension( mandatory). Example legi.grenoble-inp.fr\n";
3024      print " -c : comment (mandatory). Example: 2016-08-22 VLAN legi-261 (INFO)\n";
3025      print "Examples:\n";
3026      print " ddt create-sector -s legi-sector03 -e legi.grenoble-inp.fr -c '2016-08-22 VLAN legi-261 (INFO)'\n";
3027      }
3028
3029   elsif ($command eq 'create-pool') {
3030      print "List of options for command: $command\n";
3031      print " -p : name of the DHCP pool. Example: pool-legi-priv\n";
3032      print " -s : sector attachment for the pool. (sector attachment must exist in file $COMPUTER_BASENAME.conf). Example: legi-sector03\n";
3033      print " -f : configuration filename on the DHCP server for the pool\n";
3034      print " -i : adresse(s) IP ou plage d'IP. Séparateur d'adresses IP: ','. Séparateur de plage '-'\n";
3035      print "Examples:\n";
3036      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";
3037      print " ddt create-pool -p legi-pool2 -s legi-sector03 -f legi-pool-public  -i 192.168.10.1-192.168.10.4\n";
3038      }
3039
3040   elsif ($command eq 'create-pxe') {
3041      print "List of options for command: $command\n";
3042      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3043      print " -n : internet IP address for the DHCP next-server.\n";
3044      print " -f : filename on TFTP server to load at boot\n";
3045      print " -c : comment (mandatory). Example: 2014-04-07 PXE Boot for CentOS (MOST)\n";
3046      }
3047
3048   elsif ($command eq 'remove-pxe') {
3049      print "List of options for command: $command\n";
3050      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3051      }
3052
3053   elsif ($command eq 'enable-pxe') {
3054      print "List of options for command: $command\n";
3055      print " -h : computer hostname (mandatory unless option -i)\n";
3056      print " -i : internet IP address (mandatory unless option -h)\n";
3057      print " -s : sector attachment (mandatory if option -h)\n";
3058      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3059      }
3060
3061   elsif ($command eq 'disable-pxe') {
3062      print "List of options for command: $command\n";
3063      print " -h : computer hostname (mandatory unless option -i)\n";
3064      print " -i : internet IP address (mandatory unless option -h)\n";
3065      print " -s : sector attachment (mandatory if option -h)\n";
3066      }
3067
3068   elsif ($command eq 'create-tag') {
3069      print "List of options for command: $command\n";
3070      print " -t : name of the TAG (mandatory). Example: restricted\n";
3071      print " -c : comment (mandatory). Example: 2014-04-07 tag restricted (INFO)\n";
3072      print "tag 'universal' is intrinsic\n";
3073      }
3074
3075   elsif ($command eq 'remove-tag') {
3076      print "List of options for command: $command\n";
3077      print " -b : name of the TAG. Example: restricted\n";
3078      }
3079
3080   elsif ($command eq 'change-mac') {
3081      print "List of options for command: $command\n";
3082      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3083      print " -h : computer hostname (mandatory unless option -i)\n";
3084      print " -i : internet IP address (mandatory unless option -h). Possible value: classical IP address or the keyword 'pool'\n";
3085      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3086      }
3087
3088   elsif ($command eq 'change-ip') {
3089      print "List of options for command: $command\n";
3090      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3091      print " -h : computer hostname (mandatory)\n";
3092      print " -i : new internet IP address (mandatory). Possible value: classical IP address\n";
3093      }
3094
3095   elsif ($command eq 'change-host') {
3096      print "List of options for command: $command\n";
3097      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3098      print " -i : internet IP address (mandatory). Possible value: classical IP address\n";
3099      print " -h : new computer hostname (mandatory)\n";
3100      print "It's not possible to change hostname for computer that belongs to a pool\n";
3101      }
3102
3103   elsif ($command eq 'change-comment') {
3104      print "List of options for command: $command\n";
3105      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3106      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3107      print " -c : new comment (mandatory)\n";
3108      }
3109
3110   elsif ($command eq 'change-sector') {
3111      print "List of options for command: $command\n";
3112      print " -s : new sector attachment (mandatory). Example: -s legi-sector03\n";
3113      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3114      print " -i : internet IP address (mandatory)\n";
3115      }
3116
3117   elsif ($command eq 'change-tag') {
3118      print "List of options for command: $command\n";
3119      print " -h : computer hostname (mandatory unless option -i or -m)\n";
3120      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3121      print " -i : internet IP address (mandatory unless option -h or -m)\n";
3122      print " -m : physical MAC address (mandatory unless option -h or -i, priority). Example: -m 0F:58:AB:2A:22:11\n";
3123      print " -t : list of tags separated by comma (mandatory). Example: -t internal,windows\n";
3124      }
3125
3126   elsif ($command eq 'load-database') {
3127      print "List of options for command: $command\n";
3128      print " -s : sector attachment\n";
3129      print " -f : input file in DHCP format\n";
3130      print " -k : possible cases (kind): dhcp, pool-dhcp, fix-address\n";
3131      }
3132
3133   elsif ($command eq 'enable-pc') {
3134      print "List of options for command: $command\n";
3135      print " -h : computer hostname (mandatory unless option -i)\n";
3136      print " -i : internet IP address (mandatory unless option -h)\n";
3137      print " -s : sector attachment (mandatory if option -h)\n";
3138      print "Examples:\n";
3139      print " ddt enable-pc -i 192.168.10.1\n";
3140      print " ddt enable-pc -s legi-sector03 -h kevinpc\n";
3141      }
3142
3143   elsif ($command eq 'enable-float') {
3144      print "List of options for command: $command\n";
3145      print " -m : physical MAC address (mandatory)\n";
3146      print " -p : name of the DHCP pool (mandatory)\n";
3147      }
3148
3149   elsif ($command eq 'disable-float') {
3150      print "List of options for command: $command\n";
3151      print " -m : physical MAC address (mandatory)\n";
3152      print " -p : name of the DHCP pool (mandatory)\n";
3153      }
3154
3155   elsif ($command eq 'disable-pc') {
3156      print "List of options for command: $command\n";
3157      print " -h : computer hostname (mandatory unless option -i)\n";
3158      print " -i : internet IP address (mandatory unless option -h)\n";
3159      print " -s : sector attachment (mandatory if option -h)\n";
3160      print "Examples:\n";
3161      print " ddt disable-pc -i 192.168.10.1\n";
3162      print " ddt disable-pc -s legi-sector03 -h kevinpc\n";
3163      }
3164
3165   elsif ($command eq 'del-pc') {
3166      print "List of options for command: $command\n";
3167      print " -s : sector attachment (mandatory)\n";
3168      print " -h : computer hostname (mandatory unless option -i)\n";
3169      print " -i : internet IP address (mandatory unless option -h)\n";
3170      }
3171
3172   elsif ($command eq 'del-float') {
3173      print "List of options for command: $command\n";
3174      print " -m : physical MAC address (mandatory)l\n";
3175      print " -p : name of the DHCP pool\n";
3176      }
3177
3178   elsif ($command eq 'search-mac') {
3179      print "List of options for command: $command\n";
3180      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3181      }
3182
3183   elsif ($command eq 'sector-add-ip') {
3184      print "List of options for command: $command\n";
3185      print " -s : sector attachment (mandatory)\n";
3186      print " -i : internet IP range address in CIDR notation (mandatory)\n";
3187      }
3188
3189   else {
3190      print "No help for command: $command\n";
3191      }
3192   exit;
3193   }
3194
3195#-------------------------------------------------------------------------------
3196
3197sub cmd_version {
3198
3199   print <<'END';
3200ddt - management of computer names and IP addresses
3201Copyright (C) 2006-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
3202Main author Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>
3203License GNU GPL version 2 or later and Perl equivalent
3204END
3205
3206   print "Database Version 1\n";
3207   print "Version $VERSION\n\n";
3208   print ' $Id: ddt 357 2018-09-14 09:58:01Z g7moreau $'."\n";
3209   return;
3210   }
3211
3212#-------------------------------------------------------------------------------
3213#Nom: usage
3214#Description: message d'aide sur les commandes du script
3215
3216sub cmd_help {
3217   print <<END;
3218ddt - management of computer names and IP addresses
3219
3220 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3221 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3222 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3223 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3224 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3225 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3226 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3227 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3228 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3229 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3230 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3231 ddt check-dns [--direct] [--reverse]
3232 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3233 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3234 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3235 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3236 ddt del-float [--pool|-p pool] [--mac|-m mac]
3237 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3238 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3239 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3240 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3241 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3242 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3243 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3244 ddt gen-dhcp-file
3245 ddt gen-dns-file [--verbose]
3246 ddt help
3247 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3248 ddt remove-pxe [--bootp|-b pxe_config]
3249 ddt remove-tag [--tag|-t tag]
3250 ddt search-mac [--mac|-m mac]
3251 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3252 ddt show-sector [--no-header|-H]
3253 ddt show
3254 ddt show-pool [--no-header|-H]
3255 ddt show-pxe [--no-header|-H]
3256 ddt show-tag [--no-header|-H]
3257 ddt version
3258
3259COMMANDS
3260
3261 * add-alias         : add an alias for a computer (like CNAME for the DNS)
3262 * add-dhcp          : add a computer with a fix DHCP IP or in a DHCP pool
3263 * add-float         : add a computer with an IP in a DHCP pool
3264 * add-static        : add a computer with a static IP
3265 * add-virtual       : add a virtual computer with a static IP but a virtual MAC (useful to declare float computer in DNS)
3266 * change-comment    : change the computer comment
3267 * change-sector     : change the sector attachment for a computer
3268 * change-host       : change the computer hostname
3269 * change-ip         : change the computer IP address
3270 * change-mac        : change the computer physical MAC address
3271 * change-tag        : change the list of TAGs associated to a computer
3272 * check-dns         : check the DNS table for base IPs
3273 * create-sector     : create a new sector
3274 * create-pool       : create a new pool for DHCP records
3275 * create-pxe        : create a new PXE/BOOTP configuration
3276 * create-tag        : create a new TAG
3277 * del-float         : remove a computer from a DHCP pool
3278 * del-pc            : remove a computer (DHCP or static IP) from the YAML database
3279 * disable-pc        : disable a computer (DHCP and/or DNS) (but keep it in the database)
3280 * disable-float     : disable a computer from a DHCP pool (but keep it in the database)
3281 * disable-pxe       : remove PXE/BOOTP configuration on a computer
3282 * enable-float      : enable a previous disable computer (DHCP and/or DNS)
3283 * enable-pc         : enable a previous disable computer (DHCP and/or DNS)
3284 * enable-pxe        : enable PXE/BOOTP configuration on a computer
3285 * gen-dhcp-file     : generate DHCP files for the isc DHCP server
3286 * gen-dns-file      : generate DNS files for the bind domain server
3287 * help              : this help
3288 * load-database     : load the YAML database (be careful)
3289 * remove-pxe        : remove a PXE/BOOTP configuration
3290 * remove-tag        : remove a TAG
3291 * search-mac        : search physical MAC address computer
3292 * ddt sector-add-ip : add IP range check on a sector
3293 * show-sector       : list all sector group of computer
3294 * show              : list all computers
3295 * show-pool         : list all pool
3296 * show-pxe          : list PXE/BOOTP configuration
3297 * show-tag          : list all TAGs
3298 * version           : return program version
3299END
3300   return;
3301   }
3302
3303################################################################
3304# documentation
3305################################################################
3306
3307__END__
3308
3309=head1 NAME
3310
3311ddt - management of computer names and IP addresses
3312
3313
3314=head1 USAGE
3315
3316 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3317 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3318 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3319 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3320 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3321 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3322 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3323 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3324 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3325 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3326 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3327 ddt check-dns [--direct] [--reverse]
3328 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3329 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3330 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3331 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3332 ddt del-float [--pool|-p pool] [--mac|-m mac]
3333 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3334 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3335 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3336 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3337 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3338 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3339 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3340 ddt gen-dhcp-file
3341 ddt gen-dns-file [--verbose]
3342 ddt help
3343 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3344 ddt remove-pxe [--bootp|-b pxe_config]
3345 ddt remove-tag [--tag|-t tag]
3346 ddt search-mac [--mac|-m mac]
3347 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3348 ddt show-sector [--no-header|-H]
3349 ddt show
3350 ddt show-pool [--no-header|-H]
3351 ddt show-pxe [--no-header|-H]
3352 ddt show-tag [--no-header|-H]
3353 ddt version
3354
3355
3356=head1 DESCRIPTION
3357
3358DDT is an acronym for DHCP-DNS-Tools.
3359The previous command name was not C<ddt> but just C<dhcp-dns-tools>...
3360In practise, DDT is an IP Address Management (IPAM) service.
3361It has been used in the LEGI laboratory for over 10 years.
3362
3363The tool is quite effective and tries to keep things simple
3364but easily configurable for your site like a swiss army knife.
3365Everything is saved in a YAML database
3366and entries could be added, deleted, or modified by the command line.
3367
3368
3369=head1 COMMANDS
3370
3371=head2 add-alias
3372
3373 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3374
3375=head2 add-dhcp
3376
3377 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3378
3379=head2 add-float
3380
3381 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3382
3383=head2 add-static
3384
3385 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3386
3387=head2 add-virtual
3388
3389 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3390
3391=head2 change-comment
3392
3393 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3394
3395=head2 change-sector
3396
3397 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3398
3399=head2 change-host
3400
3401 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3402
3403=head2 change-ip
3404
3405 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3406
3407=head2 change-mac
3408
3409 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3410
3411=head2 change-tag
3412
3413 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3414
3415=head2 check-dns
3416
3417 ddt check-dns [--direct] [--reverse]
3418
3419=head2 create-sector
3420
3421 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3422
3423=head2 create-pool
3424
3425 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3426
3427=head2 create-pxe
3428
3429 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3430
3431=head2 create-tag
3432
3433 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3434
3435=head2 del-float
3436
3437 ddt del-float [--pool|-p pool] [--mac|-m mac]
3438
3439=head2 del-pc
3440
3441 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3442
3443=head2 disable-pc
3444
3445 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3446
3447=head2 disable-float
3448
3449 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3450
3451=head2 disable-pxe
3452
3453 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3454
3455=head2 enable-float
3456
3457 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3458
3459=head2 enable-pc
3460
3461 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3462
3463=head2 enable-pxe
3464
3465 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3466
3467=head2 gen-dhcp-file
3468
3469 ddt gen-dhcp-file
3470
3471=head2 gen-dns-file
3472
3473 ddt gen-dns-file [--verbose]
3474
3475=head2 help
3476
3477 ddt help
3478
3479=head2 load-database
3480
3481 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3482
3483=head2 remove-pxe
3484
3485 ddt remove-pxe [--bootp|-b pxe_config]
3486
3487=head2 remove-tag
3488
3489 ddt remove-tag [--tag|-t tag]
3490
3491=head2 search-mac
3492
3493 ddt search-mac [--mac|-m mac]
3494
3495=head2 sector-add-ip
3496
3497 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3498
3499=head2 show-sector
3500
3501 ddt show-sector [--no-header|-H]
3502
3503=head2 show
3504
3505 ddt show
3506
3507=head2 show-pool
3508
3509 ddt show-pool [--no-header|-H]
3510
3511=head2 show-pxe
3512
3513 ddt show-pxe [--no-header|-H]
3514
3515=head2 show-tag
3516
3517 ddt show-tag [--no-header|-H]
3518
3519=head2 version
3520
3521 ddt version
3522
3523
3524=head1 AUTHORS
3525
3526Written by Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>, Kevin Reverchon, Olivier De-Marchi - Grenoble - France
3527
3528
3529=head1 LICENSE AND COPYRIGHT
3530
3531License GNU GPL version 2 or later and Perl equivalent
3532
3533Copyright (C) 2006-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
Note: See TracBrowser for help on using the repository browser.