migration_amon_26.py
1 |
#!/usr/bin/env python
|
---|---|
2 |
# -*- coding: UTF-8 -*-
|
3 |
|
4 |
import sys |
5 |
if '/usr/share/eole/orl' not in sys.path: |
6 |
sys.path.append('/usr/share/eole/orl')
|
7 |
if '/usr/share/eole/orl/scripts' not in sys.path: |
8 |
sys.path.append('/usr/share/eole/orl/scripts')
|
9 |
###########################################################################
|
10 |
# Eole - 2014
|
11 |
# Copyright Pole de Competence Eole (Ministere Education - Academie Dijon)
|
12 |
# Licence CeCill cf /root/LicenceEole.txt
|
13 |
# eole@ac-dijon.fr
|
14 |
#
|
15 |
# migration_2.4.py
|
16 |
#
|
17 |
# squelette de script permettant de générer des configurations de migration
|
18 |
# en mode batch (via l'API XMLRPC de Zéphir)
|
19 |
#
|
20 |
# Ce script génère une configuration de la même façon qu'en utilisant
|
21 |
# le bouton "générer un configuration de migration' de l'application web.
|
22 |
#
|
23 |
# Il est possible de personnaliser la fonction update_conf pour gérer
|
24 |
# des variables supplémentaires non gérées par la fonction d'origine.
|
25 |
# (variables déclarées au niveau des variantes / serveurs).
|
26 |
#
|
27 |
###########################################################################
|
28 |
|
29 |
import csv,getpass,os |
30 |
import base64,xmlrpclib |
31 |
from zephir.utils.creolewrap import ZephirDict |
32 |
import sys |
33 |
reload(sys)
|
34 |
import string |
35 |
# force l'encodage par défaut à utf-8 pour les chaînes unicode
|
36 |
sys.setdefaultencoding('utf-8')
|
37 |
|
38 |
# à redéfinir si utilisé à distance
|
39 |
adresse_zephir='localhost'
|
40 |
|
41 |
# délimiteur de champ pour le fichier CSV décrivant les serveurs à traiter
|
42 |
delimiter = ';'
|
43 |
# contenu des champs du fichier csv:
|
44 |
# id_serveur;id_variante_destination
|
45 |
|
46 |
# !! mettre à True pour vérifier les valeurs lors de tests (la configuration ne sera pas sauvegardée) !!
|
47 |
debug = False
|
48 |
|
49 |
#######################################################
|
50 |
## FONCTIONS UTILITAIRES POUR LE TRAITEMENT DES VALEURS
|
51 |
|
52 |
def is_empty(value): |
53 |
# renvoie True si value est 'vide' :
|
54 |
# liste vide / chaine vide / liste de chaines vides
|
55 |
return len(u"".join(value)) == 0 |
56 |
|
57 |
def is_equal(dico, nom_var, test): |
58 |
"""renvoie True si la valeur de la variable nom_var est équivalente à test
|
59 |
gère le cas des chaines unicode ou non et des listes 'vides'
|
60 |
"""
|
61 |
if nom_var in dico.liste_vars: |
62 |
if test in ([], [''], [u'']): |
63 |
if dico.get_value(nom_var) in ([], [''], [u'']): |
64 |
return True |
65 |
if dico.get_value(nom_var) == test or \ |
66 |
dico.get_value(nom_var) == [test] or \
|
67 |
dico.get_value(nom_var) == [unicode(test)]:
|
68 |
return True |
69 |
return False |
70 |
else:
|
71 |
print u"Appel de is_equal sur une variable inconnue : {0}".format(nom_var) |
72 |
|
73 |
def copy_val(dico, nom_var, value): |
74 |
""" définit une valeur sur une variable en transformant
|
75 |
les chaînes non unicode en unicode dico est une configuration 2.4
|
76 |
"""
|
77 |
if nom_var in dico.liste_vars: |
78 |
if value == "[u'']" or value == "['']": |
79 |
value = [] |
80 |
if value != '[]' and type(value) != list: |
81 |
#print "START", nom_var
|
82 |
if value.startswith(u"["): |
83 |
value = eval(value)
|
84 |
# si le dictionnaire de destination est de type 'creole3' (eole 2.4),
|
85 |
# on transforme les type 'str' en 'unicode'
|
86 |
if dico.version == 'creole3': |
87 |
if type(value) == list: |
88 |
for index ,val in enumerate(value): |
89 |
if type(val) == str: |
90 |
value[index] = unicode(val, 'utf-8') |
91 |
elif type(value) == str: |
92 |
value = unicode(value, 'utf-8') |
93 |
dico.get_var(nom_var) |
94 |
dico.set_value(value) |
95 |
else:
|
96 |
print u"Appel de copy_val sur une variable inconnue : {0}".format(nom_var) |
97 |
|
98 |
def read_val(dico, nom_var): |
99 |
if nom_var in dico.liste_vars: |
100 |
value = dico.get_value(nom_var) |
101 |
if value == "[u'']" or value == "['']" or value == ['']: |
102 |
value = [] |
103 |
if value != '[]' and type(value) != list: |
104 |
#print "START", nom_var
|
105 |
if value.startswith(u"["): |
106 |
value = eval(value)
|
107 |
if type(value) == list: |
108 |
for index,v in enumerate(value): |
109 |
if type(v) == str: |
110 |
value[index] = unicode(v, 'utf-8') |
111 |
return value
|
112 |
else:
|
113 |
return unicode(dico.get_value(nom_var), 'utf-8') |
114 |
else:
|
115 |
print u"Appel de read_val sur une variable inconnue : {0}".format(nom_var) |
116 |
|
117 |
###AJOUT ORLEANS
|
118 |
nat_agr={"18":"20", |
119 |
"28":"21", |
120 |
"36":"22", |
121 |
"37":"23", |
122 |
"41":"24", |
123 |
"45":"25", |
124 |
"99":"25" |
125 |
} |
126 |
|
127 |
def sub_octet_4(ip, octet4): |
128 |
octets=ip.split(".")
|
129 |
octets.__delitem__(3)
|
130 |
octets.append(str(octet4))
|
131 |
return ".".join(octets) |
132 |
|
133 |
def sub_octet_1D(ip): |
134 |
octets=ip.split(".")
|
135 |
octets[1]="1"+octets[1] |
136 |
return ".".join(octets) |
137 |
|
138 |
def concat_list(liste1, liste2): |
139 |
new_liste=[] |
140 |
for i in liste1: |
141 |
new_liste.append(i) |
142 |
for j in liste2: |
143 |
new_liste.append(j) |
144 |
return new_liste
|
145 |
|
146 |
def del_index_list(index, liste): |
147 |
return liste.__delitem__(index)
|
148 |
|
149 |
######################################
|
150 |
## FONCTION PERSONNALISEE DE MIGRATION
|
151 |
|
152 |
def update_conf(d_eole1, d_eole2, variante, proxy, domaine, ip_scribe, smtp, type_etab, statut, vm, version, maxchildren_adm, maxchildren_peda, lst_ips): |
153 |
"""
|
154 |
traitement automatique des variables
|
155 |
|
156 |
met à jour la configuration de migration en fonction de la configuration actuelle
|
157 |
|
158 |
d_eole1 : dictionnaire avec la configuration d'origine du serveur
|
159 |
d_eole2 : dictionnaire qui sera sauvegardé sur Zéphir comme 'migration.eol'
|
160 |
(configuration à appliquer sur le serveur migré)
|
161 |
variante: identifiant de la variante du serveur après migration
|
162 |
proxy: proxy XMLRPC utilisable pour faire des appels à l'API Zéphir
|
163 |
|
164 |
lire la valeur d'une variable (dico 1 ou 2):
|
165 |
|
166 |
d_eoleX.get_value('nom_var')
|
167 |
!ATTENTION! : get_value renvoie toujours une liste de valeur.
|
168 |
En cas de test sur une valeur, récupérer la valeur voulue
|
169 |
ex: if read_val(d_eole1,'activer_squid_auth')[0] == 'pedago':
|
170 |
|
171 |
copier la valeur d'une variable de dico1 vers une variabel de dico2:
|
172 |
copy_val(d_eole2,'nom_variable2.4',d_eole1.get_value('nom_variable2.2'))
|
173 |
|
174 |
modifier la valeur d'une variable du dictionnaire eole 2:
|
175 |
|
176 |
copy_val(d_eole2,'nom_var',u'valeur')
|
177 |
|
178 |
pour une variable multiple : copy_val(d_eole2,'nom_var',[u'valeur1',u'valeur2', ...])
|
179 |
|
180 |
vérifier si une variable est présente dans un dictionnaire:
|
181 |
|
182 |
if 'nom_variable' in d_eoleX.liste_vars:
|
183 |
.....
|
184 |
|
185 |
une bonne pratique peut être de créer des sous fonctions spécifiques à chaque variante
|
186 |
|
187 |
Pour plus d'informations sur l'utilisation de l'API de Zéphir:
|
188 |
https://<adresse_ip_zephir>:8070/aide/devel
|
189 |
https://<adresse_ip_zephir>:8070/aide/api
|
190 |
"""
|
191 |
|
192 |
# ----- inclure les traitements des variables ici
|
193 |
# --- !! pour éviter des problèmes d'indentation, configurez l'éditeur pour remplacer
|
194 |
# --- les tabulations par 4 espaces (ou éditez le fichier avec vi sur un module eole)
|
195 |
#
|
196 |
# --- Dans la mesure du possible, utilisez de préférence la modification des valeurs par défaut
|
197 |
# --- des modules/variantes eole NG dans l'application web si les valeurs à renseigner sont les mêmes
|
198 |
# --- pour tous les serveurs d'un(e) variante/module.
|
199 |
|
200 |
|
201 |
### Attention, pour la migration vers EOLE 2.4 :
|
202 |
#
|
203 |
# pour set_value sur d_eole2, il faut utiliser des chaînes unicode pour les chaînes de caractères :
|
204 |
# par exemple:
|
205 |
# - d_eole2.get_var('passerelle_smtp') : sélectionne la variable
|
206 |
# - d_eole2.set_value(u'smtp.in.ac-dijon.fr') : applique la valeur (unicode)
|
207 |
#
|
208 |
# utiliser de préférence les fonction copy_val et read_val, qui convertissent les chaînes si besoin :
|
209 |
# copy_val(d_eole2, 'passerelle_smtp', u'smtp.in.ac-dijon.fr') : ici, u est optionnel
|
210 |
###
|
211 |
|
212 |
# exemple1 : mettre le nombre de cartes à 3 si le modèle de pare-feu dans la configuration amon-1.5
|
213 |
# contient la chaine '3zones'
|
214 |
#
|
215 |
#if 'type_amon' in d_eole1.liste_vars:
|
216 |
# if '3zones' in d_eole1.get_value('type_amon'):
|
217 |
# d_eole2.dico.set_value('nombre_interfaces','3')
|
218 |
|
219 |
# exemple2 : pour la variante 8, activer le serveur sso si le frontend ead-web est activé
|
220 |
#
|
221 |
#if variante == 8:
|
222 |
# if isequal(d_eole2, 'ead_web', 'oui'):
|
223 |
# copy_val(d_eole2,'adresse_ip_sso', read_val(d_eole1,'adresse_ip_eth0'))
|
224 |
|
225 |
# exemple 3:
|
226 |
#
|
227 |
# passage à oui de 'activer_ajout_hosts' si des noms supplémentaires ont été ajoutés par la variante 2.4
|
228 |
# (forcé à non au moment de l'upgrade si la configuration d_eole1 ne contient pas de noms supplémentaire)
|
229 |
#
|
230 |
#if len(d_eole2.get_value('adresse_ip_hosts')) != 0:
|
231 |
# copy_val(d_eole2, 'activer_ajout_hosts', u'oui')
|
232 |
###
|
233 |
# Calul du département
|
234 |
rne=read_val(d_eole1,'numero_etab')[0] |
235 |
dept=rne[1:3] |
236 |
# Mise à jour des variables
|
237 |
#conf wpad
|
238 |
copy_val(d_eole2,'proxy_bypass_eth1','oui') |
239 |
if read_val(d_eole1,'nombre_interfaces')[0]=='4': |
240 |
copy_val(d_eole2,'proxy_bypass_eth3','non') |
241 |
if type_etab=="lyc": |
242 |
copy_val(d_eole2,'proxy_bypass_eth2','oui') |
243 |
copy_val(d_eole2,'proxy_bypass_network_eth2',['192.168.232.0','192.168.236.0','192.168.220.0','192.168.224.0','172.16.0.0','192.168.122.0']) |
244 |
copy_val(d_eole2,'proxy_bypass_netmask_eth2',['255.255.252.0','255.255.255.0','255.255.252.0','255.255.248.0','255.248.0.0','255.255.255.0']) |
245 |
copy_val(d_eole2,'proxy_bypass_network_eth1',['172.16.0.0','172.24.0.0','10.0.0.0','161.48.0.0','192.168.232.0','192.168.236.0','192.168.220.0','192.168.224.0','192.168.122.0']) |
246 |
copy_val(d_eole2,'proxy_bypass_netmask_eth1',['255.248.0.0','255.248.0.0','255.0.0.0','255.255.224.0','255.255.252.0','255.255.255.0','255.255.252.0','255.255.248.0','255.255.255.0']) |
247 |
else:
|
248 |
copy_val(d_eole2,'proxy_bypass_network_eth1',['172.16.0.0','172.24.0.0','10.0.0.0','161.48.0.0']) |
249 |
copy_val(d_eole2,'proxy_bypass_netmask_eth1',['255.248.0.0','255.248.0.0','255.0.0.0','255.255.224.0']) |
250 |
copy_val(d_eole2,'proxy_bypass_eth2','non') |
251 |
copy_val(d_eole2,'proxy_bypass_domain_eth1','etab.ac-orleans-tours.fr') |
252 |
copy_val(d_eole2,'proxy_bypass_domain_eth2',domaine+'.ac-orleans-tours.fr') |
253 |
if read_val(d_eole1,'nombre_interfaces')[0]=='4': |
254 |
copy_val(d_eole2,'proxy_bypass_domain_eth3',domaine+'.ac-orleans-tours.fr') |
255 |
|
256 |
#safesearch via DNS
|
257 |
copy_val(d_eole2,'nom_domaine_local_supp','rpz.com') |
258 |
|
259 |
#pour proxy.wifi
|
260 |
lst_vlan=read_val(d_eole1,'vlan_id_eth2')
|
261 |
lst_dns_fw=read_val(d_eole1,'dns_forward_vlan_eth2')
|
262 |
if "24" in lst_vlan: |
263 |
index=read_val(d_eole1,'vlan_id_eth2').index("24") |
264 |
lst_dns_fw[index]=u"oui"
|
265 |
copy_val(d_eole2,'dns_forward_vlan_eth2',lst_dns_fw)
|
266 |
if "25" in lst_vlan: |
267 |
index=read_val(d_eole1,'vlan_id_eth2').index("25") |
268 |
lst_dns_fw[index]=u"oui"
|
269 |
copy_val(d_eole2,'dns_forward_vlan_eth2',lst_dns_fw)
|
270 |
if "26" in lst_vlan: |
271 |
index=read_val(d_eole1,'vlan_id_eth2').index("26") |
272 |
lst_dns_fw[index]=u"oui"
|
273 |
copy_val(d_eole2,'dns_forward_vlan_eth2',lst_dns_fw)
|
274 |
#vmtools
|
275 |
if vm=="1": |
276 |
copy_val(d_eole2,'orl_vmware_tools','oui') |
277 |
|
278 |
#maxchildren passe en httpworkers
|
279 |
#c'est géré par le script migration_conf qui demande les valeurs d'apres la ram
|
280 |
|
281 |
#https://dev-eole.ac-dijon.fr/issues/15792
|
282 |
copy_val(d_eole2,'half_closed_clients','off') |
283 |
|
284 |
if type_etab=="lyc": |
285 |
copy_val(d_eole2,'orl_filtrage_youtube','aucun') |
286 |
# ---- fin des traitements
|
287 |
|
288 |
return d_eole2
|
289 |
|
290 |
###AJOUT ORLEANS
|
291 |
def get_pass(): |
292 |
fic=open("/root/pwd", "r") |
293 |
pwd=fic.readline().strip() |
294 |
fic.close() |
295 |
os.system("rm -f /root/pwd")
|
296 |
login=pwd.split(";")[0] |
297 |
passwd=pwd.split(";")[1] |
298 |
return [login, passwd]
|
299 |
|
300 |
######################
|
301 |
## FONCTION PRINCIPALE
|
302 |
|
303 |
def migrate_serveurs(fic_csv_name="migration.csv", main_loop=False): |
304 |
"""
|
305 |
boucle principal de parcours des serveurs
|
306 |
"""
|
307 |
login, passwd = get_pass() |
308 |
# lecture du fichier csv
|
309 |
fic_csv_name = "/root/amon.csv"
|
310 |
fic_csv = open(fic_csv_name)
|
311 |
parser = csv.reader(fic_csv,delimiter=delimiter) |
312 |
proxy = xmlrpclib.ServerProxy('http://%s:%s@%s:7081' % (login,passwd,adresse_zephir))
|
313 |
# informations sur les module et variantes
|
314 |
|
315 |
# parsing des données
|
316 |
erreurs = [] |
317 |
while True: |
318 |
try:
|
319 |
# lecture d'une ligne du fichier csv
|
320 |
data_serveur = parser.next() |
321 |
except StopIteration: |
322 |
# fin du fichier
|
323 |
fic_csv.close() |
324 |
break
|
325 |
# chaque ligne indique un numéro de serveur et le n° de la variante à utiliser après migration
|
326 |
id_serveur, variante, domaine, ip_scribe, smtp, type_etab, statut, vm, version, maxchildren_adm, maxchildren_peda, lst_ips = data_serveur |
327 |
id_serveur = int(id_serveur)
|
328 |
variante = int(variante)
|
329 |
# migration du serveur (équivalent de 'générer la 'générer les données de migration' dans l'appli web)
|
330 |
try:
|
331 |
# récupération du dictionnaire creole du serveur dans sa version actuelle
|
332 |
code, data_ori = proxy.serveurs.get_dico(id_serveur,'modif_config',True) |
333 |
# passage 2.4.2 ou 2.5.2 à 2.6.2
|
334 |
d_eole1 = ZephirDict(mode='', version='creole3') |
335 |
d_eole1.init_from_zephir(data_ori) |
336 |
# initialisation du dictionnaire creole2
|
337 |
code, data_migration = proxy.serveurs.migrate_conf(int(id_serveur), 'migration', int(variante)) |
338 |
if code == 0: |
339 |
raise Exception, data_migration |
340 |
## IMPORTANT, pour la migration vers eole 2.4, bien spécifier version='creole3'
|
341 |
d_eole2 = ZephirDict(mode='', version='creole3') |
342 |
# initialisation du dictionnaire depuis les valeurs renvoyées par Zéphir
|
343 |
d_eole2.init_from_zephir(data_migration) |
344 |
# déblocage temporaire des variables cachées et vérouillées ?
|
345 |
#settings = d_eole2.dico.cfgimpl_get_settings()
|
346 |
#settings.remove('disabled')
|
347 |
#settings.remove('frozen')
|
348 |
# mise à jour du dictionnaire de migration
|
349 |
# APPEL DE LA FONCTION DE MIGRATION PERSONNALISEE
|
350 |
d_eole2 = update_conf(d_eole1, d_eole2, int(variante), proxy, domaine, ip_scribe, smtp, type_etab, statut, vm, version, maxchildren_adm, maxchildren_peda, lst_ips)
|
351 |
if debug:
|
352 |
print "\n--- configuration du serveur %s\n" % id_serveur |
353 |
for var in d_eole2.liste_vars: |
354 |
print var, '-->', d_eole2.get_value(var) |
355 |
if not main_loop: |
356 |
# mod debug et appel depuis shell python: on retourne
|
357 |
# les 2 dictionnaires pour le premier serveur du fichier CSV
|
358 |
# pour faciliter les diagnostics
|
359 |
fic_csv.close() |
360 |
return d_eole1, d_eole2
|
361 |
else:
|
362 |
save_data = d_eole2.save(force=False) #,eol_file='/tmp/test.txt') |
363 |
# sauvegarde de la conf sur zephir (migration.eol)
|
364 |
code, detail = proxy.serveurs.save_conf(id_serveur, save_data, 'migration')
|
365 |
print "serveur modifié : %s" % id_serveur |
366 |
except Exception, e: |
367 |
if debug:
|
368 |
# trace complète en mode debug
|
369 |
import traceback |
370 |
traceback.print_exc() |
371 |
print "erreur de modification du serveur %s : %s" % (id_serveur, str(e)) |
372 |
erreurs.append(delimiter.join(data_serveur)) |
373 |
|
374 |
# on stocke dans un fichier csv les serveurs non ajoutés
|
375 |
if len(erreurs) > 0: |
376 |
f=open("error.csv","w") |
377 |
f.write('\n'.join(erreurs))
|
378 |
f.close() |
379 |
print "\nDes erreurs ont été rencontrées :\n" |
380 |
print "- Vous pouvez consulter les logs du service zephir pour plus d'informations:\n" |
381 |
print " /var/log/rsyslog/local/zephir_backend/zephir_backend.info.log\n" |
382 |
print "- un fichier error.csv a été généré pour relancer ce script sur les serveurs en erreur\n" |
383 |
|
384 |
if __name__ == '__main__': |
385 |
try:
|
386 |
# on regarde si un fichier csv est passé en argument
|
387 |
assert os.path.isfile(sys.argv[1]) |
388 |
fic_csv = sys.argv[1]
|
389 |
except:
|
390 |
fic_csv = ""
|
391 |
migrate_serveurs(fic_csv, main_loop=True)
|