Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
4d22796
add "Action" and "ActionMap" classes
Jun 24, 2019
ff5ec07
update ActionMap usage in the "hardware_expect" method
Jun 25, 2019
4871fee
replace Action map OrderedDict with ActionMap class
Jun 26, 2019
85b9efa
fix error map initialization
Jul 2, 2019
4324f8f
replace "super(Class, self)" calls with "super()" call
Jul 2, 2019
695612b
use f-Strings instead of str.format
Jul 2, 2019
7fd66e9
add unit tests for the "action_map" module
Jul 2, 2019
0deac1b
update ActionMap.__add__ method logic
Jul 2, 2019
97984d0
add "Error" and "ErrorMap" classes
Jul 8, 2019
29a231e
small fixes for the action_map module
Jul 8, 2019
58c2dca
update ErrorMap usage in the "hardware_expect" method
Jul 8, 2019
3f170f0
fix unittest and bugs for the "error_map" module
Jul 8, 2019
6b63e34
add unit tests for the "error_map" module
Jul 8, 2019
0b35ece
use compiled re pattern in the "error_map" and "action_map" modules
Jul 8, 2019
49b4641
move "__call__" function to "process" in ActionMap and ErrorMap classes
Jul 12, 2019
4cdf9f7
simplify ActionMap and ErrorMap "__add__" methods
Jul 12, 2019
502c994
pass "output" argument to the ErrorMap "__call__" method
Jul 12, 2019
eceb263
fix unit test for the ErrorMap class
Jul 12, 2019
dab9bb2
update docstrings and error messages
Jul 3, 2019
af60403
rename ExcpectSession to AbstractSession
Jul 11, 2019
cd4b5d2
move "hardware_expect" to separate class
Aug 1, 2019
0073e4b
Create py2-py3-packages-ci.yml
saklar13 Dec 10, 2020
a54a493
Delete .travis.yml
saklar13 Dec 10, 2020
5df9fbe
Update README.md
saklar13 Dec 10, 2020
98909bf
update pre-commit, build the package quiet
saklar13 Dec 10, 2020
ae7a8de
set cryptography < 3.3
saklar13 Dec 10, 2020
dda48fa
update version
saklar13 Dec 10, 2020
839dc44
Update requirements.txt
saklar13 Dec 10, 2020
66e03f4
Merge branch 'master' into dev
saklar13 Dec 10, 2020
c6b8a0d
fix getting the target branch
saklar13 Jan 5, 2021
1d25646
Add basic implementation
yaroslavNqualisystems Jul 19, 2021
4003911
Add phassphrase, fix unittests
yaroslavNqualisystems Jul 19, 2021
9a38ff3
Version 4.1.0
yaroslavNqualisystems Jul 19, 2021
684f281
take^Cndefined session list from session dict
yaroslavNqualisystems Nov 15, 2020
8645b2e
Create list from list of lists
yaroslavNqualisystems Nov 15, 2020
7a00648
fix getting the target branch
saklar13 Jan 5, 2021
e2e7a59
Add basic implementation
yaroslavNqualisystems Jul 19, 2021
13b8c5d
Add phassphrase, fix unittests
yaroslavNqualisystems Jul 19, 2021
e13db0f
Version 4.1.0
yaroslavNqualisystems Jul 19, 2021
48f88dc
Version 5.0.0
yaroslavNqualisystems Aug 12, 2021
12463ae
Merge branch 'master' of github.com:QualiSystems/cloudshell-cli into dev
yaroslavNqualisystems Aug 12, 2021
89accbe
Added cli_service_helper, implemented send command with retries
yaroslavNqualisystems May 29, 2020
948b8d4
Fixed default values. Fixed added return
yaroslavNqualisystems Jun 15, 2020
fed7cfd
add "Action" and "ActionMap" classes
Jun 24, 2019
3312f85
update ActionMap usage in the "hardware_expect" method
Jun 25, 2019
e23bb20
replace Action map OrderedDict with ActionMap class
Jun 26, 2019
89c403a
fix error map initialization
Jul 2, 2019
025c3eb
replace "super(Class, self)" calls with "super()" call
Jul 2, 2019
ce10499
use f-Strings instead of str.format
Jul 2, 2019
75b31e1
add unit tests for the "action_map" module
Jul 2, 2019
5337d03
update ActionMap.__add__ method logic
Jul 2, 2019
452c7d6
add "Error" and "ErrorMap" classes
Jul 8, 2019
5b10935
small fixes for the action_map module
Jul 8, 2019
29b98ba
update ErrorMap usage in the "hardware_expect" method
Jul 8, 2019
fff5750
fix unittest and bugs for the "error_map" module
Jul 8, 2019
2830219
add unit tests for the "error_map" module
Jul 8, 2019
e2bb755
use compiled re pattern in the "error_map" and "action_map" modules
Jul 8, 2019
2070463
move "__call__" function to "process" in ActionMap and ErrorMap classes
Jul 12, 2019
a6bc634
simplify ActionMap and ErrorMap "__add__" methods
Jul 12, 2019
671dd4c
pass "output" argument to the ErrorMap "__call__" method
Jul 12, 2019
7fb1d8f
fix unit test for the ErrorMap class
Jul 12, 2019
e320607
Merge rework_hardware_expect
yaroslavNqualisystems Aug 17, 2021
e1ced21
Merge pull request #128 from QualiSystems/feature/apiddubny_refactori…
yaroslavNqualisystems Aug 17, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/py2-py3-packages-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,14 @@ jobs:
run: |
python_version="${{ matrix.python-version }}"
py_version="${python_version/./}"
branch=(`[[ 'refs/head/master' == ${{ github.ref }} ]] && echo 'master' || echo 'dev'`)
target_branch=${{ github.base_ref || github.ref }}
target_branch=(`[[ ${target_branch::10} == 'refs/heads' ]] && echo ${target_branch:11} || echo $target_branch`)
echo "target_branch =" $target_branch
is_master=(`[[ $target_branch == 'master' ]] && echo 'true' || echo 'false'`)
is_tag=${{ startsWith(github.ref, 'refs/tags') }}
echo "is_master =" $is_master
echo "is_tag =" $is_tag
branch=(`[[ $is_master == 'true' || $is_tag == 'true' ]] && echo 'master' || echo 'dev'`)
TOXENV="py$py_version-$branch"
echo $TOXENV
echo "TOXENV=$TOXENV" >> $GITHUB_ENV
Expand Down
37 changes: 21 additions & 16 deletions cloudshell/cli/command_template/command_template.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import re
from collections import OrderedDict
import re

