diff options
author | Pradeep Sathasivam <psathasi@brocade.com> | 2015-08-07 14:49:48 +0530 |
---|---|---|
committer | Angela Smith <aallen@brocade.com> | 2016-03-17 15:52:05 -0700 |
commit | e2c8ecd218280c1cd7869fa8040ad02bf0f6b02b (patch) | |
tree | 2f712242b406abfc4c6261ffd1234db0db7d59cb | |
parent | 9d3c974cbb6ba66ffaf383aa047544201a3c1789 (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.ini | 4 | ||||
-rw-r--r-- | etc/neutron/plugins/ml2/ml2_conf_brocade_fi_ni.ini | 6 | ||||
-rw-r--r-- | networking_brocade/mlx/ml2/device_connector.py | 60 | ||||
-rw-r--r-- | networking_brocade/mlx/ml2/fi_ni/brcd_config.py | 8 | ||||
-rw-r--r-- | networking_brocade/mlx/ml2/ssh_connector.py | 114 | ||||
-rw-r--r-- | networking_brocade/mlx/ml2/telnet_connector.py | 83 | ||||
-rw-r--r-- | networking_brocade/test_discover/test_discover.py | 5 |
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 | """ |
21 | import networking_brocade.mlx.ml2.commands as Commands | 21 | from networking_brocade.mlx.ml2 import commands |
22 | from oslo_log import log as logging | 22 | from oslo_log import log as logging |
23 | 23 | ||
24 | LOG = logging.getLogger(__name__) | 24 | LOG = 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 | ] |
49 | L3_BROCADE = [cfg.StrOpt('address', default='', | 53 | L3_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 | ] |
62 | cfg.CONF.register_opts(SWITCHES, 'ml2_brocade_fi_ni') | 70 | cfg.CONF.register_opts(SWITCHES, 'ml2_brocade_fi_ni') |
63 | cfg.CONF.register_opts(SWITCHES, 'l3_brocade_mlx') | 71 | cfg.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 | ||
18 | import networking_brocade.mlx.ml2.commands as Commands | 18 | from networking_brocade.mlx.ml2 import device_connector as dev_conn |
19 | from networking_brocade.mlx.ml2.device_connector import ( | ||
20 | DeviceConnector as DevConn) | ||
21 | from neutron.i18n import _LE | 19 | from neutron.i18n import _LE |
22 | from oslo_log import log as logging | 20 | from oslo_log import log as logging |
21 | |||
23 | import paramiko | 22 | import paramiko |
23 | import time | ||
24 | 24 | ||
25 | LOG = logging.getLogger(__name__) | 25 | LOG = logging.getLogger(__name__) |
26 | WRITE = "wb" | 26 | PROMPT = '>' |
27 | READ = "rb" | 27 | ENABLE_PROMPT = '#' |
28 | ENABLE_USERNAME_PROMPT = 'User Name:' | ||
29 | ENABLE_PASSWORD_PROMPT = 'Password:' | ||
30 | CONFIG_MODE = '(config)#' | ||
31 | |||
32 | CONFIG_COMMAND = "conf t\n" | ||
33 | ENABLE_COMMAND = "en\n" | ||
34 | NEW_LINE = "\n" | ||
35 | |||
36 | TIMEOUT = 30.0 | ||
37 | SLEEP_TIME = 1 | ||
28 | 38 | ||
29 | 39 | ||
30 | class SSHConnector(DevConn): | 40 | class 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 | ||
18 | import telnetlib | 18 | import telnetlib |
19 | import time | ||
19 | 20 | ||
20 | from networking_brocade.mlx.ml2.device_connector import ( | 21 | from networking_brocade.mlx.ml2 import device_connector as dev_conn |
21 | DeviceConnector as DevConn) | ||
22 | from neutron.i18n import _LE | 22 | from neutron.i18n import _LE |
23 | from oslo_log import log as logging | 23 | from oslo_log import log as logging |
24 | 24 | ||
@@ -32,15 +32,23 @@ SUPER_USER_AUTH = '^Password\\:$' | |||
32 | TERMINAL_LENGTH = "terminal length 0" | 32 | TERMINAL_LENGTH = "terminal length 0" |
33 | 33 | ||
34 | END_OF_LINE = "\r" | 34 | END_OF_LINE = "\r" |
35 | TELNET_TERMINAL = ">" | 35 | PROMPT = ">" |
36 | ENABLE_PROMPT = '#' | ||
36 | CONFIGURE_TERMINAL = "#" | 37 | CONFIGURE_TERMINAL = "#" |
38 | ENABLE_USERNAME_PROMPT = 'User Name:' | ||
39 | ENABLE_PASSWORD_PROMPT = 'Password:' | ||
40 | CONFIG_MODE = "(config)#" | ||
41 | |||
42 | RETURN_COMMAND = "\r" | ||
43 | ENABLE_COMMAND = "en\r" | ||
44 | CONFIG_COMMAND = "conf t\r" | ||
37 | 45 | ||
38 | MIN_TIMEOUT = 2 | 46 | MIN_TIMEOUT = 2 |
39 | AVG_TIMEOUT = 4 | 47 | AVG_TIMEOUT = 4 |
40 | MAX_TIMEOUT = 8 | 48 | MAX_TIMEOUT = 8 |
41 | 49 | ||
42 | 50 | ||
43 | class TelnetConnector(DevConn): | 51 | class 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)) |