start adding support for query to re2o instance
This commit is contained in:
parent
056b5e8df0
commit
92be56731d
1 changed files with 86 additions and 13 deletions
|
@ -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")
|
||||||
|
|
Loading…
Reference in a new issue