pulp_smash.cli

Location: Pulp SmashAPI Documentationpulp_smash.cli

A client for working with Pulp hosts 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 hosts.

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

This base class also offers a context manager to temporary disable SELinux. It is useful when managing services on hosts running RHEL 6 and earlier, 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(cfg, response_handler=None, pulp_host=None)

A convenience object for working with a CLI.

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

>>> from pulp_smash import cli, config
>>> client = cli.Client(config.PulpSmashConfig.load())
>>> response = client.run(('echo', '-n', 'foo'))
>>> response.returncode == 0
True
>>> response.stdout == 'foo'
True
>>> response.stderr == ''
True

Smartly chosen defaults make this example concise, but it’s also quite flexible. For example, if a single Pulp application is deployed across several hosts, one can choose on which host commands are executed:

>>> from pulp_smash import cli, config
>>> cfg = config.PulpSmashConfig.load()
>>> client = cli.Client(cfg, pulp_host=cfg.get_hosts('shell')[0])
>>> response = client.run(('echo', '-n', 'foo'))

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_host.roles['shell']['transport'] is 'local' or 'ssh, machine will be set so that commands run locally or over SSH, respectively. If pulp_host.roles['shell']['transport'] is None, the constructor will guess how to set machine by comparing the hostname embedded in pulp_host.hostname against the current host’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 manages services on all Pulp hosts.

Each instance of this class manages a single service. When a method like start() is executed, it will start a service on all hosts that are declared as running that service. For example, imagine that the following is executed:

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

In this case, the service manager will iterate over all hosts in cfg. For each host that is declared as fulfilling the api role, Apache (httpd) will be restarted.

When asked to perform an action, this object may talk to each target host 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.

For conceptual information on why both a pulp_smash.cli.ServiceManager and a pulp_smash.cli.GlobalServiceManager are necessary, see pulp_smash.config.PulpSmashConfig.

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 hosts.
restart(services)

Restart the services on every host that has the services.

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

Start the services on every host that has the services.

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

Stop the services on every host that has the services.

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

A package manager on a host.

Each instance of this class represents the package manager on a host. 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 host and uses simple heuristics to determine which package manager is used. As a result, it’s possible to manage packages on heterogeneous host with homogeneous commands.

Upon instantiation, this object talks to the target host 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 host.
Raises:pulp_smash.exceptions.NoKnownPackageManagerError – If unable to find any package manager on the target host.
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_host)

A service manager on a host.

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

>>> from pulp_smash import cli, config
>>> cfg = config.get_config()
>>> pulp_host = cfg.get_get_services(('api',))[0]
>>> svc_mgr = cli.ServiceManager(cfg, pulp_host)
>>> completed_process_list = svc_mgr.stop(['httpd'])
>>> completed_process_list = svc_mgr.start(['httpd'])

In the example above, svc_mgr represents the service manager (such as SysV or systemd) on a host. Upon instantiation, a ServiceManager object talks to its target host and uses simple heuristics to determine which service manager is available. As a result, it’s possible to manage services on heterogeneous hosts with homogeneous commands.

Upon instantiation, this object talks to the target host 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.

For conceptual information on why both a pulp_smash.cli.ServiceManager and a pulp_smash.cli.GlobalServiceManager are necessary, see pulp_smash.config.PulpSmashConfig.

Parameters:
Raises:

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

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.

pulp_smash.cli.is_root(cfg, pulp_host=None)

Tell if we are root on the target host.

Parameters:
Returns:

Either True or False.