Bonjour,

Je développe une interface qui permet d’éteindre un certain nombre de serveur linux de manière rapide et sans aller en ssh sur chacun. (environ 50).

Pour cela, je développe sous django.

J'ai cependant un problème, en effet, j'utilise des Thread pour exécuter la commande d'arrêt en simultanée sur l'ensemble des serveurs afin de maximiser le temps d'arrêt, mais lors du lancement du code, certains serveurs ne s'éteignent pas (je ne sais pas s'il est possible de voir la commande dans les logs des serveurs).

Ci dessous le code (ou du moins la partie qui nous concernent).

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
############ -THREAD ARRET TOTAL- ########################
def th_arret_total(request,p1,p2, p3,p4, dechiffre_pwd):
    today = timezone.now()
    print "today UTC: %s" % today
 
    #p1 = param['serveur']
    #p2 = param['pwd']
    #p3 = param['ip']
    #p4 = param['username']
 
    cmd_arret = str('init 0')
 
    try:
        output = subprocess.check_output(['sshpass -p '+dechiffre_pwd+' ssh -o ConnectTimeout=2 '+p4+'@'+p3+ ' '+cmd_arret],shell=True,stderr=subprocess.STDOUT)  # LE shell=True permet d'executer avec des option ssh
        print "Sortie premiere commande: %s" % output
 
        print "\n----------Srv P: %s" % p1 +"---------------\n"
        print "Resultat %s : %s" % (p1,output)
 
        fichier_cnf = io.open(chemin_du_fichier_log, "a", encoding='utf8')
 
        fichier_cnf.write(u'{nl}{nl}********-LOG ARRET -*****************************\
                            {nl}date execution script = {date}\
                            {nl}Serveur = {p1}\
                            {nl}*************************************{nl}'.format(
            date=today,
            p1=p1,
            nl='\n')
        )
        fichier_cnf.close()
 
 
    except subprocess.CalledProcessError as grepexc:
        print "\nCode Erreur ", grepexc.returncode, grepexc.output
 
        fichier_cnf = io.open(chemin_du_fichier_log, "a", encoding='utf8')
 
        fichier_cnf.write(u'{nl}{nl}********-LOG ARRET (erreur)-*****************************\
                            {nl}date execution script = {date}\
                            {nl}Serveur = {p1}\
                            {nl}code erreur = {code_erreur}\
                            {nl}*************************************{nl}'.format(
            date=today,
            p1=p1,
            code_erreur=grepexc.output,
            nl='\n')
        )
        fichier_cnf.close()
 
 
        print type(grepexc.output), str(grepexc.output)
        erreur_verif_key = str('Host key verification failed.')
 
        # COMPARAISON DE RETOUR D'ERREUR "Host key verification failed." AVEC LA VARIBLE grepexc.output
 
        error1 = [(grepexc.output).decode("utf-8").rstrip('\n\r')]  # Permet de supprimer le retour chariot a la fin
 
        print "\n----------Srv P: %s" % p1 +"---------------\n"
        print 'Erreur_1: %s - %s' % (p1, error1)
 
        for place in error1:
            print ('Verification %s with %s: %s' % (place, erreur_verif_key, place == erreur_verif_key))
            print (place == erreur_verif_key)
 
        if (place == erreur_verif_key) == True:
            # SI L'ERREUR EST POSITIVE, ALORS ON ENTRE LA CLE ECDSA DANS LE FICHIER KNOW_HOST DE SSH
            output1 = str(
                'sshpass -p ' + dechiffre_pwd + ' ssh -o StrictHostKeyChecking=no ' + p4 + '@' + p3 + ' exit')
            print output1
            os.system(output1)
 
            print "\n----------Srv P: %s" % p1 +"---------------\n"
            print('\nSortie Cle ECDSA: ', output1.decode('UTF-8'))
            # RENVOI DE LA COMMANDE DE MANIERE AUTOMATIQUE
            try:
                output = subprocess.check_output(['sshpass -p '+dechiffre_pwd+' ssh -o ConnectTimeout=2 '+p4+'@'+p3+ ' '+cmd_arret], shell=True,
                                                 stderr=subprocess.STDOUT)
                print('Sortie relance Cmd: ', output.decode('UTF-8'))
 
                fichier_cnf = io.open(chemin_du_fichier_log, "a", encoding='utf8')
 
                fichier_cnf.write(u'{nl}{nl}********-LOG ARRET (relance)-*****************************\
                                    {nl}date execution script = {date}\
                                    {nl}Serveur = {p1}\
                                    {nl}Sortie relance = {output}\
                                    {nl}*************************************{nl}'.format(
                    date=today,
                    p1=p1,
                    output=output,
                    nl='\n')
                )
                fichier_cnf.close()
 
            # SI ERREUR, AFFICHAGE DU MESSAGE D'ERREUR SUR LA PAGE "retour_global.html"
            except subprocess.CalledProcessError as grepexc:
                print "\n----------Srv P: %s" % p1 +"---------------\n"
                print "\nCode Generale", grepexc.returncode, grepexc.output
 
                fichier_cnf = io.open(chemin_du_fichier_log, "a", encoding='utf8')
 
                fichier_cnf.write(u'{nl}{nl}********-LOG ARRET (relance)-*****************************\
                                    {nl}date execution script = {date}\
                                    {nl}Serveur = {p1}\
                                    {nl}Sortie generale = {sortie_generale}\
                                    {nl}*************************************{nl}'.format(
                    date=today,
                    p1=p1,
                    sortie_generale=grepexc.output,
                    nl='\n')
                )
                fichier_cnf.close()
 
                return render(request, 'retour_global.html', {'output': grepexc.output})
 
    except request.Timeout as err:
        print "TIMEOUT"
        print err.message
        pass
 
 
    except CalledProcessError:
        #return redirect('ping')
        return render(request, 'ping.html')
 
    except:
        print "PASS"
        pass
 
 
def arret_total(request):
    print request.user.has_perm("sar.executer_commande_arret")
    if not request.user.has_perm("sar.executer_commande_arret"):
        return HttpResponse('The user is not superuser')
    else:
        # RECUPERATION FUSEAU HORAIRE FR
        PT = pytz.country_timezones['FR']
        print PT
 
        # HEURE AU FORMAT UTC
        today = timezone.now()
        print "today UTC: %s" % today
 
        # HEURE AU FORMAT UTC+1
        today_11 = timezone.localtime()
        print "today UTC+11: %s" % today_11
 
        delta_10min = timezone.now() + timedelta(minutes=10)
        print type(delta_10min)
 
        delta = delta_10min.strftime('%Y-%m-%d %H:%M')
        print "delta: %s" % delta
        print type(delta)
 
 
 
        if request.method == 'POST':
            arret_form = ArretTotalForm(request.POST)
            mastercode = MasterCodeForm(request.POST)
 
            if arret_form.is_valid() and mastercode.is_valid():
 
                code1 = arret_form.cleaned_data['code1']
                code2 = arret_form.cleaned_data['code2']
 
                code_maitre = mastercode.cleaned_data['code_maitre']
 
 
                try:
                    recup_date = ArretTotal.objects.get(Q(code1=code1) & Q(code2=code2)).date
 
                    verif_code_master = MasterCode.objects.values('code_maitre').filter(code_maitre__startswith='C')
 
 
                    for result in verif_code_master:
                        solution = result['code_maitre']
 
                        substring = "C"
 
                        print solution
 
                        if solution.find(substring) is not -1:
                            print 'solution %s' % solution
                        else:
                            print solution.find(substring)
                            messages.error(request, messages.INFO, "Error")
                            return render(request, 'arret_total.html', {'arret_form': arret_form, 'mastercode': mastercode})
 
                    print "recup_date"
                    print recup_date
 
                except ObjectDoesNotExist:
                    return redirect('erreur_code_arret')
 
 
                compare_heure = (today_11 - recup_date).seconds
                print "compare_heure: %s" % compare_heure
                print type(compare_heure)
 
                if compare_heure < int(600) and solution == code_maitre:
 
                    liste_srv = Globale.objects.values('serveur', 'pwd', 'ip', 'username').exclude(type=10).exclude(type=9).order_by('priorite')
                    print liste_srv.query
 
 
                    for param in liste_srv:
 
                        p1 = param['serveur']
                        p2 = param['pwd']
                        p3 = param['ip']
                        p4 = param['username']
 
                        dechiffre_pwd = dechiffre.dechiffre(p2)
                        threading.Thread(target=th_arret_total, args=(request, p1,p2,p3,p4, dechiffre_pwd)).start()
 
 
 
                    # SUPPRESSION DES CODES 1 ET 2  ET DU CODE MAITRE DE LA BDD
                    lst = [Q(code1=code1), Q(code2=code2)]
 
                    obj = ArretTotal.objects.filter(reduce(AND,lst))
                    obj2 = MasterCode.objects.filter(code_maitre=code_maitre)
                    print obj.query
                    obj.delete()
                    obj2.delete()
 
                    # GENERATION D'UN NOUVEAU CODE MAITRE
                    generation_code_maitre = random.randrange(100000, 500000)
                    Exe = MasterCode(code_maitre= str('C')+str(generation_code_maitre))
                    Exe.save()
 
                    print request.user.email
 
                    # PERMET D'ENVOYER LE MAIL
                    perms = Permission.objects.get(codename='executer_commande_arret')
                    users = User.objects.get(username='admin').email
                    print 'users: %s' % users
 
 
                    sujet = 'CODE MAITRE'
                    message = 'Bonjour,\n' \
                              'Voici le Code Maitre pour valider l\'arrêt :\n\n' \
                              '######################## - CODE MAITRE - ########################\n\n' \
                              'CODE MAITRE: C' + str(generation_code_maitre) + '\n\n' \
                              '######################## - CODE MAITRE - ########################\n\n' \
                              'Celui-ci n\'est valide que pour une seule utilisation, il est auto-généré.\n' \
                              'Cette commande à été demandée par l\'utilisateur: ' + request.user.username + '.\n' \
                             'Cdt\n' \
                             '--Mail automatique ne pas répondre.--'
 
                    envoyeur = 'user@logtest.com'
                    destinataires = [users]
                    send_mail(sujet, message, envoyeur, destinataires)
 
                    return HttpResponseRedirect('ping')
        else:
            arret_form = ArretTotalForm()
            mastercode = MasterCodeForm()
 
        return render(request, 'arret_total.html', {'arret_form': arret_form, 'mastercode': mastercode})
J'ai aussi cette erreur qui s'affiche lors de l'execution du script, généralement à la fin sur plusieurs lignes:
Nom : Capture.PNG
Affichages : 130
Taille : 494,0 Ko

J'ai bien conscience que mon code n'est pas parfait, mais cela pourra faire l'objet d'un second poste pour l'optimiser.

Merci à vous