Script de sauvegarde [Fermé]

Signaler
Messages postés
63
Date d'inscription
vendredi 17 mars 2017
Statut
Membre
Dernière intervention
11 août 2017
-
Messages postés
63
Date d'inscription
vendredi 17 mars 2017
Statut
Membre
Dernière intervention
11 août 2017
-
Bonjour,

Je tiens a préciser que je suis débutant sur ce langage et dont j'ai beaucoup de mal a mis mettre donc essayé d’être le plus précis possible pour que je puisse bien comprendre.

Dans l'optique de créer un script de sauvegarde d'équipements automatique,

Je souhaite lire un fichier txt contenant des informations, sous la forme ci-dessous, pour les attribuer chacune à une variable.

-----------------------------------------------
exemple.txt :

info1:info11:info12:info13
info2:info21:info22:info23
etc...
-----------------------------------------------

Pour obtenir le résultat suivant :

$ip = info1
$port = info11
$nom_eqpmt=info12
etc...

Utiliser les variables précédemment créés pour se connecter etc sur un équipement pour faire la sauvegarde du matos et d'effectuer cette action pour chaque ligne du fichier txt (une ligne correspondant à un équipement différent).
Si quelqu'un arrive à me mettre sur la voie, se serais au top.

J'espère que j'ai été assez compréhensible sinon n'hésité pas a me poser des questions.

3 réponses

Messages postés
5541
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2021
933
Salut Lartishot,

Utiliser
split()
, comme proposé par Felice_, est une façon de faire appropriée car ta structure repose sur un séparateur, à savoir
:
. Si tu as 4 champs, comme tu semblais le dire sur ton jeu de données d'exemple, il faudra rajouter la récupération de ce 4ème champ dans le code de Felice_

Autrement, on peut aussi utiliser une regexp qui offre plus de contrôle, et permet de valider le format de tes lignes, par rapport à ton exemple où il doit il avoir 4 champs par lignes, comprenant du texte non vide séparé par des
:
avec des champs non vides.

#!/usr/bin/perl

use strict;
use warnings;

my $fichier = "monFichier.txt";
open(my $descripteur, '<:encoding(UTF-8)', $fichier)
    or die "Ouverture impossible du fichier '$fichier' $!";

while (my $row = <$descripteur>) {
    chomp $row;
    if ($row =~ /^([^:]+):([^:]+):([^:]+):([^:]+)$/) {
        my ($ip, $port, $nom_eqpmt, $comment) = ($1, $2, $3, $4);
        print "J'ai récupéré ip=$ip - port=$port - ".
            "nom_eqpmt=$nom_eqpmt - comment=$comment\n";
        # faire quelque chose avec ces données
        # lancer la sauvegarde, etc.
    } else {
        print "Erreur de format, ligne : $row\n";
    }
}
print "Terminé !\n";

La regexp en ligne 12 permet à la fois de vérifier qu'il y a bien 4 champs, séparés par 3
:
, que chaque champ comporte au moins un caractère, et de capturer le contenu de ces champs dans les variables $1, $2, $3, $4 dont le contenu est ensuite passé à tes variables de travail.

Si ce format n'est pas respecté, une erreur est signalée en ligne 19.

Dal
1
Merci

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

CCM 65492 internautes nous ont dit merci ce mois-ci

Messages postés
63
Date d'inscription
vendredi 17 mars 2017
Statut
Membre
Dernière intervention
11 août 2017
13
Merci pour ta réponse (avec les détails qui vont avec) ! ton script a été plus facile a assimiler que celui de Felice_. J'ai réussi assez facilement a l'adapter a mon contexte.
Ne reste plus que je fasse la partie du script qui permettra, pour chaque ligne récupérer, la connexion au routeur et la récupération du fichier de sauvegarde via tftp.
Messages postés
63
Date d'inscription
vendredi 17 mars 2017
Statut
Membre
Dernière intervention
11 août 2017
13
Si je rajoute ceci en dessous du print :


# -*- Coding: utf-8 -*-

 $obj    = shift;                                                                    
 my $prompt = shift;                                                          

        $obj->raw_pty(0);                                                                  
        $obj->log_stdout(0);                                                                 
        $obj->log_file($log_file);                                                             

        unless ( $obj->spawn("/usr/bin/telnet $ip") ) {                                    
                $return = "Commande TELNET non disponible";
                return "NOK\n";
          }

        unless ( $obj->expect(15, "User Name: " )) {                                             
                 $return = "Impossible de ce connecter en TELNET";
                 return "NOK\n";
        }

        $obj->send("$login\n");

        unless ( $obj->expect(15, "Password: " )) {                                              
                $return = "Impossible de ce connecter en TELNET";
                return "NOK\n";
        }

        $obj->send("$password\n");

        unless ($obj->expect(15, "$prompt>" )) {                                                
                $return = "Prompt invalide ou mot de passe invalide";
                return NOK, $return;
        }

        return OK, $return;

