blob: e564c9ef2218716e85d878b4f0e12fde25d49280 [file] [log] [blame]
Steve McIntyre30bf4db2014-08-12 18:08:22 +01001#! /usr/bin/python
2
Steve McIntyre94ef65e2015-09-25 01:08:14 +01003# Copyright 2014-2015 Linaro Limited
Steve McIntyre30bf4db2014-08-12 18:08:22 +01004#
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
20import time
21import logging
22
Steve McIntyreb826fc72015-07-27 17:57:40 +010023from errors import InputError, PExpectError
24
Steve McIntyre96f2c652015-02-12 04:25:55 +000025class SwitchErrors:
26 """ Error logging and statistics class """
27
28 def __init__(self):
29 self.errors_in = 0
30 self.errors_out = 0
31
32 def __repr__(self):
Steve McIntyrea67473a2015-02-12 08:26:33 +000033 return "<SwitchErrors: errors_in: %d, errors_out: %d>" % (self.errors_in, self.errors_out)
Steve McIntyre96f2c652015-02-12 04:25:55 +000034
35 # For now, just count the error. Later on we might add stats and
36 # analysis
37 def log_error_in(self, text):
38 self.errors_in += 1
39
40 # For now, just count the error. Later on we might add stats and
41 # analysis
42 def log_error_out(self, text):
43 self.errors_out += 1
44
Steve McIntyre30bf4db2014-08-12 18:08:22 +010045class SwitchDriver(object):
Steve McIntyre366046f2014-08-18 18:57:03 +010046
Steve McIntyre30bf4db2014-08-12 18:08:22 +010047 connection = None
48 hostname = ""
Steve McIntyre366046f2014-08-18 18:57:03 +010049 serial_number = ''
50
Steve McIntyre9936d002014-10-01 15:54:10 +010051 _allowed_port_modes = [ "trunk", "access" ]
Steve McIntyre366046f2014-08-18 18:57:03 +010052 _ports = []
Steve McIntyre1a7bad52015-07-20 15:21:42 +010053 _port_modes = {}
Steve McIntyred5cfde12015-08-05 13:49:42 +010054 _port_numbers = {}
Steve McIntyre366046f2014-08-18 18:57:03 +010055 _prompt_name = ''
Steve McIntyre115350d2015-07-14 17:11:30 +010056 _username = ''
57 _password = ''
58 _enable_password = ''
59 _systemdata = []
Steve McIntyre30bf4db2014-08-12 18:08:22 +010060
Steve McIntyre2396f622015-07-14 15:35:03 +010061 def __init__ (self, switch_hostname, debug):
62
63 if debug:
64 # Configure logging for pexpect output if we have debug
65 # enabled
66
67 # get the logger
68 self.logger = logging.getLogger(switch_hostname)
69
70 # give the logger the methods required by pexpect
71 self.logger.write = self._log_write
72 self.logger.flush = self._log_do_nothing
73
74 else:
75 self.logger = None
76
Steve McIntyre37870ef2015-07-14 16:25:12 +010077 self.hostname = switch_hostname
78
79 # Connect to the switch and log in
80 def switch_connect(self, username, password, enablepassword):
81 self._username = username
82 self._password = password
83 self._enable_password = enablepassword
84 self._switch_connect()
85
86 # Log out of the switch and drop the connection and all state
87 def switch_disconnect(self):
88 self._logout()
89 logging.debug("Closing connection to %s", self.hostname)
Steve McIntyre37870ef2015-07-14 16:25:12 +010090 self._ports = []
Steve McIntyre8de82cf2015-07-21 17:45:44 +010091 self._port_modes.clear()
Steve McIntyred5cfde12015-08-05 13:49:42 +010092 self._port_numbers.clear()
Steve McIntyre37870ef2015-07-14 16:25:12 +010093 self._prompt_name = ''
94 self._systemdata = []
95 del(self)
96
Steve McIntyre5fa22652015-04-01 18:01:45 +010097 def dump_list(self, data):
Steve McIntyre30bf4db2014-08-12 18:08:22 +010098 i = 0
Steve McIntyre2b4c07b2014-12-22 16:10:04 +000099 for line in data:
Steve McIntyre30bf4db2014-08-12 18:08:22 +0100100 print "%d: \"%s\"" % (i, line)
101 i += 1
102
103 def _delay(self):
104 time.sleep(0.5)
105
Steve McIntyre366046f2014-08-18 18:57:03 +0100106 # List the capabilities of the switch (and driver) - some things
107 # make no sense to abstract. Returns a dict of strings, each one
108 # describing an extra feature that that higher levels may care
109 # about
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100110 def switch_get_capabilities(self):
Steve McIntyre366046f2014-08-18 18:57:03 +0100111 return self._capabilities
112
113 # List the names of all the ports on the switch
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100114 def switch_get_port_names(self):
Steve McIntyre366046f2014-08-18 18:57:03 +0100115 return self._ports
116
117 def _is_port_name_valid(self, name):
Steve McIntyre366046f2014-08-18 18:57:03 +0100118 for port in self._ports:
119 if name == port:
120 return True
121 return False
122
123 def _is_port_mode_valid(self, mode):
Steve McIntyre366046f2014-08-18 18:57:03 +0100124 for allowed in self._allowed_port_modes:
125 if allowed == mode:
126 return True
127 return False
128
Steve McIntyre1a7bad52015-07-20 15:21:42 +0100129 # Try to look up a port mode in our cache. If not there, go ask
130 # the switch and cache the result
131 def port_get_mode(self, port):
132 if not self._is_port_name_valid(port):
133 raise InputError("Port name %s not recognised" % port)
134 if port in self._port_modes:
Steve McIntyre4e75c5b2015-07-21 17:46:05 +0100135 logging.debug("port_get_mode: returning mode %s from cache for port %s", self._port_modes[port], port)
Steve McIntyre1a7bad52015-07-20 15:21:42 +0100136 return self._port_modes[port]
137 else:
138 mode = self._port_get_mode(port)
139 self._port_modes[port] = mode
Steve McIntyre4e75c5b2015-07-21 17:46:05 +0100140 logging.debug("port_get_mode: found mode %s for port %s, adding to cache", self._port_modes[port], port)
Steve McIntyre1a7bad52015-07-20 15:21:42 +0100141 return mode
142
Steve McIntyred5cfde12015-08-05 13:49:42 +0100143 def port_map_name_to_number(self, port_name):
144 if not self._is_port_name_valid(port_name):
145 raise InputError("Port name %s not recognised" % port_name)
146 logging.debug("port_map_name_to_number: returning %d for port_name %s", self._port_numbers[port_name], port_name)
147 return self._port_numbers[port_name]
148
Steve McIntyre2396f622015-07-14 15:35:03 +0100149 # Wrappers to adapt logging for pexpect when we've configured on a
150 # switch.
151 # This will be the method called by the pexpect object to write a
152 # log message
153 def _log_write(self, *args, **kwargs):
154 # ignore other parameters, pexpect only uses one arg
155 content = args[0]
156
157 if content in [' ', '', '\n', '\r', '\r\n']:
158 return # don't log empty lines
159
160 # Split the output into multiple lines so we get a
161 # well-formatted logfile
162 for line in content.split('\r\n'):
163 logging.info(line)
164
165 # This is the flush method for pexpect
166 def _log_do_nothing(self):
167 pass