source: trunk/ddt/ddt @ 355

Last change on this file since 355 was 355, checked in by g7moreau, 6 years ago
  • Show IP range in show sector
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 117.0 KB
Line 
1#!/usr/bin/perl
2#
3# Copyright (C) 2006-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
4# License GNU GPL version 2 or later and Perl equivalent
5#
6# apt-get install perl-base perl-modules libyaml-syck-perl libnet-netmask-perl libreadonly-perl libfile-touch-perl libtext-table-perl libnetaddr-ip-perl
7
8package DDT::RE;
9
10use strict;
11#use warnings;
12
13use Readonly;
14
15Readonly our $MAC_ADDRESS  => qr{ (?: [0-9A-F]{2} :){5} [0-9A-F]{2} }xms;
16Readonly our $IPv4_ADDRESS => qr{ [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} }xms;
17
18
19package main;
20
21use strict;
22#use warnings;
23use version; our $VERSION = version->declare('0.11.7');
24
25use Getopt::Long qw(GetOptions);
26#use YAML;
27use YAML::Syck;
28use Net::Netmask;
29use File::Touch;
30use File::Copy;
31use Socket;
32use Text::Table;
33use NetAddr::IP;
34
35my $command = shift @ARGV || 'help';
36
37my %cmd_db = (
38   'add-alias'          => \&cmd_add_alias,
39   'add-dhcp'           => \&cmd_add_dhcp,
40   'add-float'          => \&cmd_add_float,
41   'add-static'         => \&cmd_add_static,
42   'add-virtual'        => \&cmd_add_virtual,
43   'change-comment'     => \&cmd_change_comment,
44   'change-sector'      => \&cmd_change_sector,
45   'change-host'        => \&cmd_change_host,
46   'change-ip'          => \&cmd_change_ip,
47   'change-mac'         => \&cmd_change_mac,
48   'change-tag'         => \&cmd_change_tag,
49   'check-dns'          => \&cmd_check_dns,
50   'create-sector'      => \&cmd_create_sector,
51   'create-pool'        => \&cmd_create_pool,
52   'create-pxe'         => \&cmd_create_pxe,
53   'create-tag'         => \&cmd_create_tag,
54   'del-pc'             => \&cmd_del_pc,
55   'del-float'          => \&cmd_del_float,
56   'disable-pc'         => \&cmd_disable_pc,
57   'disable-float'      => \&cmd_disable_float,
58   'disable-pxe'        => \&cmd_disable_pxe,
59   'enable-pc'          => \&cmd_enable_pc,
60   'enable-float'       => \&cmd_enable_float,
61   'enable-pxe'         => \&cmd_enable_pxe,
62   'gen-dhcp-file'      => \&cmd_generate_dhcp_file,
63   'gen-dns-file'       => \&cmd_generate_dns_file,
64   'help'               => \&cmd_help,
65   'load-database'      => \&cmd_load_database,
66   'remove-pxe'         => \&cmd_remove_pxe,
67   'remove-tag'         => \&cmd_remove_tag,
68   'search-mac'         => \&cmd_search_mac,
69   'sector-add-ip'      => \&cmd_sector_add_ip,
70   'show'               => \&cmd_show_host,
71   'show-sector'        => \&cmd_show_sector,
72   'show-pool'          => \&cmd_show_pool,
73   'show-pxe'           => \&cmd_show_pxe,
74   'show-tag'           => \&cmd_show_tag,
75   'upgrade-db'         => \&cmd_upgrade_db,
76   'version'            => \&cmd_version,
77   );
78
79#-------------------------------------------------------------------------------
80
81my $CONFIG;
82
83my $xdg_config_home = $ENV{'XDG_CONFIG_HOME'} || "$ENV{'HOME'}/.config";
84$CONFIG = config_load("$xdg_config_home/ddt/config.yml") if -e "$xdg_config_home/ddt/config.yml";
85
86my $COMPUTER_BASENAME   = $CONFIG->{'database'}{'basename'} || 'ddt';
87my $COMPUTER_EXT        = $CONFIG->{'database'}{'ext'}      || 'db';
88
89my $FOLDER_APP          = $CONFIG->{'database'}{'folder'}   || '/var/lib/ddt';
90my $FOLDER_BACKUP       = $CONFIG->{'database'}{'backup'}   || "$FOLDER_APP/backup";
91my $FOLDER_GEN_DHCP     = $CONFIG->{'generate'}{'dhcp'}     || "$FOLDER_APP/dhcp";
92my $FOLDER_GEN_DNS      = $CONFIG->{'generate'}{'dns'}      || "$FOLDER_APP/dns";
93my $SCRIPT_UPDATE       = $CONFIG->{'script'}{'update'}     || '/usr/share/ddt/update-dhcp-server';
94
95my $COMPUTER_YAML       = "$FOLDER_APP/$COMPUTER_BASENAME.$COMPUTER_EXT";
96
97#-------------------------------------------------------------------------------
98
99mkdir $FOLDER_APP, 0755      if not -d $FOLDER_APP;
100mkdir $FOLDER_BACKUP, 0755   if not -d $FOLDER_BACKUP;
101mkdir $FOLDER_GEN_DHCP, 0755 if not -d $FOLDER_GEN_DHCP;
102mkdir $FOLDER_GEN_DNS, 0755  if not -d $FOLDER_GEN_DNS;
103
104if (defined $cmd_db{$command}) {
105   $cmd_db{$command}->(@ARGV);
106   }
107else {
108   print {*STDERR} "ddt: command $command not found\n\n";
109   $cmd_db{'help'}->();
110   exit 1;
111   }
112
113exit;
114
115#--------------------------------------------------------------------------------
116# LOAD SAVE section
117#--------------------------------------------------------------------------------
118
119sub config_load {
120   my $config_file = shift;
121
122   my $configdb = YAML::Syck::LoadFile($config_file);
123
124   return $configdb;
125   }
126
127#---------------------------------------------------------------
128# Load computer database
129
130sub ipamdb_load {
131   my $database_yaml = shift;
132
133   touch $database_yaml if not -e $database_yaml;
134   my $computer_db = YAML::Syck::LoadFile($database_yaml);
135
136   # add database version if not exist
137   if (not exists $computer_db->{'version'}) {
138      $computer_db->{'version'} = 1;
139      }
140
141   return $computer_db;
142   }
143
144#---------------------------------------------------------------
145# Save computer database
146
147sub ipamdb_save {
148   my ($database_yaml, $computer_db) = @_;
149
150   my $dirdb = $database_yaml;
151      $dirdb =~ s{ / [^/]* $}{}xms;
152   mkdir "$dirdb", 0755 unless -d "$dirdb";
153   YAML::Syck::DumpFile($database_yaml, $computer_db);
154
155   return $computer_db;
156   }
157
158#--------------------------------------------------------------------------------
159# CONTROL section
160#--------------------------------------------------------------------------------
161
162sub control_exist_pool {
163   my ($computer_db, $pool) = @_;
164
165   return exists $computer_db->{'pool'}{$pool} ? 1 : 0;
166   }
167
168#-------------------------------------------------------------------------------
169#Nom: control_exist_sector
170#Description: controle l'existence d'un sector dans le fichier YAML
171#             return 0 (faux) ou 1 (vrai)
172
173sub control_exist_sector {
174   my ($computer_db, $sector) = @_;
175
176   return 1 if exists $computer_db->{$sector};
177
178   print {*STDERR} "Error: sector $sector not found\n";
179   return 0;
180   }
181
182#-------------------------------------------------------------------------------
183#Nom: control_exist_hostname
184#Description: controle l'existence d'un nom de machine dans le fichier YAML
185#             return 0 (si trouvé) ou 1 (si non trouvé)
186
187sub control_exist_hostname {
188   my ($computer_db, $sector, $hostname) = @_;
189
190   if ($computer_db->{$sector} eq '') {
191      return 1;
192      }
193
194   my @sectordb = @{$computer_db->{$sector}};
195
196   for my $computer (@sectordb) {
197      my ($mac_address, $attribute) = %{$computer};
198      return 0 if $attribute->{'hostname'} eq $hostname;
199      }
200   return 1;
201   }
202
203#-------------------------------------------------------------------------------
204#Nom: control_exist_mac
205#Description: controle l'existence d'une adresse MAC dans le fichier YAML
206#             return 0 (si trouvé) ou 1 (si non trouvé)
207
208sub control_exist_mac {
209   my ($computer_db, $mac) = @_;
210
211   for my $sector_current (keys %{$computer_db}) {
212      next if $sector_current eq 'dset';
213      next if $sector_current eq 'pool';
214      next if $sector_current eq 'pxe';
215      next if $sector_current eq 'tag';
216      next if $sector_current eq 'version';
217
218      my @sectordb = @{$computer_db->{$sector_current}};
219
220      LOOP_ON_COMPUTER:
221      for my $computer (@sectordb) {
222         my ($mac_address, $attribute) = %{$computer};
223         return 0 if $mac_address eq $mac;
224         }
225      }
226   return 1;
227   }
228
229#-------------------------------------------------------------------------------
230#Nom: control_exist_ip
231#Description: controle l'existence d'une adresse IP dans le fichier YAML
232#             return 0 (si trouvé) ou 1 (si non trouvé)
233
234sub control_exist_ip {
235   my ($computer_db, $ip) = @_;
236
237   for my $sector_current (keys %{$computer_db}) {
238      next if $sector_current eq 'dset';
239      next if $sector_current eq 'pool';
240      next if $sector_current eq 'pxe';
241      next if $sector_current eq 'tag';
242      next if $sector_current eq 'version';
243
244      LOOP_ON_COMPUTER:
245      for my $computer (@{$computer_db->{$sector_current}}) {
246         my ($mac_address, $attribute) = %{$computer};
247         #print "Erreur: cette adresse IP $ip existe déjà\n";
248         return 0 if $attribute->{'ip'} eq $ip;
249         }
250      }
251
252   for my $current_pool (keys %{$computer_db->{'pool'}}) {
253      #--- Cette partie pour tester les ip des pools est bonne ne plus la changer ---#
254      my @T_pool_ip = @{$computer_db->{'pool'}{$current_pool}{'ip'}};
255
256      for my $pool_ip (@T_pool_ip) {
257         #print "Erreur: cette adresse IP $ip existe déjà\n";
258         return 0 if $pool_ip eq $ip;
259         }
260      }
261
262   return 1;
263   }
264
265#-------------------------------------------------------------------------------
266
267sub control_ip_in_range {
268   my ($computer_db, $sector, $ip) = @_;
269
270   return 1 if not exists $computer_db->{'dset'}{$sector}{'ip_range'}; # No IP range defined for this sector
271
272   my $ip_addr = NetAddr::IP->new($ip);
273
274   LOOP_ON_IP_RANGE:
275   for my $ip_range_current (@{$computer_db->{'dset'}{$sector}{'ip_range'}}) {
276      my $range = NetAddr::IP->new($ip_range_current);
277      return 1 if $range->contains($ip_addr);
278      }
279
280   return 0;
281   }
282
283#-------------------------------------------------------------------------------------
284#Nom: control_syntaxe_mac
285#Description: controle la syntaxe d'une adresse MAC (juste la longueur pas les valeurs)
286#             return 0 (si trouvé) ou 1 (si non trouvé)
287
288sub control_syntax_mac_address {
289   my $mac = shift;
290
291   if (scalar(split /:/, $mac) == 6 and $mac =~ $DDT::RE::MAC_ADDRESS) {
292      return 1;
293      }
294
295   print {*STDERR} "Error: bad MAC syntax: $mac\n";
296   return 0;
297   }
298
299#-------------------------------------------------------------------------------------
300#Nom: control_syntax_ip
301#Description: controle la syntaxe d'une adresse IP (juste la longueur pas les valeurs)
302#             return 0 (si trouvé) ou 1 (si non trouvé)
303
304sub control_syntax_ip {
305   my $ip = shift;
306
307   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 0 if $cidr !~ m{^(\d+\.){3}\d+/\d+$};
324   return 0 if not NetAddr::IP->new($cidr);
325   return 1;
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 => 'IP-Range'},
2232     {align  => 'left',   align_title => 'left',   title => 'Date'},
2233     {align  => 'left',   align_title => 'left',   title => 'Comment'},
2234     {align  => 'left',   align_title => 'left',   title => 'Category'},
2235     );
2236
2237   LOOP_ON_SECTOR:
2238   for my $sector_current (sort keys %{$computer_db}) {
2239      next if $sector_current eq 'dset';
2240      next if $sector_current eq 'pool';
2241      next if $sector_current eq 'pxe';
2242      next if $sector_current eq 'tag';
2243      next if $sector_current eq 'version';
2244
2245      $tb_computer->add($sector_current), next LOOP_ON_SECTOR if not exists $computer_db->{'dset'}{$sector_current};
2246
2247      my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $computer_db->{'dset'}{$sector_current}{'modify_time'};
2248      $year += 1900;
2249      $mon++;
2250      my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2251
2252      my $ip_range;
2253      $ip_range = join ',', @{$computer_db->{'dset'}{$sector_current}{'ip-range'}} if exists $computer_db->{'dset'}{$sector_current}{'ip-range'};
2254
2255      my $category;
2256      my $comment = $computer_db->{'dset'}{$sector_current}{'comment'};
2257      $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2258      $comment =~ s/\s+(\(\w+\))$// and $category = $1;
2259
2260      $tb_computer->add($sector_current,
2261         $computer_db->{'dset'}{$sector_current}{'dns_extension'},
2262         $ip_range,
2263         $date,
2264         $comment,
2265         $category,
2266         );
2267      }
2268
2269   print $tb_computer->title(),
2270         $tb_computer->rule('-') if not $no_header;
2271   print $tb_computer->body();
2272   }
2273
2274#--------------------------------------------------------------------------------
2275
2276sub cmd_search_mac {
2277   local @ARGV = @_;
2278
2279   my $help = get_cmd_name();
2280   my ($mac);
2281
2282   GetOptions(
2283      'mac|m=s' => \$mac,
2284      );
2285
2286   exit_on_error_option($help)
2287      if $mac eq '';
2288
2289   $mac = normalize_mac_address($mac);
2290
2291   my $computer_db = ipamdb_load($COMPUTER_YAML);
2292
2293   control_syntax_mac_address($mac) or exit;
2294
2295   LOOP_ON_SECTOR:
2296   for my $sector_current (keys %{$computer_db}) {
2297      next if $sector_current eq 'dset';
2298      next if $sector_current eq 'pool';
2299      next if $sector_current eq 'pxe';
2300      next if $sector_current eq 'tag';
2301      next if $sector_current eq 'version';
2302
2303      my @sectordb = @{$computer_db->{$sector_current}};
2304
2305      LOOP_ON_COMPUTER:
2306      for my $computer (@sectordb) {
2307         my ($mac_address, $attribute) = %{$computer};
2308
2309         next LOOP_ON_COMPUTER if $mac_address ne $mac;
2310
2311         my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $attribute->{'modify_time'};
2312         $year += 1900;
2313         $mon++;
2314         my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2315
2316         my $comment = $attribute->{'comment'};
2317         $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2318
2319         my $enable = $attribute->{'enabled'};
2320         if (exists $attribute->{'pxe_config'}) {
2321            $enable .= '/' . $attribute->{'pxe_config'};
2322            }
2323         if (exists $attribute->{'tag'}) {
2324            $enable .= ':' . $attribute->{'tag'};
2325            }
2326
2327         printf "%-30s  %-20s %17s %9s %3s %10s %s\n",
2328            $attribute->{'hostname'} . '.' . $sector_current,
2329            $attribute->{'ip'},
2330            $mac_address,
2331            $attribute->{'address_type'},
2332            $enable,
2333            $date,
2334            $comment;
2335         }
2336      }
2337   }
2338
2339#--------------------------------------------------------------------------------
2340#Nom: show
2341#Description: liste les machines à partir du fichier YAML par nom de domaine.
2342
2343sub cmd_show_host {
2344   my %ipdb = ();
2345
2346   my $computer_db = ipamdb_load($COMPUTER_YAML);
2347
2348   my $tb_computer = Text::Table->new(
2349     {align  => 'left',   align_title => 'left',   title => 'Hostname.Sector'},
2350     {is_sep => 1,        body        => '  '},
2351     {align  => 'left',   align_title => 'left',   title => 'IPv4-Address'},
2352     {is_sep => 1,        body        => '  '},
2353     {align  => 'center', align_title => 'center', title => 'MAC-Address'},
2354     {is_sep => 1,        body        => '  '},
2355     {align  => 'right',  align_title => 'right',  title => 'Type'},
2356     {align  => 'right',  align_title => 'right',  title => 'Status'},
2357     {is_sep => 1,        body        => '  '},
2358     {align  => 'left',   align_title => 'left',   title => 'Date'},
2359     {align  => 'left',   align_title => 'left',   title => 'Comment'},
2360     );
2361
2362  LOOP_ON_SECTOR:
2363   for my $sector_current (sort keys %{$computer_db}) {
2364      next if $sector_current eq 'dset';
2365      next if $sector_current eq 'pool';
2366      next if $sector_current eq 'pxe';
2367      next if $sector_current eq 'tag';
2368      next if $sector_current eq 'version';
2369
2370      my @sectordb = @{$computer_db->{$sector_current}};
2371
2372      LOOP_ON_COMPUTER:
2373      for my $computer (@sectordb) {
2374         my ($mac_address, $attribute) = %{$computer};
2375         my $ip = $attribute->{'ip'};
2376
2377         if ($ip =~ m/$DDT::RE::IPv4_ADDRESS/xms) {
2378            if ( not exists $ipdb{$ip} ) {
2379               $ipdb{$ip} = {
2380                  'mac_address'  => $mac_address,
2381                  %{$attribute},
2382                  'sector'    => $sector_current,
2383                  };
2384               }
2385            else {
2386               print {*STDERR} "# Warning: $ip already exists in the database with MAC $mac_address!\n";
2387               }
2388            next LOOP_ON_COMPUTER;
2389            }
2390
2391         my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $attribute->{'modify_time'};
2392         $year += 1900;
2393         $mon++;
2394         my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2395
2396         my $comment = normalize_comment($attribute->{'comment'});
2397         $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2398
2399         my $enable = $attribute->{'enabled'};
2400         if (exists $attribute->{'pxe_config'}) {
2401            $enable .= '/' . $attribute->{'pxe_config'};
2402            }
2403         if (exists $attribute->{'tag'}) {
2404            $enable .= ':' . $attribute->{'tag'};
2405            }
2406
2407         #printf "%-30s  %-20s %17s %9s %3s %10s %s\n",
2408         $tb_computer->add(
2409            $attribute->{'hostname'} . '.' . $sector_current,
2410            $ip,
2411            $mac_address,
2412            $attribute->{'address_type'},
2413            $enable,
2414            $date,
2415            $comment,
2416            );
2417         }
2418      #print "\n# *** List of pool computers in the sector: $sector_current ***\n";
2419      }
2420
2421   #print "\n# *** List of computers ordered by IP and sector ***\n";
2422   LOOP_ON_IP_ADDRESS:
2423   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %ipdb)) {
2424      my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $ipdb{$ip}->{'modify_time'};
2425      $year += 1900;
2426      $mon++;
2427      my $date = sprintf '%04i-%02i-%02i', $year, $mon, $mday;
2428
2429      my $comment =$ipdb{$ip}->{'comment'};
2430      $comment =~ s/^\d\d\d\d-\d\d-\d\d\s//;
2431
2432      my $enable = $ipdb{$ip}->{'enabled'};
2433      if (exists $ipdb{$ip}->{'pxe_config'}) {
2434         $enable .= '/' . $ipdb{$ip}->{'pxe_config'};
2435         }
2436      if (exists $ipdb{$ip}->{'tag'}) {
2437         $enable .= ':' . $ipdb{$ip}->{'tag'};
2438         }
2439
2440      #printf "%-30s %-20s %17s %9s %3s %10s %s\n",
2441      $tb_computer->add(
2442         $ipdb{$ip}->{'hostname'} . '.' . $ipdb{$ip}->{'sector'},
2443         $ip,
2444         normalize_mac_address($ipdb{$ip}->{'mac_address'}),
2445         $ipdb{$ip}->{'address_type'},
2446         $enable,
2447         $date,
2448         $comment
2449         );
2450      }
2451
2452   print $tb_computer->title();
2453   print $tb_computer->rule('-');
2454   print $tb_computer->body();
2455   }
2456
2457#-------------------------------------------------------------------------------
2458#Nom: cmd_generate_dhcp_file
2459#Description: génère les fichiers de configuration des machines et des pools du dhcp
2460
2461sub cmd_generate_dhcp_file {
2462   backup_database();
2463
2464   my $computer_db = ipamdb_load($COMPUTER_YAML);
2465
2466   my %file_pool;
2467
2468   for my $sector_current (keys %{$computer_db}) {
2469      next if $sector_current eq 'dset';
2470      next if $sector_current eq 'pool';
2471      next if $sector_current eq 'pxe';
2472      next if $sector_current eq 'tag';
2473      next if $sector_current eq 'version';
2474
2475      open FILE_VLAN, '>', "$FOLDER_GEN_DHCP/$sector_current";
2476      my @sectordb = @{$computer_db->{$sector_current}};
2477      for my $value (@sectordb) {
2478         ALL_MAC_ADDRESS:
2479         for my $mac_addres (keys %{$value}) {
2480            #host pcdavoust {  deny-unknown-clients;
2481            #hardware ethernet 0:6:5b:b8:13:d1;
2482            #fixed-address 194.254.66.72;
2483            #}
2484
2485            my $hostname     = $value->{$mac_addres}{'hostname'};
2486            my $ip           = $value->{$mac_addres}{'ip'};
2487            my $comment      = $value->{$mac_addres}{'comment'};
2488            my $address_type = $value->{$mac_addres}{'address_type'};
2489            my $enabled      = $value->{$mac_addres}{'enabled'};
2490            my $tags         = $value->{$mac_addres}{'tag'} || 'universal';
2491
2492            my $buffer;
2493            if ($address_type eq 'dhcp') {
2494               if ($enabled eq 'yes') {
2495                  $buffer  = "host $hostname {\n"; # deny-unknown-clients;
2496                  $buffer .= "   hardware ethernet $mac_addres;\n";
2497                  $buffer .= "   fixed-address $ip;\n";
2498
2499                  if (exists $value->{$mac_addres}{'pxe_config'}) {
2500                     my $pxe_config     = $value->{$mac_addres}{'pxe_config'};
2501                     my $ip_next_server = $computer_db->{'pxe'}{$pxe_config}{'ip_next_server'};
2502                     my $filename       = $computer_db->{'pxe'}{$pxe_config}{'filename'};
2503                     $buffer .= "   next-server $ip_next_server;\n";
2504                     $buffer .= "   filename \"$filename\";\n";
2505                     }
2506                  $buffer .= "   #comment: $comment\n";
2507                  $buffer .= "   }\n";
2508                  $buffer .= "\n";
2509
2510                  for my $tag (split/,/, $tags) {
2511                     $file_pool{"tag-$tag"} ||= [];
2512                     push @{$file_pool{"tag-$tag"}}, "subclass \"tag-$tag\" 1:$mac_addres; # $comment\n";
2513                     }
2514                  }
2515               else {
2516                  $buffer  = "#host $hostname {\n"; # deny-unknown-clients;
2517                  $buffer .= "#   hardware ethernet $mac_addres;\n";
2518                  $buffer .= "#   fixed-address $ip;\n";
2519                  $buffer .= "#   comment: $comment \n";
2520                  $buffer .= "#   }\n";
2521                  $buffer .= "\n";
2522                  }
2523               print FILE_VLAN $buffer;
2524               }
2525            elsif ($address_type eq 'pool-dhcp') {
2526               #--- Génère les fichiers pool dhcp ---#
2527               for my $current_pool (keys %{$computer_db->{'pool'}}) {
2528                  next if $current_pool ne $ip;
2529
2530                  if ($enabled eq 'yes') {
2531                     $buffer = "subclass \"$current_pool\" 1:$mac_addres; # $comment\n";
2532
2533                     for my $tag (split/,/, $tags) {
2534                        $file_pool{"tag-$tag"} ||= [];
2535                        push @{$file_pool{"tag-$tag"}}, "subclass \"tag-$tag\" 1:$mac_addres; # $comment\n";
2536                        }
2537                     }
2538                  else {
2539                     $buffer = "#subclass \"$current_pool\" 1:$mac_addres; # $comment\n";
2540                     }
2541
2542                  my $current_pool_file_name = $computer_db->{'pool'}{$current_pool}{'file'};
2543
2544                  $file_pool{$current_pool_file_name} ||= [];
2545                  push @{$file_pool{$current_pool_file_name}}, $buffer;
2546                  }
2547               }
2548            }
2549         }
2550
2551      close FILE_VLAN;
2552
2553      for my $file_name (keys %file_pool) {
2554         open FILE_POOL, '>', "$FOLDER_GEN_DHCP/$file_name";
2555         print FILE_POOL @{$file_pool{$file_name}};
2556         close FILE_POOL;
2557         }
2558      }
2559      print "Copy DHCP files from $FOLDER_GEN_DHCP to /etc/dhcp/include/\n";
2560      exec $SCRIPT_UPDATE;
2561   }
2562
2563#-------------------------------------------------------------------------------
2564#Nom: cmd_generate_dns_file
2565#Description: génère les fichiers d'enregistrements DNS
2566
2567sub cmd_generate_dns_file {
2568   local @ARGV = @_;
2569
2570   my $help = get_cmd_name();
2571   my ($verbose);
2572
2573   GetOptions(
2574      'verbose|v' => \$verbose,
2575      );
2576
2577   my $buffer_fwd;
2578   my $buffer_rev;
2579   my $pool_domain;
2580
2581   my $computer_db = ipamdb_load($COMPUTER_YAML);
2582
2583   for my $sector_current (keys %{$computer_db}) {
2584      next if $sector_current eq 'dset';
2585      next if $sector_current eq 'pool';
2586      next if $sector_current eq 'pxe';
2587      next if $sector_current eq 'tag';
2588      next if $sector_current eq 'version';
2589
2590      if ($sector_current eq 'pool') {
2591         LOOP_ON_COMPUTER:
2592         for my $computer (@{$computer_db->{$sector_current}}) {
2593            for my $pool_name (keys %{$computer}) {
2594               $pool_domain = $computer->{$pool_name}->{'domain'}."\n";
2595               #print $computer->{$pool_name}->{'file'};
2596               chomp $pool_domain;
2597               open FILE_FORWARD_DNS, '>>', "$FOLDER_GEN_DNS/db.$pool_domain.fwd";
2598               open FILE_REVERSE_DNS, '>>', "$FOLDER_GEN_DNS/db.$pool_domain.rev";
2599               my @T_pool_ip = @{$computer->{$pool_name}->{'ip'}};
2600               for my $pool_ip (@T_pool_ip) {
2601                  my @T_split = split(/\./ , $pool_ip);
2602                  $buffer_fwd = sprintf "%-24s IN  A  %-15s ;\n", "$pool_name$T_split[3]", $pool_ip;
2603                  $buffer_rev = "$T_split[3]   IN PTR   $pool_name$T_split[3].$pool_domain.\n";
2604                  print FILE_FORWARD_DNS $buffer_fwd;
2605                  print FILE_REVERSE_DNS $buffer_rev;
2606                  }
2607               close FILE_FORWARD_DNS;
2608               close FILE_REVERSE_DNS;
2609               }
2610            }
2611         }
2612
2613      else {
2614         #--- Création du fichier non-reverse ---#
2615         open FILE_FORWARD_DNS, ">> $FOLDER_GEN_DNS/db.$sector_current.fwd";
2616         open FILE_REVERSE_DNS, ">> $FOLDER_GEN_DNS/db.$sector_current.rev";
2617
2618         my @sectordb = @{$computer_db->{$sector_current}};
2619
2620         LOOP_ON_COMPUTER:
2621         for my $computer (@sectordb) {
2622            my ($mac_address, $attribute) = %{$computer};
2623
2624            #host pcdavoust {  deny-unknown-clients;
2625            #hardware ethernet 0:6:5b:b8:13:d1;
2626            #fixed-address 194.254.66.72;
2627            #}
2628
2629            my $hostname     = $attribute->{'hostname'};
2630            my $ip           = $attribute->{'ip'};
2631            my $comment      = $attribute->{'comment'};
2632            my $address_type = $attribute->{'address_type'};
2633            my $enabled      = $attribute->{'enabled'};
2634
2635            next LOOP_ON_COMPUTER if not (($address_type eq 'dhcp') or ($address_type eq 'static'));
2636
2637            my $dns_domain = $sector_current;
2638            if (exists $computer_db->{'dset'}{$sector_current}) {
2639               $dns_domain = $computer_db->{'dset'}{$sector_current}{'dns_extension'};
2640               }
2641
2642            my @ip_split = split /\./, $ip;
2643            if ($enabled eq 'yes') {
2644               if (exists $attribute->{'dns_extension'}
2645                     and "$attribute->{'dns_extension'}" != "$dns_domain") {
2646                  print "A FAIRE\n";
2647                  }
2648               $buffer_fwd = sprintf "%-24s  IN A   %-15s ; %s\n", $hostname, $ip, $comment;
2649               $buffer_rev = sprintf "%3i    IN PTR %-15s\n", $ip_split[3], "$hostname.$dns_domain.";
2650               }
2651
2652            else {
2653               $buffer_fwd = sprintf ";%-24s IN A   %-15s ; %s\n", $hostname, $ip, $comment;
2654               $buffer_rev = sprintf ";%3i   IN PTR %-15s\n", $ip_split[3], "$hostname.$dns_domain.";
2655               }
2656            print FILE_REVERSE_DNS $buffer_rev;
2657            print FILE_FORWARD_DNS $buffer_fwd;
2658            }
2659         close FILE_REVERSE_DNS;
2660         close FILE_FORWARD_DNS;
2661         print "- DNS: db.$sector_current.fwd db.$sector_current.rev [CREATE].\n" if $verbose;
2662         print "  Ex : sort -k 4n -t . $FOLDER_GEN_DNS/db.$sector_current.fwd\n"     if $verbose;
2663         }
2664      }
2665   }
2666
2667#--------------------------------------------------------------------------------
2668
2669sub shell_command {
2670   my $cmd = shift;
2671
2672   require FileHandle;
2673   my $fh     = new FileHandle;
2674   my @result = ();
2675   open $fh, q{-|}, "LANG=C $cmd" or die "Can't exec $cmd\n";
2676   @result = <$fh>;
2677   close $fh;
2678   chomp @result;
2679   return @result;
2680   }
2681
2682#--------------------------------------------------------------------------------
2683
2684sub cmd_check_dns {
2685   local @ARGV = @_;
2686
2687   my $help = get_cmd_name();
2688   my ($opt_direct, $opt_reverse);
2689
2690   GetOptions(
2691      'direct|d'  => \$opt_direct,
2692      'reverse|r' => \$opt_reverse,
2693      );
2694
2695   my $computer_db = ipamdb_load($COMPUTER_YAML);
2696
2697   if ($opt_direct or not $opt_reverse) { # DDT to DNS check
2698      LOOP_ON_SECTOR:
2699      for my $sector_current (keys %{$computer_db}) {
2700         next if $sector_current eq 'dset';
2701         next if $sector_current eq 'pool';
2702         next if $sector_current eq 'pxe';
2703         next if $sector_current eq 'tag';
2704         next if $sector_current eq 'version';
2705
2706         my @sectordb = @{$computer_db->{$sector_current}};
2707
2708         LOOP_ON_COMPUTER:
2709         for my $computer (@sectordb) {
2710            my ($mac_address, $attribute) = %{$computer};
2711            #my $new_mac = normalize_mac_address($mac_address);
2712            my $ip = $attribute->{'ip'};
2713            next LOOP_ON_COMPUTER if not $ip =~ m/$DDT::RE::IPv4_ADDRESS/xms;
2714            next LOOP_ON_COMPUTER if $attribute->{'enabled'} eq 'no';
2715
2716            my $dns_hostname_fq = scalar gethostbyaddr(inet_aton($ip), AF_INET);
2717            my ($dns_hostname) = split /\./, $dns_hostname_fq;
2718
2719            if ($attribute->{'hostname'} ne $dns_hostname) {
2720               print "$mac_address ($sector_current) $ip - $dns_hostname / $attribute->{'hostname'} # $attribute->{'comment'}\n";
2721               next LOOP_ON_COMPUTER;
2722               }
2723
2724            my $packed_ip = scalar gethostbyname($dns_hostname_fq);
2725            if (defined $packed_ip) {
2726               my $ip_address = inet_ntoa($packed_ip);
2727               if ($ip ne $ip_address) {
2728                  print "Error: bad IP for reverse DNS on $dns_hostname_fq / $ip\n";
2729                  next LOOP_ON_COMPUTER;
2730                  }
2731               }
2732            }
2733         }
2734      }
2735
2736   if ($opt_reverse) {  # DNS to DDT check
2737      my %saw; # count for unique member
2738      my @dns_domain_list = sort grep !$saw{$_}++,
2739         map $computer_db->{'dset'}{$_}{'dns_extension'},
2740         grep exists($computer_db->{'dset'}{$_}{'dns_extension'}),
2741         keys $computer_db->{'dset'};
2742      LOOP_ON_DNS:
2743      for my $dns (@dns_domain_list) {
2744         LOOP_ON_IP:
2745         for (shell_command("host -t A -l $dns")) {
2746            # smtp2.legi.grenoble-inp.fr has address 194.254.67.37
2747            next if not m/has address/;
2748            next if not m/^(\w[\w-_\.]+\w)\s+has\saddress\s+(\d[\d\.]+\d)$/;
2749            my ($hostname_fq, $ip) = ($1, $2);
2750            control_syntax_ip($ip) or next LOOP_ON_IP;
2751            if (control_exist_ip($computer_db, $ip) == 1) {
2752               printf "Unkown IP: %-15s / %s\n", $ip, $hostname_fq;
2753               next LOOP_ON_IP;
2754               }
2755            }
2756         }
2757      }
2758   }
2759
2760#-------------------------------------------------------------------------------
2761#Nom: load_data_dhcp
2762#Description: permet de charger le fichier de données YAML via les fichiers de configuration
2763#             machines.
2764#            ATTENTION: LES COMMENTAIRES DU FICHIER DISPARAITRONT.
2765
2766sub load_data_dhcp {
2767   my ($sector, $input_file) = @_;
2768
2769   my $computer_db = ipamdb_load($COMPUTER_YAML);
2770
2771   my @T_mac;
2772   my @T_host;
2773   my @T_ip;
2774   my $cpt;
2775   open (FILE, "<$input_file");
2776   my @buffer = <FILE>;
2777   close(FILE);
2778
2779   for my $ligne (@buffer) {
2780      #--
2781      $ligne =~ s/#.*$//;
2782      $ligne =~ s/\s+/ /;
2783      $ligne =~ s/^\s+//;
2784      next if $ligne eq '';
2785
2786      if ($ligne =~ /^host /) {
2787         $cpt=0;
2788         my @T_split = split(/host\s+/, $ligne);
2789         @T_host = split(/ /, $T_split[1]);
2790         chomp($T_host[0]);
2791
2792         $cpt++;
2793         }
2794
2795      if ($ligne =~ /^*ethernet /) {
2796         $ligne =~ s/;//g;
2797         @T_mac = split(/ethernet\s+/, $ligne);
2798         chomp($T_mac[1]);
2799         $cpt++;
2800         }
2801
2802      if ($ligne =~ /^*address /) {
2803         $ligne =~ s/;//g;
2804         @T_ip = split(/address\s+/, $ligne);
2805         chomp($T_ip[1]);
2806
2807         $cpt++;
2808         }
2809
2810      if ($cpt == 3) {
2811         #   print "MAC $T_mac[1] HOST $T_host[0] IP $T_ip[1].\n";
2812         my $mac = $T_mac[1];
2813         my $hostname = $T_host[0];
2814         my $ip = $T_ip[1];
2815         $cpt = 0;
2816
2817         if ( control_exist_hostname($computer_db, $sector, $hostname) == 0 ) {
2818            print "Error: host already exist in sector $sector: $hostname\n";
2819            next;
2820            }
2821         control_syntax_mac_address($mac) or next;
2822         if ( control_exist_mac($computer_db, $mac) == 0) {
2823            print "Error: physical MAC address already exists: $mac\n";
2824            next;
2825            }
2826
2827         control_syntax_ip($ip) or next;
2828         if ( control_exist_ip($computer_db, $ip) == 0 ) {
2829            print "Error: IP address already exists: $ip\n";
2830            next;
2831            }
2832         my $timestamp = time;
2833         push @{$computer_db->{$sector}}, { $mac => {
2834            'hostname'     => $hostname,
2835            'ip'           => $ip,
2836            'address_type' => 'dhcp',
2837            'enabled'      => 'yes',
2838            'create_time'  => $timestamp,
2839            'modify_time'  => $timestamp,
2840            'alias'        =>  '',
2841            }};
2842         }
2843      }
2844   }
2845
2846#-------------------------------------------------------------------------------
2847#Nom: load_data_pool
2848#Description: permet de charger le fichier YAML via les fichiers de conf 'pool' du dhcp.
2849
2850sub load_data_pool {
2851   my ($sector, $input_file) = @_;
2852
2853   my @T_mac;
2854
2855   open (FILE, "<$input_file");
2856   my @buffer = <FILE>;
2857   close(FILE);
2858
2859   my $computer_db = ipamdb_load($COMPUTER_YAML);
2860
2861   for my $ligne (@buffer) {
2862      #--
2863      $ligne =~ s/#.*$//;
2864      $ligne =~ s/\s+/ /;
2865      $ligne =~ s/^\s+//;
2866      $ligne =~ s/;//g;
2867      $ligne =~ s/"//g;
2868      next if $ligne eq '';
2869
2870      if (($ligne =~ /^subclass/)) {
2871         my @T_split = split(/ / ,$ligne);
2872         my $pool = $T_split[1];
2873
2874         @T_mac = split(/:/ , $T_split[2]);
2875         my $mac = $T_mac[1].":".$T_mac[2].":".$T_mac[3].":".$T_mac[4].":".$T_mac[5].":".$T_mac[6];
2876         control_syntax_mac_address($mac) or next;
2877         if (control_exist_mac($computer_db, $mac) == 0) {
2878            print "Error: physical MAC address already exists: $mac\n";
2879            next;
2880            }
2881
2882         #--- cette partie teste si le pool existe.
2883         if (not exists $computer_db->{'pool'}{$pool}) {
2884            print "Error: create pool with create_pool command before load database: $pool\n";
2885            exit;
2886            }
2887
2888         if ($computer_db->{'pool'}{'domain'} eq $sector) {
2889            my $timestamp = time;
2890            push @{$computer_db->{$sector}}, { $mac => {
2891               'hostname'     => $pool,
2892               'ip'           => $pool,
2893               'address_type' => 'pool-dhcp',
2894               'enabled'      => 'yes',
2895               'create_time'  => $timestamp,
2896               'modify_time'  => $timestamp,
2897               }};
2898            }
2899         else {
2900            print "Ajout de la machine $mac [FAILED]\n";
2901            print "Error: the pool doesn't exists: $pool, for the domain: $sector\n";
2902            }
2903         }
2904      }
2905   }
2906
2907#-------------------------------------------------------------------------------
2908
2909sub load_data_file {
2910   my ($sector, $input_file, $type_file) = @_;
2911
2912   my $computer_db = ipamdb_load($COMPUTER_YAML);
2913
2914   #$computer_db
2915   if ($type_file eq 'dhcp') {
2916      load_data_dhcp($sector, $input_file);
2917      }
2918
2919   elsif ($type_file eq 'pool-dhcp') {
2920      load_data_pool($sector, $input_file);
2921      }
2922
2923   ipamdb_save("$COMPUTER_YAML", $computer_db);
2924   }
2925
2926#-------------------------------------------------------------------------------
2927
2928sub cmd_load_database {
2929   local @ARGV = @_;
2930
2931   my $help = get_cmd_name();
2932   my ($sector, $input_file, $type_file);
2933
2934   GetOptions(
2935      'sector|s|d=s'    => \$sector,
2936      'filename|f=s'    => \$input_file,
2937      'kind|k=s'        => \$type_file,
2938      );
2939
2940   exit_on_error_option($help)
2941      if $sector  eq ''
2942      or $input_file eq ''
2943      or $type_file  eq '';
2944
2945   load_data_file($sector, $input_file, $type_file);
2946   }
2947
2948#-------------------------------------------------------------------------------
2949#Nom: backup_database
2950#Description: sauvegarde et réinitialise les fichiers d'enregistrements DHCP.
2951
2952sub backup_database {
2953   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime time;
2954   $year += 1900;
2955   $mon++;
2956   my $date = sprintf '%04i-%02i-%02i-%02i-%02i-%02i', $year, $mon, $mday, $hour, $min, $sec;
2957
2958   copy($COMPUTER_YAML, "$FOLDER_BACKUP/$COMPUTER_BASENAME-$date.conf") or die "Error: database copy backup failed: $!\n";
2959   }
2960
2961#-------------------------------------------------------------------------------
2962# HELP section
2963#-------------------------------------------------------------------------------
2964
2965#-------------------------------------------------------------------------------
2966#Nom: exit_on_error_option
2967#Description: messages d'aide des options pour les différentes commandes
2968
2969sub exit_on_error_option {
2970  my ($command) = @_;
2971
2972   if ($command eq 'add-dhcp') {
2973      print "List of options for command: $command\n";
2974      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
2975      print " -h : computer hostname (mandatory if option -i != 'pool'). Example: -h info8pc154\n";
2976      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A\n";
2977      print " -i : internet IP address (mandatory). Possible value: classical IP address or the keyword 'pool'\n";
2978      print " -p : name of the DHCP pool to which the machine belongs (mandatory if option -i == 'pool')\n";
2979      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
2980      print "Example:\n";
2981      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";
2982      }
2983
2984   elsif ($command eq 'add-float') {
2985      print "List of options for command: $command\n";
2986      print " -s : sector attachment (mandatory)\n";
2987      print " -p : name of the DHCP pool to which the machine belongs (mandatory)\n";
2988      print " -m : physical MAC address (mandatory)\n";
2989      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
2990      print "Example:\n";
2991      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";
2992      }
2993
2994   elsif ($command eq 'add-static') {
2995      print "List of options for command: $command\n";
2996      print " -s : sector attachment (mandatory)\n";
2997      print " -i : internet IP address (mandatory)\n";
2998      print " -h : computer hostname (mandatory)\n";
2999      print " -m : physical MAC address (mandatory)\n";
3000      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
3001      print "Example:\n";
3002      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";
3003      }
3004
3005   elsif ($command eq 'add-virtual') {
3006      print "List of options for command: $command\n";
3007      print " -s : sector attachment (mandatory)\n";
3008      print " -i : internet IP address (mandatory)\n";
3009      print " -h : computer hostname (mandatory)\n";
3010      print " -c : comment (mandatory). Example: 2014-04-07 DELL Laptop 6400 - Olivier Toto (INFO)\n";
3011      print "Example:\n";
3012      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";
3013      }
3014
3015   elsif ($command eq 'add-alias') {
3016      print "List of options for command: $command\n";
3017      print " -s : sector attachment (mandatory)\n";
3018      print " -h : computer hostname (mandatory)\n";
3019      print " -a : computer alias name (mandatory)\n";
3020      }
3021
3022   elsif ($command eq 'create-sector') {
3023      print "List of options for command: $command\n";
3024      print " -s : new sector (mandatory)\n";
3025      print " -e : DNS domain name extension( mandatory). Example legi.grenoble-inp.fr\n";
3026      print " -c : comment (mandatory). Example: 2016-08-22 VLAN legi-261 (INFO)\n";
3027      print "Examples:\n";
3028      print " ddt create-sector -s legi-sector03 -e legi.grenoble-inp.fr -c '2016-08-22 VLAN legi-261 (INFO)'\n";
3029      }
3030
3031   elsif ($command eq 'create-pool') {
3032      print "List of options for command: $command\n";
3033      print " -p : name of the DHCP pool. Example: pool-legi-priv\n";
3034      print " -s : sector attachment for the pool. (sector attachment must exist in file $COMPUTER_BASENAME.conf). Example: legi-sector03\n";
3035      print " -f : configuration filename on the DHCP server for the pool\n";
3036      print " -i : adresse(s) IP ou plage d'IP. Séparateur d'adresses IP: ','. Séparateur de plage '-'\n";
3037      print "Examples:\n";
3038      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";
3039      print " ddt create-pool -p legi-pool2 -s legi-sector03 -f legi-pool-public  -i 192.168.10.1-192.168.10.4\n";
3040      }
3041
3042   elsif ($command eq 'create-pxe') {
3043      print "List of options for command: $command\n";
3044      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3045      print " -n : internet IP address for the DHCP next-server.\n";
3046      print " -f : filename on TFTP server to load at boot\n";
3047      print " -c : comment (mandatory). Example: 2014-04-07 PXE Boot for CentOS (MOST)\n";
3048      }
3049
3050   elsif ($command eq 'remove-pxe') {
3051      print "List of options for command: $command\n";
3052      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3053      }
3054
3055   elsif ($command eq 'enable-pxe') {
3056      print "List of options for command: $command\n";
3057      print " -h : computer hostname (mandatory unless option -i)\n";
3058      print " -i : internet IP address (mandatory unless option -h)\n";
3059      print " -s : sector attachment (mandatory if option -h)\n";
3060      print " -b : name of the PXE/BOOTP configuration. Example: most\n";
3061      }
3062
3063   elsif ($command eq 'disable-pxe') {
3064      print "List of options for command: $command\n";
3065      print " -h : computer hostname (mandatory unless option -i)\n";
3066      print " -i : internet IP address (mandatory unless option -h)\n";
3067      print " -s : sector attachment (mandatory if option -h)\n";
3068      }
3069
3070   elsif ($command eq 'create-tag') {
3071      print "List of options for command: $command\n";
3072      print " -t : name of the TAG (mandatory). Example: restricted\n";
3073      print " -c : comment (mandatory). Example: 2014-04-07 tag restricted (INFO)\n";
3074      print "tag 'universal' is intrinsic\n";
3075      }
3076
3077   elsif ($command eq 'remove-tag') {
3078      print "List of options for command: $command\n";
3079      print " -b : name of the TAG. Example: restricted\n";
3080      }
3081
3082   elsif ($command eq 'change-mac') {
3083      print "List of options for command: $command\n";
3084      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3085      print " -h : computer hostname (mandatory unless option -i)\n";
3086      print " -i : internet IP address (mandatory unless option -h). Possible value: classical IP address or the keyword 'pool'\n";
3087      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3088      }
3089
3090   elsif ($command eq 'change-ip') {
3091      print "List of options for command: $command\n";
3092      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3093      print " -h : computer hostname (mandatory)\n";
3094      print " -i : new internet IP address (mandatory). Possible value: classical IP address\n";
3095      }
3096
3097   elsif ($command eq 'change-host') {
3098      print "List of options for command: $command\n";
3099      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3100      print " -i : internet IP address (mandatory). Possible value: classical IP address\n";
3101      print " -h : new computer hostname (mandatory)\n";
3102      print "It's not possible to change hostname for computer that belongs to a pool\n";
3103      }
3104
3105   elsif ($command eq 'change-comment') {
3106      print "List of options for command: $command\n";
3107      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3108      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3109      print " -c : new comment (mandatory)\n";
3110      }
3111
3112   elsif ($command eq 'change-sector') {
3113      print "List of options for command: $command\n";
3114      print " -s : new sector attachment (mandatory). Example: -s legi-sector03\n";
3115      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3116      print " -i : internet IP address (mandatory)\n";
3117      }
3118
3119   elsif ($command eq 'change-tag') {
3120      print "List of options for command: $command\n";
3121      print " -h : computer hostname (mandatory unless option -i or -m)\n";
3122      print " -s : sector attachment (mandatory). Example: -s legi-sector03\n";
3123      print " -i : internet IP address (mandatory unless option -h or -m)\n";
3124      print " -m : physical MAC address (mandatory unless option -h or -i, priority). Example: -m 0F:58:AB:2A:22:11\n";
3125      print " -t : list of tags separated by comma (mandatory). Example: -t internal,windows\n";
3126      }
3127
3128   elsif ($command eq 'load-database') {
3129      print "List of options for command: $command\n";
3130      print " -s : sector attachment\n";
3131      print " -f : input file in DHCP format\n";
3132      print " -k : possible cases (kind): dhcp, pool-dhcp, fix-address\n";
3133      }
3134
3135   elsif ($command eq 'enable-pc') {
3136      print "List of options for command: $command\n";
3137      print " -h : computer hostname (mandatory unless option -i)\n";
3138      print " -i : internet IP address (mandatory unless option -h)\n";
3139      print " -s : sector attachment (mandatory if option -h)\n";
3140      print "Examples:\n";
3141      print " ddt enable-pc -i 192.168.10.1\n";
3142      print " ddt enable-pc -s legi-sector03 -h kevinpc\n";
3143      }
3144
3145   elsif ($command eq 'enable-float') {
3146      print "List of options for command: $command\n";
3147      print " -m : physical MAC address (mandatory)\n";
3148      print " -p : name of the DHCP pool (mandatory)\n";
3149      }
3150
3151   elsif ($command eq 'disable-float') {
3152      print "List of options for command: $command\n";
3153      print " -m : physical MAC address (mandatory)\n";
3154      print " -p : name of the DHCP pool (mandatory)\n";
3155      }
3156
3157   elsif ($command eq 'disable-pc') {
3158      print "List of options for command: $command\n";
3159      print " -h : computer hostname (mandatory unless option -i)\n";
3160      print " -i : internet IP address (mandatory unless option -h)\n";
3161      print " -s : sector attachment (mandatory if option -h)\n";
3162      print "Examples:\n";
3163      print " ddt disable-pc -i 192.168.10.1\n";
3164      print " ddt disable-pc -s legi-sector03 -h kevinpc\n";
3165      }
3166
3167   elsif ($command eq 'del-pc') {
3168      print "List of options for command: $command\n";
3169      print " -s : sector attachment (mandatory)\n";
3170      print " -h : computer hostname (mandatory unless option -i)\n";
3171      print " -i : internet IP address (mandatory unless option -h)\n";
3172      }
3173
3174   elsif ($command eq 'del-float') {
3175      print "List of options for command: $command\n";
3176      print " -m : physical MAC address (mandatory)l\n";
3177      print " -p : name of the DHCP pool\n";
3178      }
3179
3180   elsif ($command eq 'search-mac') {
3181      print "List of options for command: $command\n";
3182      print " -m : physical MAC address (mandatory). Example: -m 0F:58:AB:2A:22:11\n";
3183      }
3184
3185   elsif ($command eq 'sector-add-ip') {
3186      print "List of options for command: $command\n";
3187      print " -s : sector attachment (mandatory)\n";
3188      print " -i : internet IP range address in CIDR notation (mandatory)\n";
3189      }
3190
3191   else {
3192      print "No help for command: $command\n";
3193      }
3194   exit;
3195   }
3196
3197#-------------------------------------------------------------------------------
3198
3199sub cmd_version {
3200
3201   print <<'END';
3202ddt - management of computer names and IP addresses
3203Copyright (C) 2006-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
3204Main author Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>
3205License GNU GPL version 2 or later and Perl equivalent
3206END
3207
3208   print "Database Version 1\n";
3209   print "Version $VERSION\n\n";
3210   print ' $Id: ddt 355 2018-09-14 08:20:51Z g7moreau $'."\n";
3211   return;
3212   }
3213
3214#-------------------------------------------------------------------------------
3215#Nom: usage
3216#Description: message d'aide sur les commandes du script
3217
3218sub cmd_help {
3219   print <<END;
3220ddt - management of computer names and IP addresses
3221
3222 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3223 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3224 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3225 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3226 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3227 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3228 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3229 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3230 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3231 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3232 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3233 ddt check-dns [--direct] [--reverse]
3234 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3235 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3236 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3237 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3238 ddt del-float [--pool|-p pool] [--mac|-m mac]
3239 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3240 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3241 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3242 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3243 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3244 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3245 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3246 ddt gen-dhcp-file
3247 ddt gen-dns-file [--verbose]
3248 ddt help
3249 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3250 ddt remove-pxe [--bootp|-b pxe_config]
3251 ddt remove-tag [--tag|-t tag]
3252 ddt search-mac [--mac|-m mac]
3253 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3254 ddt show-sector [--no-header|-H]
3255 ddt show
3256 ddt show-pool [--no-header|-H]
3257 ddt show-pxe [--no-header|-H]
3258 ddt show-tag [--no-header|-H]
3259 ddt version
3260
3261COMMANDS
3262
3263 * add-alias         : add an alias for a computer (like CNAME for the DNS)
3264 * add-dhcp          : add a computer with a fix DHCP IP or in a DHCP pool
3265 * add-float         : add a computer with an IP in a DHCP pool
3266 * add-static        : add a computer with a static IP
3267 * add-virtual       : add a virtual computer with a static IP but a virtual MAC (useful to declare float computer in DNS)
3268 * change-comment    : change the computer comment
3269 * change-sector     : change the sector attachment for a computer
3270 * change-host       : change the computer hostname
3271 * change-ip         : change the computer IP address
3272 * change-mac        : change the computer physical MAC address
3273 * change-tag        : change the list of TAGs associated to a computer
3274 * check-dns         : check the DNS table for base IPs
3275 * create-sector     : create a new sector
3276 * create-pool       : create a new pool for DHCP records
3277 * create-pxe        : create a new PXE/BOOTP configuration
3278 * create-tag        : create a new TAG
3279 * del-float         : remove a computer from a DHCP pool
3280 * del-pc            : remove a computer (DHCP or static IP) from the YAML database
3281 * disable-pc        : disable a computer (DHCP and/or DNS) (but keep it in the database)
3282 * disable-float     : disable a computer from a DHCP pool (but keep it in the database)
3283 * disable-pxe       : remove PXE/BOOTP configuration on a computer
3284 * enable-float      : enable a previous disable computer (DHCP and/or DNS)
3285 * enable-pc         : enable a previous disable computer (DHCP and/or DNS)
3286 * enable-pxe        : enable PXE/BOOTP configuration on a computer
3287 * gen-dhcp-file     : generate DHCP files for the isc DHCP server
3288 * gen-dns-file      : generate DNS files for the bind domain server
3289 * help              : this help
3290 * load-database     : load the YAML database (be careful)
3291 * remove-pxe        : remove a PXE/BOOTP configuration
3292 * remove-tag        : remove a TAG
3293 * search-mac        : search physical MAC address computer
3294 * ddt sector-add-ip : add IP range check on a sector
3295 * show-sector       : list all sector group of computer
3296 * show              : list all computers
3297 * show-pool         : list all pool
3298 * show-pxe          : list PXE/BOOTP configuration
3299 * show-tag          : list all TAGs
3300 * version           : return program version
3301END
3302   return;
3303   }
3304
3305################################################################
3306# documentation
3307################################################################
3308
3309__END__
3310
3311=head1 NAME
3312
3313ddt - management of computer names and IP addresses
3314
3315
3316=head1 USAGE
3317
3318 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3319 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3320 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3321 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3322 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3323 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3324 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3325 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3326 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3327 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3328 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3329 ddt check-dns [--direct] [--reverse]
3330 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3331 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3332 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3333 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3334 ddt del-float [--pool|-p pool] [--mac|-m mac]
3335 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3336 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3337 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3338 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3339 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3340 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3341 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3342 ddt gen-dhcp-file
3343 ddt gen-dns-file [--verbose]
3344 ddt help
3345 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3346 ddt remove-pxe [--bootp|-b pxe_config]
3347 ddt remove-tag [--tag|-t tag]
3348 ddt search-mac [--mac|-m mac]
3349 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3350 ddt show-sector [--no-header|-H]
3351 ddt show
3352 ddt show-pool [--no-header|-H]
3353 ddt show-pxe [--no-header|-H]
3354 ddt show-tag [--no-header|-H]
3355 ddt version
3356
3357
3358=head1 DESCRIPTION
3359
3360DDT is an acronym for DHCP-DNS-Tools.
3361The previous command name was not C<ddt> but just C<dhcp-dns-tools>...
3362In practise, DDT is an IP Address Management (IPAM) service.
3363It has been used in the LEGI laboratory for over 10 years.
3364
3365The tool is quite effective and tries to keep things simple
3366but easily configurable for your site like a swiss army knife.
3367Everything is saved in a YAML database
3368and entries could be added, deleted, or modified by the command line.
3369
3370
3371=head1 COMMANDS
3372
3373=head2 add-alias
3374
3375 ddt add-alias [--hostname|-h hostname] [--sector|-s|-d sector] [--alias|-a alias]
3376
3377=head2 add-dhcp
3378
3379 ddt add-dhcp [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3380
3381=head2 add-float
3382
3383 ddt add-float [--pool|-p pool] [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3384
3385=head2 add-static
3386
3387 ddt add-static [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--comment|-c comment]
3388
3389=head2 add-virtual
3390
3391 ddt add-virtual [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--comment|-c comment]
3392
3393=head2 change-comment
3394
3395 ddt change-comment [--sector|-s|-d sector] [--mac|-m mac] [--comment|-c comment]
3396
3397=head2 change-sector
3398
3399 ddt change-sector [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3400
3401=head2 change-host
3402
3403 ddt change-host [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3404
3405=head2 change-ip
3406
3407 ddt change-ip [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3408
3409=head2 change-mac
3410
3411 ddt change-mac [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac]
3412
3413=head2 change-tag
3414
3415 ddt change-tag [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--mac|-m mac] [--tag|-t tag]
3416
3417=head2 check-dns
3418
3419 ddt check-dns [--direct] [--reverse]
3420
3421=head2 create-sector
3422
3423 ddt create-sector [--sector|-s|-d sector] [--dns-extension|-e dns_extension] [--comment|-c comment]
3424
3425=head2 create-pool
3426
3427 ddt create-pool [--pool|-p pool] [--sector|-s|-d sector] [--file-pool|-f file_pool] [--ipaddress-pool|-i ipaddress_pool]
3428
3429=head2 create-pxe
3430
3431 ddt create-pxe [--bootp|-b pxe_config] [--next-server|-n next_server] [--filename|-f filename] [--comment|-c comment]
3432
3433=head2 create-tag
3434
3435 ddt create-tag [--tag|-t tag] [--comment|-c comment]
3436
3437=head2 del-float
3438
3439 ddt del-float [--pool|-p pool] [--mac|-m mac]
3440
3441=head2 del-pc
3442
3443 ddt del-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3444
3445=head2 disable-pc
3446
3447 ddt disable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3448
3449=head2 disable-float
3450
3451 ddt disable-float [--pool|-p pool] [--mac|-m mac]
3452
3453=head2 disable-pxe
3454
3455 ddt disable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3456
3457=head2 enable-float
3458
3459 ddt enable-float [--pool|-p pool] [--mac|-m mac]
3460
3461=head2 enable-pc
3462
3463 ddt enable-pc [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip]
3464
3465=head2 enable-pxe
3466
3467 ddt enable-pxe [--hostname|-h hostname] [--sector|-s|-d sector] [--ip|-i ip] [--bootp|-b pxe_config]
3468
3469=head2 gen-dhcp-file
3470
3471 ddt gen-dhcp-file
3472
3473=head2 gen-dns-file
3474
3475 ddt gen-dns-file [--verbose]
3476
3477=head2 help
3478
3479 ddt help
3480
3481=head2 load-database
3482
3483 ddt load-database [--sector|-s|-d sector] [--filename|-f filename] [--kind|-k kind]
3484
3485=head2 remove-pxe
3486
3487 ddt remove-pxe [--bootp|-b pxe_config]
3488
3489=head2 remove-tag
3490
3491 ddt remove-tag [--tag|-t tag]
3492
3493=head2 search-mac
3494
3495 ddt search-mac [--mac|-m mac]
3496
3497=head2 sector-add-ip
3498
3499 ddt sector-add-ip [--sector|-s|-d sector] [--ip-range|-i ip_cidr]
3500
3501=head2 show-sector
3502
3503 ddt show-sector [--no-header|-H]
3504
3505=head2 show
3506
3507 ddt show
3508
3509=head2 show-pool
3510
3511 ddt show-pool [--no-header|-H]
3512
3513=head2 show-pxe
3514
3515 ddt show-pxe [--no-header|-H]
3516
3517=head2 show-tag
3518
3519 ddt show-tag [--no-header|-H]
3520
3521=head2 version
3522
3523 ddt version
3524
3525
3526=head1 AUTHORS
3527
3528Written by Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>, Kevin Reverchon, Olivier De-Marchi - Grenoble - France
3529
3530
3531=head1 LICENSE AND COPYRIGHT
3532
3533License GNU GPL version 2 or later and Perl equivalent
3534
3535Copyright (C) 2006-2018, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
Note: See TracBrowser for help on using the repository browser.