Skip to content

Commit 9326f1f

Browse files
committed
Public Release of DreamHack Switch Configuration System
0 parents  commit 9326f1f

19 files changed

+2475
-0
lines changed

README.md

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# swboot
2+
3+
On-demand switch configuration system.
4+
5+
License is GPLv3 if nothing else is stated.
6+
7+
## Dependencies
8+
sudo apt-get install redis-server python-redis libsnmp-python python-tempita python-ipcalc isc-dhcp-server snmp
9+
10+
## Config
11+
sudo /sbin/ifconfig eth1 inet 192.168.8.10 netmask 255.255.255.0
12+
13+
## Install
14+
cp config-sample.py config.py
15+
16+
## dhcpd.conf
17+
include "/srv/swboot/dhcpd.conf";
18+
19+
## Start swtftpd
20+
sudo python swtftpd.py
21+
22+
## Test generation of configuration
23+
python generate.py D20-A WS-C2950T-24
24+
25+
## Boot procedure
26+
27+
The Cisco switches will try to get DHCP and boot via TFTP if no config exists (wr erase).
28+
If you want to have a config stored on the switch it must include "boot host dhcp".
29+
30+
## Default switch conf
31+
32+
For event configs, see SVN allevents/access/default-paste/
33+
34+
In general, something like this will work:
35+
36+
en
37+
conf t
38+
boot host dhcp
39+
interface vlan 1
40+
no ip address
41+
no shut
42+
!
43+
snmp-server community public RO
44+
snmp-server community private RW
45+
snmp-server system-shutdown
46+
!
47+
wr
48+
!
49+
50+
51+
## Dist switch
52+
53+
en
54+
conf t
55+
ip routing
56+
!
57+
ip dhcp snooping vlan 1
58+
! Perhaps needed:
59+
! ip dhcp snooping information option allow-untrusted
60+
ip dhcp snooping
61+
!
62+
!
63+
interface GigabitEthernet1/0/5
64+
description DHCP-server
65+
switchport access vlan 123
66+
switchport mode access
67+
spanning-tree portfast
68+
ip dhcp snooping trust
69+
!
70+
interface GigabitEthernet1/0/20
71+
spanning-tree portfast
72+
ip dhcp snooping vlan 1 information option format-type circuit-id string B01-B
73+
!
74+
interface Vlan1
75+
ip address 10.80.10.1 255.255.255.0
76+
ip helper-address 10.255.253.2
77+
!
78+
interface Vlan123
79+
ip address 10.255.253.5 255.255.255.0
80+
!

config-sample.py

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import config
2+
import ipcalc
3+
import sqlite3
4+
import sys
5+
import tempita
6+
from tempita import bunch
7+
import hashlib
8+
9+
# Note: To add new variables, the generate function will need to
10+
# be modified as well
11+
12+
password = ""
13+
enable = ""
14+
snmp_ro = ""
15+
snmp_salt = ""
16+
radius = ""
17+
# NOTE(bluecmd): 2950 doesn't support VLAN aware context, which means that
18+
# WhereAmI and dhmon needs v2. No reason to have v3 in that case.
19+
#snmp_user = ""
20+
#snmp_auth = ""
21+
#snmp_priv = ""
22+
wifi_vlanid = 851
23+
24+
# Enable this if we cannot set special option82 tags
25+
franken_net_switches = [ ]
26+
27+
# If you have franken net, you need snmpv3 credentials to dist
28+
# NOTE: THERE IS NO NEED TO USE THIS IF is_franken_net == False
29+
snmpv3_username = ''
30+
snmpv3_auth = ''
31+
snmpv3_priv = ''
32+
33+
models = {
34+
"WS-C2950T-24" : bunch(template="switchconfig/c2950t.cfg",eth=24),
35+
"WS-C2950G-24-EI" : bunch(template="switchconfig/c2950t.cfg",eth=24),
36+
"WS-C2950T-48-SI" : bunch(template="switchconfig/c2950t.cfg",eth=48),
37+
"WS-C2960G-48TC-L" : bunch(template="switchconfig/c2960g.cfg",eth=48),
38+
"WS-C2960X-48TS-L" : bunch(template="switchconfig/c2960x.cfg",eth=48),
39+
}
40+
41+
wifi_switches = [ ]
42+
43+
#wifi_switches = [
44+
# "B01-A", "B05-A", "B10-A", "B16-A", "B22-C", "B26-C", "B31-C", "B37-C",
45+
# "C04-A", "C08-A", "C12-A", "C17-C", "C21-C", "C25-C", "C29-C",
46+
# "D03-A", "D09-B", "D19-B", "D23-A", "D29-A", "D34-C", "D40-C", "D44-C", "D48-C", "D56-C", "D62-C"
47+
#]
48+
49+
# Files to be served as they are to all devices
50+
static_files = {
51+
"c2950.bin" : "ios/c2950-i6k2l2q4-mz.121-22.EA14.bin",
52+
}
53+
54+
# ===============================================================
55+
# Do not change below this if you do not know what you're doing!
56+
# ===============================================================
57+
58+
def generate(switch, model_id):
59+
model = config.models[model_id]
60+
61+
mgmt, vlanid = parse_metadata(switch)
62+
if mgmt is None:
63+
raise Exception("The switch " + switch + " was not found in ipplan")
64+
65+
cfg = tempita.Template(file(model.template).read())
66+
return \
67+
cfg.substitute(
68+
hostname=switch,
69+
model=model,
70+
mgmt_ip=mgmt['ip'],
71+
mgmt_mask=mgmt['mask'],
72+
mgmt_gw=mgmt['gw'],
73+
mgmt_vlanid=mgmt['vlanid'],
74+
vlanid=vlanid,
75+
wifi_switches=config.wifi_switches,
76+
wifi_vlanid=config.wifi_vlanid,
77+
password=config.password,
78+
enable=config.enable,
79+
radius=config.radius,
80+
snmp_ro=config.snmp_ro,
81+
snmp_rw=hashlib.sha1(config.snmp_salt + mgmt['ip']).hexdigest(),
82+
# snmp_user=config.snmp_user,
83+
# snmp_auth=config.snmp_auth,
84+
# snmp_priv=config.snmp_priv
85+
)
86+
87+
def parse_metadata(switch):
88+
sql = '''SELECT n_mgmt.ipv4_txt, h.ipv4_addr_txt, n_mgmt.ipv4_gateway_txt,
89+
n_mgmt.vlan, n.vlan FROM active_switch as s, network as n, host as h,
90+
network as n_mgmt WHERE s.switch_name LIKE ? AND n.node_id = s.node_id
91+
AND h.name = s.switch_name AND n_mgmt.node_id = h.network_id'''
92+
93+
db = sqlite3.connect('/etc/ipplan.db')
94+
cursor = db.cursor()
95+
96+
network_str, mgmt_ip, gateway, mgmt_vlan, vlan = cursor.execute(
97+
sql, ('%s%%' % switch.lower(),)).fetchone()
98+
99+
network = ipcalc.Network(network_str)
100+
101+
mgmt = {}
102+
mgmt['ip'] = mgmt_ip
103+
mgmt['mask'] = str(network.netmask())
104+
mgmt['gw'] = str(network.host_first())
105+
mgmt['vlanid'] = mgmt_vlan
106+
107+
return mgmt, vlan
108+
109+
if __name__ == '__main__':
110+
if len(sys.argv) == 3 and sys.argv[1] == 'dump-snmp-rw':
111+
mgmt, _ = parse_metadata(sys.argv[2])
112+
print hashlib.sha1(config.snmp_salt + mgmt['ip']).hexdigest()
113+
else:
114+
print generate("D23-A", "WS-C2950T-24")

