Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions netztp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ def create_app():
netztp_env = os.getenv('NETZTP_ENV', 'DEFAULT').capitalize()
app.config.from_object(f'netztp.config.{netztp_env}')

inventory.authenticate(app.config['INVENTORY_API_TOKEN'])

from netztp.eos import bp as eos
app.register_blueprint(eos, url_prefix='/eos')

Expand Down
9 changes: 8 additions & 1 deletion netztp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,21 @@ class Default(object):
'sqlite:///{}'.format(os.path.join(basedir, 'netztp.db'))
SQLALCHEMY_TRACK_MODIFICATIONS = False

INVENTORY_API_TOKEN = os.environ.get('INVENTORY_API_TOKEN')
JSONIFY_PRETTYPRINT_REGULAR = True

LOG_DESTINATIONS = [{
'destination': '192.168.50.2:514',
'level': 'DEBUG'
}]

FIRMWARE_SERVER = 'https://firmware.yzguy.io'
EOS_VERSIONS = {
'4.21.7.1M': 'vEOS-lab-4.21.7.1M.swi',
'4.22.2.1F': 'vEOS-lab-4.22.2.1F.swi',
'4.23.0.1F': 'vEOS-lab-4.23.0.1F.swi',
'4.24.2.1F': 'vEOS-lab-4.24.2.1F.swi',
'default': '4.24.2.1F'
}

class Development(Default):
FLASK_ENV = 'development'
Expand Down
35 changes: 21 additions & 14 deletions netztp/eos/routes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from flask import make_response, jsonify, request, url_for, redirect, abort, \
render_template, current_app
from netztp.util import response_with_content_type, generate_checksum
from netztp import inventory
from netztp import inventory as inv
from netztp.eos import bp

from datetime import datetime
Expand Down Expand Up @@ -75,23 +75,30 @@ def ztp_nodes():
# copy_file - download and save file
@bp.route('/ztp/nodes/<serialnum>')
def ztp_nodes_serial(serialnum):
# Look for Device

actions = []

# If not device, return unknown/no actions
# return jsonify({
# 'name': 'Unknown Device',
# 'actions': []
# }), 404
device = inv.device(serialnum)
# Look for Device
if not device:
return jsonify({
'name': 'Unknown Device',
'actions': []
}), 404

# Get firmware version from inventory or use default
eos_versions = current_app.config['EOS_VERSIONS']
version = device.custom_fields['firmware']
if not version:
version = eos_versions['default']
filename = eos_versions[version]

# Upgrade Software Action
actions.append({
'name': 'Upgrade Operating System',
'action': 'install_image',
'attributes': {
'url': f"{current_app.config['FIRMWARE_SERVER']}/eos/vEOS-lab-4.24.2.1F.swi",
'version': '4.21.8M'
'url': f"{current_app.config['FIRMWARE_SERVER']}/eos/{filename}",
'version': version
},
'always_execute': True
})
Expand Down Expand Up @@ -121,7 +128,7 @@ def ztp_nodes_serial(serialnum):
'name': 'Install static startup-config file',
'action': 'replace_config',
'attributes': {
'url': '/nodes/{}/startup-config'.format(serialnum)
'url': f'/nodes/{serialnum}/startup-config'
},
'always_execute': True
})
Expand All @@ -131,7 +138,7 @@ def ztp_nodes_serial(serialnum):
'name': 'Signal ZTP Completion',
'action': 'copy_file',
'attributes': {
'src_url': '/{}/ztp_finished'.format(serialnum),
'src_url': f'/{serialnum}/ztp_finished',
'dst_url': '/mnt/flash',
'mode': '0644',
'overwrite': 'replace'
Expand Down Expand Up @@ -166,14 +173,14 @@ def ztp_cli_commands():
# Node retreives device-specific startup-config
@bp.route('/ztp/nodes/<serialnum>/startup-config')
def ztp_startup_config(serialnum):
device = inventory.device(serialnum)
device = inv.device(serialnum)
return response_with_content_type(render_template('eos.j2', device=device),
'text/plain')

# Node retrieves checksum for startup-config
@bp.route('/ztp/meta/nodes/<serialnum>/startup-config')
def meta_serial_startup_config(serialnum):
device = inventory.device(serialnum)
device = inv.device(serialnum)
return jsonify(generate_checksum(render_template('eos.j2', device=device)))

# Node retrieves the time it finished ZTP
Expand Down
4 changes: 2 additions & 2 deletions netztp/eos/templates/eos.j2
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
! Command: show running-config
! device: {{ device.hostname }}
! device: {{ device.name }}
!
hostname {{ device.hostname }}
hostname {{ device.name }}
ip domain-name {{ device.domain_name }}
!
username admin privilege 15 role network-admin secret admin
Expand Down
54 changes: 22 additions & 32 deletions netztp/inventory.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,28 @@

class Inventory(object):

DATA = {
'abc123': {
'hostname': 'abc123',
'domain_name': 'yzguy.io',
'ip_address': '192.168.50.200',
'subnet_mask': '255.255.255.0',
'gateway': '192.168.50.1'
},
'123abc': {
'hostname': '123abc',
'domain_name': 'yzguy.io',
'ip_address': '192.168.50.201',
'subnet_mask': '255.255.255.0',
'gateway': '192.168.50.1'
},
'000c29a0de4d': {
'hostname': '000c29a0de4d',
'domain_name': 'yzguy.io',
'ip_address': '192.168.50.202',
'subnet_mask': '255.255.255.0',
'gateway': '192.168.50.1'
}
}
import pynetbox, os

class Inventory(object):
def __init__(self):
self.api_token = None
netbox = pynetbox.api(
os.getenv('NETBOX_URL'),
token=os.getenv('NETBOX_TOKEN'),
threading=True
)
self.inv = netbox

def authenticate(self, api_token):
self.api_token = api_token
def devices(self):
devices = self.inv.dcim.devices.all()
return devices

def device(self, id):
if id in self.DATA:
return self.DATA[id]
def device(self, identifier):
device = self.inv.dcim.devices.filter(serial=identifier)
if device:
device = device[0]
device['interfaces'] = self._interfaces(device['id'])
return device
else:
return None

return {}
def _interfaces(self, device_id):
interfaces = self.inv.dcim.interfaces.filter(device_id=device_id)
return interfaces
7 changes: 7 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
certifi==2020.12.5
chardet==4.0.0
click==7.1.2
Flask==1.1.2
gunicorn==20.0.4
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.3
MarkupSafe==1.1.1
pynetbox==5.3.1
requests==2.25.1
six==1.15.0
urllib3==1.26.3
Werkzeug==1.0.1