from cloudshell.cli.service.action_map import ActionMap
from cloudshell.cli.service.error_map import ErrorMap


class CommandTemplate:
Expand All @@ -8,40 +11,42 @@ def __init__(self, command, action_map=None, error_map=None):

:type command: str
:type action_map: dict
:param error_map: expected error map with subclass of CommandExecutionException
or str
:type error_map: dict[str, cloudshell.cli.session.session_exceptions.CommandExecutionException|str] # noqa: E501
:param error_map: expected error map with subclass of CommandExecutionException or str
:type error_map: dict[str, cloudshell.cli.session.session_exceptions.CommandExecutionException|str]
"""
self._command = command
self._action_map = action_map or OrderedDict()
self._error_map = error_map or OrderedDict()
self._action_map = action_map or ActionMap()
self._error_map = error_map or ErrorMap()

@property
def action_map(self):
"""Property for action map.

:rtype: OrderedDict()
:rtype: cloudshell.cli.service.action_map.ActionMap
"""
return self._action_map

@property
def error_map(self):
"""Property for error map.

:rtype: OrderedDict
:rtype: cloudshell.cli.service.error_map.ErrorMap
"""
return self._error_map

# ToDo: Needs to be reviewed
def get_command(self, **kwargs):
action_map = OrderedDict(kwargs.get("action_map", None) or OrderedDict())
action_map.update(self._action_map)
error_map = OrderedDict(self._error_map)
error_map.update(kwargs.get("error_map", None) or OrderedDict())
# todo: verify action map creation
action_map = kwargs.get('action_map') or ActionMap()
action_map.extend(self.action_map)

error_map = kwargs.get("error_map") or ErrorMap()
error_map.extend(self.error_map)

return {
"command": self.prepare_command(**kwargs),
"action_map": action_map,
"error_map": error_map,
'command': self.prepare_command(**kwargs),
'action_map': action_map,
'error_map': error_map
}

def prepare_command(self, **kwargs):
Expand All @@ -52,7 +57,7 @@ def prepare_command(self, **kwargs):
cmd = re.sub(r"\[[^[]*?{{{key}}}.*?\]".format(key=key), r"", cmd)

if not cmd:
raise Exception(self.__class__.__name__, "Unable to prepare command")
raise Exception("Unable to prepare command")

cmd = re.sub(r"\s+", " ", cmd).strip(" \t\n\r")
result = re.sub(r"\[|\]", "", cmd).format(**kwargs)
Expand Down
58 changes: 17 additions & 41 deletions cloudshell/cli/command_template/command_template_executor.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections import OrderedDict
from cloudshell.cli.service.action_map import ActionMap
from cloudshell.cli.service.error_map import ErrorMap


class CommandTemplateExecutor(object):
Expand All @@ -14,57 +15,32 @@ def __init__(
):
"""Initialize Command template executor.

