aboutsummaryrefslogtreecommitdiff
path: root/vland.py
blob: 20127bc67d6956a033c44bd7c39c65f027e1b8f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#! /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
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.1"
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 <switch_name>'
    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
    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?'

    # 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?'

    # 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?'

    # 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?'

    # 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)