blob: fb649eebfa43585c558a3b07e7b4d544fcfef991 [file] [log] [blame]
Steve McIntyree5043dd2014-12-10 16:49:28 +00001#! /usr/bin/python
2
3# Copyright 2014 Linaro Limited
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18# MA 02110-1301, USA.
19#
20# Main VLANd module
21#
22
Steve McIntyre1cb0b482014-12-22 17:18:11 +000023import os, sys
Steve McIntyree5043dd2014-12-10 16:49:28 +000024import time
25import logging
26
27vlandpath = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0])))
28sys.path.insert(0, vlandpath)
29
30import drivers
31from config.config import VlanConfig
32from db.db import VlanDB
Steve McIntyre6c44fb22014-12-12 22:11:45 +000033from ipc.ipc import VlanIpc
34from errors import CriticalError, InputError, ConfigError, SocketError
Steve McIntyref1c04f92014-12-16 18:23:15 +000035from util import VlanUtil
Steve McIntyree5043dd2014-12-10 16:49:28 +000036
Steve McIntyre231354b2014-12-16 19:22:12 +000037class DaemonState:
38 """ Simple container for stuff to make for nicer syntax """
Steve McIntyree5043dd2014-12-10 16:49:28 +000039
Steve McIntyre231354b2014-12-16 19:22:12 +000040state = DaemonState()
41state.version = "0.0.0-DEV"
42state.banner = "Linaro VLANd version %s" % state.version
43state.starttime = time.time()
44
45print '%s' % state.banner
Steve McIntyree5043dd2014-12-10 16:49:28 +000046
47print 'Parsing Config...'
Steve McIntyre231354b2014-12-16 19:22:12 +000048state.config = VlanConfig(filenames=('./vland.cfg',))
49print ' Config knows about %d switches' % len(state.config.switches)
Steve McIntyree5043dd2014-12-10 16:49:28 +000050
Steve McIntyref1c04f92014-12-16 18:23:15 +000051util = VlanUtil()
52
Steve McIntyree5043dd2014-12-10 16:49:28 +000053print 'Connecting to DB...'
Steve McIntyre283d5f22014-12-17 13:12:04 +000054state.db = VlanDB(db_name=state.config.database.dbname,
55 username=state.config.database.username)
Steve McIntyree5043dd2014-12-10 16:49:28 +000056
Steve McIntyre283d5f22014-12-17 13:12:04 +000057switches = state.db.all_switches()
Steve McIntyree5043dd2014-12-10 16:49:28 +000058print ' DB knows about %d switches' % len(switches)
Steve McIntyre283d5f22014-12-17 13:12:04 +000059ports = state.db.all_ports()
Steve McIntyree5043dd2014-12-10 16:49:28 +000060print ' DB knows about %d ports' % len(ports)
Steve McIntyre283d5f22014-12-17 13:12:04 +000061vlans = state.db.all_vlans()
Steve McIntyree5043dd2014-12-10 16:49:28 +000062print ' DB knows about %d vlans' % len(vlans)
63
Steve McIntyreae286192014-12-12 22:10:43 +000064# Initial startup sanity chacking
Steve McIntyree5043dd2014-12-10 16:49:28 +000065
Steve McIntyrec12f6312014-12-15 15:00:12 +000066# For sanity, we need to know the vlan_id for the default vlan (tag
67# 1). Make sure we know that before anybody attempts to create things
68# that depend on it.
Steve McIntyre283d5f22014-12-17 13:12:04 +000069state.default_vlan_id = state.db.get_vlan_id_by_tag(state.config.vland.default_vlan_tag)
70if state.default_vlan_id is None:
Steve McIntyrec12f6312014-12-15 15:00:12 +000071 # It doesn't exist - create it and try again
Steve McIntyre283d5f22014-12-17 13:12:04 +000072 state.default_vlan_id = state.db.create_vlan("DEFAULT",
73 state.config.vland.default_vlan_tag,
74 True)
Steve McIntyrec12f6312014-12-15 15:00:12 +000075
Steve McIntyre231354b2014-12-16 19:22:12 +000076if len(switches) != len(state.config.switches):
77 print 'You have configured access details for %d switch(es), ' % len(state.config.switches)
Steve McIntyre96855db2014-12-15 16:52:00 +000078 print 'but have %d switch(es) registered in your database.' % len(switches)
Steve McIntyreae286192014-12-12 22:10:43 +000079 print 'You must fix this difference for VLANd to work sensibly.'
80 print 'HINT: Running admin.py --auto-import-switch <switch_name>'
Steve McIntyrebd7ce372014-12-17 16:27:41 +000081 print 'for each of your switches may help!'
Steve McIntyreae286192014-12-12 22:10:43 +000082 print
Steve McIntyree5043dd2014-12-10 16:49:28 +000083
Steve McIntyre6c44fb22014-12-12 22:11:45 +000084# Now start up the core loop. Listen for command connections and
85# process them
86ipc = VlanIpc()
Steve McIntyre231354b2014-12-16 19:22:12 +000087ipc.server_init('localhost', state.config.vland.port)
Steve McIntyre6c44fb22014-12-12 22:11:45 +000088while True:
Steve McIntyref1c04f92014-12-16 18:23:15 +000089 try:
90 ipc.server_listen()
91 json_data = ipc.server_recv()
92 except SocketError as e:
93 print e
94 print 'Caught IPC error, ignoring'
95 continue
Steve McIntyref1c04f92014-12-16 18:23:15 +000096 except:
97 ipc.server_close()
98 raise
Steve McIntyre6c44fb22014-12-12 22:11:45 +000099
Steve McIntyref1c04f92014-12-16 18:23:15 +0000100 print "client %s sent us:" % json_data['client_name']
Steve McIntyre6c44fb22014-12-12 22:11:45 +0000101 print json_data
102
Steve McIntyref1c04f92014-12-16 18:23:15 +0000103 response = {}
104
Steve McIntyre0ebf5832014-12-16 19:23:10 +0000105 # Several types of IPC message here, with potentially different
106 # access control and safety
107
108 # First - simple queries to the database only. Should be safe!
109 if json_data['type'] == 'db_query':
110 response['type'] = 'response'
Steve McIntyref1c04f92014-12-16 18:23:15 +0000111 try:
Steve McIntyre208241a2014-12-17 13:12:26 +0000112 response['data'] = util.perform_db_query(state, json_data['command'], json_data['data'])
Steve McIntyre0ebf5832014-12-16 19:23:10 +0000113 response['response'] = 'ACK'
114 except InputError as e:
115 print e
116 response['response'] = 'ERROR'
117 response['error'] = e.__str__()
118 print 'FOO?'
Steve McIntyre0ebf5832014-12-16 19:23:10 +0000119
120 # Next - simple queries about daemon state only. Should be safe!
121 if json_data['type'] == 'daemon_query':
122 response['type'] = 'response'
123 try:
124 response['data'] = util.perform_daemon_query(state, json_data['command'], json_data['data'])
Steve McIntyref1c04f92014-12-16 18:23:15 +0000125 response['response'] = 'ACK'
126 except InputError as e:
127 print e
128 response['response'] = 'ERROR'
129 response['error'] = e.__str__()
130 print 'FOO?'
Steve McIntyref1c04f92014-12-16 18:23:15 +0000131
Steve McIntyre995a10c2014-12-17 13:12:58 +0000132 # Next, calls that manipulate objects in the database only
133 # (switches and ports). These are safe and don't need actual
Steve McIntyrec3b659b2014-12-17 16:28:37 +0000134 # co-ordinating with hardware directly.
Steve McIntyre995a10c2014-12-17 13:12:58 +0000135 #
136 # As/when/if we add authentication, use of this function will need
137 # it.
138 if json_data['type'] == 'db_update':
139 response['type'] = 'response'
140 try:
141 response['data'] = util.perform_db_update(state, json_data['command'], json_data['data'])
142 response['response'] = 'ACK'
143 except InputError as e:
144 print e
145 response['response'] = 'ERROR'
146 response['error'] = e.__str__()
147 print 'FOO?'
Steve McIntyre995a10c2014-12-17 13:12:58 +0000148
Steve McIntyre50767152014-12-17 16:29:01 +0000149 # Next, calls that may manipulate switch state *as well* as state
150 # in the database - changes to VLAN setup.
151 #
152 # As/when/if we add authentication, use of this function will need
153 # it.
154 if json_data['type'] == 'vlan_update':
155 response['type'] = 'response'
156 try:
157 response['data'] = util.perform_vlan_update(state, json_data['command'], json_data['data'])
158 response['response'] = 'ACK'
159 except InputError as e:
160 print e
161 response['response'] = 'ERROR'
162 response['error'] = e.__str__()
163 print 'FOO?'
Steve McIntyre50767152014-12-17 16:29:01 +0000164
165 # Finally, IPC interface for more complex API calls.
166 # NOT IMPLEMENTED YET
167 if json_data['type'] == 'vland_api':
168 response['type'] = 'response'
169 response['response'] = 'ERROR'
170 response['error'] = 'VLANd API not yet implemented...'
171
Steve McIntyre6c44fb22014-12-12 22:11:45 +0000172 print "sending reply:"
173 print response
174
175 ipc.server_reply(response)
176