pulp_smash.cli

Location: Pulp SmashAPI Documentationpulp_smash.cli

A client for working with Pulp systems via their CLI.

class pulp_smash.cli.BaseServiceManager

A base service manager.

Each subclass must implement the abstract methods to provide the service management on a single or multiple systems.

Subclasses should take advantage of the helper methods offered by this class in order to manage services and check the proper service manager softeare available on a system.

This base class also offers a context manager to temporary disable SELinux. It is useful when managing services on RHEL systems earlier than 7 which has SELinux issues when running on Jenkins.

Make sure to call this class __init__ method on the subclass __init__ method to ensure the helper methods functionality.

restart(services)

Restart the given services.

Parameters:services – A list or tuple of services to be restarted.
start(services)

Start the given services.

Parameters:services – A list or tuple of services to be started.
stop(services)

Stop the given services.

Parameters:services – A list or tuple of services to be stopped.
class pulp_smash.cli.Client(server_config, response_handler=None, pulp_system=None)

A convenience object for working with a CLI.

This class provides the ability to execute shell commands on either the local system or a remote system. Here is a pedagogic usage example:

>>> from pulp_smash import cli, config
>>> system = (
...     config.PulpSystem('localhost', {'shell': {'transport': 'local'}})
... )
>>> cfg = config.PulpSmashConfig(systems=[system])
>>> client = cli.Client(cfg, pulp_system=system)
>>> response = client.run(('echo', '-n', 'foo'))
>>> response.returncode == 0
True
>>> response.stdout == 'foo'
True
>>> response.stderr == ''
True

The above example shows how various classes fit together. It’s also verbose: smartly chosen defaults mean that most real code is much more concise.

You can customize how Client objects execute commands and handle responses by fiddling with the two public instance attributes:

machine
A Plumbum machine. run() delegates all command execution responsibilities to this object.
response_handler
A callback function. Each time machine executes a command, the result is handed to this callback, and the callback’s return value is handed to the user.

If pulp_system.roles['shell']['transport'] is 'local' or 'ssh, machine will be set so that commands run locally or over SSH, respectively. If pulp_system.roles['shell']['transport'] is None, the constructor will guess how to set machine by comparing the hostname embedded in pulp_system.hostname against the current system’s hostname. If they match, machine is set to execute commands locally; and vice versa.

Parameters:
run(args, **kwargs)

Run a command and return self.response_handler(result).

This method is a thin wrapper around Plumbum’s BaseCommand.run method, which is itself a thin wrapper around the standard library’s subprocess.Popen class. See their documentation for detailed usage instructions. See pulp_smash.cli.Client for a usage example.

class pulp_smash.cli.CompletedProcess(args, returncode, stdout, stderr)

A process that has finished running.

This class is similar to the subprocess.CompletedProcess class available in Python 3.5 and above. Significant differences include the following:

  • All constructor arguments are required.
  • check_returncode() returns a custom exception, not subprocess.CalledProcessError.

All constructor arguments are stored as instance attributes.

Parameters:
  • args – A string or a sequence. The arguments passed to pulp_smash.cli.Client.run().
  • returncode – The integer exit code of the executed process. Negative for signals.
  • stdout – The standard output of the executed process.
  • stderr – The standard error of the executed process.
check_returncode()

Raise an exception if returncode is non-zero.

Raise pulp_smash.exceptions.CalledProcessError if returncode is non-zero.

Why not raise subprocess.CalledProcessError? Because stdout and stderr are not included when str() is called on a CalledProcessError object. A typical message is:

"Command '('ls', 'foo')' returned non-zero exit status 2"

This information is valuable. One could still make subprocess.CalledProcessError work by overloading args:

>>> if isinstance(args, (str, bytes)):
...     custom_args = (args, stdout, stderr)
... else:
...     custom_args = tuple(args) + (stdout, stderr)
>>> subprocess.CalledProcessError(args, returncode)

But this seems like a hack.

In addition, it’s generally good for an application to raise expected exceptions from its own namespace, so as to better abstract away dependencies.

class pulp_smash.cli.GlobalServiceManager(cfg)

A service manager that manage services across all Pulp systems.

Each instance of this class will manage services on all Pulp systems available on the pulp_smash.config.PulpSmashConfig object provided.

This means that asking this service manager, for example, to start httpd it will iterate over all the available systems and will start the service on every system that has the api role. The example below illustrate this:

>>> from pulp_smash import cli, config
>>> svc_mgr = cli.GlobalServiceManager(config.get_config())
>>> svc_manager.start(['httpd'])

