Skip to content

Commit

Permalink
Refactor ssh module
Browse files Browse the repository at this point in the history
This refactor completely removes paramiko as a ssh backend.
All ssh interactions are now routed through broker Host objects or
children of said objects.
This refactor also reinforces and establishes new patterns for ssh
interaction with a remote host.
Finally, cleaned up tests that are no longer needed and changed behavior
where necessary.
  • Loading branch information
JacobCallahan authored and mshriver committed Sep 24, 2021
1 parent 2d99b1d commit e6b65fb
Show file tree
Hide file tree
Showing 91 changed files with 920 additions and 2,231 deletions.
3 changes: 1 addition & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ automated, suited for use in a continuous integration environment, and `data
driven`_. There are three types of tests:

* UI tests, which rely on Selenium's `WebDriver`_ through `airgun`_.
* CLI tests, which currently rely on `Paramiko`_ , but are being converted to use `ssh2-python`_.
* CLI tests, which rely on `ssh2-python`_.
* API tests, which rely on `Requests`_ through `nailgun`_.

The `full documentation
Expand All @@ -37,7 +37,6 @@ ReadTheDocs. It can also be generated locally::
make docs

.. _data driven: http://en.wikipedia.org/wiki/Data-driven_testing
.. _Paramiko: http://www.paramiko.org/
.. _ssh2-python: https://pypi.org/project/ssh2-python/
.. _Requests: http://docs.python-requests.org/en/latest/
.. _Robottelo: https://github.com/SatelliteQE/robottelo
Expand Down
2 changes: 1 addition & 1 deletion docs/features/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Assuming you have ipython installed you will see a console like:
In [1]: rt.ssh.command('uname -r')
2016-09-16 13:54:57 - robottelo.ssh - DEBUG - Connected to [foreman-server.com]
Out[1]: SSHCommandResult(stdout=['3.10.0-327.el7.x86_64', ''], stderr='', return_code=0, output_format=None)
Out[1]: result(stdout=['3.10.0-327.el7.x86_64', ''], stderr=(0, ''), status=0)
In [2]: exit
This is the Robottelo's interactive shell welcome screen and you can see some
Expand Down
28 changes: 0 additions & 28 deletions docs/features/decorators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,6 @@ Robottelo decorators are located under
control if a test must be skipped or executed accordingly with specific
configurations.

skip_if_os
----------

``skip_if_os`` skips test based on Foreman/Satellite host os version. It
communicates with host defined on ``robottello.properties`` to get its os
version. Currently it checks only Red Hat Enterprise Linux versions. Example::

from robottelo.decorators.host import skip_if_os

@skip_if_os('RHEL6')
def test_positive_create_custom_ostree_repo(self):
"""Create Custom ostree repository"""

@skip_if_os('RHEL6', 'RHEL5')
def test_negative_create_custom_ostree_repo(self):
"""Create Custom ostree repository"""

The first test will be skipped if host os is RHEL6.x.y, where x and y can be
any number. If ``RHEL6.1`` was used as parameter it would skip for any
RHEL6.1.z version and so on.

Arbitrary number versions can be passed as parameters. On second test both RHEL
5 and 6 families would be skipped.

This decorator is used to avoid false failures when an feature is supported
only on one os version. For example, ostree repository is available
in RHEL7 but not in RHEL6.


cacheable
---------
Expand Down
44 changes: 3 additions & 41 deletions docs/features/ssh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,6 @@ Robottelo uses ssh extensively to access remote servers.
Functions from ``robottello.ssh`` make ssh access easier and are
explained on next sections.

SSHCommandResult
----------------

``SSHCommandResult`` represents the result of a ssh command.
It holds ``stdout`` on attribute with same name.
``stderr`` and ``return_code`` are available the same way.
An example of typical result is presented bellow::

SSHCommandResult(
stdout=['Red Hat Enterprise Linux Server release 7.2 (Maipo)', ''],
stderr='',
return_code=0,
output_format=None
)

Attribute ``output_format`` can be ``None``, ``csv`` or
``json``.
The former two options are heavily used to define output format on Hammer CLI.

Main Functions
--------------

Expand All @@ -41,32 +22,15 @@ Its full signature is::
password=None, key_filename=None, timeout=10):
"""Executes SSH command(s) on remote hostname."""

Most of parameters can be read from ``robottelo.properties`` file.
Most of parameters can be read from ``conf/server.yaml`` file.
So in a properly configured project commands can be easily executed on host.
The function returns a ``SSHCommandResult`` instance.
The function returns a result object containing the attributes: stdout, stderr, and status.
The following code was executed to generate the example of first section of
this document::

>>> from robottelo import ssh
>>> print(ssh.command('cat /etc/redhat-release'))
SSHCommandResult(
stdout=['Red Hat Enterprise Linux Server release 7.2 (Maipo)', ''],
stderr='',
return_code=0,
output_format=None
)

Another important function is ``execute_command``.
It is similar to ``command``.
But it reuses an existing connection.
So several commands can be executed on a single connection, saving resources
and execution time::

with ssh.get_connection(..) as connection:
ssh.execute_command('cp /orign /destiny', connection)
ssh.execute_command('chmod 0777 /destiny', connection)
ssh.execute_command("echo 'foo' > /destiny/bar")

Red Hat Enterprise Linux Server release 7.2 (Maipo)

Helper Functions
----------------
Expand All @@ -75,6 +39,4 @@ The module provide some helper functions which use ``command`` internally
for common ssh operations:

- **add_authorized_key**: Add public key to remote authorized keys;
- **upload_file**: Upload file to remote host;
- **download_file**: Download file from remote host;
- **is_ssh_pub_key**: Validate public key.
14 changes: 5 additions & 9 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ automated, suited for use in a continuous integration environment, and `data
driven`_. There are three types of tests:

* UI tests, which rely on Selenium's `WebDriver`_.
* CLI tests, which rely on `Paramiko`_.
* CLI tests, which rely on `ssh2-python`_.
* API tests, which rely on `Requests`_.

.. contents::
Expand All @@ -17,13 +17,12 @@ Quickstart
The following is only a brief setup guide for `Robottelo`_. The section on
`Running the Tests`_ provides a more comprehensive guide to using Robottelo.

Robottelo requires SSH access to the Satellite 6 system under test, and this
SSH access is implemented by Paramiko. Install the headers for the following to
ensure that Paramiko's dependencies build correctly:
Robottelo requires SSH access to the Satellite system under test, and this
SSH access is implemented by ssh2-python. Install the headers for the following to
ensure that ssh2-python's dependencies build correctly:

* OpenSSL
* Python development headers
* libffi


Recommendation: Create a virtual python environment for the following setup.
Expand All @@ -41,9 +40,6 @@ For python3.x::
dnf install -y gcc git libffi-devel openssl-devel python38-devel \
redhat-rpm-config libcurl-devel libxml2-devel

For more information, see `Paramiko: Installing
<http://www.paramiko.org/installing.html>`_.

