summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPradeep Sathasivam <psathasi@brocade.com>2015-08-07 14:49:48 +0530
committerAngela Smith <aallen@brocade.com>2016-03-17 15:52:05 -0700
commite2c8ecd218280c1cd7869fa8040ad02bf0f6b02b (patch)
tree2f712242b406abfc4c6261ffd1234db0db7d59cb
parent9d3c974cbb6ba66ffaf383aa047544201a3c1789 (diff)
Support for enable password configuration
When enable password is configured in device, ML2 plugin will not be able to configure the device via SSH or TELNET. Now this is supported by reading the response of each command and identifying the prompt. Change-Id: I3344f63b2f076809046fdbe92b9c9227bc0f1e1c Closes-Bug: 1481161
Notes
Notes (review): Code-Review+2: Shiv Haris <shivharis@hotmail.com> Workflow+1: Shiv Haris <shivharis@hotmail.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Mon, 28 Mar 2016 19:24:53 +0000 Reviewed-on: https://review.openstack.org/210271 Project: openstack/networking-brocade Branch: refs/heads/master
-rw-r--r--etc/neutron/plugins/brocade/brocade_mlx.ini4
-rw-r--r--etc/neutron/plugins/ml2/ml2_conf_brocade_fi_ni.ini6
-rw-r--r--networking_brocade/mlx/ml2/device_connector.py60
-rw-r--r--networking_brocade/mlx/ml2/fi_ni/brcd_config.py8
-rw-r--r--networking_brocade/mlx/ml2/ssh_connector.py114
-rw-r--r--networking_brocade/mlx/ml2/telnet_connector.py83
-rw-r--r--networking_brocade/test_discover/test_discover.py5
7 files changed, 182 insertions, 98 deletions
diff --git a/etc/neutron/plugins/brocade/brocade_mlx.ini b/etc/neutron/plugins/brocade/brocade_mlx.ini
index 3e1e338..8165bb4 100644
--- a/etc/neutron/plugins/brocade/brocade_mlx.ini
+++ b/etc/neutron/plugins/brocade/brocade_mlx.ini
@@ -9,6 +9,8 @@
9# password = The SSH password to use to connect to device 9# password = The SSH password to use to connect to device
10# physical_networks = Allowed physical networks for VLAN configuration 10# physical_networks = Allowed physical networks for VLAN configuration
11# ports = Comma separated list of ports on the switch which needs to be tagged to VLAN 11# ports = Comma separated list of ports on the switch which needs to be tagged to VLAN
12# enable_username = The username for the enable configuration prompt, if any.
13# enable_password = The password for the enable configuration prompt, if any.
12# 14#
13# Example: 15# Example:
14# [mlx] 16# [mlx]
@@ -17,3 +19,5 @@
17# password = password 19# password = password
18# physical_networks = physnet1 20# physical_networks = physnet1
19# ports = 3/3, 3/9 21# ports = 3/3, 3/9
22# enable_username = admin
23# enable_password = password
diff --git a/etc/neutron/plugins/ml2/ml2_conf_brocade_fi_ni.ini b/etc/neutron/plugins/ml2/ml2_conf_brocade_fi_ni.ini
index b37fa43..6207e9b 100644
--- a/etc/neutron/plugins/ml2/ml2_conf_brocade_fi_ni.ini
+++ b/etc/neutron/plugins/ml2/ml2_conf_brocade_fi_ni.ini
@@ -11,6 +11,8 @@
11# ports = Ports on the switch which needs to tagged to VLAN. Multiple ports can be separated by a comma. 11# ports = Ports on the switch which needs to tagged to VLAN. Multiple ports can be separated by a comma.
12# transport = Protocol to use for device connection(SSH or Telnet). Default is SSH. This is an optional parameter 12# transport = Protocol to use for device connection(SSH or Telnet). Default is SSH. This is an optional parameter
13# ostype = Optional parameter, which will identify the firmware version(FI/NI) 13# ostype = Optional parameter, which will identify the firmware version(FI/NI)
14# enable_username = The username for the enable configuration prompt, if any.
15# enable_password = The password for the enable configuration prompt, if any.
14# 16#
15# Example: 17# Example:
16# [icx-1] 18# [icx-1]
@@ -21,6 +23,8 @@
21# ports = 1/1/1, 1/1/2 23# ports = 1/1/1, 1/1/2
22# transport = SSH 24# transport = SSH
23# ostype = FI 25# ostype = FI
26# enable_username = admin
27# enable_password = password
24 28
25# Example: 29# Example:
26# [mlx] 30# [mlx]
@@ -31,3 +35,5 @@
31# ports = 3/3, 3/9 35# ports = 3/3, 3/9
32# transport = SSH 36# transport = SSH
33# ostype = NI 37# ostype = NI
38# enable_username = admin
39# enable_password = password
diff --git a/networking_brocade/mlx/ml2/device_connector.py b/networking_brocade/mlx/ml2/device_connector.py
index 8012d81..d027e25 100644
--- a/networking_brocade/mlx/ml2/device_connector.py
+++ b/networking_brocade/mlx/ml2/device_connector.py
@@ -18,7 +18,7 @@
18 Decides which connector to use - TELNET or SSH, based on 18 Decides which connector to use - TELNET or SSH, based on
19 the argument passed 19 the argument passed
20""" 20"""
21import networking_brocade.mlx.ml2.commands as Commands 21from networking_brocade.mlx.ml2 import commands
22from oslo_log import log as logging 22from oslo_log import log as logging
23 23
24LOG = logging.getLogger(__name__) 24LOG = logging.getLogger(__name__)
@@ -36,31 +36,10 @@ class DeviceConnector(object):
36 self.host = device_info.get('address') 36 self.host = device_info.get('address')
37 self.username = device_info.get('username') 37 self.username = device_info.get('username')
38 self.password = device_info.get('password') 38 self.password = device_info.get('password')
39 self.enable_username = device_info.get('enable_username')
40 self.enable_password = device_info.get('enable_password')
39 self.transport = device_info.get('transport') 41 self.transport = device_info.get('transport')
40 42
41 def enter_configuration_mode(self):
42 """
43 Enter configuration mode. First it enters enable mode
44 and then to configuration mode. There should be no
45 Enable password.
46 """
47
48 self.write(Commands.ENABLE_TERMINAL_CMD)
49 self.write(Commands.CONFIGURE_TERMINAL_CMD)
50
51 def exit_configuration_mode(self):
52 """
53 Exit Configuration mode.
54 """
55 self.send_exit(2)
56
57 def exit_from_device(self):
58 """
59 Exit Configuration mode and device.
60 """
61 self.exit_configuration_mode()
62 self.send_exit(1)
63
64 def create_vlan(self, vlanid, ports): 43 def create_vlan(self, vlanid, ports):
65 """ 44 """
66 Creates VLAN and tags the ports to the created VLAN 45 Creates VLAN and tags the ports to the created VLAN
@@ -72,7 +51,7 @@ class DeviceConnector(object):
72 "device %(host)s", {'vlanid': vlanid, 'host': self.host}) 51 "device %(host)s", {'vlanid': vlanid, 'host': self.host})
73 self.enter_configuration_mode() 52 self.enter_configuration_mode()
74 self.write( 53 self.write(
75 Commands.CONFIGURE_VLAN.format( 54 commands.CONFIGURE_VLAN.format(
76 vlan_id=vlanid)) 55 vlan_id=vlanid))
77 LOG.debug( 56 LOG.debug(
78 "Created VLAN with id %(vlanid)s on device %(host)s", { 57 "Created VLAN with id %(vlanid)s on device %(host)s", {
@@ -80,8 +59,6 @@ class DeviceConnector(object):
80 for port in ports: 59 for port in ports:
81 self.tag_port(port) 60 self.tag_port(port)
82 LOG.debug("tagged port %(port)s", {'port': port}) 61 LOG.debug("tagged port %(port)s", {'port': port})
83 self.send_exit(1)
84 self.exit_from_device()
85 return self.read_response() 62 return self.read_response()
86 63
87 def tag_port(self, port): 64 def tag_port(self, port):
@@ -92,7 +69,7 @@ class DeviceConnector(object):
92 LOG.debug("DeviceConnector:tag_port:Tagging port %(portid)s on device" 69 LOG.debug("DeviceConnector:tag_port:Tagging port %(portid)s on device"
93 " %(host)s", {'portid': port, 'host': self.host}) 70 " %(host)s", {'portid': port, 'host': self.host})
94 self.write( 71 self.write(
95 Commands.CONFIGURE_ETHERNET.format( 72 commands.CONFIGURE_ETHERNET.format(
96 port_number=port)) 73 port_number=port))
97 74
98 def delete_vlan(self, vlan_id): 75 def delete_vlan(self, vlan_id):
@@ -106,12 +83,11 @@ class DeviceConnector(object):
106 'host': self.host}) 83 'host': self.host})
107 self.enter_configuration_mode() 84 self.enter_configuration_mode()
108 self.write( 85 self.write(
109 Commands.DELETE_CONFIGURED_VLAN.format( 86 commands.DELETE_CONFIGURED_VLAN.format(
110 vlan_id=vlan_id)) 87 vlan_id=vlan_id))
111 LOG.debug( 88 LOG.debug(
112 "Deleted VLAN with id %(vlan_id)s on device %(host)s", { 89 "Deleted VLAN with id %(vlan_id)s on device %(host)s", {
113 'vlan_id': vlan_id, 'host': self.host}) 90 'vlan_id': vlan_id, 'host': self.host})
114 self.exit_from_device()
115 return self.read_response() 91 return self.read_response()
116 92
117 def get_version(self): 93 def get_version(self):
@@ -121,10 +97,9 @@ class DeviceConnector(object):
121 """ 97 """
122 LOG.debug("DeviceConnector:get_version:Executing show version for " 98 LOG.debug("DeviceConnector:get_version:Executing show version for "
123 "device %(host)s", {'host': self.host}) 99 "device %(host)s", {'host': self.host})
124 self.write(Commands.SHOW_VERSION) 100 self.write(commands.SHOW_VERSION)
125 self.write(Commands.CTRL_C) 101 self.write(commands.CTRL_C)
126 self.send_exit(1) 102 return self.read_response()
127 return self.read_response(read_lines=False)
128 103
129 def create_l3_router(self, vlan_id, gateway_ip_cidr): 104 def create_l3_router(self, vlan_id, gateway_ip_cidr):
130 """Configures a Router Interface interface 105 """Configures a Router Interface interface
@@ -144,7 +119,6 @@ class DeviceConnector(object):
144 LOG.debug(("DeviceConnector:create_l3_router:Configured router " 119 LOG.debug(("DeviceConnector:create_l3_router:Configured router "
145 "interface with id %(vlanid)s on device %(host)s"), 120 "interface with id %(vlanid)s on device %(host)s"),
146 {'vlanid': vlan_id, 'host': self.host}) 121 {'vlanid': vlan_id, 'host': self.host})
147 self.exit_from_device()
148 return self.read_response() 122 return self.read_response()
149 123
150 def _create_router_interface(self, vlan_id): 124 def _create_router_interface(self, vlan_id):
@@ -158,16 +132,15 @@ class DeviceConnector(object):
158 "%(host)s", {'vlanid': vlan_id, 132 "%(host)s", {'vlanid': vlan_id,
159 'host': self.host}) 133 'host': self.host})
160 self.write( 134 self.write(
161 Commands.CONFIGURE_VLAN.format( 135 commands.CONFIGURE_VLAN.format(
162 vlan_id=vlan_id)) 136 vlan_id=vlan_id))
163 self.write( 137 self.write(
164 Commands.CONFIGURE_ROUTER_INTERFACE.format( 138 commands.CONFIGURE_ROUTER_INTERFACE.format(
165 vlan_id=vlan_id)) 139 vlan_id=vlan_id))
166 LOG.debug("DeviceConnector:_create_router_interface:Created l3 " 140 LOG.debug("DeviceConnector:_create_router_interface:Created l3 "
167 "router interface %(vlanid)s on device " 141 "router interface %(vlanid)s on device "
168 "%(host)s", {'vlanid': vlan_id, 142 "%(host)s", {'vlanid': vlan_id,
169 'host': self.host}) 143 'host': self.host})
170 self.send_exit(1)
171 144
172 def _configure_ipaddress(self, vlan_id, gateway_ip_cidr): 145 def _configure_ipaddress(self, vlan_id, gateway_ip_cidr):
173 """Assigns Gateway ip for the configured vlan 146 """Assigns Gateway ip for the configured vlan
@@ -182,17 +155,16 @@ class DeviceConnector(object):
182 'vlanid': vlan_id, 155 'vlanid': vlan_id,
183 'host': self.host}) 156 'host': self.host})
184 self.write( 157 self.write(
185 Commands.CONFIGURE_INTERFACE.format( 158 commands.CONFIGURE_INTERFACE.format(
186 vlan_id=vlan_id)) 159 vlan_id=vlan_id))
187 self.write( 160 self.write(
188 Commands.CONFIGURE_GATEWAY_IP.format( 161 commands.CONFIGURE_GATEWAY_IP.format(
189 gateway_ip_addr=gateway_ip_cidr)) 162 gateway_ip_addr=gateway_ip_cidr))
190 LOG.debug("DeviceConnector:_configure_ipaddress:Assigned IP address" 163 LOG.debug("DeviceConnector:_configure_ipaddress:Assigned IP address"
191 " %(ipaddr)s to the router interface %(vlanid)s on device" 164 " %(ipaddr)s to the router interface %(vlanid)s on device"
192 " %(host)s", {'ipaddr': gateway_ip_cidr, 165 " %(host)s", {'ipaddr': gateway_ip_cidr,
193 'vlanid': vlan_id, 166 'vlanid': vlan_id,
194 'host': self.host}) 167 'host': self.host})
195 self.send_exit(1)
196 168
197 def delete_l3_router(self, vlan_id): 169 def delete_l3_router(self, vlan_id):
198 """ 170 """
@@ -209,15 +181,13 @@ class DeviceConnector(object):
209 " %(vlan_id)s from vlan %(vlan_id)s on device %(host)s"), 181 " %(vlan_id)s from vlan %(vlan_id)s on device %(host)s"),
210 {'vlan_id': vlan_id, 'host': self.host}) 182 {'vlan_id': vlan_id, 'host': self.host})
211 self.write( 183 self.write(
212 Commands.CONFIGURE_VLAN.format(vlan_id=vlan_id)) 184 commands.CONFIGURE_VLAN.format(vlan_id=vlan_id))
213 self.write( 185 self.write(
214 Commands.DELETE_ROUTER_INTERFACE.format( 186 commands.DELETE_ROUTER_INTERFACE.format(
215 vlan_id=vlan_id)) 187 vlan_id=vlan_id))
216 self.send_exit(1)
217 188
218 LOG.debug(("DeviceConnector:delete_l3_router:Deleted router interface" 189 LOG.debug(("DeviceConnector:delete_l3_router:Deleted router interface"
219 " %(vlan_id)s from vlan %(vlan_id)s on device %(host)s"), 190 " %(vlan_id)s from vlan %(vlan_id)s on device %(host)s"),
220 {'vlan_id': vlan_id, 'host': self.host}) 191 {'vlan_id': vlan_id, 'host': self.host})
221 192
222 self.exit_from_device()
223 return self.read_response() 193 return self.read_response()
diff --git a/networking_brocade/mlx/ml2/fi_ni/brcd_config.py b/networking_brocade/mlx/ml2/fi_ni/brcd_config.py
index c982b79..06c8ba3 100644
--- a/networking_brocade/mlx/ml2/fi_ni/brcd_config.py
+++ b/networking_brocade/mlx/ml2/fi_ni/brcd_config.py
@@ -45,6 +45,10 @@ ML2_BROCADE = [cfg.StrOpt('address', default='',
45 help=('OS type of the device. NI is NetIron ' 45 help=('OS type of the device. NI is NetIron '
46 'for MLX switches. FI is FastIron for ' 46 'for MLX switches. FI is FastIron for '
47 'ICX switches.')), 47 'ICX switches.')),
48 cfg.StrOpt('enable_username', default='admin',
49 help=('Username of the enable config prompt')),
50 cfg.StrOpt('enable_password', default='password', secret=True,
51 help=('Password of the enable config prompt')),
48 ] 52 ]
49L3_BROCADE = [cfg.StrOpt('address', default='', 53L3_BROCADE = [cfg.StrOpt('address', default='',
50 help=('The IP address of the MLX switch')), 54 help=('The IP address of the MLX switch')),
@@ -58,6 +62,10 @@ L3_BROCADE = [cfg.StrOpt('address', default='',
58 cfg.StrOpt('ports', default='', 62 cfg.StrOpt('ports', default='',
59 help=('Ports to be tagged in the VLAN being ' 63 help=('Ports to be tagged in the VLAN being '
60 'configured on the switch')), 64 'configured on the switch')),
65 cfg.StrOpt('enable_username', default='admin',
66 help=('Username of the enable config prompt')),
67 cfg.StrOpt('enable_password', default='password', secret=True,
68 help=('Password of the enable config prompt')),
61 ] 69 ]
62cfg.CONF.register_opts(SWITCHES, 'ml2_brocade_fi_ni') 70cfg.CONF.register_opts(SWITCHES, 'ml2_brocade_fi_ni')
63cfg.CONF.register_opts(SWITCHES, 'l3_brocade_mlx') 71cfg.CONF.register_opts(SWITCHES, 'l3_brocade_mlx')
diff --git a/networking_brocade/mlx/ml2/ssh_connector.py b/networking_brocade/mlx/ml2/ssh_connector.py
index 8d1ed1d..03d83e2 100644
--- a/networking_brocade/mlx/ml2/ssh_connector.py
+++ b/networking_brocade/mlx/ml2/ssh_connector.py
@@ -15,19 +15,29 @@
15 15
16""" Implementation of SSH Connector""" 16""" Implementation of SSH Connector"""
17 17
18import networking_brocade.mlx.ml2.commands as Commands 18from networking_brocade.mlx.ml2 import device_connector as dev_conn
19from networking_brocade.mlx.ml2.device_connector import (
20 DeviceConnector as DevConn)
21from neutron.i18n import _LE 19from neutron.i18n import _LE
22from oslo_log import log as logging 20from oslo_log import log as logging
21
23import paramiko 22import paramiko
23import time
24 24
25LOG = logging.getLogger(__name__) 25LOG = logging.getLogger(__name__)
26WRITE = "wb" 26PROMPT = '>'
27READ = "rb" 27ENABLE_PROMPT = '#'
28ENABLE_USERNAME_PROMPT = 'User Name:'
29ENABLE_PASSWORD_PROMPT = 'Password:'
30CONFIG_MODE = '(config)#'
31
32CONFIG_COMMAND = "conf t\n"
33ENABLE_COMMAND = "en\n"
34NEW_LINE = "\n"
35
36TIMEOUT = 30.0
37SLEEP_TIME = 1
28 38
29 39
30class SSHConnector(DevConn): 40class SSHConnector(dev_conn.DeviceConnector):
31 41
32 """ 42 """
33 Uses SSH to connect to device 43 Uses SSH to connect to device
@@ -46,10 +56,10 @@ class SSHConnector(DevConn):
46 username=self.username, 56 username=self.username,
47 password=self.password) 57 password=self.password)
48 58
49 channel = self.connector.invoke_shell() 59 self.channel = self.connector.invoke_shell()
50 self.stdin_stream = channel.makefile(WRITE) 60 self.channel.settimeout(TIMEOUT)
51 self.stdout_stream = channel.makefile(READ) 61 self.channel_data = str()
52 self.stderr_stream = channel.makefile(READ) 62 self._enter_prompt(False)
53 63
54 except Exception as e: 64 except Exception as e:
55 LOG.exception(_LE("Connect failed to switch %(host)s with error" 65 LOG.exception(_LE("Connect failed to switch %(host)s with error"
@@ -57,45 +67,75 @@ class SSHConnector(DevConn):
57 {'host': self.host, 'error': e.args}) 67 {'host': self.host, 'error': e.args})
58 raise Exception(_("Connection Failed")) 68 raise Exception(_("Connection Failed"))
59 69
70 def _send_command(self, prompt, command):
71 """
72 Executes the command passed, if the response matches the prompt
73 """
74 execution_state = False
75 if self.channel_data.endswith(prompt):
76 self.channel.send(command)
77 execution_state = True
78 return execution_state
79
80 def _enter_prompt(self, is_config_mode):
81 """
82 Enters enable prompt mode or config mode based on the parameter
83
84 param:is_config_mode: if this is True, will enter config mode, else
85 it will make sure it is in enable prompt.
86 """
87 commands = []
88 prompt_command = {}
89 if is_config_mode:
90 prompts = [ENABLE_PROMPT, CONFIG_MODE]
91 prompt_command = {ENABLE_PROMPT: CONFIG_COMMAND,
92 CONFIG_MODE: NEW_LINE}
93 else:
94 prompts = [PROMPT, ENABLE_USERNAME_PROMPT,
95 ENABLE_PASSWORD_PROMPT, ENABLE_PROMPT]
96 prompt_command = {PROMPT: ENABLE_COMMAND,
97 ENABLE_USERNAME_PROMPT: self.enable_username +
98 NEW_LINE,
99 ENABLE_PASSWORD_PROMPT: self.enable_password +
100 NEW_LINE,
101 ENABLE_PROMPT: NEW_LINE}
102 cmd_executed = True
103 # Send new line so that channel will have something to read for the
104 # first time.
105 self.channel.send(NEW_LINE)
106 index = 0
107 while index < len(commands):
108 prompt = prompts[index]
109 if cmd_executed:
110 self.channel_data += self.channel.recv(9999)
111 command = prompt_command.get(prompt)
112 cmd_executed = self._send_command(prompt, command)
113 index += 1
114 time.sleep(SLEEP_TIME)
115
116 def enter_configuration_mode(self):
117 """
118 This method will ensure the session is in configuration mode
119 """
120 self._enter_prompt(True)
121
60 def write(self, command): 122 def write(self, command):
61 """ 123 """
62 Write from input stream to device 124 Write from input stream to device
63 125
64 :param:command: Command to be executed on the device 126 :param:command: Command to be executed on the device
65 """ 127 """
66 self.stdin_stream.write(command) 128 self.channel.send(command)
67 self.stdin_stream.flush() 129 time.sleep(SLEEP_TIME)
130 self.channel_data += self.channel.recv(9999)
68 131
69 def read_response(self, read_lines=True): 132 def read_response(self, read_lines=True):
70 """Read the response from the output stream. 133 """Read the response from the output stream.
71
72 :param:read_lines: Boolean value which indicated to read multiple line
73 or single line. It is true by default.
74 :returns: Response from the device as list when read_lines is True or
75 string when read_lines is false.
76 """ 134 """
77 response = None 135 return self.channel_data
78 if read_lines:
79 response = self.stdout_stream.readlines()
80 else:
81 response = self.stdout_stream.read()
82 return response
83
84 def send_exit(self, count):
85 """Send Exit command.
86
87 :param:count: Indicates number of times to execute exit command
88 """
89 index = 0
90 while index < count:
91 self.stdin_stream.write(Commands.EXIT)
92 self.stdin_stream.flush()
93 index += 1
94 136
95 def close_session(self): 137 def close_session(self):
96 """Close SSH session.""" 138 """Close SSH session."""
97 if self.connector: 139 if self.connector:
98 self.stdin_stream.close() 140 self.channel.close()
99 self.stdout_stream.close()
100 self.stderr_stream.close()
101 self.connector.close() 141 self.connector.close()
diff --git a/networking_brocade/mlx/ml2/telnet_connector.py b/networking_brocade/mlx/ml2/telnet_connector.py
index 730687d..4f61bc5 100644
--- a/networking_brocade/mlx/ml2/telnet_connector.py
+++ b/networking_brocade/mlx/ml2/telnet_connector.py
@@ -16,9 +16,9 @@
16""" Implementation of Telnet Connector """ 16""" Implementation of Telnet Connector """
17 17
18import telnetlib 18import telnetlib
19import time
19 20
20from networking_brocade.mlx.ml2.device_connector import ( 21from networking_brocade.mlx.ml2 import device_connector as dev_conn
21 DeviceConnector as DevConn)
22from neutron.i18n import _LE 22from neutron.i18n import _LE
23from oslo_log import log as logging 23from oslo_log import log as logging
24 24
@@ -32,15 +32,23 @@ SUPER_USER_AUTH = '^Password\\:$'
32TERMINAL_LENGTH = "terminal length 0" 32TERMINAL_LENGTH = "terminal length 0"
33 33
34END_OF_LINE = "\r" 34END_OF_LINE = "\r"
35TELNET_TERMINAL = ">" 35PROMPT = ">"
36ENABLE_PROMPT = '#'
36CONFIGURE_TERMINAL = "#" 37CONFIGURE_TERMINAL = "#"
38ENABLE_USERNAME_PROMPT = 'User Name:'
39ENABLE_PASSWORD_PROMPT = 'Password:'
40CONFIG_MODE = "(config)#"
41
42RETURN_COMMAND = "\r"
43ENABLE_COMMAND = "en\r"
44CONFIG_COMMAND = "conf t\r"
37 45
38MIN_TIMEOUT = 2 46MIN_TIMEOUT = 2
39AVG_TIMEOUT = 4 47AVG_TIMEOUT = 4
40MAX_TIMEOUT = 8 48MAX_TIMEOUT = 8
41 49
42 50
43class TelnetConnector(DevConn): 51class TelnetConnector(dev_conn.DeviceConnector):
44 52
45 """ 53 """
46 Uses Telnet to connect to device 54 Uses Telnet to connect to device
@@ -56,13 +64,66 @@ class TelnetConnector(DevConn):
56 self.connector.write(self.username + END_OF_LINE) 64 self.connector.write(self.username + END_OF_LINE)
57 self.connector.read_until(LOGIN_PASS_TOKEN, AVG_TIMEOUT) 65 self.connector.read_until(LOGIN_PASS_TOKEN, AVG_TIMEOUT)
58 self.connector.write(self.password + END_OF_LINE) 66 self.connector.write(self.password + END_OF_LINE)
59 self.connector.read_until(TELNET_TERMINAL, MAX_TIMEOUT) 67 self.response = str()
68 self._enter_prompt(False)
60 except Exception as e: 69 except Exception as e:
61 LOG.exception(_LE("Connect failed to switch %(host)s with error" 70 LOG.exception(_LE("Connect failed to switch %(host)s with error"
62 " %(error)s"), 71 " %(error)s"),
63 {'host': self.host, 'error': e.args}) 72 {'host': self.host, 'error': e.args})
64 raise Exception(_("Connection Failed")) 73 raise Exception(_("Connection Failed"))
65 74
75 def _send_command(self, prompt, command):
76 """
77 Executes the command passed, if the response matches the prompt
78 """
79 execution_state = False
80 if self.response.endswith(prompt):
81 self.connector.write(command)
82 execution_state = True
83 return execution_state
84
85 def _enter_prompt(self, is_config_mode):
86 """
87 Enters enable prompt mode or config mode based on the parameter
88
89 param:is_config_mode: if this is True, will enter config mode, else
90 it will make sure it is in enable prompt.
91 """
92 commands = []
93 prompt_command = {}
94 if is_config_mode:
95 prompts = [ENABLE_PROMPT, CONFIG_MODE]
96 prompt_command = {ENABLE_PROMPT: CONFIG_COMMAND,
97 CONFIG_MODE: RETURN_COMMAND}
98 else:
99 prompts = [PROMPT, ENABLE_USERNAME_PROMPT,
100 ENABLE_PASSWORD_PROMPT, ENABLE_PROMPT]
101 prompt_command = {PROMPT: ENABLE_COMMAND,
102 ENABLE_USERNAME_PROMPT: self.enable_username +
103 RETURN_COMMAND,
104 ENABLE_PASSWORD_PROMPT: self.enable_password +
105 RETURN_COMMAND,
106 ENABLE_PROMPT: RETURN_COMMAND}
107 cmd_executed = True
108 # Send new line so that channel will have something to read for the
109 # first time.
110 self.connector.write(RETURN_COMMAND)
111 index = 0
112 while index < len(commands):
113 prompt = prompts[index]
114 if cmd_executed:
115 self.response += self.connector.read_until(prompt, AVG_TIMEOUT)
116 command = prompt_command.get(prompt)
117 cmd_executed = self._send_command(prompt, command)
118 index += 1
119 time.sleep(MIN_TIMEOUT)
120
121 def enter_configuration_mode(self):
122 """
123 This method will ensure the session is in configuration mode
124 """
125 self._enter_prompt(True)
126
66 def write(self, command): 127 def write(self, command):
67 """ 128 """
68 Write from input stream to device 129 Write from input stream to device
@@ -70,21 +131,17 @@ class TelnetConnector(DevConn):
70 :param:command: Command to be executed on the device 131 :param:command: Command to be executed on the device
71 """ 132 """
72 self.connector.write(command) 133 self.connector.write(command)
134 self.response += self.connector.read_until(PROMPT, MAX_TIMEOUT)
73 135
74 def read_response(self, read_lines=True): 136 def read_response(self):
75 """Read the response from the output stream. 137 """Read the response from the output stream.
76 138
77 :param:read_lines: This is used only by the SSH connector. 139 :returns: Response from the device as string.
78 :returns: Response from the device as list.
79 """ 140 """
80 return self.connector.read_until(CONFIGURE_TERMINAL, MIN_TIMEOUT) 141 return self.response
81 142
82 def close_session(self): 143 def close_session(self):
83 """Close TELNET session.""" 144 """Close TELNET session."""
84 if self.connector: 145 if self.connector:
85 self.connector.close() 146 self.connector.close()
86 self.connector = None 147 self.connector = None
87
88 def send_exit(self, count):
89 """No operation. Used by SSH connector only."""
90 pass
diff --git a/networking_brocade/test_discover/test_discover.py b/networking_brocade/test_discover/test_discover.py
index fa4a9d9..9da6ff6 100644
--- a/networking_brocade/test_discover/test_discover.py
+++ b/networking_brocade/test_discover/test_discover.py
@@ -28,10 +28,9 @@ def load_tests(loader, tests, pattern):
28 base_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0] 28 base_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0]
29 base_path = os.path.split(base_path)[0] 29 base_path = os.path.split(base_path)[0]
30 test_dirs = {'./networking_brocade/tests', 30 test_dirs = {'./networking_brocade/tests',
31# './networking_brocade/vdx/tests/unit/ml2/drivers/brocade', 31 './networking_brocade/vdx/tests/unit/ml2/drivers/brocade',
32 MLX_TEST_BASE_PATH + '/unit/ml2/drivers/brocade', 32 MLX_TEST_BASE_PATH + '/unit/ml2/drivers/brocade',
33 MLX_TEST_BASE_PATH + '/unit/services/l3_router/brocade', 33 MLX_TEST_BASE_PATH + '/unit/services/l3_router/brocade'}
34 }
35 for test_dir in test_dirs: 34 for test_dir in test_dirs:
36 if not pattern: 35 if not pattern:
37 suite.addTests(loader.discover(test_dir, top_level_dir=base_path)) 36 suite.addTests(loader.discover(test_dir, top_level_dir=base_path))