blob: 6832f3b5a829d75c6c3fe7f09f9f6493d5165b0f [file] [log] [blame]
Steve McIntyre30bf4db2014-08-12 18:08:22 +01001#! /usr/bin/python
2
3# Copyright 2014 Linaro Limited
Steve McIntyre6103e982014-09-18 23:37:54 +01004
Steve McIntyre30bf4db2014-08-12 18:08:22 +01005#
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
21import time
22import logging
23
Steve McIntyreb826fc72015-07-27 17:57:40 +010024from errors import InputError, PExpectError
25
Steve McIntyre96f2c652015-02-12 04:25:55 +000026class SwitchErrors:
27 """ Error logging and statistics class """
28
29 def __init__(self):
30 self.errors_in = 0
31 self.errors_out = 0
32
33 def __repr__(self):
Steve McIntyrea67473a2015-02-12 08:26:33 +000034 return "<SwitchErrors: errors_in: %d, errors_out: %d>" % (self.errors_in, self.errors_out)
Steve McIntyre96f2c652015-02-12 04:25:55 +000035
36 # For now, just count the error. Later on we might add stats and
37 # analysis
38 def log_error_in(self, text):
39 self.errors_in += 1
40
41 # For now, just count the error. Later on we might add stats and
42 # analysis
43 def log_error_out(self, text):
44 self.errors_out += 1
45
Steve McIntyre30bf4db2014-08-12 18:08:22 +010046class SwitchDriver(object):
Steve McIntyre366046f2014-08-18 18:57:03 +010047
Steve McIntyre30bf4db2014-08-12 18:08:22 +010048 connection = None
49 hostname = ""
Steve McIntyre366046f2014-08-18 18:57:03 +010050 serial_number = ''
51
Steve McIntyre9936d002014-10-01 15:54:10 +010052 _allowed_port_modes = [ "trunk", "access" ]
Steve McIntyre366046f2014-08-18 18:57:03 +010053 _ports = []
Steve McIntyre1a7bad52015-07-20 15:21:42 +010054 _port_modes = {}
Steve McIntyred5cfde12015-08-05 13:49:42 +010055 _port_numbers = {}
Steve McIntyre366046f2014-08-18 18:57:03 +010056 _prompt_name = ''
Steve McIntyre115350d2015-07-14 17:11:30 +010057 _username = ''
58 _password = ''
59 _enable_password = ''
60 _systemdata = []
Steve McIntyre30bf4db2014-08-12 18:08:22 +010061
Steve McIntyre2396f622015-07-14 15:35:03 +010062 def __init__ (self, switch_hostname, debug):
63
64 if debug:
65 # Configure logging for pexpect output if we have debug
66 # enabled
67
68 # get the logger
69 self.logger = logging.getLogger(switch_hostname)
70
71 # give the logger the methods required by pexpect
72 self.logger.write = self._log_write
73 self.logger.flush = self._log_do_nothing
74
75 else:
76 self.logger = None
77
Steve McIntyre37870ef2015-07-14 16:25:12 +010078 self.hostname = switch_hostname
79
80 # Connect to the switch and log in
81 def switch_connect(self, username, password, enablepassword):
82 self._username = username
83 self._password = password
84 self._enable_password = enablepassword
85 self._switch_connect()
86
87 # Log out of the switch and drop the connection and all state
88 def switch_disconnect(self):
89 self._logout()
90 logging.debug("Closing connection to %s", self.hostname)
91 self.connection.close(True)
92 self._ports = []
Steve McIntyre8de82cf2015-07-21 17:45:44 +010093 self._port_modes.clear()
Steve McIntyred5cfde12015-08-05 13:49:42 +010094 self._port_numbers.clear()
Steve McIntyre37870ef2015-07-14 16:25:12 +010095 self._prompt_name = ''
96 self._systemdata = []
97 del(self)
98
Steve McIntyre5fa22652015-04-01 18:01:45 +010099 def dump_list(self, data):
Steve McIntyre30bf4db2014-08-12 18:08:22 +0100100 i = 0
Steve McIntyre2b4c07b2014-12-22 16:10:04 +0000101 for line in data:
Steve McIntyre30bf4db2014-08-12 18:08:22 +0100102 print "%d: \"%s\"" % (i, line)
103 i += 1
104
105 def _delay(self):
106 time.sleep(0.5)
107
Steve McIntyre366046f2014-08-18 18:57:03 +0100108 # List the capabilities of the switch (and driver) - some things
109 # make no sense to abstract. Returns a dict of strings, each one
110 # describing an extra feature that that higher levels may care
111 # about
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100112 def switch_get_capabilities(self):
Steve McIntyre366046f2014-08-18 18:57:03 +0100113 return self._capabilities
114
115 # List the names of all the ports on the switch
Steve McIntyre9b09b9d2014-09-24 15:08:10 +0100116 def switch_get_port_names(self):
Steve McIntyre366046f2014-08-18 18:57:03 +0100117 return self._ports
118
119 def _is_port_name_valid(self, name):
Steve McIntyre366046f2014-08-18 18:57:03 +0100120 for port in self._ports:
121 if name == port:
122 return True
123 return False
124
125 def _is_port_mode_valid(self, mode):
Steve McIntyre366046f2014-08-18 18:57:03 +0100126 for allowed in self._allowed_port_modes:
127 if allowed == mode:
128 return True
129 return False
130
Steve McIntyre1a7bad52015-07-20 15:21:42 +0100131 # Try to look up a port mode in our cache. If not there, go ask
132 # the switch and cache the result
133 def port_get_mode(self, port):
134 if not self._is_port_name_valid(port):
135 raise InputError("Port name %s not recognised" % port)
136 if port in self._port_modes:
Steve McIntyre4e75c5b2015-07-21 17:46:05 +0100137 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 +0100138 return self._port_modes[port]
139 else:
140 mode = self._port_get_mode(port)
141 self._port_modes[port] = mode
Steve McIntyre4e75c5b2015-07-21 17:46:05 +0100142 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 +0100143 return mode
144
Steve McIntyred5cfde12015-08-05 13:49:42 +0100145 def port_map_name_to_number(self, port_name):
146 if not self._is_port_name_valid(port_name):
147 raise InputError("Port name %s not recognised" % port_name)
148 logging.debug("port_map_name_to_number: returning %d for port_name %s", self._port_numbers[port_name], port_name)
149 return self._port_numbers[port_name]
150
Steve McIntyre2396f622015-07-14 15:35:03 +0100151 # Wrappers to adapt logging for pexpect when we've configured on a
152 # switch.
153 # This will be the method called by the pexpect object to write a
154 # log message
155 def _log_write(self, *args, **kwargs):
156 # ignore other parameters, pexpect only uses one arg
157 content = args[0]
158
159 if content in [' ', '', '\n', '\r', '\r\n']:
160 return # don't log empty lines
161
162 # Split the output into multiple lines so we get a
163 # well-formatted logfile
164 for line in content.split('\r\n'):
165 logging.info(line)
166
167 # This is the flush method for pexpect
168 def _log_do_nothing(self):
169 pass
170