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
9 changes: 0 additions & 9 deletions config-sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,6 @@
#snmp_priv = ""
wifi_vlanid = yaml_conf['wifi']['vlan_id']

# Enable this if we cannot set special option82 tags
franken_net_switches = [ ]

# If you have franken net, you need snmpv3 credentials to dist
# NOTE: THERE IS NO NEED TO USE THIS IF is_franken_net == False
snmpv3_username = ''
snmpv3_auth = ''
snmpv3_priv = ''

models = {}
for model in yaml_conf['models']:
data = bunch(template=model['path'],eth=model['ports'])
Expand Down
2 changes: 1 addition & 1 deletion dhcp-hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
sql = "SELECT short_name FROM network WHERE ipv4_gateway_txt = ?"
networkname = cursor.execute(sql, (swRelay, )).fetchone()[0]
db.set('networkname-{}'.format(swIp), networkname)
if "Juniper" not in :swClient
if "Juniper" not in swClient:
# We don't need any SNMP or base config for Juniper.
os.system("/scripts/swboot/configure " + swIp + " &")
2 changes: 1 addition & 1 deletion dhcpd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ on commit {
if agentType = "0" {
set swName = pick-first-value(binary-to-ascii(16, 8, ":", substring(option agent.circuit-id, 4, 2)), "None");
} else {
set swName = pick-first-value(substring(option agent.circuit-id, 2, 10), "None");
set swName = pick-first-value(substring(option agent.circuit-id, 2, 50), "None");
}
set swMac = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
set swIp = binary-to-ascii(10, 8, ".", leased-address);
Expand Down
136 changes: 136 additions & 0 deletions swcommon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@

#!/usr/bin/env python
import tempfile
import syslog
import redis
import netsnmp
import os
import re
import traceback
import time

import config

db = redis.Redis()

def log(*args):
print time.strftime("%Y-%m-%d %H:%M:%S") + ':', ' '.join(args)
syslog.syslog(syslog.LOG_INFO, ' '.join(args))

def error(*args):
print time.strftime("%Y-%m-%d %H:%M:%S") + ': ERROR:', ' '.join(args)
syslog.syslog(syslog.LOG_ERR, ' '.join(args))

def sw_reload(ip):
error("Reloading switch")
try:
os.system("/scripts/swboot/reload " + ip + " &")
except:
error("Exception in reload:", traceback.format_exc())

def generate(out, ip, switch):
model = db.get('client-{}'.format(ip))
if model == None:
# Get Cisco model name (two tries)
for i in xrange(2):
var = netsnmp.Varbind('.1.3.6.1.2.1.47.1.1.1.1.13.1')
model = netsnmp.snmpget(var, Version=2, DestHost=ip, Community='private')[0]

if model == None:
var = netsnmp.Varbind('.1.3.6.1.2.1.47.1.1.1.1.13.1001')
model = netsnmp.snmpget(var, Version=2, DestHost=ip, Community='private')[0]

if model == None:
sw_reload(ip)
error("Could not get model for switch" , ip)
return

if not model in config.models:
sw_reload(ip)
error("Template for model", model_id, "not found")
return

# Throws exception if something bad happens
try:
txt = config.generate(switch, model)
out.write(txt)
except:
sw_reload(ip)
error("Exception in generation for %s :" % switch, traceback.format_exc())
out.close()
return None

return out

def base(out, switch):
out.write("snmp-server community private rw\n")
out.write("hostname BASE\n")
out.write("no vlan 2-4094\n")
out.write("end\n\n")

def select_file(file_to_transfer, ip):
if file_to_transfer in config.static_files:
return file(config.static_files[file_to_transfer])

global db
switch = db.get(ip)
if switch is None:
error('No record of switch', ip, 'in Redis, ignoring ..')
return None

log('Switch is', switch)
db.set('switchname-%s' % ip, switch)

model = db.get('client-{}'.format(ip))

if not re.match('^([A-Z]{1,2}[0-9][0-9]-[A-C]|DIST:[A-Z]{1,2}-[A-Z]-[A-Z]+-S[TW])$', switch):
sw_reload(ip)
error("Switch", ip, "does not match regexp, invalid option 82? Received '", switch, "' as option 82")
return None

# Dist config.
if "DIST:" in switch and file_to_transfer.lower().endswith("-confg"):
if re.match(r'^[a-zA-Z0-9:-]+$', switch) and os.path.isfile('distconfig/%s' % switch[5:]):
log("Sending config to", switch)
f = open('distconfig/%s' % switch[5:])
return f
error('Dist config not found for', ip)
return None

# Juniper config.
if file_to_transfer == "juniper-confg":
log("Generating Juniper config for", ip, "name =", switch)
f = tempfile.TemporaryFile()
f.write(config.generate(switch, model))
f.seek(0)
return f

# Switch base config.
if (file_to_transfer == "network-confg" or
file_to_transfer == "Switch-confg"):
log("Generating config for", ip, "name =", switch)
f = tempfile.TemporaryFile()
base(f, switch)
f.seek(0)
return f

# Juniper image.
if file_to_transfer == "juniper.tgz":
if (model in config.models) and ('image' in config.models[model]):
log("Sending JunOS image to ", ip, "name =", switch)
return file(config.models[model]['image'])
log("Missing image file for", ip, "name =", switch)

# Final config for non-Juniper switches.
if file_to_transfer.lower().endswith("-confg"):
f = tempfile.TemporaryFile()
log("Generating config for", ip,"config =", switch)
if generate(f, ip, switch) == None:
return None
f.seek(0)
return f

error("Switch", ip, "config =", switch, "tried to get file",
file_to_transfer)
return None

56 changes: 16 additions & 40 deletions swhttpd.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
#!/usr/bin/env python
import sys, logging
import redis
import syslog
import socket
import re
import tempfile
import SimpleHTTPServer
import SocketServer
import time

import config
import swcommon

def log(*args):
print time.strftime("%Y-%m-%d %H:%M:%S") + ':', ' '.join(args)
Expand All @@ -21,45 +19,24 @@ def error(*args):

class swbootHttpHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
db = redis.Redis()
switch = db.get(self.client_address[0])
model = db.get('client-{}'.format(self.client_address[0]))
if switch == None or model == None:
log("Switch not found:", self.client_address[0])
# self.path is the path of the requested file.
file_handle = swcommon.select_file(self.path.lstrip("/"), self.client_address[0])

if file_handle == None:
self.send_error(404, "File not found")
return None
if self.path == "/juniper-confg":
log("Generating Juniper config for",
self.client_address[0], "name =", switch)
f = tempfile.TemporaryFile()
f.write(config.generate(switch, model))
content_length = f.tell()
f.seek(0)

self.send_response(200)
self.send_header("Content-type", "application/octet-stream")
self.send_header("Content-Length", content_length)
self.end_headers()
self.copyfile(f, self.wfile)
log("Config sent to", self.client_address[0], "name =", switch)
# Go to the end of the file to get the length of it.
file_handle.seek(0, 2)
content_length = file_handle.tell()
file_handle.seek(0)

self.send_response(200)
self.send_header("Content-type", "application/octet-stream")
self.send_header("Content-Length", content_length)
self.end_headers()
self.copyfile(file_handle, self.wfile)

f.close()
return
elif self.path == "/juniper.tgz":
log("Sending JunOS file", config.models[model]['image'], "to",
self.client_address[0], "name =", switch)
if (model in config.models) and ('image' in config.models[model]):
# All good! Overwrite the requested file path and send our own.
self.path = config.models[model]['image']
f = self.send_head()
if f:
self.copyfile(f, self.wfile)
log("Sent JunOS to", self.client_address[0], "name =", switch)
f.close()
else:
log("Unknown file:", self.path)
self.send_error(404, "File not found")

# We write our own logs.
def log_request(self, code='-', size='-'):
pass
Expand All @@ -70,10 +47,9 @@ class swbootTCPServer(SocketServer.ForkingTCPServer):
def server_bind(self):
self.socket.bind(self.server_address)

log("swhttpd started")

try:
httpd = swbootTCPServer(("", 80), swbootHttpHandler)
log("swhttpd started")
httpd.serve_forever()
except socket.error, err:
sys.stderr.write("Socket error: %s\n" % str(err))
Expand Down
Loading