Messages postés
5541
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
7 mai 2021
933
Expect est parfois un peu délicat à manier, le module Expect de Perl assez complexe. Si c'est ce que tu utilises, tu ne le fais pas de la manière suggérée par les exemples de la doc : https://metacpan.org/pod/release/RGIERSIG/Expect-1.15/Expect.pod#Source_Examples

Si tu vas utiliser Telnet systématiquement, tu pourrais utiliser Net::Telnet, qui est plus simple.

https://metacpan.org/pod/release/JROGERS/Net-Telnet-3.04/lib/Net/Telnet.pm
https://metacpan.org/pod/release/JROGERS/Net-Telnet-3.04/lib/Net/Telnet.pm#EXAMPLES

Il faut bien paramétrer le prompt si tu veux que cela fonctionne.

Dal
Messages postés
63
Date d'inscription
vendredi 17 mars 2017
Statut
Membre
Dernière intervention
11 août 2017
13
J'ai trouvé ce bout de code aussi mais qui utilise SSH. J'arrive mieux a cerné ce code par contre par rapport a mon précédent.

#!/usr/bin/perl

use strict; 
use warnings; 
  
use Net::SSH::Expect; 
  
my $ssh = Net::SSH::Expect->new( 
  host     => '192.168.1.1', 
  password => 'cisco', 
  user     => 'admin', 
  raw_pty  => 1 
); 
  
my $enable_passwd = "cisco"; 
my $login_output  = $ssh->login(); 
  
$ssh->send("enable"); 
$ssh->waitfor( 'Password:\s*\z', 1 ) or die "prompt 'password' not found after 1 second"; 
$ssh->send($enable_passwd); 
  
my $ls = $ssh->exec("show vlan"); 
print "$ls\n"; 
  
#Première façon de récupérer une sortie longue: 
$ssh->send("show running-config"); 
while ( my $line = $ssh->read_line() ) { 
  print "$line\n"; 
} 
Messages postés
265
Date d'inscription
mardi 25 avril 2017
Statut
Membre
Dernière intervention
20 juillet 2017
10
En Perl 5

# -*- Coding: utf-8 -*-

use strict;
use warnings;

my $fichier = 'monFichier.txt';

if(-e $fichier && -f $fichier) {
   my $descripteur;
   
   if(!open($descripteur, '<', $fichier)) {
       exit(1);
   }
   
   my $ligne;
   my @donnees;
   my $ip;
   my $port;
   my $nom_eqpmt;

   while(defined($ligne = <$descripteur>)) {
       chomp $ligne;
       
       @donnees   = split(':', $ligne);
       $ip        = $donnees[0];
       $port      = $donnees[1];
       $nom_eqpmt = $donnees[2];
   }
   
   close($descripteur);
}
Messages postés
265
Date d'inscription
mardi 25 avril 2017
Statut
Membre
Dernière intervention
20 juillet 2017
10
En Perl 6 :

# -*- Coding: utf-8 -*-

my $fichier = 'monFichier.txt';

if $fichier.IO.e && $fichier.IO.f {
   my $descripteur = open $fichier, :r;
   
   if !$descripteur {
       exit(1);
   }
   
   my $ligne;
   my @donnees;
   my $ip;
   my $port;
   my $nom_eqpmt;
   
   for $fichier.IO.lines -> $ligne {
       chomp $ligne;
       
       @donnees   = split(':', $ligne);
       $ip        = @donnees[0];
       $port      = @donnees[1];
       $nom_eqpmt = @donnees[2];
   }
   
   $descripteur.close;
}
Messages postés
63
Date d'inscription
vendredi 17 mars 2017
Statut
Membre
Dernière intervention
11 août 2017
13
Alors là je vous demande vos avis sur le code que j'ai fais (trouver en partie sur le net :
#!/usr/bin/perl


use Expect; # Utilisation du module Expect

#$Expect::Log_Stdout=1;

#Chargement du fichier de commandes

print "\nChargement du fichier contenant la liste des commandes 'liste.commandes'...";

$ListeCommandes = 'liste.commandes' ;
open(LISTECOMMANDES, "<$ListeCommandes" ) || die "\nNe peux lire le fichier $ListeCommandes: $!";
@commandes = <LISTECOMMANDES> ;
close(LISTECOMMANDES) ;

print "OK\n";


#Chargement du fichier de hosts

print "\nChargement du fichier contenant la liste des equipements...";

my $ListeHosts  = "liste.ciscosmb";



