blob: 1736bbd02c81e1a06091462d9e43f1a504f18a77 [file] [log] [blame]
Steve McIntyre6f59b972014-12-10 16:43:37 +00001#! /usr/bin/python
2
3# Copyright 2014 Linaro Limited
4# Author: Steve McIntyre <steve.mcintyre@linaro.org>
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19# MA 02110-1301, USA.
20#
21# VLANd simple config parser
22#
23
24import ConfigParser
25import os, sys, re
26
27if __name__ == '__main__':
28 vlandpath = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0])))
29 sys.path.insert(0, vlandpath)
30 sys.path.insert(0, "%s/.." % vlandpath)
31
Steve McIntyre6d84ec12014-12-18 16:56:56 +000032from errors import ConfigError
Steve McIntyre6f59b972014-12-10 16:43:37 +000033
Steve McIntyrec9e72e82015-07-14 15:25:08 +010034def is_positive(text):
35 if text in ('1', 'y', 'Y', 't', 'T', 'True', 'true'):
36 return True
37 elif text in ('0', 'n', 'N', 'f', 'F', 'False', 'false'):
38 return False
39
Steve McIntyrea9875062014-12-12 17:15:15 +000040class DaemonConfigClass:
41 """ Simple container for stuff to make for nicer syntax """
42
43 def __repr__(self):
44 return "<DaemonConfig: port: %s>" % (self.port)
45
Steve McIntyre6f59b972014-12-10 16:43:37 +000046class DBConfigClass:
47 """ Simple container for stuff to make for nicer syntax """
48
49 def __repr__(self):
Steve McIntyrea9875062014-12-12 17:15:15 +000050 return "<DBConfig: server: %s, port: %s, dbname: %s, username: %s, password: %s>" % (self.server, self.port, self.dbname, self.username, self.password)
Steve McIntyre6f59b972014-12-10 16:43:37 +000051
Steve McIntyredbe6aa52015-02-12 07:48:22 +000052class LoggingConfigClass:
53 """ Simple container for stuff to make for nicer syntax """
54
55 def __repr__(self):
56 return "<LoggingConfig: level: %s, filename: %s>" % (self.level, self.filename)
57
Steve McIntyre6f59b972014-12-10 16:43:37 +000058class SwitchConfigClass:
59 """ Simple container for stuff to make for nicer syntax """
60 def __repr__(self):
Steve McIntyrea9875062014-12-12 17:15:15 +000061 return "<SwitchConfig: name: %s, section: %s, driver: %s, username: %s, password: %s, enable_password: %s>" % (self.name, self.section, self.driver, self.username, self.password, self.enable_password)
Steve McIntyre6f59b972014-12-10 16:43:37 +000062
63class VlanConfig:
64 """VLANd config class"""
65 def __init__(self, filenames):
Steve McIntyred773cac2014-12-10 23:27:07 +000066
Steve McIntyre6f59b972014-12-10 16:43:37 +000067 config = ConfigParser.RawConfigParser({
68 # Set default values
69 'server': None,
70 'port': None,
71 'dbname': None,
72 'username': None,
73 'password': None,
74 'name': None,
75 'driver': None,
Steve McIntyrec9e72e82015-07-14 15:25:08 +010076 'enable_password': None,
77 'debug': False,
Steve McIntyre6f59b972014-12-10 16:43:37 +000078 })
79
80 config.read(filenames)
81
82 # Parse out the config file
83 # Must have a [database] section
Steve McIntyrea9875062014-12-12 17:15:15 +000084 # May have a [vland] section
Steve McIntyre6f59b972014-12-10 16:43:37 +000085 # May have a [logging] section
86 # May have multiple [switch 'foo'] sections
87 if not config.has_section('database'):
88 raise ConfigError('No database configuration section found')
89
Steve McIntyrea9875062014-12-12 17:15:15 +000090 # No DB-specific defaults to set
Steve McIntyre6f59b972014-12-10 16:43:37 +000091 self.database = DBConfigClass()
Steve McIntyrea9875062014-12-12 17:15:15 +000092
Steve McIntyredbe6aa52015-02-12 07:48:22 +000093 # Set defaults logging details
94 self.logging = LoggingConfigClass()
95 self.logging.level = None
96 self.logging.filename = None
97
Steve McIntyrec12f6312014-12-15 15:00:12 +000098 # Set default port number and VLAN tag
Steve McIntyrea9875062014-12-12 17:15:15 +000099 self.vland = DaemonConfigClass()
100 self.vland.port = 3080
Steve McIntyrec12f6312014-12-15 15:00:12 +0000101 self.vland.default_vlan_tag = 1
Steve McIntyrea9875062014-12-12 17:15:15 +0000102
103 # No switch-specific defaults to set
Steve McIntyre6f59b972014-12-10 16:43:37 +0000104 self.switches = {}
105
106 sw_regex = re.compile('(switch)\ (.*)', flags=re.I)
107 for section in config.sections():
108 if section == 'database':
109 try:
110 self.database.server = config.get(section, 'server')
Steve McIntyrea9875062014-12-12 17:15:15 +0000111 except ConfigParser.NoOptionError:
112 pass
Steve McIntyre38a30eb2014-12-11 16:10:55 +0000113 except:
114 raise ConfigError('Invalid database configuration (server)')
115
116 try:
Steve McIntyrea9875062014-12-12 17:15:15 +0000117 port = config.get(section, 'port')
118 if port is not None:
119 self.database.port = config.getint(section, 'port')
120 except ConfigParser.NoOptionError:
121 pass
Steve McIntyre38a30eb2014-12-11 16:10:55 +0000122 except:
123 raise ConfigError('Invalid database configuration (port)')
124
125 try:
Steve McIntyre6f59b972014-12-10 16:43:37 +0000126 self.database.dbname = config.get(section, 'dbname')
Steve McIntyrea9875062014-12-12 17:15:15 +0000127 except ConfigParser.NoOptionError:
128 pass
Steve McIntyre38a30eb2014-12-11 16:10:55 +0000129 except:
130 raise ConfigError('Invalid database configuration (dbname)')
131
132 try:
Steve McIntyre6f59b972014-12-10 16:43:37 +0000133 self.database.username = config.get(section, 'username')
Steve McIntyrea9875062014-12-12 17:15:15 +0000134 except ConfigParser.NoOptionError:
135 pass
Steve McIntyre38a30eb2014-12-11 16:10:55 +0000136 except:
137 raise ConfigError('Invalid database configuration (username)')
138
139 try:
Steve McIntyre6f59b972014-12-10 16:43:37 +0000140 self.database.password = config.get(section, 'password')
Steve McIntyrea9875062014-12-12 17:15:15 +0000141 except ConfigParser.NoOptionError:
142 pass
Steve McIntyre6f59b972014-12-10 16:43:37 +0000143 except:
Steve McIntyre38a30eb2014-12-11 16:10:55 +0000144 raise ConfigError('Invalid database configuration (password)')
Steve McIntyrea9875062014-12-12 17:15:15 +0000145
146 # Other database config options are optional, but these are not
Steve McIntyre6f59b972014-12-10 16:43:37 +0000147 if self.database.dbname is None or self.database.username is None:
148 raise ConfigError('Database configuration section incomplete')
Steve McIntyrea9875062014-12-12 17:15:15 +0000149
Steve McIntyre6f59b972014-12-10 16:43:37 +0000150 elif section == 'logging':
Steve McIntyredbe6aa52015-02-12 07:48:22 +0000151 try:
152 self.logging.level = config.get(section, 'level')
153 except ConfigParser.NoOptionError:
154 pass
155 except:
156 raise ConfigError('Invalid logging configuration (level)')
157
158 try:
Steve McIntyre19e6b062015-02-12 08:05:08 +0000159 self.logging.filename = config.get(section, 'filename')
Steve McIntyredbe6aa52015-02-12 07:48:22 +0000160 except ConfigParser.NoOptionError:
161 pass
162 except:
163 raise ConfigError('Invalid logging configuration (filename)')
Steve McIntyrea9875062014-12-12 17:15:15 +0000164
165 elif section == 'vland':
166 try:
167 self.vland.port = config.getint(section, 'port')
168 except ConfigParser.NoOptionError:
169 pass
170 except:
171 raise ConfigError('Invalid vland configuration (port)')
172
Steve McIntyrec12f6312014-12-15 15:00:12 +0000173 try:
Steve McIntyrec6906982014-12-23 13:22:38 +0000174 self.vland.default_vlan_tag = config.getint(section, 'default_vlan_tag')
Steve McIntyrec12f6312014-12-15 15:00:12 +0000175 except ConfigParser.NoOptionError:
176 pass
177 except:
178 raise ConfigError('Invalid vland configuration (default_vlan_tag)')
179
Steve McIntyre6f59b972014-12-10 16:43:37 +0000180 else:
181 match = sw_regex.match(section)
182 if match:
183 # Constraint: switch names must be unique! See if
184 # there's already a switch with this name
185 name = config.get(section, 'name')
186 for key in self.switches.keys():
187 if name == key:
188 raise ConfigError('Found switches with the same name (%s)' % name)
189 self.switches[name] = SwitchConfigClass()
190 self.switches[name].name = name
191 self.switches[name].section = section
192 self.switches[name].driver = config.get(section, 'driver')
193 self.switches[name].username = config.get(section, 'username')
194 self.switches[name].password = config.get(section, 'password')
195 self.switches[name].enable_password = config.get(section, 'enable_password')
Steve McIntyrec9e72e82015-07-14 15:25:08 +0100196 self.switches[name].debug = config.get(section, 'debug')
197 if not is_positive(self.switches[name].debug):
198 self.switches[name].debug = False
199 elif is_positive(self.switches[name].debug):
200 self.switches[name].debug = True
201 else:
202 raise ConfigError('Invalid vland configuration (switch "%s", debug "%s"' % (name, self.switches[name].debug))
Steve McIntyre6f59b972014-12-10 16:43:37 +0000203 else:
204 raise ConfigError('Unrecognised config section %s' % section)
205
206 def __del__(self):
207 pass
208
209if __name__ == '__main__':
Steve McIntyre6d84ec12014-12-18 16:56:56 +0000210 c = VlanConfig(filenames=('./vland.cfg',))
211 print c.database
212 print c.vland
213 for switch in c.switches:
214 print c.switches[switch]
Steve McIntyre6f59b972014-12-10 16:43:37 +0000215