Skip to content

Commit

Permalink
Merge pull request #58 from nokia/newlinesend_options
Browse files Browse the repository at this point in the history
Newlinesend options
  • Loading branch information
Ernold11 authored Oct 12, 2018
2 parents 8bf4b0f + 9490ba2 commit 4b62048
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 22 deletions.
3 changes: 2 additions & 1 deletion moler/cmd/unix/exit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@


class Exit(GenericUnixCommand):
def __init__(self, connection, prompt=None, expected_prompt='>', new_line_chars=None, runner=None):
def __init__(self, connection, prompt=None, expected_prompt='>', new_line_chars=None, runner=None, target_newline="\n"):
"""
:param connection:
:param prompt: Prompt of the starting shell
Expand All @@ -22,6 +22,7 @@ def __init__(self, connection, prompt=None, expected_prompt='>', new_line_chars=
"""
super(Exit, self).__init__(connection=connection, prompt=prompt, new_line_chars=new_line_chars, runner=runner)
self.ret_required = False
self.target_newline = target_newline

# Parameters defined by calling the command
self._re_expected_prompt = CommandTextualGeneric._calculate_prompt(expected_prompt) # Expected prompt on device
Expand Down
29 changes: 25 additions & 4 deletions moler/cmd/unix/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,26 @@ class Ssh(GenericUnixCommand):

def __init__(self, connection, login, password, host, prompt=None, expected_prompt='>', port=0,
known_hosts_on_failure='keygen', set_timeout=r'export TMOUT=\"2678400\"', set_prompt=None,
term_mono="TERM=xterm-mono", new_line_chars=None, encrypt_password=True, runner=None):

term_mono="TERM=xterm-mono", new_line_chars=None, encrypt_password=True, runner=None,
target_newline="\n"):

"""
:param connection: moler connection to device, terminal when command is executed
:param login: ssh login
:param password: ssh password
:param host: host to ssh
:param prompt: start prompt (on system where command ssh starts)
:param expected_prompt: final prompt (on system where command ssh connects)
:param port: port to ssh connect
:param known_hosts_on_failure: "rm" or "keygen" how to deal with error. If empty then ssh fails.
:param set_timeout: Command to set timeout after ssh connects
:param set_prompt: Command to set prompt after ssh connects
:param term_mono: Params to set ssh mono connection (useful in script)
:param new_line_chars: Characters to split lines
:param encrypt_password: If True then * will be in logs when password is sent, otherwise plain text
:param runner: Runner to run command
:param target_newline: newline chars on remote system where ssh connects
"""
super(Ssh, self).__init__(connection=connection, prompt=prompt, new_line_chars=new_line_chars, runner=runner)

# Parameters defined by calling the command
Expand All @@ -41,6 +59,7 @@ def __init__(self, connection, login, password, host, prompt=None, expected_prom
self.set_prompt = set_prompt
self.term_mono = term_mono
self.encrypt_password = encrypt_password
self.target_newline = target_newline

self.ret_required = False

Expand Down Expand Up @@ -141,14 +160,16 @@ def timeout_set_needed(self):
return self.set_timeout and not self._sent_timeout

def send_timeout_set(self):
self.connection.sendline("\n" + self.set_timeout)
cmd = "{}{}{}".format(self.target_newline, self.set_timeout, self.target_newline)
self.connection.send(cmd)
self._sent_timeout = True

def prompt_set_needed(self):
return self.set_prompt and not self._sent_prompt

def send_prompt_set(self):
self.connection.sendline("\n" + self.set_prompt)
cmd = "{}{}{}".format(self.target_newline, self.set_prompt, self.target_newline)
self.connection.send(cmd)
self._sent_prompt = True

def is_failure_indication(self, line):
Expand Down
11 changes: 6 additions & 5 deletions moler/cmd/unix/telnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Telnet(GenericUnixCommand):
def __init__(self, connection, host, login=None, password=None, port=0, prompt=None, expected_prompt=r'^>\s*',
set_timeout=r'export TMOUT=\"2678400\"', set_prompt=None, term_mono="TERM=xterm-mono", prefix=None,
new_line_chars=None, cmds_before_establish_connection=[], cmds_after_establish_connection=[],
telnet_prompt=r"^\s*telnet>\s*", encrypt_password=True, runner=None):
telnet_prompt=r"^\s*telnet>\s*", encrypt_password=True, runner=None, target_newline="\n"):
super(Telnet, self).__init__(connection=connection, prompt=prompt, new_line_chars=new_line_chars, runner=runner)

