Skip to content

Commit 6185ca5

Browse files
author
Yaroslav Nikonorov
authored
Merge pull request #64 from QualiSystems/dev
Release 3.1.1
2 parents 9c7f981 + e5a6661 commit 6185ca5

34 files changed

Lines changed: 439 additions & 317 deletions

.coveragerc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[report]
2+
omit =
3+
*__init__*
4+
*/examples/*

.travis.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
language: python
22
python:
3-
- '2.7'
4-
5-
before_install:
6-
- pip install coveralls
7-
- pip install -r test_requirements.txt --extra-index-url https://testpypi.python.org/pypi
3+
- "2.7"
84

95
install:
10-
- pip install -r requirements.txt --extra-index-url https://testpypi.python.org/pypi
11-
- python setup.py install
6+
- 'if [ ${TRAVIS_BRANCH} \!= "master" ] && [ -f dev_requirements.txt ]; then
7+
pip install --extra-index-url https://testpypi.python.org/pypi -r dev_requirements.txt;
8+
python setup.py develop --no-deps;
9+
else
10+
python setup.py install;
11+
fi'
12+
- pip install -r test_requirements.txt
13+
- pip install coveralls
1214

1315
script:
14-
- python runtests.py --with-coverage --cover-package=cloudshell
15-
- python setup.py develop
16-
- python setup.py sdist --format zip
16+
- nosetests --with-coverage --cover-package=cloudshell.cli tests
1717

1818
after_success:
19-
- coveralls
19+
- coveralls

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# cloudshell-cli
2-
![alt tag](https://travis-ci.org/QualiSystems/cloudshell-cli.svg?branch=7.0_refactoring)
2+
[![Build status](https://travis-ci.org/QualiSystems/cloudshell-cli.svg?branch=dev)](https://travis-ci.org/QualiSystems/cloudshell-cli)
33
[![Coverage Status](https://coveralls.io/repos/github/QualiSystems/cloudshell-cli/badge.svg?branch=dev)](https://coveralls.io/github/QualiSystems/cloudshell-cli?branch=dev)
44
[![PyPI version](https://badge.fury.io/py/cloudshell-cli.svg)](https://badge.fury.io/py/cloudshell-cli)
55
[![Dependency Status](https://dependencyci.com/github/QualiSystems/cloudshell-cli/badge)](https://dependencyci.com/github/QualiSystems/cloudshell-cli)

cloudshell/cli/command_mode_helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def determine_current_mode(session, command_mode, logger):
2222
defined_modes = CommandModeHelper.defined_modes_by_prompt(command_mode)
2323
prompts_re = r'|'.join(defined_modes.keys())
2424
try:
25-
result = session.hardware_expect('', expected_string=prompts_re, logger=logger)
25+
result = session.probe_for_prompt(expected_string=prompts_re, logger=logger)
2626
except Exception as e:
2727
logger.debug(e.message)
2828
raise CommandModeException(CommandModeHelper.__class__.__name__,

cloudshell/cli/session/connection_params.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ def __init__(self, host, port=None, on_session_start=None, pkey=None):
2525
self.on_session_start = on_session_start
2626
self.pkey = pkey
2727

28+
def _on_session_start(self, logger):
29+
if self.on_session_start and callable(self.on_session_start):
30+
self.on_session_start(self, logger)
31+
2832
def __eq__(self, other):
2933
"""
3034
:param other:

cloudshell/cli/session/console_session.py

Lines changed: 0 additions & 119 deletions
This file was deleted.

cloudshell/cli/session/expect_session.py

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import socket
1+
import re
22
import time
3+
from abc import ABCMeta, abstractmethod
34
from collections import OrderedDict
45

5-
from abc import ABCMeta
6+
from cloudshell.cli.helper.normalize_buffer import normalize_buffer
7+
from cloudshell.cli.session.session import Session
68
from cloudshell.cli.session.session_exceptions import SessionLoopDetectorException, SessionLoopLimitException, \
79
ExpectedSessionException, CommandExecutionException, SessionReadTimeout, SessionReadEmptyData
8-
import re
9-
from cloudshell.cli.session.session import Session
10-
from cloudshell.cli.helper.normalize_buffer import normalize_buffer
1110

1211

1312
class ExpectSession(Session):
@@ -60,6 +59,26 @@ def __init__(self, timeout=READ_TIMEOUT, new_line='\r', max_loop_retries=MAX_LOO
6059
def session_type(self):
6160
return self.SESSION_TYPE
6261

62+
@abstractmethod
63+
def _connect_actions(self, prompt, logger):
64+
"""Read out buffer and run on_session_start actions
65+
:param prompt: expected string in output
66+
:param logger: logger
67+
"""
68+
69+
pass
70+
71+
@abstractmethod
72+
def _initialize_session(self, prompt, logger):
73+
"""Create handler and initialize session
74+
:param prompt: expected string in output
75+
:param logger: logger
76+
"""
77+
pass
78+
79+
def set_active(self, state):
80+
self._active = state
81+
6382
def active(self):
6483
return self._active
6584

@@ -82,6 +101,20 @@ def _clear_buffer(self, timeout, logger):
82101
break
83102
return out
84103

104+
def connect(self, prompt, logger):
105+
"""Connect to device.
106+
:param prompt: expected string in output
107+
:param logger: logger
108+
"""
109+
110+
try:
111+
self._initialize_session(prompt, logger)
112+
self._connect_actions(prompt, logger)
113+
self.set_active(True)
114+
except:
115+
self.disconnect()
116+
raise
117+
85118
def send_line(self, command, logger):
86119
"""
87120
Add new line to the end of command string and send
@@ -112,6 +145,9 @@ def _receive_all(self, timeout, logger):
112145
elif time.time() - start_time > timeout:
113146
raise ExpectedSessionException(self.__class__.__name__, 'Socket closed by timeout')
114147

148+
def probe_for_prompt(self, expected_string, logger):
149+
return self.hardware_expect('', expected_string, logger)
150+
115151
def hardware_expect(self, command, expected_string, logger, action_map=None, error_map=None,
116152
timeout=None, retries=None, check_action_loop_detector=True, empty_loop_timeout=None,
117153
remove_command_from_output=True, **optional_args):
@@ -170,7 +206,7 @@ def hardware_expect(self, command, expected_string, logger, action_map=None, err
170206

171207
if read_buffer:
172208
read_buffer = normalize_buffer(read_buffer)
173-
logger.info(read_buffer)
209+
logger.debug(read_buffer)
174210
output_str += read_buffer
175211
# if option remove_command_from_output is set to True, look for command in output buffer,
176212
# remove it in case of found
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import re
2+
import socket
3+
4+
from cloudshell.cli.session.tcp_session import TCPSession
5+
6+
7+
class SCPISession(TCPSession):
8+
SESSION_TYPE = 'SCPI'
9+
BUFFER_SIZE = 1024
10+
11+
def __init__(self, host, port, on_session_start=None, *args, **kwargs):
12+
super(SCPISession, self).__init__(host, port, on_session_start, *args, **kwargs)
13+
14+
def _initialize_session(self, prompt, logger):
15+
self._handler = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
16+
17+
server_address = (self.host, self.port)
18+
self._handler.connect(server_address)
19+
self._handler.settimeout(self._timeout)
20+
21+
def _connect_actions(self, prompt, logger):
22+
self._on_session_start(logger)
23+
24+
def probe_for_prompt(self, expected_string, logger):
25+
return 'DUMMY_PROMPT'
26+
27+
def hardware_expect(self, command, expected_string, logger, action_map=None, error_map=None, timeout=None,
28+
retries=None, check_action_loop_detector=True, empty_loop_timeout=None,
29+
remove_command_from_output=True, **optional_args):
30+
31+
if ';:system:error?' not in command.lower():
32+
command += ';:system:error?'
33+
34+
statusre = r'([-0-9]+), "(.*)"[\r\n]*$'
35+
36+
remove_command_from_output = False # avoid 'multiple repeat' error from '?' in the command - bug in expect_session
37+
38+
rv = super(SCPISession, self).hardware_expect(command, statusre, logger, action_map, error_map, timeout,
39+
retries, check_action_loop_detector, empty_loop_timeout,
40+
remove_command_from_output, **optional_args)
41+
42+
m = re.search(statusre, rv)
43+
if not m:
44+
raise Exception('SCPI status code not found in output: %s' % rv)
45+
46+
code, message = m.groups()
47+
if code < 0:
48+
raise Exception('SCPI error: %d: %s' % (code, message))
49+
50+
return rv

cloudshell/cli/session/session.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from collections import OrderedDict
2-
31
from abc import ABCMeta, abstractmethod
2+
from collections import OrderedDict
43

54

65
class Session(object):
@@ -32,10 +31,18 @@ def hardware_expect(self, command, expected_string, logger, action_map=OrderedDi
3231
**optional_args):
3332
pass
3433

34+
@abstractmethod
35+
def probe_for_prompt(self, expected_string, logger):
36+
pass
37+
3538
@abstractmethod
3639
def reconnect(self, prompt, logger, timeout=None):
3740
pass
3841

3942
@abstractmethod
4043
def active(self):
4144
pass
45+
46+
@abstractmethod
47+
def set_active(self, state):
48+
pass

cloudshell/cli/session/ssh_session.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,13 @@ def __eq__(self, other):
5151
def __del__(self):
5252
self.disconnect()
5353

54-
def connect(self, prompt, logger):
55-
"""Connect to device through ssh
56-
:param prompt: expected string in output
57-
:param logger: logger
58-
"""
59-
60-
if not self._handler:
61-
self._handler = paramiko.SSHClient()
62-
self._handler.load_system_host_keys()
63-
self._handler.set_missing_host_key_policy(paramiko.AutoAddPolicy())
54+
def _create_handler(self):
55+
self._handler = paramiko.SSHClient()
56+
self._handler.load_system_host_keys()
57+
self._handler.set_missing_host_key_policy(paramiko.AutoAddPolicy())
6458

59+
def _initialize_session(self, prompt, logger):
60+
self._create_handler()
6561
try:
6662
self._handler.connect(self.host, self.port, self.username, self.password, timeout=self._timeout,
6763
banner_timeout=30, allow_agent=False, look_for_keys=False, pkey=self.pkey)
@@ -73,10 +69,9 @@ def connect(self, prompt, logger):
7369
self._current_channel = self._handler.invoke_shell()
7470
self._current_channel.settimeout(self._timeout)
7571

72+
def _connect_actions(self, prompt, logger):
7673
self.hardware_expect(None, expected_string=prompt, timeout=self._timeout, logger=logger)
77-
if self.on_session_start and callable(self.on_session_start):
78-
self.on_session_start(self, logger)
79-
self._active = True
74+
self._on_session_start(logger)
8075

8176
def disconnect(self):
8277
"""Disconnect from device

0 commit comments

Comments
 (0)