Get the source code and install dependencies::

$ git clone git://github.com/SatelliteQE/robottelo.git
Expand Down Expand Up @@ -289,7 +285,7 @@ The design and development for this software is led by `Og Maciel`_.
.. _graphviz: http://graphviz.org/
.. _nose: https://nose.readthedocs.org/en/latest/index.html
.. _Og Maciel: http://www.ogmaciel.com
.. _Paramiko: http://www.paramiko.org/
.. _ssh2-python: https://pypi.org/project/ssh2-python/
.. _Pytest: https://docs.pytest.org/en/latest/contents.html
.. _Requests: http://docs.python-requests.org/en/latest/
.. _Robottelo: https://github.com/SatelliteQE/robottelo
Expand Down
2 changes: 1 addition & 1 deletion pytest_fixtures/oscap_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def tailoring_file_path():
def oscap_content_path(default_sat):
"""Download scap content from satellite and return local path of it."""
local_file = robottelo_tmp_dir.joinpath(PurePath(settings.oscap.content_path).name)
default_sat.download(remote_path=settings.oscap.content_path, local_path=local_file)
default_sat.put(remote_path=settings.oscap.content_path, local_path=local_file)
return local_file


Expand Down
5 changes: 2 additions & 3 deletions pytest_fixtures/satellite_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,10 +335,9 @@ def enroll_ad_and_configure_external_auth(request, ad_data):

# update the AD name server
run_command(cmd='chattr -i /etc/resolv.conf')
result = run_command(
line_number = run_command(
cmd="awk -v search='nameserver' '$0~search{print NR; exit}' /etc/resolv.conf"
)
line_number = int(''.join(result))
run_command(cmd=f'sed -i "{line_number}i nameserver {ad_data.nameserver}" /etc/resolv.conf')
run_command(cmd='chattr +i /etc/resolv.conf')

Expand All @@ -350,7 +349,7 @@ def enroll_ad_and_configure_external_auth(request, ad_data):

# gather the apache id
result = run_command(cmd='id -u apache')
id_apache = "".join(result)
id_apache = result
http_conf_content = (
f'[service/HTTP]\nmechs = krb5\ncred_store = keytab:/etc/krb5.keytab'
f'\ncred_store = ccache:/var/lib/gssproxy/clients/krb5cc_%U'
Expand Down
9 changes: 4 additions & 5 deletions pytest_fixtures/templatesync_fixtures.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import pytest
from fauxfactory import gen_string

from robottelo import ssh
from robottelo.constants import FOREMAN_TEMPLATE_ROOT_DIR


@pytest.fixture()
def create_import_export_local_dir():
def create_import_export_local_dir(default_sat):
"""Creates a local directory inside root_dir on satellite from where the templates will
be imported from or exported to.
Expand All @@ -18,13 +17,13 @@ def create_import_export_local_dir():
root_dir = FOREMAN_TEMPLATE_ROOT_DIR
dir_path = f'{root_dir}/{dir_name}'
# Creating the directory and set the write context
ssh.command(
default_sat.execute(
f'mkdir -p {dir_path} && '
f'chown foreman -R {root_dir} && '
f'restorecon -R -v {root_dir} && '
f'chcon -t httpd_sys_rw_content_t {dir_path} -R'
)
# Copying the file to new directory to be modified by tests
ssh.command(f'cp example_template.erb {dir_path}')
default_sat.execute(f'cp example_template.erb {dir_path}')
yield dir_name, dir_path
ssh.command(f'rm -rf {dir_path}')
default_sat.execute(f'rm -rf {dir_path}')
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ fauxfactory==3.1.0
Inflector==3.0.1
jinja2==3.0.1
navmazing==1.1.6
paramiko==2.7.2
pexpect==4.8.0
productmd==1.32
pyotp==2.6.0
Expand Down
2 changes: 1 addition & 1 deletion robottelo/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ def wait_for_syncplan_tasks(repo_backend_id=None, timeout=10, repo_name=None):
# Fetch the Pulp password
pulp_pass = ssh.command(
'grep "^default_password" /etc/pulp/server.conf | awk \'{print $2}\''
).stdout[0]
).stdout.splitlinies()[0]
# Set the Timeout value
timeup = time.time() + int(timeout) * 60
# Search Filter to filter out the task based on backend-id and sync action
Expand Down
Loading

0 comments on commit e6b65fb

Please sign in to comment.