From cdd5fab8e4692e80aa13d17eceebea86dd282223 Mon Sep 17 00:00:00 2001 From: Stefan Thierolf Date: Mon, 30 Dec 2024 20:02:57 +0100 Subject: [PATCH] transfer github --- ansible/README.md | 23 ++ ansible/cisco-asa-firewalls-serial-nums.yaml | 77 +++++ ansible/collect_mac_address.yaml | 21 ++ .../netbox-cisco-asa-firewall-serialnums.yaml | 38 +++ ansible/netbox-cisco-switch-serialnums.yaml | 37 +++ ansible/windows-graylog-example/README.md | 2 +- ansible/windows-snmp-example/README.md | 2 +- netbox/README.md | 15 + netbox/backup2git.py | 303 ++++++++++++++++++ netbox/netbox-librenms-graph.py | 63 ++++ netbox/netbox-librenms.py | 70 ++++ netbox/netbox-snipeit.php | 48 +++ netbox/netbox-snipeit.py | 75 +++++ netbox/qrcode-snipeit.py | 50 +++ 14 files changed, 822 insertions(+), 2 deletions(-) create mode 100644 ansible/README.md create mode 100644 ansible/cisco-asa-firewalls-serial-nums.yaml create mode 100644 ansible/collect_mac_address.yaml create mode 100644 ansible/netbox-cisco-asa-firewall-serialnums.yaml create mode 100644 ansible/netbox-cisco-switch-serialnums.yaml create mode 100644 netbox/README.md create mode 100644 netbox/backup2git.py create mode 100644 netbox/netbox-librenms-graph.py create mode 100644 netbox/netbox-librenms.py create mode 100644 netbox/netbox-snipeit.php create mode 100644 netbox/netbox-snipeit.py create mode 100644 netbox/qrcode-snipeit.py diff --git a/ansible/README.md b/ansible/README.md new file mode 100644 index 0000000..0fe5394 --- /dev/null +++ b/ansible/README.md @@ -0,0 +1,23 @@ +# Ansible + +## Complete examples + +Example and code fragments for Cisco, Netbox and Ansible. + +* `debian-graylog-example` Ansible Role to onboard Debian Linux Servers in Graylog Open +* +* `windows-graylog-example` Ansible Role to onboard Windows Servers in Graylog Open + +* `windows-snmp-example` OpenSSH Server on Windows and SNMP Service installation with Ansible + +* `windows-nsclientplusplus-example` NSCLient++ on Windows installation with Ansible + +## Code snippets + +* `cisco-asa-firewalls-serial-nums.yaml` Collects minimum facts from ASA in single or clustered mode + +* `netbox-cisco-asa-firewall-serialnums.yaml` Update Serial number of single and clustered ASA firewall + +* `netbox-cisco-switch-serialnums.yaml` Update Serial number of single and stacked switch + +* `collect_mac_address.yaml` Collect MAC addresses from Cisco Switches diff --git a/ansible/cisco-asa-firewalls-serial-nums.yaml b/ansible/cisco-asa-firewalls-serial-nums.yaml new file mode 100644 index 0000000..9acb248 --- /dev/null +++ b/ansible/cisco-asa-firewalls-serial-nums.yaml @@ -0,0 +1,77 @@ +--- +# ASA / Min-Facts +# =============== +# Collects minimum facts from ASA in single or clustered mode +# +# 2023-08-26 stefan init +# +- name: "Block: Min-Facts Firewall-Single" + block: + + - name: "Firewall-Single: Get Min-Facts" + cisco.asa.asa_command: + commands: + - show run | include hostname + - show version + - show inventory + register: asa_vars + + - name: "Firewall-Single: Extract Min-Facts" + set_fact: + ansible_net_hostname: "{{ asa_vars.stdout[0].split()[1] }}" + ansible_net_version: "{{ asa_vars.stdout[1].split('\n')[0].split()[6] }}" + ansible_net_model: "{{ asa_vars.stdout[2].split('\n')[1].split()[1] }}" + ansible_net_serialnum: "{{ asa_vars.stdout[2].split('\n')[1].split()[7] }}" + + - name: "Firewall-Single: Display Min-Facts" + debug: + msg: "Device: {{ ansible_net_hostname }} is model: {{ ansible_net_model }} with serial: {{ ansible_net_serialnum }} and version: {{ ansible_net_version }}" + + when: role == "Firewall-Single" + + + +- name: "Block: Min-Facts Firewall-Cluster" + block: + + - name: "Firewall-Cluster: Get Min-Facts Primary" + cisco.asa.asa_command: + commands: + - show run | include hostname + - show version + - show inventory + register: asa_vars_primary + + - name: "Firewall-Cluster: Get Min-Facts Failover" + cisco.asa.asa_command: + commands: + - failover exec mate show run | include hostname + - failover exec mate show version + - failover exec mate show inventory + register: asa_vars_failover + ignore_errors: yes + + - name: "Firewall-Cluster: Extract Min-Facts Hostname/Version" + set_fact: + ansible_net_hostname: "{{ asa_vars_primary.stdout[0].split()[1] }}" + ansible_net_version: "{{ asa_vars_primary.stdout[1].split('\n')[0].split()[6] }}" + + - name: "Firewall-Cluster: Extract Min-Facts Stacked Models" + set_fact: + ansible_net_stacked_models: + - "{{ asa_vars_primary.stdout[2].split('\n')[1].split()[1] }}" + - "{{ asa_vars_failover.stdout[2].split('\n')[1].split()[1] }}" + ignore_errors: yes + + - name: "Firewall-Cluster: Extract Min-Facts Stacked Serials" + set_fact: + ansible_net_stacked_serialnums: + - "{{ asa_vars_primary.stdout[2].split('\n')[1].split()[7] }}" + - "{{ asa_vars_failover.stdout[2].split('\n')[1].split()[7] }}" + ignore_errors: yes + + - name: "Firewall-Cluster: Display Min-Facts" + debug: + msg: "Device: {{ ansible_net_hostname }} is model: {{ ansible_net_stacked_models }} with serial: {{ ansible_net_stacked_serialnums }} and version: {{ ansible_net_version }}" + + when: role == "Firewall-Cluster" diff --git a/ansible/collect_mac_address.yaml b/ansible/collect_mac_address.yaml new file mode 100644 index 0000000..8b11df8 --- /dev/null +++ b/ansible/collect_mac_address.yaml @@ -0,0 +1,21 @@ +--- +# Collect MAC Address Table +# ========================= +# 2023-10-25 stefan init + +- name: "Collect MAC Address" + block: + + - name: "Get facts" + cisco.ios.ios_facts: + gather_subset: all + + - name: "Register output of show command" + cisco.ios.ios_command: + commands: 'show mac address-table dynamic' + register: mac_addr + + - name: "Save output to file" + ansible.builtin.copy: + content="{{ mac_addr.stdout | replace('\\n', '\n') }}" + dest=/home/stefan/mac_addr/{{ inventory_hostname }}.txt diff --git a/ansible/netbox-cisco-asa-firewall-serialnums.yaml b/ansible/netbox-cisco-asa-firewall-serialnums.yaml new file mode 100644 index 0000000..6e1da1f --- /dev/null +++ b/ansible/netbox-cisco-asa-firewall-serialnums.yaml @@ -0,0 +1,38 @@ +--- +# NetBox / Update Serial Numbers +# ============================== +# Update Serial number of single and clustered ASA firewall +# +# 2023-08-26 stefan init +# + + # + # Update Serial Number of Single Firewall + # + - name: "Firewall-Single: Update Serial Number" + netbox.netbox.netbox_device: + netbox_url: "{{ netbox_url }}" + netbox_token: "{{ netbox_token }}" + validate_certs: no + data: + name: "{{ fqdn }}" + serial: "{{ ansible_net_serialnum }}" + state: present + ignore_errors: yes + + # + # Update Serial Number of Clustered Firewall + # + - name: "Firewall-Cluster: Update Serial Numbers" + netbox.netbox.netbox_device: + netbox_url: "{{ netbox_url }}" + netbox_token: "{{ netbox_token }}" + validate_certs: no + data: + name: "{{ item.name }}" + serial: "{{ ansible_net_stacked_serialnums[idx_stack] }}" + state: present + loop: "{{ vchassis_stacked_firewalls }}" + loop_control: + index_var: idx_stack + ignore_errors: yes diff --git a/ansible/netbox-cisco-switch-serialnums.yaml b/ansible/netbox-cisco-switch-serialnums.yaml new file mode 100644 index 0000000..4d7c9e9 --- /dev/null +++ b/ansible/netbox-cisco-switch-serialnums.yaml @@ -0,0 +1,37 @@ +--- +# NetBox / Update Serial Numbers +# ============================== +# Update Serial number of single and stacked switch +# +# 2023-08-26 stefan init +# + + # + # Update Serial Number of Single Switch + # + - name: "Switch-Single: Update Serial" + netbox.netbox.netbox_device: + netbox_url: "{{ netbox_url }}" + netbox_token: "{{ netbox_token }}" + validate_certs: no + data: + name: "{{ name }}" + serial: "{{ ansible_net_serialnum }}" + state: present + + # + # Update all Serial Number of Switch-Stack + # + - name: "Switch-Stack: Update Serials" + netbox.netbox.netbox_device: + netbox_url: "{{ netbox_url }}" + netbox_token: "{{ netbox_token }}" + validate_certs: no + data: + name: "{{ item.name }}" + serial: "{{ ansible_net_stacked_serialnums[idx_stack] }}" + state: present + loop: "{{ vchassis_stacked_switches }}" + loop_control: + index_var: idx_stack + \ No newline at end of file diff --git a/ansible/windows-graylog-example/README.md b/ansible/windows-graylog-example/README.md index 26e96b4..d309b43 100644 --- a/ansible/windows-graylog-example/README.md +++ b/ansible/windows-graylog-example/README.md @@ -2,7 +2,7 @@ ## English -πŸ‡ΊπŸ‡Έ [Ansible Role to onboard Windows Servers in Graylog Open](https://www.thierolf.org/en/ansible/ansible-role-to-onboard-windows-server-in-graylog-open) +πŸ‡¬πŸ‡§ [Ansible Role to onboard Windows Servers in Graylog Open](https://www.thierolf.org/en/ansible/ansible-role-to-onboard-windows-server-in-graylog-open) ## Deutsch diff --git a/ansible/windows-snmp-example/README.md b/ansible/windows-snmp-example/README.md index c3335a2..2bc58a6 100644 --- a/ansible/windows-snmp-example/README.md +++ b/ansible/windows-snmp-example/README.md @@ -2,7 +2,7 @@ ## English -πŸ‡ΊπŸ‡Έ [OpenSSH Server on Windows and SNMP Service Installation with Ansible](https://www.thierolf.org/posts/openssh-server-on-windows-and-snmp-service-installation-with-ansible/) +πŸ‡¬πŸ‡§ [OpenSSH Server on Windows and SNMP Service Installation with Ansible](https://www.thierolf.org/posts/openssh-server-on-windows-and-snmp-service-installation-with-ansible/) ## Deutsch diff --git a/netbox/README.md b/netbox/README.md new file mode 100644 index 0000000..6a79805 --- /dev/null +++ b/netbox/README.md @@ -0,0 +1,15 @@ +# Netbox + +Example and code fragments for Cisco, Netbox and Ansible. + +* `backup2git.py` Python script to backup Cisco configs controlled by Netbox status and pushing them to GitLab + +* `netbox-librenms-graph.py` Include Interface graphs from LibreNMS in Netbox + +* `netbox-librenms.py` Pass (link) device from Netbox to LibreNMS + +* `netbox-snipeit.php` Pass (link) device from Netbox to Snipe-IT (PHP) + +* `netbox-snipeit.py` Pass (link) device from Netbox to Snipe-IT (Python) + +* `qrcode-snipeit.py` QR-Codes Snipe-IT diff --git a/netbox/backup2git.py b/netbox/backup2git.py new file mode 100644 index 0000000..552270d --- /dev/null +++ b/netbox/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 diff --git a/netbox/netbox-librenms-graph.py b/netbox/netbox-librenms-graph.py new file mode 100644 index 0000000..211e2b8 --- /dev/null +++ b/netbox/netbox-librenms-graph.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 +# This file is copyright under the latest version of the EUPL. +# Please see LICENSE file for your rights under this license. +import requests +import cgi +import cgitb +import time +import urllib.parse +import sys + +# +# LibreNMS HOST and API token +# +librenms_host = 'https://LIBRENMS_HOST' +token = 'LIBRENMS_API_TOKEN' + +# +# get form data +# +cgitb.enable() +form = cgi.FieldStorage() + +if "device" in form and "interface" in form: + + timefrom = str(int(time.time()) - 28800) + device = form.getvalue('device') + interface = form.getvalue('interface') + + for i in range(0,9): + device = device.replace(':' + str(i), '') + + device = urllib.parse.quote(device, safe='') + interface = urllib.parse.quote(interface, safe='') + + url = librenms_host + '/api/v0/devices/' + device + '/ports/' + interface + '/port_bits?width=780&height=200&from=' + timefrom + headers = {'X-Auth-Token': token} + r = requests.get(url, headers = headers) + + # + # if status code is 200, then print interface graph + # + if r.status_code == requests.codes.ok: + # + # LibreNMS must return something like an ID + # If there is no ID, then just list all devices + # + print ("Content-Type: image/png") + print () + sys.stdout.flush() + sys.stdout.buffer.write(r.content) + + else: + print ('Content-Type: text/html') + print () + print ('error') + +# +# handle all other errors by printing out error +# +else: + print ('Content-Type: text/html') + print () + print ('error') diff --git a/netbox/netbox-librenms.py b/netbox/netbox-librenms.py new file mode 100644 index 0000000..6b8c787 --- /dev/null +++ b/netbox/netbox-librenms.py @@ -0,0 +1,70 @@ +#!/usr/bin/python3 +# This file is copyright under the latest version of the EUPL. +# Please see LICENSE file for your rights under this license. +import requests +import cgi +import cgitb +import json + +# +# LibreNMS HOST and API token +# +librenms_host = 'https://LIBRENMS_HOST' +token = 'LIBRENMS_TOKEN' + +# +# get form data +# +cgitb.enable() +form = cgi.FieldStorage() + +# +# handle devices +# +if "devicegroup" in form: + devicegroup = form.getvalue('devicegroup') + url = librenms_host + '/api/v0/devicegroups' + headers = {'X-Auth-Token': token} + r = requests.get(url, headers = headers) + + # + # if status code is 200, then redirect to device group + # + if r.status_code == requests.codes.ok: + # + # LibreNMS must return something like an ID + # If there is no ID, then just list all devices + # + try: + data = r.json() + # + # LibreNMS API returns a count of device groups + # + rows = data['count'] + + # + # Look up ID by group name + # + for i in range(0, rows): + group_name = str(data['groups'][i]['name']) + + # + # if group_name matches the passed devicegroup, + # then get the corresponding ID + # + if group_name == devicegroup: + group_id = str(data['groups'][i]['id']) + print ('Location: ' + librenms_host + '/devices/group=' + group_id + '\n') + else: + print ('Location: ' + librenms_host + '/devices/' + '\n') + + except IndexError: + print ('Location: ' + librenms_host + '/devices/' + '\n') + else: + print ('Location: ' + librenms_host +'\n') + +# +# handle all other errors by just forwarding to the LibreNMS host +# +else: + print ('Location: ' + librenms_host +'\n') diff --git a/netbox/netbox-snipeit.php b/netbox/netbox-snipeit.php new file mode 100644 index 0000000..87bcc2f --- /dev/null +++ b/netbox/netbox-snipeit.php @@ -0,0 +1,48 @@ + 'Bearer API_TOKEN_GOES_HERE + 'accept' => 'application/json', + 'content-type' => 'application/json', + 'url' => 'https://SNIPEIT_FQDN/api/v1/locations?limit=1&offset=0&search=', +); +# +# Verify if a location parameter is passed as HTTP GET +# +if(isset($_GET['location'])) { + # + # Set CURL options and get data + # + $ch = curl_init($snipeit['url'] . $_GET['location']); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_URL, $snipeit['url'] . $_GET['location']); + curl_setopt($ch, CURLOPT_HTTPHEADER, Array('authorization: ' . $snipeit['token'])); + $data = curl_exec($ch); + # + # If CURL returns HTTP status code 200 (OK), then we can + # parse the json data and redirect to Snipe-IT location + # + if(curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200){ + # + # use json data as object + # + $object = json_decode($data); + # + # DEBUG to verify output + # + #print_r($object); + #print $object->rows[0]->id; + # + # Do an HTTP redirect to Snipe-IT location by the ID + # + $redirect = 'Location: https://SNIPEIT_FQDN/locations/' . $object->rows[0]->id; + header($redirect); + exit; + } + curl_close($ch); +} +?> \ No newline at end of file diff --git a/netbox/netbox-snipeit.py b/netbox/netbox-snipeit.py new file mode 100644 index 0000000..4e4a167 --- /dev/null +++ b/netbox/netbox-snipeit.py @@ -0,0 +1,75 @@ +#!/usr/bin/python3 +# This file is copyright under the latest version of the EUPL. +# Please see LICENSE file for your rights under this license. +import requests +import cgi +import cgitb +import json + +# +# Snipe-IT HOST and API token +# +snipeit_host = 'https://SNIPE-IT_HOST' +token = 'Bearer SNIPE-IT_API_TOKEN' + +# +# get form data +# +cgitb.enable() +form = cgi.FieldStorage() + +# +# handle devices +# +if "device" in form: + device = form.getvalue('device') + url = snipeit_host + '/api/v1/hardware?limit=1&offset=0&search=' + headers = {'authorization': token} + r = requests.get(url + device, headers = headers) + + # + # if status code is 200, then redirect to hardware + # + if r.status_code == requests.codes.ok: + # + # Snipe-IT must return something like an ID + # If there is no ID, then just list all hardware + # + try: + data = r.json() + device_id = str(data['rows'][0]['id']) + print ('Location: ' + snipeit_host + '/hardware/' + device_id + '\n') + except IndexError: + print ('Location: ' + snipeit_host + '/hardware/' + '\n') + else: + print ('Location: ' + snipeit_host +'\n') +# +# handle locations +# +elif "location" in form: + location = form.getvalue('location') + url = snipeit_host + '/api/v1/locations?limit=1&offset=0&search=' + headers = {'authorization': token} + r = requests.get(url + location, headers = headers) + + # + # if status code is 200, then redirect to location + # + if r.status_code == requests.codes.ok: + # + # Snipe-IT must return something like an ID + # If there is no ID, then just list all locations + # + try: + data = r.json() + location_id = str(data['rows'][0]['id']) + print ('Location: ' + snipeit_host + '/locations/' + location_id + '\n') + except IndexError: + print ('Location: ' + snipeit_host + '/locations/' +'\n') + else: + print ('Location: ' + snipeit_host +'\n') +# +# handle all other errors by just forwarding to the Snipe-IT host +# +else: + print ('Location: ' + snipeit_host +'\n') diff --git a/netbox/qrcode-snipeit.py b/netbox/qrcode-snipeit.py new file mode 100644 index 0000000..652dffe --- /dev/null +++ b/netbox/qrcode-snipeit.py @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +# This file is copyright under the latest version of the EUPL. +# Please see LICENSE file for your rights under this license. +import requests +import cgi +import cgitb +import json + +# +# Snipe-IT HOST and API token +# +snipeit_host = '[SNIPE_IT_HOST]' +token = 'Bearer [SNIPE_IT_AUTH_TOKEN]' + +# +# get form data +# +cgitb.enable() +form = cgi.FieldStorage() + +# +# handle devices +# +if "tag" in form: + tag = form.getvalue('tag') + url = snipeit_host + '/api/v1/hardware/bytag/' + headers = {'authorization': token} + r = requests.get(url + tag, headers = headers) + + # + # if status code is 200, then redirect to hardware + # + if r.status_code == requests.codes.ok: + # + # Snipe-IT must return something like an ID + # If there is no ID, then just list all hardware + # + try: + data = r.json() + device_id = str(data['id']) + print ('Location: ' + snipeit_host + '/hardware/' + device_id + '\n') + except: + print ('Location: ' + snipeit_host + '/hardware/' + '\n') + else: + print ('Location: ' + snipeit_host +'\n') +# +# handle all other errors by just forwarding to the Snipe-IT host +# +else: + print ('Location: ' + snipeit_host +'\n')