-
Notifications
You must be signed in to change notification settings - Fork 0
/
hp.py
executable file
·167 lines (147 loc) · 6.21 KB
/
hp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/python
#
# Copyright 2014 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""An HP ProCurve switch device .
This module implements the base device interface of base_device.py for
Hewlett-Packard ProCurve Ethernet switches.
"""
__author__ = '[email protected] (Andreux Fort)'
import os
import re
import pexpect
import gflags
import logging
import base_device
import pexpect_connection
import push_exceptions as exceptions
FLAGS = gflags.FLAGS
gflags.DEFINE_float('hp_timeout_response', None,
'HP device response timeout in seconds.')
gflags.DEFINE_float('hp_timeout_connect', 22.0,
'HP device connect timeout in seconds.')
gflags.DEFINE_float('hp_timeout_idle', None,
'HP device idle timeout in seconds.')
gflags.DEFINE_float('hp_timeout_disconnect', None,
'HP device disconnect timeout in seconds.')
gflags.DEFINE_float('hp_timeout_act_user', None,
'HP device user activation timeout in seconds.')
class HpDevice(base_device.BaseDevice):
"""A base device model for Hewlett-Packard ProCurve switches."""
RE_INVALID = re.compile(r'^(Invalid|Ambiguous) input:', re.I | re.M)
RE_PAGER = re.compile(r'-- MORE --, next page: Space, next line: Enter, '
'quit: Control-C')
def __init__(self, **kwargs):
self.vendor_name = 'hp'
super(HpDevice, self).__init__(**kwargs)
# The response regexp indicating connection success.
self._success = r'ProCurve .*[Ss]witch'
def _Connect(self, username, password=None, ssh_keys=None,
enable_password=None, ssl_cert_set=None):
# Quieten pylint.
_ = ssl_cert_set
self._connection = pexpect_connection.HpSshFilterConnection(
self.loopback_ipv4, username, password, success=self._success,
timeout=self.timeout_connect, find_prompt=True, ssh_keys=ssh_keys,
enable_password=enable_password)
try:
self._connection.Connect()
self._DisablePager()
except pexpect_connection.ConnectionError, e:
self.connected = False
raise exceptions.ConnectError(e)
except pexpect_connection.TimeoutError, e:
self.connected = False
raise exceptions.ConnectError('Timed out connecting to %s(%s) after '
'%s seconds.' %
(self.host, self.loopback_ipv4, str(e)))
def _Cmd(self, command, mode=None, called_already=False):
_ = mode
# Strip question marks and short-circuit if we have nothing more.
command = command.replace('?', '')
if not command:
return ''
try:
self._connection.child.send(command+'\r')
self._connection.child.expect(command+'\n')
result = ''
while True:
i = self._connection.child.expect([self._connection.re_prompt,
self.RE_PAGER],
timeout=self.timeout_response,
searchwindowsize=128)
# HP prefers \n\r to \r\n.
result += self._connection.child.before.replace('\n\r', os.linesep)
if i == 1:
self._connection.child.send(' ')
else:
break
# Check if the device told us our command was not recognized.
if self.RE_INVALID.search(result) is not None:
raise exceptions.CmdError('Command %r invalid on %s(%s)' %
(command, self.host, self.loopback_ipv4))
return result
except pexpect.TIMEOUT, e:
self.connected = False
raise exceptions.CmdError('%s: %s' % (e.__class__, str(e)))
except pexpect.EOF, e:
if not called_already:
return self._Cmd(command, mode=mode, called_already=True)
else:
self.connected = False
raise exceptions.CmdError('%s: %s' % (e.__class__, str(e)))
def _DisablePager(self):
"""Enables and logs in so the pager can be disabled."""
# Maximum terminal size on sw version M.08.74 (8095) is 1920x1000.
try:
self._connection.child.send('terminal length 1000\r')
self._connection.child.expect(self._connection.re_prompt,
timeout=self.timeout_act_user,
searchwindowsize=128)
self._connection.child.send('terminal width 1920\r')
self._connection.child.expect(self._connection.re_prompt,
timeout=self.timeout_act_user,
searchwindowsize=128)
except (pexpect.EOF, pexpect.TIMEOUT), e:
self.connected = False
raise exceptions.CmdError('%s: %s' % (e.__class__, str(e)))
def _Disconnect(self):
"""Disconnects from the device."""
if hasattr(self, '_connection'):
try:
try:
self._connection.child.send('exit\r')
while True:
i = self._connection.child.expect([r'\S(?:#|>) ',
r'Do you want to log out',
r'Do you want to save'],
timeout=self.timeout_act_user)
if i == 0:
self._connection.child.send('exit\r')
continue
elif i == 1:
self._connection.child.send('y')
return
elif i == 2:
self._connection.child.send('n')
logging.warn('Uncomitted config on %s(%s). Not saving.',
self.host, self.loopback_ipv4)
return
except pexpect.TIMEOUT, e:
raise exceptions.DisconnectError('%s: %s' % (e.__class__, str(e)))
except pexpect.EOF, e:
# An EOF now means nothing more than a disconnect.
pass
finally:
self.connected = False