2018-06-27 19:00:53 +02:00
#!/usr/bin/env python3
2018-05-24 15:27:42 +02:00
from configparser import ConfigParser
2018-05-26 23:04:14 +02:00
import socket
2018-05-24 15:27:42 +02:00
from re2oapi import Re2oAPIClient
2018-07-02 10:40:45 +02:00
from jinja2 import Environment , FileSystemLoader
2018-07-11 02:35:13 +02:00
import requests
import base64
import json
2018-10-13 22:46:46 +02:00
import datetime
2018-08-08 20:30:55 +02:00
import sys
2018-05-24 15:27:42 +02:00
config = ConfigParser ( )
config . read ( ' config.ini ' )
2018-05-26 23:04:14 +02:00
api_hostname = config . get ( ' Re2o ' , ' hostname ' )
api_password = config . get ( ' Re2o ' , ' password ' )
api_username = config . get ( ' Re2o ' , ' username ' )
api_client = Re2oAPIClient ( api_hostname , api_username , api_password )
client_hostname = socket . gethostname ( ) . split ( ' . ' , 1 ) [ 0 ]
2018-07-02 10:40:45 +02:00
all_switchs = api_client . list ( " switchs/ports-config/ " )
# Création de l'environnement Jinja
ENV = Environment ( loader = FileSystemLoader ( ' . ' ) )
# Création du template final avec les valeurs contenues dans le dictionnaire "valeurs" - Ces valeurs sont positionnées dans un objet "temp", qui sera utilisé par le moteur, et que l'on retrouve dans le template.
2018-09-20 20:31:47 +02:00
2018-08-08 20:30:55 +02:00
2018-07-08 19:59:13 +02:00
class Switch :
def __init__ ( self ) :
self . additionnal = None
self . all_vlans = api_client . list ( " machines/vlan/ " )
2018-07-11 23:58:16 +02:00
self . settings = api_client . view ( " preferences/optionaltopologie/ " )
2018-07-08 19:59:13 +02:00
# Import du fichier template dans une variable "template"
self . hp_tpl = ENV . get_template ( " templates/hp.tpl " )
self . conf = None
self . name = None
self . switch = None
2018-07-11 02:35:13 +02:00
self . headers = None
self . creds_dict = None
2018-07-08 19:59:13 +02:00
def get_conf_file_name ( self ) :
return self . switch [ " short_name " ] + " .conf "
def preprocess_hp ( self ) :
""" Prérempli certains valeurs renvoyées directement à jinja, pour plus de simplicité """
2018-10-13 22:46:46 +02:00
2018-07-08 19:59:13 +02:00
def add_to_vlans ( vlans , vlan , port , tagged = True ) :
if not vlan [ ' vlan_id ' ] in vlans :
if not tagged :
vlans [ vlan [ ' vlan_id ' ] ] = { ' ports_untagged ' : [ str ( port [ ' port ' ] ) ] , ' ports_tagged ' : [ ] , ' name ' : vlan [ ' name ' ] }
else :
vlans [ vlan [ ' vlan_id ' ] ] = { ' ports_tagged ' : [ str ( port [ ' port ' ] ) ] , ' ports_untagged ' : [ ] , ' name ' : vlan [ ' name ' ] }
2018-07-08 19:13:58 +02:00
else :
2018-07-08 19:59:13 +02:00
if not tagged :
vlans [ vlan [ ' vlan_id ' ] ] [ ' ports_untagged ' ] . append ( str ( port [ ' port ' ] ) )
else :
vlans [ vlan [ ' vlan_id ' ] ] [ ' ports_tagged ' ] . append ( str ( port [ ' port ' ] ) )
2018-07-08 19:13:58 +02:00
2018-07-08 19:59:13 +02:00
vlans = dict ( )
2018-07-08 19:13:58 +02:00
2018-07-08 19:59:13 +02:00
for port in self . switch [ ' ports ' ] :
2018-10-13 22:46:46 +02:00
if port [ ' get_port_profile ' ] [ ' vlan_untagged ' ] :
add_to_vlans ( vlans , port [ ' get_port_profile ' ] [ ' vlan_untagged ' ] , port , tagged = False )
if port [ ' get_port_profile ' ] [ ' vlan_tagged ' ] :
for vlan in port [ ' get_port_profile ' ] [ ' vlan_tagged ' ] :
2018-07-08 19:59:13 +02:00
add_to_vlans ( vlans , vlan , port )
2018-07-08 19:13:58 +02:00
2018-07-12 16:55:15 +02:00
#Trie les ip par vlan, et les ajoute ainsi que les subnet
2018-07-12 16:53:35 +02:00
for ip , subnet in self . switch [ " interfaces_subnet " ] . items ( ) :
2018-09-20 20:31:47 +02:00
if not subnet [ 0 ] [ " vlan_id " ] in vlans :
raise RuntimeError ( " La config est dangeureuse, le vlan d ' administration n ' est pas propagé au switch ! " )
2018-07-12 16:53:35 +02:00
vlans [ subnet [ 0 ] [ " vlan_id " ] ] . setdefault ( " ipv4 " , { } )
vlans [ subnet [ 0 ] [ " vlan_id " ] ] [ " ipv4 " ] [ ip ] = subnet
for ipv6 , subnet in self . switch [ " interfaces6_subnet " ] . items ( ) :
vlans [ subnet [ " vlan_id " ] ] . setdefault ( " ipv6 " , { } )
vlans [ subnet [ " vlan_id " ] ] [ " ipv6 " ] [ ipv6 ] = subnet
2018-07-12 16:55:15 +02:00
#Regroupement des options par vlans : dhcp_soop,arp, et dhcpv6, ainsi que igmp, mld , ra-guard et loop_protect
2018-07-08 19:59:13 +02:00
arp_protect_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " arp_protect " ] ]
dhcp_snooping_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " dhcp_snooping " ] ]
dhcpv6_snooping_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " dhcpv6_snooping " ] ]
2018-07-08 20:31:04 +02:00
igmp_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " igmp " ] ]
mld_vlans = [ vlan [ " vlan_id " ] for vlan in self . all_vlans if vlan [ " mld " ] ]
2018-10-13 22:46:46 +02:00
ra_guarded = [ str ( port [ ' port ' ] ) for port in self . switch [ ' ports ' ] if port [ ' get_port_profile ' ] [ ' ra_guard ' ] ]
loop_protected = [ str ( port [ ' port ' ] ) for port in self . switch [ ' ports ' ] if port [ ' get_port_profile ' ] [ ' loop_protect ' ] ]
2018-07-08 19:13:58 +02:00
2018-07-11 23:58:16 +02:00
self . additionals = { ' ra_guarded ' : ra_guarded , ' loop_protected ' : loop_protected , ' vlans ' : vlans , ' arp_protect_vlans ' : arp_protect_vlans , ' dhcp_snooping_vlans ' : dhcp_snooping_vlans , ' dhcpv6_snooping_vlans ' : dhcpv6_snooping_vlans , ' igmp_vlans ' : igmp_vlans , ' mld_vlans ' : mld_vlans }
2018-07-08 19:13:58 +02:00
2018-07-08 19:59:13 +02:00
def gen_conf_hp ( self ) :
""" Génère la config pour ce switch hp """
self . preprocess_hp ( )
2018-10-13 22:46:46 +02:00
self . conf = self . hp_tpl . render ( switch = self . switch , settings = self . settings , additionals = self . additionals , date_gen = datetime . datetime . now ( ) )
2018-07-08 19:59:13 +02:00
2018-07-11 02:35:13 +02:00
def check_and_get_login ( self ) :
""" Récupère les login/mdp du switch, renvoie false si ils sont indisponibles """
self . creds_dict = self . switch [ " get_management_cred_value " ]
if self . creds_dict :
return True
else :
return False
def login_hp ( self ) :
""" Login into rest interface of this switch """
url_login = " http:// " + self . switch [ " ipv4 " ] + " /rest/v3/login-sessions "
2018-10-13 22:46:46 +02:00
2018-07-11 02:35:13 +02:00
payload_login = {
2018-10-13 22:46:46 +02:00
" userName " : self . creds_dict [ " id " ] ,
2018-07-11 02:35:13 +02:00
" password " : self . creds_dict [ " pass " ]
}
get_cookie = requests . post ( url_login , data = json . dumps ( payload_login ) )
cookie = get_cookie . json ( ) [ ' cookie ' ]
self . headers = { " Cookie " : cookie }
def apply_conf_hp ( self ) :
""" Apply config restore via rest """
url_restore = " http:// " + self . switch [ " ipv4 " ] + " /rest/v4/system/config/cfg_restore "
2018-07-12 17:37:48 +02:00
provision_mode = self . settings [ " switchs_provision " ]
if provision_mode == " tftp " :
data = {
" server_type " : " ST_TFTP " ,
" file_name " : self . get_conf_file_name ( ) ,
" tftp_server_address " : {
" server_address " : {
" ip_address " : {
" version " : " IAV_IP_V4 " ,
" octets " : self . settings [ " switchs_management_interface_ip " ] } } } ,
" is_forced_reboot_enabled " : True ,
}
elif provision_mode == " sftp " :
data = {
" server_type " : " ST_SFTP " ,
" file_name " : self . get_conf_file_name ( ) ,
" tftp_server_address " : {
" server_address " : {
" ip_address " : {
" version " : " IAV_IP_V4 " ,
" octets " : self . settings [ " switchs_management_interface_ip " ] } } ,
" user_name " : self . settings [ " switchs_management_sftp_creds " ] [ " login " ] ,
" password " : self . settings [ " switchs_management_sftp_creds " ] [ " pass " ] ,
} ,
" is_forced_reboot_enabled " : True ,
}
2018-07-11 02:35:13 +02:00
# Nous lançons la requête de type POST.
post_restore = requests . post ( url_restore , data = json . dumps ( data ) , headers = self . headers )
2018-07-09 00:43:21 +02:00
def gen_conf_and_write ( self ) :
""" Génère la conf suivant le bon constructeur et l ' écrit """
if self . switch [ " model " ] :
constructor = self . switch [ " model " ] [ " constructor " ] . lower ( )
2018-09-20 20:31:47 +02:00
try :
if " hp " in constructor or " aruba " in constructor :
self . gen_conf_hp ( )
self . write_conf ( )
except RuntimeError :
print ( " Il y a eu une erreur pour le switch %s , la config proposée n ' est pas intègre " % self . switch [ " short_name " ] )
2018-07-09 00:43:21 +02:00
2018-07-11 02:35:13 +02:00
def apply_conf ( self ) :
if self . check_and_get_login ( ) :
2018-07-12 00:02:07 +02:00
if self . switch [ " model " ] and self . switch [ " automatic_provision " ] == True and self . settings [ " provision_switchs_enabled " ] :
2018-07-11 02:35:13 +02:00
constructor = self . switch [ " model " ] [ " constructor " ] . lower ( )
if " hp " in constructor or " aruba " in constructor :
self . login_hp ( )
self . apply_conf_hp ( )
2018-07-08 19:59:13 +02:00
def write_conf ( self ) :
2018-07-09 00:43:21 +02:00
""" Ecriture de la conf du switch dans le fichier qui va bien """
2018-07-08 19:59:13 +02:00
with open ( " generated/ " + self . get_conf_file_name ( ) , ' w+ ' ) as f :
f . write ( self . conf )
2018-07-08 19:13:58 +02:00
2018-09-20 20:31:47 +02:00
for arg in sys . argv :
if arg == " --force " :
sw = Switch ( )
for switch in all_switchs :
sw . switch = switch
sw . gen_conf_and_write ( )
try :
sw . apply_conf ( )
except :
print ( " Erreur dans l ' application de la conf pour " + switch [ " short_name " ] )
2018-07-08 19:13:58 +02:00
2018-08-08 20:30:55 +02:00
for service in api_client . list ( " services/regen/ " ) :
if service [ ' hostname ' ] == client_hostname and \
service [ ' service_name ' ] == ' switchs ' and \
service [ ' need_regen ' ] :
2018-09-20 20:31:47 +02:00
error = False
2018-08-08 20:30:55 +02:00
sw = Switch ( )
for switch in all_switchs :
sw . switch = switch
sw . gen_conf_and_write ( )
try :
sw . apply_conf ( )
except :
2018-10-13 22:46:46 +02:00
error = True
2018-08-08 20:30:55 +02:00
api_client . patch ( service [ ' api_url ' ] , data = { ' need_regen ' : error } )