source: trunk/ddt/ddt

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