configure

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/bin/bash
2+
#
3+
# Tell a switch to fetch configuration from TFTP.
4+
#
5+
# Wait until it responds to SNMP and wait until the transfer is complete.
6+
#
7+
8+
ID=$RANDOM
9+
IP=$1
10+
11+
CNT=0
12+
while [ true ];
13+
do
14+
snmpget -Ov -v 2c -c private $IP 1.3.6.1.2.1.1.5.0 &> /dev/null
15+
if [ "$?" = "0" ]; then
16+
break
17+
fi
18+
19+
CNT=$(($CNT + 1))
20+
if [ "$CNT" = 20 ]; then
21+
echo "Timeout waiting for SNMP for $IP." \
22+
| logger -p error -t configure
23+
exit 1
24+
fi
25+
26+
echo "Waiting for SNMP ..."
27+
sleep 5
28+
done
29+
30+
snmpset -v 2c -c private $IP .1.3.6.1.4.1.9.9.96.1.1.1.1.2.$ID i 1
31+
snmpset -v 2c -c private $IP .1.3.6.1.4.1.9.9.96.1.1.1.1.3.$ID i 1
32+
snmpset -v 2c -c private $IP .1.3.6.1.4.1.9.9.96.1.1.1.1.4.$ID i 4
33+
snmpset -v 2c -c private $IP .1.3.6.1.4.1.9.9.96.1.1.1.1.5.$ID a 192.168.20.10
34+
snmpset -v 2c -c private $IP .1.3.6.1.4.1.9.9.96.1.1.1.1.6.$ID s BASE-confg
35+
snmpset -v 2c -c private $IP .1.3.6.1.4.1.9.9.96.1.1.1.1.14.$ID i 1
36+
37+
RET=2
38+
CNT=0
39+
while [ "$RET" = "2" ];
40+
do
41+
echo "Waiting for switch to apply configuration ..."
42+
sleep 10
43+
RET=$(snmpget -Ov -v 2c -c private $IP \
44+
.1.3.6.1.4.1.9.9.96.1.1.1.1.10.$ID | cut -f 2 -d ' ')
45+
CNT=$(($CNT + 1))
46+
if [ "$CNT" = 6 ]; then
47+
echo "Timeout waiting for switch to apply configuration for $IP." \
48+
| logger -p error -t configure
49+
exit 1
50+
fi
51+
done
52+
53+
echo "Return: $RET"
54+
snmpset -v 2c -c private $IP .1.3.6.1.4.1.9.9.96.1.1.1.1.14.$ID i 6
55+
56+
SWITCH=$(redis-cli --raw get $IP)
57+
echo "Successfully pushed configuration to $SWITCH ($IP)" \
58+
| logger -t configure

dhcp-hook.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env python
2+
import os
3+
import redis
4+
import sys
5+
6+
db = redis.Redis()
7+
8+
if sys.argv[1] == "commit":
9+
ip = sys.argv[2]
10+
sw = sys.argv[3]
11+
relay = sys.argv[5]
12+
db.set(ip, sw)
13+
if relay != '0.0.0.0':
14+
db.set('relay-%s' % ip, relay)
15+
os.system("/srv/swboot/configure " + ip + " &")

0 commit comments

Comments
 (0)