# Parameters defined by calling the command
Expand All @@ -46,6 +46,7 @@ def __init__(self, connection, host, login=None, password=None, port=0, prompt=N
self.encrypt_password = encrypt_password
self.cmds_before_establish_connection = copy.deepcopy(cmds_before_establish_connection)
self.cmds_after_establish_connection = copy.deepcopy(cmds_after_establish_connection)
self.target_newline = target_newline

# Internal variables
self._sent_timeout = False
Expand Down Expand Up @@ -99,7 +100,7 @@ def _settings_after_login(self, line, is_full_line):

def _just_connected(self, line):
if self._regex_helper.search_compiled(Telnet._re_has_just_connected, line):
self.connection.sendline("")
self.connection.send(self.target_newline)
raise ParsingDone()

def _send_telnet_commands(self, line, is_full_line, commands):
Expand All @@ -118,7 +119,7 @@ def _send_commands_before_establish_connection_if_requested(self, line, is_full_
def _send_commands_after_establish_connection_if_requested(self, line, is_full_line):
if self._telnet_command_mode:
if self._send_telnet_commands(line, is_full_line, self.cmds_after_establish_connection):
self.connection.sendline("")
self.connection.send(self.target_newline)
self._telnet_command_mode = False
raise ParsingDone()

Expand All @@ -129,14 +130,14 @@ def _change_telnet_to_setting_commands(self):

def _send_login_if_requested(self, line):
if (not self._sent_login) and self._is_login_requested(line) and self.login:
self.connection.sendline(self.login)
self.connection.send("{}{}".format(self.login, self.target_newline))
self._sent_login = True
self._sent_password = False
raise ParsingDone()

def _send_password_if_requested(self, line):
if (not self._sent_password) and self._is_password_requested(line) and self.password:
self.connection.sendline(self.password, encrypt=self.encrypt_password)
self.connection.send("{}{}".format(self.password, self.target_newline), encrypt=self.encrypt_password)
self._sent_login = False
self._sent_password = True
raise ParsingDone()
Expand Down
17 changes: 16 additions & 1 deletion moler/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Connection(object):
"""Connection API required by ConnectionObservers."""

def __init__(self, how2send=None, encoder=identity_transformation, decoder=identity_transformation,
name=None, newline='\n', logger_name=""):
name=None, newline='\r\n', logger_name=""):
"""
Create Connection via registering external-IO
Expand Down Expand Up @@ -146,6 +146,21 @@ def send(self, data, timeout=30, encrypt=False):
encoded_data = self.encode(data)
self.how2send(encoded_data)

def change_newline_seq(self, newline_seq="\n"):
"""
Method to change newline char(s). Useful when connect from one point to another if newline chars change (i.e. "\n", "\r\n")
:param newline_seq: Sequence of chars to send as new line char(s)
:return: Nothing
"""

characters = [ord(char) for char in self.newline]
newline_old = "0x" + ''.join("'{:02X}'".format(a) for a in characters)
characters = [ord(char) for char in newline_seq]
newline_new = "0x" + ''.join("'{:02X}'".format(a) for a in characters)
# 11 15:30:32.855 DEBUG moler.connection.UnixRemote1 |changing newline seq old '0x'0D''0A'' -> new '0x'0A''
self._log(logging.DEBUG, "changing newline seq old '{}' -> new '{}'".format(newline_old, newline_new))
self.newline = newline_seq

def sendline(self, data, timeout=30, encrypt=False):
"""Outgoing-IO API: Send data line over external-IO."""
line = data + self.newline
Expand Down
32 changes: 22 additions & 10 deletions moler/device/textualdevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(self, name=None, io_connection=None, io_type=None, variant=None, sm
:param variant: connection implementation variant, ex. 'threaded', 'twisted', 'asyncio', ...
(if not given then default one is taken)
"""
sm_params = sm_params.copy()
self.states = []
self.goto_states_triggers = []
self._name = name
Expand All @@ -61,7 +62,7 @@ def __init__(self, name=None, io_connection=None, io_type=None, variant=None, sm
self._state_prompts = {}
self._prompts_events = {}
self._configurations = dict()

self._newline_chars = dict() # key is state, value is chars to send as newline
if io_connection:
self.io_connection = io_connection
else:
Expand All @@ -75,6 +76,7 @@ def __init__(self, name=None, io_connection=None, io_type=None, variant=None, sm
self._prepare_transitions()
self._prepare_state_hops()
self._configure_state_machine(sm_params)
self._prepare_newline_chars()

self.io_connection.notify(callback=self.on_connection_made, when="connection_made")
# TODO: Need test to ensure above sentence for all connection
Expand Down Expand Up @@ -117,6 +119,10 @@ def _prepare_transitions(self):
def _prepare_state_prompts(self):
pass

@abc.abstractmethod
def _prepare_newline_chars(self):
pass

@abc.abstractmethod
def _prepare_state_hops(self):
pass
Expand Down Expand Up @@ -230,10 +236,6 @@ def _trigger_change_state(self, next_state, timeout, rerun, send_enter_after_cha
while (retrying <= rerun) and (not entered_state):
try:
change_state_method(self.current_state, next_state, timeout=timeout)

if send_enter_after_changed_state:
self._send_enter_after_changed_state()

entered_state = True
except Exception as ex:
if retrying == rerun:
Expand All @@ -245,10 +247,11 @@ def _trigger_change_state(self, next_state, timeout, rerun, send_enter_after_cha
retrying += 1
self._log(logging.DEBUG, "Cannot change state into '{}'. "
"Retrying '{}' of '{}' times.".format(next_state, retrying, rerun))

if send_enter_after_changed_state:
self._send_enter_after_changed_state()

self.io_connection.moler_connection.change_newline_seq(self._get_newline(state=next_state))
if send_enter_after_changed_state:
self._send_enter_after_changed_state()
self._log(logging.DEBUG, "Successfully enter state '{}'".format(next_state))
else:
exc = DeviceFailure(
Expand Down Expand Up @@ -368,15 +371,17 @@ def validate_device_state_before_observer_start(*args, **kargs):
observer._validate_start = validate_device_state_before_observer_start
return observer

def get_cmd(self, cmd_name, cmd_params={}, check_state=True):
def get_cmd(self, cmd_name, cmd_params=dict(), check_state=True):
cmd_params = cmd_params.copy()
if "prompt" not in cmd_params:
cmd_params["prompt"] = self.get_prompt()
cmd = self.get_observer(observer_name=cmd_name, observer_type=TextualDevice.cmds,
observer_exception=CommandWrongState, check_state=check_state, **cmd_params)
assert isinstance(cmd, CommandTextualGeneric)
return cmd

def get_event(self, event_name, event_params={}, check_state=True):
def get_event(self, event_name, event_params=dict(), check_state=True):
event_params = event_params.copy()
event = self.get_observer(observer_name=event_name, observer_type=TextualDevice.events,
observer_exception=EventWrongState, check_state=check_state, **event_params)

Expand Down Expand Up @@ -539,7 +544,14 @@ def _send_enter_after_changed_state(self, *args, **kwargs):

try:
cmd_enter = Enter(connection=self.io_connection.moler_connection)
result = cmd_enter()
cmd_enter()
except Exception as ex:
self._log(logging.DEBUG, "Cannot execute command 'enter' properly: {}".format(ex))
pass

def _get_newline(self, state=None):
if not state:
state = self.current_state
if state and state in self._newline_chars:
return self._newline_chars[state]
return "\r\n"
1 change: 1 addition & 0 deletions moler/device/unixlocal.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class UnixLocal(TextualDevice):
unix_local = "UNIX_LOCAL"

def __init__(self, name=None, io_connection=None, io_type=None, variant=None, sm_params=dict()):
sm_params = sm_params.copy()
super(UnixLocal, self).__init__(name=name, io_connection=io_connection, io_type=io_type, variant=variant,
sm_params=sm_params)

Expand Down
17 changes: 16 additions & 1 deletion moler/device/unixremote.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def __init__(self, name=None, io_connection=None, io_type=None, variant=None, sm
:param io_type: External-IO connection connection type
:param variant: External-IO connection variant
"""
sm_params = sm_params.copy()
super(UnixRemote, self).__init__(name=name, io_connection=io_connection, io_type=io_type, variant=variant,
sm_params=sm_params)

Expand All @@ -34,6 +35,7 @@ def _get_default_sm_configuration(self):
UnixRemote.unix_remote: { # to
"execute_command": "ssh", # using command
"command_params": { # with parameters
"target_newline": "\r\n"
},
"required_command_params": [
"host",
Expand All @@ -47,7 +49,8 @@ def _get_default_sm_configuration(self):
UnixRemote.unix_local: { # to
"execute_command": "exit", # using command
"command_params": { # with parameters
"expected_prompt": r'^moler_bash#'
"expected_prompt": r'^moler_bash#',
"target_newline": "\r\n"
},
"required_command_params": [
]
Expand Down Expand Up @@ -91,6 +94,18 @@ def _prepare_state_prompts(self):
self._state_prompts.update(state_prompts)
super(UnixRemote, self)._prepare_state_prompts()

def _prepare_newline_chars(self):
newline_chars = {
UnixRemote.unix_remote:
self._configurations[UnixRemote.connection_hops][UnixRemote.unix_local][UnixRemote.unix_remote][
"command_params"]["target_newline"],
UnixRemote.unix_local:
self._configurations[UnixRemote.connection_hops][UnixRemote.unix_remote][UnixRemote.unix_local][
"command_params"]["target_newline"],
}
self._newline_chars.update(newline_chars)
super(UnixRemote, self)._prepare_newline_chars()

def _prepare_state_hops(self):
state_hops = {
UnixLocal.not_connected: {
Expand Down

0 comments on commit 4b62048

Please sign in to comment.