source: trunk/ddt/ddt @ 361

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