:param cli_service:
:type cli_service: CliService
:param command_template:
:type command_template: cloudshell.cli.command_template.command_template.CommandTemplate # noqa: E501
:param error_map: expected error map with subclass of CommandExecutionException
or str
:type error_map: dict[str, cloudshell.cli.session.session_exceptions.CommandExecutionException|str] # noqa: E501
:param cloudshell.cli.service.cli_service.CliService cli_service:
:param cloudshell.cli.command_template.command_template.CommandTemplate command_template:
:param cloudshell.cli.service.action_map.ActionMap action_map:
:param cloudshell.cli.service.error_map.ErrorMap error_map:
:return:
"""
self._cli_service = cli_service
self._command_template = command_template
self._action_map = action_map or OrderedDict()
self._error_map = error_map or OrderedDict()
self._optional_kwargs = optional_kwargs

@property
def action_map(self):
"""Return updated action."""
action_map = self._action_map.copy()
action_map.update(self._command_template.action_map)
return action_map
self._action_map = action_map or ActionMap()
self._action_map.extend(command_template.action_map)

@property
def error_map(self):
error_map = self._error_map.copy()
error_map.update(self._command_template.error_map)
return error_map
self._error_map = error_map or ErrorMap()
self._error_map.extend(command_template.error_map)

@property
def optional_kwargs(self):
return self._optional_kwargs
self._optional_kwargs = optional_kwargs

def execute_command(self, **command_kwargs):
"""Execute command.

:param command_kwargs:
:param dict command_kwargs:
:return: Command output
:rtype: str
"""
command = self._command_template.prepare_command(**command_kwargs)
return self._cli_service.send_command(
command,
action_map=self.action_map,
error_map=self.error_map,
**self.optional_kwargs
)

def update_action_map(self, action_map):
self._action_map.update(action_map)

def update_error_map(self, error_map):
self._error_map.update(error_map)

def update_optional_kwargs(self, **optional_kwargs):
self.optional_kwargs.update(optional_kwargs)
return self._cli_service.send_command(command,
action_map=self._action_map,
error_map=self._error_map,
**self._optional_kwargs)
75 changes: 32 additions & 43 deletions cloudshell/cli/configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
# -*- coding: utf-8 -*-
import sys
from abc import ABCMeta, abstractmethod
from collections import defaultdict

from cloudshell.cli.factory.session_factory import (
CloudInfoAccessKeySessionFactory,
GenericSessionFactory,
SessionFactory,
)
from cloudshell.cli.service.cli import CLI
from cloudshell.cli.session.ssh_session import SSHSession
from cloudshell.cli.session.telnet_session import TelnetSession
Expand All @@ -16,39 +22,30 @@


class CLIServiceConfigurator(object):
REGISTERED_SESSIONS = (SSHSession, TelnetSession)

def __init__(self, resource_config, logger, cli=None, registered_sessions=None):
REGISTERED_SESSIONS = (CloudInfoAccessKeySessionFactory(SSHSession), TelnetSession)
"""Using factories instead of """

def __init__(
self,
resource_config,
logger,
cli=None,
registered_sessions=None,
reservation_context=None,
):
"""Initialize CLI service configurator.