The GlobalServiceManager object will create clients and check if is running as root on demand for every system when managing services. If on a given deployment it has 4 systems and only 2 have the related services available then a connection will be done to those 2 an not on all 4.

Also, the GlobalServiceManager object will try to cache as much information as possible to avoid doing many connections.

Parameters:cfg (pulp_smash.config.PulpSmashConfig) – Information about the Pulp deployment.
Raises:pulp_smash.exceptions.NoKnownServiceManagerError – If unable to find any service manager on one of the target systems.
restart(services)

Restart the services on every system that has the services.

Parameters:services – An iterable of service names.
Returns:A dict mapping the affected systems’ hostnames with a list of pulp_smash.cli.CompletedProcess objects.
start(services)

Start the services on every system that has the services.

Parameters:services – An iterable of service names.
Returns:A dict mapping the affected systems’ hostnames with a list of pulp_smash.cli.CompletedProcess objects.
stop(services)

Stop the services on every system that has the services.

Parameters:services – An iterable of service names.
Returns:A dict mapping the affected systems’ hostnames with a list of pulp_smash.cli.CompletedProcess objects.
class pulp_smash.cli.PackageManager(cfg)

A package manager on a system.

Each instance of this class represents the package manager on a system. An example may help to clarify this idea:

>>> from pulp_smash import cli, config
>>> pkg_mgr = cli.PackageManager(config.get_config())
>>> completed_process = pkg_mgr.install('vim')
>>> completed_process = pkg_mgr.uninstall('vim')

In the example above, the pkg_mgr object represents the package manager on the host referenced by pulp_smash.config.get_config().

Upon instantiation, a PackageManager object talks to its target system and uses simple heuristics to determine which package manager is used. As a result, it’s possible to manage packages on heterogeneous systems with homogeneous commands.

Upon instantiation, a PackageManager object also talks to its target system and determines whether it is running as root. If not root, all commands are prefixed with “sudo”. Please ensure that Pulp Smash can either execute commands as root or can successfully execute sudo. You may need to edit your ~/.ssh/config file.

Parameters:cfg (pulp_smash.config.PulpSmashConfig) – Information about the target system.
Raises:pulp_smash.exceptions.NoKnownPackageManagerError – If unable to find any package manager on the target system.
install(*args)

Install the named packages.

Return type:pulp_smash.cli.CompletedProcess
uninstall(*args)

Uninstall the named packages.

Return type:pulp_smash.cli.CompletedProcess
upgrade(*args)

Upgrade the named packages.

Return type:pulp_smash.cli.CompletedProcess
class pulp_smash.cli.ServiceManager(cfg, pulp_system)

A service manager on a system.

Each instance of this class represents the service manager on a system. An example may help to clarify this idea:

from pulp_smash import cli, config >>> svc_mgr = cli.ServiceManager(config.get_config(), pulp_system) >>> completed_process_list = svc_manager.stop([‘httpd’]) >>> completed_process_list = svc_manager.start([‘httpd’])

In the example above, the svc_mgr object represents the service manager on the host referenced by pulp_system.

Upon instantiation, a ServiceManager object talks to its target system and uses simple heuristics to determine which service manager is available. As a result, it’s possible to manage services on heterogeneous systems with homogeneous commands.

Upon instantiation, a ServiceManager object also talks to its target system and determines whether it is running as root. If not root, all commands are prefixed with “sudo”. Please ensure that Pulp Smash can either execute commands as root or can successfully execute sudo. You may need to edit your ~/.ssh/config file.

Parameters:
Raises:

pulp_smash.exceptions.NoKnownServiceManagerError – If unable to find any service manager on the target system.

restart(services)

Restart the given services.

Parameters:services – An iterable of service names.
Returns:An iterable of pulp_smash.cli.CompletedProcess objects.
start(services)

Start the given services.

Parameters:services – An iterable of service names.
Returns:An iterable of pulp_smash.cli.CompletedProcess objects.
stop(services)

Stop the given services.

Parameters:services – An iterable of service names.
Returns:An iterable of pulp_smash.cli.CompletedProcess objects.
pulp_smash.cli.code_handler(completed_proc)

Check the process for a non-zero return code. Return the process.

Check the return code by calling completed_proc.check_returncode(). See: pulp_smash.cli.CompletedProcess.check_returncode().

pulp_smash.cli.echo_handler(completed_proc)

Immediately return completed_proc.