From 2165da2bfde293e418fd4ddd33e8b26e9e1ba0aa Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 31 Dec 2024 21:53:07 +0100 Subject: [PATCH] transfer from github --- python/backup2git.py | 303 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 python/backup2git.py diff --git a/python/backup2git.py b/python/backup2git.py new file mode 100644 index 0000000..39c5c2b --- /dev/null +++ b/python/backup2git.py @@ -0,0 +1,303 @@ +#!/usr/bin/python3 +import pynetbox +import requests +import urllib3 +import pexpect +import sys +import json +import gitlab +from datetime import date +today = str(date.today()) + +############################################################################### +# +# Set global variables +# +############################################################################### +# Netbox URL and Token +netbox_url = "https://HOST_OR_IP" +netbox_token = "TOKEN" +# Gitlab URL and Token +gitlab_url = "https://HOST_OR_IP" +gitlab_token = "TOKEN" +# SCP User, Password and Host (SCP host can be same like Netbox host) +scp_user = "USERNAME" +scp_pass = "PASSWORD" +scp_host = "HOST_OR_IP" +# Set User, Password and Enable to connect with SSH to devices +backup_user = "USERNAME" +backup_pass = "PASSWORD" +backup_enable = "ENABLE_PASSWORD" +# Set Gitlab project ID +project_id = PROJECT_ID + + +############################################################################### +def getDevicesFromNetbox(): + urllib3.disable_warnings() + requests.packages.urllib3.disable_warnings() + netbox = pynetbox.api( + url = netbox_url, + token = netbox_token, + threading = True + ) + netbox.http_session.verify = False + + # init empty device array + devices_netbox = [] + + # + # Build a list with Core-Switches + # Note: The filtering by role depends on the roles defined in netbox + # + # the list needs at minimum the following information: + # device / site / hostname / status / ipv4 address + # device: used to determine the device and what CLI commands are required to start a backup + # site: used to build a directory structure in gitlab project + # hostname: the hostname of the device to build .cfg + # status: to determine if device can be backed up or is out of it + # ipv4: IP address to connect to the device + + core_switch = netbox.dcim.devices.filter(role='net-core-switch') + for i in range(0, len(core_switch)): + data = netbox.dcim.devices.get(name = core_switch[i]) + hostname = str(data).split(":") + hostname = hostname[0] + device_details = ["switch", str(data.site), hostname, str(data.primary_ip), str(data.status)] + devices_netbox.append(device_details) + + access_switch = netbox.dcim.devices.filter(role='net-access-switch') + for i in range(0, len(access_switch)): + data = netbox.dcim.devices.get(name = access_switch[i]) + hostname = str(data).split(":") + hostname = hostname[0] + device_details = ["switch", str(data.site), hostname, str(data.primary_ip), str(data.status)] + devices_netbox.append(device_details) + + wifi_controller = netbox.dcim.devices.filter(role='net-wireless-lan-controller') + for i in range(0, len(wifi_controller)): + data = netbox.dcim.devices.get(name = wifi_controller[i]) + hostname = str(data).split(":") + hostname = hostname[0] + device_details = ["wificontroller", str(data.site), hostname, str(data.primary_ip), str(data.status)] + devices_netbox.append(device_details) + + wan_firewall = netbox.dcim.devices.filter(role='net-wan-firewall') + for i in range(0, len(wan_firewall)): + data = netbox.dcim.devices.get(name = wan_firewall[i]) + hostname = str(data).split(":") + hostname = hostname[0] + device_details = ["wanfirewall", str(data.site), hostname, str(data.primary_ip), str(data.status)] + devices_netbox.append(device_details) + + return devices_netbox + +############################################################################### +def cliCiscoSwitch(): + try: + print ("INFO: Connecting to device: " + hostname + " with IP: " + ipv4) + sshconn = pexpect.spawn('ssh %s@%s' % (backup_user, ipv4)) + #sshconn.logfile = sys.stdout.buffer + sshconn.timeout = 30 + + sshconn.expect('.*assword:.*') + sshconn.sendline(backup_pass) + sshconn.expect('#') + sshconn.sendline('term len 0') + sshconn.expect('#') + + print ('INFO: Set exec banner') + sshconn.sendline('conf t') + sshconn.expect('#') + sshconn.sendline('file prompt quiet') + sshconn.expect('#') + sshconn.sendline('banner exec ^') + sshconn.sendline(today + ' - Config saved by backup2git') + sshconn.sendline('^') + sshconn.expect('#') + sshconn.sendline('exit') + + print ('INFO: Executing write memory command') + sshconn.sendline('wr mem') + sshconn.expect('.*OK.*') + + print ('INFO: Executing copy run scp command') + sshconn.sendline('copy run scp://' + scp_user + ':' + scp_pass + '@' + scp_host + '//tmp/' + hostname + '.cfg') + sshconn.expect('.*copied.*') + + print ('INFO: Log out from device: ' + hostname + " with ip: " + ipv4) + sshconn.sendline('logout') + + except pexpect.TIMEOUT: + print ("ERROR: No login to device: " + hostname + " with ip: " + ipv4) + pass + +############################################################################### +def cliCiscoWirelessController(): + try: + print ("INFO: Connecting to device: " + hostname + " with IP: " + ipv4) + sshconn = pexpect.spawn('ssh %s@%s' % (backup_user, ipv4)) + #sshconn.logfile = sys.stdout.buffer + sshconn.timeout = 30 + + sshconn.expect('.*ser:.*') + sshconn.sendline(backup_user) + sshconn.expect('.*assword:.*') + sshconn.sendline(backup_pass) + sshconn.expect('>') + print ('INFO: Executing save config command') + sshconn.sendline('save config') + sshconn.expect('(y/n)') + sshconn.sendline('y') + + print ('INFO: set transfer parameters') + sshconn.sendline('transfer upload datatype config') + sshconn.expect('>') + sshconn.sendline('transfer upload mode sftp') + sshconn.expect('>') + sshconn.sendline('transfer upload serverip ' + scp_host) + sshconn.expect('>') + sshconn.sendline('transfer upload filename ' + hostname + ".cfg") + sshconn.expect('>') + sshconn.sendline('transfer upload path /tmp/') + sshconn.expect('>') + sshconn.sendline('transfer upload username ' + scp_user) + sshconn.expect('>') + sshconn.sendline('transfer upload password ' + scp_pass) + sshconn.expect('>') + + print ('INFO: Executing transfer upload start command') + sshconn.sendline('transfer upload start') + sshconn.expect('(y/N)') + sshconn.sendline('y') + sshconn.expect('successfully.') + + print ('INFO: Log out from device: ' + hostname + " with ip: " + ipv4) + sshconn.sendline('logout') + + except pexpect.TIMEOUT: + print ("ERROR: No login to device: " + hostname + " with ip: " + ipv4) + pass + +############################################################################### +def cliCiscoAsaFirewall(): + try: + print ("INFO: Connecting to device: " + hostname + " with IP: " + ipv4) + sshconn = pexpect.spawn('ssh %s@%s' % (backup_user, ipv4)) + #sshconn.logfile = sys.stdout.buffer + sshconn.timeout = 30 + + sshconn.expect('.*assword:.*') + sshconn.sendline(backup_pass) + sshconn.expect('>') + sshconn.sendline('enable') + sshconn.expect('.*assword:.*') + sshconn.sendline(backup_pass) + + print ('INFO: Executing write memory command') + sshconn.sendline('wr mem') + sshconn.expect('.*OK.*') + + print ('INFO: Executing copy run scp command') + sshconn.sendline('copy run scp://' + scp_user + ':' + scp_pass + '@' + scp_host + '//tmp/' + hostname + '.cfg') + sshconn.expect('.*ource') + sshconn.sendline() + sshconn.expect('.*ddress') + sshconn.sendline() + sshconn.expect('.*sername') + sshconn.sendline() + sshconn.expect('.*ilename') + sshconn.sendline() + sshconn.expect('continue connecting') + sshconn.sendline('yes') + sshconn.expect('copied') + sshconn.sendline('logout') + + print ('INFO: Log out from device: ' + hostname + " with ip: " + ipv4) + sshconn.sendline('logout') + + except pexpect.TIMEOUT: + print ("ERROR: No login to device: " + hostname + " with ip: " + ipv4) + pass + + +############################################################################### +# Get the devices from Netbox +devices = getDevicesFromNetbox() + + # Use a for-loop to go through the devices and check in the configuration files + for i in range(0, len(devices)): + + # Split list + role = str(devices[i][0]) + location = str(devices[i][1]) + hostname = str(devices[i][2]) + ipv4 = str(devices[i][3])[:len(str(devices[i][3]))-3] + status = str(devices[i][4]) + + # If device is active and has a primary IPv4 address (ssh connect action) + if status == "Active" and ipv4 != "N": + + # role is a switch + if role == "switch": + cliCiscoSwitch() + # role is a wlc + elif role == "wificontroller": + cliCiscoWirelessController() + # role is a firewall + elif role == "wanfirewall": + cliCiscoAsaFirewall() + + # handle list from netbox if device is missing ipv4 or if + # device status is set to something else than active + else: + print ("WARN: device not set to active or IP missing") + + # If device is active and has primary IPv4 address (open file action) + if status == "Active" and ipv4 != "N": + # open config file and read it into a string variable + try: + content = open('/tmp/' + hostname + '.cfg').read() + except: + print ("ERROR: Cannot open file: " + hostname + ".cfg") + + urllib3.disable_warnings() + requests.packages.urllib3.disable_warnings() + gl = gitlab.Gitlab(gitlab_url, ssl_verify=False, private_token=gitlab_token) + # authenticate + gl.auth() + # get gitlab project + project = gl.projects.get(project_id) + + # try with a commit create if file does not exist on gitlab project + try: + data_create = { + 'branch': 'master', + 'commit_message': 'Initial commit of config file on ' + today + ' by backup2git', + 'actions': [ + { + 'action': 'create', + 'file_path': location + '/' + hostname + '.cfg', + 'content': open('/tmp/' + hostname + '.cfg').read(), + } + ] + } + except: + print ("Cannot build commit create JSON") + pass + # If file exists, use commit update to check in new version of file + try: + data_update = { + 'branch': 'master', + 'commit_message': 'Update of config file on ' + today + ' by backup2git', + 'actions': [ + { + 'action': 'update', + 'file_path': location + '/' + hostname + '.cfg', + 'content': open('/tmp/' + hostname + '.cfg').read(), + } + ] + } + except: + print ("Cannot build commit update JSON") + pass \ No newline at end of file