open(LISTEHOSTS, '<:encoding(UTF-8)', $ListeHosts) || die "Ouverture impossible du fichier '$ListeHosts' $!\n";
@hosts = <LISTEHOSTS> ;
while (my $row = <LISTEHOSTS>) 

{
 	chomp $row;
    if ($row =~ /^([^:]+):([^:]+):([^:]+):([^:]+):([^:]+):([^:]+)$/) 
    	{
        
        my ($ip, $port, $login, $pwd, $enablemdp, $iptftp) = ($1, $2, $3, $4, $5, $6);
        print " IP=$ip - Port=$port - Login=$login - Password=$pwd - EnablePassword=$enablemdp - IpTFTP=$iptftp\n";
    	
    	} 
}

close(LISTEHOSTS) ;

print "OK\n";

# Demande du login a utiliser

print "\nChargement du login";
my $user = "$login";

print "\nChargement du mot de passe";
my $loginpass = "$pwd";

print "\nChargement mot de passe Enable";
my $enablepass = "$enablempd";


### Connexion sur les equipements

# Creation du fichier de log avec comme extension le type de device puis la date

# Appel de la fonction localtime
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year+=1900; # ajout de 1900 a l'annee
$mon+=1; # ajout de 1 au mois car le premier est zero

print "\nCreation du fichier de log...";

open(LOG_FILE, ">log.ciscosmb.${year}${mon}${mday}${hour}${min}") || die "\nNe peux ecrire dans le fichier log.ciscosmb: $!";

print "OK\n";

# Avertissement du fonctionnement en mode de test

if ($testonly==1) {
        print LOG_FILE "Mode Test: les commandes suivantes ne seront pas envoyees au equipement\n";
        }

# Insertion des commandes dans le fichier de log

print LOG_FILE "Liste des commandes entrée:\n\n";
foreach $commande (@commandes) {
        last if $commande eq "\n" ; # Arret sur la premiere ligne vide
        next if /^#/; # va a la ligne suivante si commentaire
        chomp ($commande); # suppresion du caractere \n
        print LOG_FILE "$commande\n";
}
print LOG_FILE "-------------------------------\n";

#Boucle globale pour chaque device de la liste

HOST: foreach $host (@hosts) {
        chomp ($host); 
        last HOST if $host eq "\n";
        next HOST if /^#/ ;
        print LOG_FILE "Host : $host\n";
        print LOG_FILE "------\n";

### Login sur l'equipement

        print LOG_FILE "Connexion a l'equipement...";
        $telnet=Expect->spawn("telnet $host");
        if ($telnet->expect(5,"Password: ")) {
                print $telnet "$loginpass\r"; 
        }
        else {
                print $telnet "\b$user\r";
                sleep 1;
                print $telnet "$loginpass\r";
        }
        $prompt  = '[\>]';
        if (!$telnet->expect(5,'-re',$prompt)) {
                print LOG_FILE "\nProbleme de login sur $host, ".$telnet->exp_error()."\n";
                $telnet->hard_close(); # Fermeture de la session
                next HOST; # On passe au suivant        
        }
        print LOG_FILE "OK\n";

### Envoie de la configuration

        print LOG_FILE "Passage en mode Enable...";
        print $telnet "enable\r";
        sleep 1;
        if (!$telnet->expect(5,"Password: ")) {
                print LOG_FILE "\nNe reconnais pas la commande enable";
                $telnet->hard_close();
                next HOST;
        }
        print $telnet "$enablepass\r";
        $prompt = '[\#]';
        if (!$telnet->expect(5,'-re',$prompt)) {
                print LOG_FILE "\nProbleme de passage en mode Enable sur $host, ".$telnet->exp_error()."\n";
                $telnet->hard_close();
                next HOST; 
        }
        print LOG_FILE "OK\n";

### Execution des commandes si on n'est pas en mode de test

        if ($testonly eq "oui") {
                $telnet->hard_close();
                next HOST;
        }

        print LOG_FILE "Envoie des commandes...";
        foreach $commande (@commandes) {
                chomp($commande);
                print $telnet "$commande\r";
                if (!$telnet->expect(20,'-re',$prompt)) {
                        print LOG_FILE "\nProbleme a la commande $commande sur $host, ".$telnet->exp_error()."\n";
               $telnet->hard_close();  # fermeture de la session
                next HOST; # On passe au suivant
                }
                sleep 1; # pause de 1 seconde entre chaque commande
        }
        print LOG_FILE "OK\n";

### Fermeture de Session

        print LOG_FILE "Ended for $host\n\n";
        $telnet->hard_close(); # Fermeture de la session

} # Fin de la boucle globale
close(LOG_FILE) || die "\nNe peux fermer le fichier log.ciscosmb : $!"; # Fermeture du fichier de log