source: trunk/ddt/ddt @ 353

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