start adding support for query to re2o instance

This commit is contained in:
Michaël Paulon 2020-09-27 21:50:16 +02:00
parent 056b5e8df0
commit 92be56731d

View file

@ -1,10 +1,12 @@
import argparse import argparse
import difflib import difflib
import getpass
import logging import logging
from pprint import pprint from pprint import pprint
import colorlog import colorlog
import requests
import termcolor import termcolor
import yaml import yaml
@ -142,8 +144,17 @@ def gen_interfaces(switch_config):
interfaces.sort(key=lambda x: x["number"]) interfaces.sort(key=lambda x: x["number"])
return interfaces, vlans, mac_based_ports, ra_guard_ports, dhcp_snooping_vlans return interfaces, vlans, mac_based_ports, ra_guard_ports, dhcp_snooping_vlans
def gen_conf(master_config, switch_config, old_config): def get_header(old_config):
header = "\n".join(old_config.split("\n")[:2]) header = "\n".join(old_config.split("\n")[:2])
return header
def conf_from_dict(config_dict):
with open("configs/config.j2", "r") as template_file:
template = Template(template_file.read())
configuration = template.render(config_dict)
return configuration
def gen_conf(master_config, switch_config, header):
interfaces, vlans, mac_based_ports, ra_guard_ports, dhcp_snooping_vlans = gen_interfaces(switch_config) interfaces, vlans, mac_based_ports, ra_guard_ports, dhcp_snooping_vlans = gen_interfaces(switch_config)
config_dict = { config_dict = {
"header": header, "header": header,
@ -164,13 +175,49 @@ def gen_conf(master_config, switch_config, old_config):
"unauth_redirect": master_config.get("unauth_redirect"), "unauth_redirect": master_config.get("unauth_redirect"),
"dhcp_snooping_vlans": syntax_from_range(dhcp_snooping_vlans, vlan_syntax=True), "dhcp_snooping_vlans": syntax_from_range(dhcp_snooping_vlans, vlan_syntax=True),
} }
with open("configs/config.j2", "r") as template_file: return conf_from_dict(config_dict)
template = Template(template_file.read())
configuration = template.render(config_dict)
return configuration
def gen_conf_re2o(re2o_config, header):
print(re2o_config.keys())
raise RuntimeError()
config_dict = {
"header": header
}
return conf_from_dict(config_dict)
def connect_as_self(base_url, username=None):
"""Get a re2o token for the current unix user """
if username is None:
username = getpass.getuser()
r = requests.post(
base_url + "token-auth",
data={
"username": username,
"password": getpass.getpass("Login to {} as {} with password :".format(base_url, username))
}
)
if r.status_code != 200:
logger.critical("Wrong login/password")
exit(1)
token = r.json().get("token")
return token
def get_switch_from_results(results, switch_name):
for s in results:
if s.get("short_name"):
return s
return None
def get_switch_from_re2o(re2o_instance, switch_name, re2o_user):
base_url = "{}/api/".format(re2o_instance)
token = connect_as_self(base_url, re2o_user)
headers = {"Authorization": "Token " + token}
r = requests.get(base_url + "switchs/ports-config", headers=headers)
sw_config = get_switch_from_results(r.json()["results"], switch_name)
while r.json().get("next") and s is None:
r = requests.get(r.json().get("next"), headers=headers)
sw_config = get_switch_from_results(r.json()["results"], switch_name)
return sw_config
if __name__ == "__main__": if __name__ == "__main__":
format_string = "%(asctime)s - %(levelname)s - %(message)s" format_string = "%(asctime)s - %(levelname)s - %(message)s"
@ -186,26 +233,52 @@ if __name__ == "__main__":
parser.add_argument("-w", "--whole", action="store_true", help="Affiche la configuration en entier au lieu du diff") parser.add_argument("-w", "--whole", action="store_true", help="Affiche la configuration en entier au lieu du diff")
parser.add_argument("switch_name", type=str, help="Génère le template de ce switch") parser.add_argument("switch_name", type=str, help="Génère le template de ce switch")
parser.add_argument("-H", "--host", type=str, required=False, help="Host sur lequel de déployer la configuration au lieu de l'adresse dans le template") parser.add_argument("-H", "--host", type=str, required=False, help="Host sur lequel de déployer la configuration au lieu de l'adresse dans le template")
parser.add_argument("-r", "--re2o", type=str, required=False, help="Si renseigné, la configuration sera récupérée depuis l'instance de re2o indiquée au lieu d'utiliser les fichiers yaml")
parser.add_argument("--re2o-user", type=str, required=False, help="Permet de choisir l'user pour se connecter à l'api re2o, par défaut on prend l'user unix courant")
parser.add_argument("-4", "--force-ipv4", action="store_true", help="Force le provisionning en ipv4")
args = parser.parse_args() args = parser.parse_args()
logger.debug("Loading master config") if args.re2o:
master_config = yaml.load(open("configs/master.yml", "r"), yaml.Loader) logger.debug("Loading master config")
logger.debug("Loading config for {}".format(args.switch_name)) master_config = yaml.load(open("configs/master.yml", "r"), yaml.Loader)
switch_config = yaml.load(open("configs/switches/{}.yml".format(args.switch_name), "r"), yaml.Loader) logger.debug("Loading config from re2o")
re2o_config = get_switch_from_re2o(args.re2o, args.switch_name, args.re2o_user)
else:
logger.debug("Loading master config")
master_config = yaml.load(open("configs/master.yml", "r"), yaml.Loader)
logger.debug("Loading config for {}".format(args.switch_name))
switch_config = yaml.load(open("configs/switches/{}.yml".format(args.switch_name), "r"), yaml.Loader)
if args.host: if args.host:
switch_address = args.host switch_address = args.host
elif args.re2o:
if args.force_ipv4:
switch_address = re2o_config.get("ipv4")
else:
switch_address = re2o_config.get("ipv6") or re2o_config.get("ipv4")
else: else:
switch_address = switch_config.get("ipv6-addr") or switch_config.get("ipv4-addr") if args.force_ipv4:
switch_address = switch_config.get("ipv4-addr")
else:
switch_address = switch_config.get("ipv6-addr") or switch_config.get("ipv4-addr")
if switch_address is None: if switch_address is None:
switch_address = "{}.switches.crans.org".format(args.switch_name) switch_address = "{}.switches.crans.org".format(args.switch_name) #TODO: crans
logger.info("Connecting to {} with address {}".format(args.switch_name, switch_address)) logger.info("Connecting to {} with address {}".format(args.switch_name, switch_address))
session = connect_to_switch(switch_address, user="root", key=master_config.get("ssh_private_key")) session = connect_to_switch(switch_address, user="root", key=master_config.get("ssh_private_key")) #TODO: spécifier chemin clef
old_config = sftp_read_file(session, "cfg/running-config").decode("utf-8") old_config = sftp_read_file(session, "cfg/running-config").decode("utf-8")
header = get_header(old_config)
# génération de la conf
logging.info("Generating configuration for {}".format(args.switch_name)) logging.info("Generating configuration for {}".format(args.switch_name))
configuration = gen_conf(master_config, switch_config, old_config) if args.re2o:
configuration = gen_conf_re2o(re2o_config, header)
else:
configuration = gen_conf(master_config, switch_config, header)
# génération du diff
for line in difflib.unified_diff(old_config.split("\n"), configuration.split("\n"), fromfile='origin', tofile='new', lineterm=""): for line in difflib.unified_diff(old_config.split("\n"), configuration.split("\n"), fromfile='origin', tofile='new', lineterm=""):
if line.startswith("-"): if line.startswith("-"):
termcolor.cprint(line, "red") termcolor.cprint(line, "red")