#! /usr/bin/python # Copyright 2014 Linaro Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. # # Main VLANd module # import os, sys, types import time import logging vlandpath = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0]))) sys.path.insert(0, vlandpath) import drivers from config.config import VlanConfig from db.db import VlanDB from ipc.ipc import VlanIpc from errors import CriticalError, InputError, ConfigError, SocketError from util import VlanUtil class DaemonState: """ Simple container for stuff to make for nicer syntax """ state = DaemonState() state.version = "0.0.0-DEV" state.banner = "Linaro VLANd version %s" % state.version state.starttime = time.time() print '%s' % state.banner print 'Parsing Config...' state.config = VlanConfig(filenames=('./vland.cfg',)) print ' Config knows about %d switches' % len(state.config.switches) util = VlanUtil() print 'Connecting to DB...' state.db = VlanDB(db_name=state.config.database.dbname, username=state.config.database.username) switches = state.db.all_switches() print ' DB knows about %d switches' % len(switches) ports = state.db.all_ports() print ' DB knows about %d ports' % len(ports) vlans = state.db.all_vlans() print ' DB knows about %d vlans' % len(vlans) # Initial startup sanity chacking # For sanity, we need to know the vlan_id for the default vlan (tag # 1). Make sure we know that before anybody attempts to create things # that depend on it. state.default_vlan_id = state.db.get_vlan_id_by_tag(state.config.vland.default_vlan_tag) if state.default_vlan_id is None: # It doesn't exist - create it and try again state.default_vlan_id = state.db.create_vlan("DEFAULT", state.config.vland.default_vlan_tag, True) if len(switches) != len(state.config.switches): print 'You have configured access details for %d switch(es), ' % len(state.config.switches) print 'but have %d switch(es) registered in your database.' % len(switches) print 'You must fix this difference for VLANd to work sensibly.' print 'HINT: Running admin.py --auto-import-switch ' print 'for each of your switches may help!' print # Now start up the core loop. Listen for command connections and # process them ipc = VlanIpc() ipc.server_init('localhost', state.config.vland.port) while True: try: ipc.server_listen() json_data = ipc.server_recv() except SocketError as e: print e print 'Caught IPC error, ignoring' continue pass except: ipc.server_close() raise print "client %s sent us:" % json_data['client_name'] print json_data response = {} # Several types of IPC message here, with potentially different # access control and safety # First - simple queries to the database only. Should be safe! if json_data['type'] == 'db_query': response['type'] = 'response' try: response['data'] = util.perform_db_query(state, json_data['command'], json_data['data']) response['response'] = 'ACK' except InputError as e: print e response['response'] = 'ERROR' response['error'] = e.__str__() print 'FOO?' pass # Next - simple queries about daemon state only. Should be safe! if json_data['type'] == 'daemon_query': response['type'] = 'response' try: response['data'] = util.perform_daemon_query(state, json_data['command'], json_data['data']) response['response'] = 'ACK' except InputError as e: print e response['response'] = 'ERROR' response['error'] = e.__str__() print 'FOO?' pass # Next, calls that manipulate objects in the database only # (switches and ports). These are safe and don't need actual # co-ordinating with hardware directly. # # As/when/if we add authentication, use of this function will need # it. if json_data['type'] == 'db_update': response['type'] = 'response' try: response['data'] = util.perform_db_update(state, json_data['command'], json_data['data']) response['response'] = 'ACK' except InputError as e: print e response['response'] = 'ERROR' response['error'] = e.__str__() print 'FOO?' pass # Next, calls that may manipulate switch state *as well* as state # in the database - changes to VLAN setup. # # As/when/if we add authentication, use of this function will need # it. if json_data['type'] == 'vlan_update': response['type'] = 'response' try: response['data'] = util.perform_vlan_update(state, json_data['command'], json_data['data']) response['response'] = 'ACK' except InputError as e: print e response['response'] = 'ERROR' response['error'] = e.__str__() print 'FOO?' pass # Finally, IPC interface for more complex API calls. # NOT IMPLEMENTED YET if json_data['type'] == 'vland_api': response['type'] = 'response' response['response'] = 'ERROR' response['error'] = 'VLANd API not yet implemented...' print "sending reply:" print response ipc.server_reply(response)