:param cloudshell.shell.standards.resource_config_generic_models.GenericCLIConfig resource_config: # noqa: E501
:param logging.Logger logger:
:param cloudshell.cli.service.cli.CLI cli:
:param registered_sessions: Session types and order
:param cloudshell.shell.core.driver_context.ReservationContextDetails reservation_context:
"""
self._cli = cli or CLI()
self._resource_config = resource_config
self._logger = logger
self._registered_sessions = registered_sessions or self.REGISTERED_SESSIONS

@property
def _username(self):
return self._resource_config.user

@property
@lru_cache()
def _password(self):
return self._resource_config.password

@property
def _resource_address(self):
"""Resource IP."""
return self._resource_config.address

@property
def _port(self):
"""Connection port property, to open socket on."""
return self._resource_config.cli_tcp_port
self._reservation_context = reservation_context

@property
def _cli_type(self):
Expand All @@ -58,31 +55,23 @@ def _cli_type(self):
@property
@lru_cache()
def _session_dict(self):
return {sess.SESSION_TYPE.lower(): [sess] for sess in self._registered_sessions}

def _on_session_start(self, session, logger):
"""Perform some default commands when session just opened.

Like 'no logging console'
"""
pass

@property
@lru_cache()
def _session_kwargs(self):
return {
"host": self._resource_address,
"username": self._username,
"password": self._password,
"port": self._port,
"on_session_start": self._on_session_start,
}
session_dict = defaultdict(list)
for sess in self._registered_sessions:
session_dict[sess.SESSION_TYPE.lower()].append(sess)
return session_dict

def initialize_session(self, session):
if not isinstance(session, SessionFactory):
session = GenericSessionFactory(session)
return session.init_session(
self._resource_config, self._logger, self._reservation_context
)

def _defined_sessions(self):
return [
sess(**self._session_kwargs)
self.initialize_session(sess)
for sess in self._session_dict.get(
self._cli_type.lower(), self._registered_sessions
self._cli_type.lower(), sum(self._session_dict.values(), [])
)
]

Expand Down
Empty file.
69 changes: 69 additions & 0 deletions cloudshell/cli/factory/session_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod

ABC = ABCMeta("ABC", (object,), {"__slots__": ()})


class SessionFactory(ABC):
"""Session factory.

Help to initialize session for specified session class.
"""

def __init__(self, session_class: type):
""":param session_class: Session class."""
self.session_class = session_class

@abstractmethod
def init_session(self, resource_config, logger, reservation_context=None):
"""Initialize session instance.

Encapsulate the logic of the session instance creation.
:param resource_config:
:param logging.Logger logger:
:param ReservationContextDetails reservation_context:
"""
raise NotImplementedError


class GenericSessionFactory(SessionFactory):
def init_session(self, resource_config, logger, reservation_context=None):
return self.session_class(
**self._session_kwargs(resource_config, logger, reservation_context)
)

@property
def SESSION_TYPE(self):
return self.session_class.SESSION_TYPE

def _on_session_start(self, session, logger):
"""Perform some default commands when session just opened.

Like 'no logging console'
"""
pass

def _session_kwargs(self, resource_config, logger, reservation_context=None):
return {
"host": resource_config.address,
"username": resource_config.user,
"password": resource_config.password,
"port": resource_config.cli_tcp_port,
"on_session_start": self._on_session_start,
}


class CloudInfoAccessKeySessionFactory(GenericSessionFactory):
def _session_kwargs(self, resource_config, logger, reservation_context=None):
access_key = ""
if reservation_context and reservation_context.cloud_info_access_key:
access_key = reservation_context.cloud_info_access_key
return {
"host": resource_config.address,
"username": resource_config.user,
"password": resource_config.password,
"port": resource_config.cli_tcp_port,
"pkey": access_key,
"on_session_start": self._on_session_start,
}
Loading