API

The public API of the Tunic library is maintained in the tunic.api module. This is done for the purposes of clearly identifying which parts of the library are public and which parts are internal.

Functionality in the tunic.core and tunic.install modules is included in this module under a single, flat namespace. This allows a simple and consistent way to interact with the library.

tunic.core

Core Tunic functionality.

class tunic.core.ProjectSetup(base, runner=None)[source]

Functionality for performing the initial creation of project directories and making sure their permissions are reasonable on a remote server.

Note that by default methods in this class rely on being able to execute commands with the Fabric sudo function. This can be disabled by passing the use_sudo=False flag to methods that accept it.

See Design for more information about the expected directory structure for deployments.

__init__(base, runner=None)[source]

Set the base path to the project that will be setup and an optional FabRunner implementation to use for running commands.

Parameters:
  • base (str) – Absolute path to the root of the code deploy
  • runner (FabRunner) – Optional runner to use for executing remote commands to set up the deploy.
Raises:

ValueError – If the base directory isn’t specified

Changed in version 0.3.0: ValueError is now raised for empty base values.

set_permissions(owner, file_perms='u+rw, g+rw, o+r', dir_perms='u+rwx, g+rws, o+rx', use_sudo=True)[source]

Set the owner and permissions of the code deploy.

The owner will be set recursively for the entire code deploy.

The directory permissions will be set on only the base of the code deploy and the releases directory. The file permissions will be set recursively for the entire code deploy.

If not specified default values will be used for file or directory permissions.

By default the Fabric sudo function will be used for changing the owner and permissions of the code deploy. Optionally, you can pass the use_sudo=False argument to skip trying to change the owner of the code deploy and to use the run function to change permissions.

This method performs between three and four network operations depending on if use_sudo is false or true, respectively.

Parameters:
  • owner (str) – User and group in the form ‘owner:group’ to set for the code deploy.
  • file_perms (str) – Permissions to set for all files in the code deploy in the form ‘u+perms,g+perms,o+perms’. Default is u+rw,g+rw,o+r.
  • dir_perms (str) – Permissions to set for the base and releases directories in the form ‘u+perms,g+perms,o+perms’. Default is u+rwx,g+rws,o+rx.
  • use_sudo (bool) – If True, use sudo() to change ownership and permissions of the code deploy. If False try to change permissions using the run() command, do not change ownership.

Changed in version 0.2.0: use_sudo=False will no longer attempt to change ownership of the code deploy since this will just be a no-op or fail.

setup_directories(use_sudo=True)[source]

Create the minimal required directories for deploying multiple releases of a project.

By default, creation of directories is done with the Fabric sudo function but can optionally use the run function.

This method performs one network operation.

Parameters:use_sudo (bool) – If True, use sudo() to create required directories. If False try to create directories using the run() command.
class tunic.core.ReleaseManager(base, runner=None)[source]

Functionality for manipulation of multiple releases of a project deployed on a remote server.

Note that functionality for managing releases relies on them being named with a timestamp based prefix that allows them to be naturally sorted – such as with the get_release_id() function.

See Design for more information about the expected directory structure for deployments.

__init__(base, runner=None)[source]

Set the base path to the project that we will be managing releases of and an optional FabRunner implementation to use for running commands.

Parameters:
  • base (str) – Absolute path to the root of the code deploy
  • runner (FabRunner) – Optional runner to use for executing remote commands to manage releases.
Raises:

ValueError – If the base directory isn’t specified

Changed in version 0.3.0: ValueError is now raised for empty base values.

cleanup(keep=5)[source]

Remove all but the keep most recent releases.

If any of the candidates for deletion are pointed to by the ‘current’ symlink, they will not be deleted.

This method performs N + 2 network operations where N is the number of old releases that are cleaned up.

Parameters:keep (int) – Number of old releases to keep around
get_current_release()[source]

Get the release ID of the “current” deployment, None if there is no current deployment.

This method performs one network operation.

Returns:Get the current release ID
Return type:str
get_previous_release()[source]

Get the release ID of the deployment immediately before the “current” deployment, None if no previous release could be determined.

This method performs two network operations.

Returns:The release ID of the release previous to the “current” release.
Return type:str
get_releases()[source]

Get a list of all previous deployments, newest first.

This method performs one network operation.

Returns:Get an ordered list of all previous deployments
Return type:list
set_current_release(release_id)[source]

Change the ‘current’ symlink to point to the given release ID.

The ‘current’ symlink will be updated in a way that ensures the switch is done atomically.

This method performs two network operations.

Parameters:release_id (str) – Release ID to mark as the current release
tunic.core.get_current_path(base)[source]

Construct the path to the ‘current release’ symlink based on the given project base path.

Note that this function does not ensure that the ‘current’ symlink exists or points to a valid release, it only returns the full path that it should be at based on the given project base directory.

See Design for more information about the expected directory structure for deployments.

Changed in version 1.1.0: ValueError is now raised for empty base values.

Parameters:base (str) – Project base directory (absolute path)
Raises:ValueError – If the base directory isn’t specified
Returns:Path to the ‘current’ symlink
Return type:str
tunic.core.get_release_id(version=None)[source]

Get a unique, time-based identifier for a deployment that optionally, also includes some sort of version number or release.

If a version is supplied, the release ID will be of the form ‘$timestamp-$version’. For example:

>>> get_release_id(version='1.4.1')
'20140214231159-1.4.1'

If the version is not supplied the release ID will be of the form ‘$timestamp’. For example:

>>> get_release_id()
'20140214231159'

The timestamp component of this release ID will be generated using the current time in UTC.

Parameters:version (str) – Version to include in the release ID
Returns:Unique name for this particular deployment
Return type:str
tunic.core.get_releases_path(base)[source]

Construct the path to the directory that contains all releases based on the given project base path.

Note that this function does not ensure that the releases directory exists, it only returns the full path that it should be at based on the given project base directory.

See Design for more information about the expected directory structure for deployments.

Changed in version 1.1.0: ValueError is now raised for empty base values.

Parameters:base (str) – Project base directory (absolute path)
Raises:ValueError – If the base directory isn’t specified
Returns:Path to the releases directory
Return type:str

tunic.install

Perform installations on remote machines.

class tunic.install.HttpArtifactInstallation(base, artifact_url, remote_name=None, retries=None, retry_delay=None, downloader=None, runner=None)[source]

Download and install a single file into a remote release directory.

This is useful for installing an application that is typically bundled as a single file, e.g. Go binaries or Java JAR files, after downloading it from some sort of artifact repository (such as a company-wide file server or artifact store like Artifactory).

Downloads are performed over HTTP or HTTPS using a call to wget on the remote machine by default. An alternate download method may be specified when creating a new instance of this installer by providing an alternate implementation. The download method is expected to conform to the following interface.

>>> def download(url, destination, retries=None, retry_delay=None):
...     pass

Where url is a URL to the artifact that should be downloaded, destination is the absolute path on the remote machine that the artifact should be downloaded to, retries is the number of download attempts made after a failure, and retry_delay is the number of seconds between retries. The function should return the result of the Fabric command run(e.g. calling ‘curl’ or ‘wget’ with fabric.api.run()).

If the remote release directory does not already exist, it will be created during the install process.

See Design for more information about the expected directory structure for deployments.

New in version 1.2.0.

__init__(base, artifact_url, remote_name=None, retries=None, retry_delay=None, downloader=None, runner=None)[source]

Set the project base directory on the remote server, URL to the artifact that should be installed remotely, and optional file name to rename the artifact to on the remote server.

Parameters:
  • base (str) – Absolute path to the root of the code deploy on the remote server
  • artifact_url (str) – URL to the artifact to be downloaded and installed on the remote server.
  • remote_name (str) – Optional file name for the artifact after it has been installed on the remote server. For example, if the artifact should always be called ‘application.jar’ on the remote server but might be named differently (‘application-1.2.3.jar’) locally, you would specify remote_name='application.jar' for this parameter.
  • retries (int) – Max number of times to retry downloads after a failure. Default is to retry once after a failure.
  • retry_delay (float) – Number of seconds between download retries. Default is not to wait between a failure and subsequent retry.
  • downloader (callable) – Function to download the artifact with the interface specified above. This is primarily for unit testing but may be useful for users that need to be able to customize how the artifact HTTP store is accessed.
  • runner (FabRunner) – Optional runner to use for executing remote and local commands to perform the installation.
Raises:

ValueError – If the base directory or artifact URL isn’t specified.

Changed in version 1.3.0: Added the retries and retry_delay parameters

install(release_id)[source]

Download and install an artifact into the remote release directory, optionally with a different name the the artifact had.

If the directory for the given release ID does not exist on the remote system, it will be created. The directory will be created according to the standard Tunic directory structure (see Design).

Parameters:release_id (str) – Timestamp-based identifier for this deployment.
Returns:The results of the download function being run. This return value should be the result of running a command with Fabric. By default this will be the result of running wget.
class tunic.install.LocalArtifactInstallation(base, local_file, remote_name=None, runner=None)[source]

Install a single local file into a remote release directory.

This can be useful for installing applications that are typically bundled as a single file, e.g. Go binaries or Java JAR files, etc.. The artifact can optionally be renamed as part of the installation process.

If the remote release directory does not already exist, it will be created during the install process.

See Design for more information about the expected directory structure for deployments.

New in version 1.1.0.

__init__(base, local_file, remote_name=None, runner=None)[source]

Set the project base directory on the remote server, local artifact (a single file) that should be installed remotely, and optional file name to rename the artifact to on the remote server.

Parameters:
  • base (str) – Absolute path to the root of the code deploy on the remote server
  • local_file (str) – Relative or absolute path to the local artifact to be installed on the remote server.
  • remote_name (str) – Optional file name for the artifact after it has been installed on the remote server. For example, if the artifact should always be called ‘application.jar’ on the remote server but might be named differently (‘application-1.2.3.jar’) locally, you would specify remote_name='application.jar' for this parameter.
  • runner (FabRunner) – Optional runner to use for executing remote and local commands to perform the installation.
Raises:

ValueError – If the base directory or local file isn’t specified.

install(release_id)[source]

Install the local artifact into the remote release directory, optionally with a different name than the artifact had locally.

If the directory for the given release ID does not exist on the remote system, it will be created. The directory will be created according to the standard Tunic directory structure (see Design).

Parameters:
  • release_id (str) – Timestamp-based identifier for this deployment.
  • retries (int) – Max number of times to retry downloads after a failure
  • retry_delay (float) – Number of seconds between download retries
Returns:

The results of the put command using Fabric. This return value is an iterable of the paths of all files uploaded on the remote server.

class tunic.install.LocalArtifactTransfer(local_path, remote_path, runner=None)[source]

Transfer a local artifact or directory of artifacts to a remote server when entering a context manager and clean the transferred files up on the remote server after leaving the block.

The value yielded when entering the context manager will be the full path to the transferred file or directory on the remote server. The value yielded will be made up of remote_path combined with the right most component of local_path.

For example, if /tmp/myapp is a local directory that contains several files, the example below will have the following effect.

>>> transfer = LocalArtifactTransfer('/tmp/myapp', '/tmp/artifacts')
>>> with transfer as remote_dest:
...     pass

The directory myapp and its contents would be copied to /tmp/artifacts/myapp on the remote machine within the scope of the context manager and the value of remote_dest would be /tmp/artifacts/myapp. After the context manager exits /tmp/artifacts/myapp on the remote machine will be removed.

If /tmp/myartifact.zip is a single local file, the example below will have the following effect.

>>> transfer = LocalArtifactTransfer('/tmp/myartifact.zip', '/tmp/artifacts')
>>> with transfer as remote_dest:
...     pass

The file myartifact.zip would be copied to /tmp/artifacts/myartifact.zip on the remote machine within the scope of the context manager and the value of remote_dest would be /tmp/artifacts/myartifact.zip. After the context manager exits /tmp/artifacts/myartifact.zip on the remote machine will be removed.

The destination of the artifacts must be a directory that is writable by the user running the deploy or that the user has permission to create.

The path yielded by the context will be removed when the context manager exits. The local artifacts are not modified or removed on exit.

New in version 0.4.0.

__enter__()[source]

Transfer the local artifacts to the appropriate place on the remote server (ensuring the path exists first) and return the remote destination path.

The remote destination path is the remote path joined with the right-most component of the local path.

Returns:The path artifacts were transferred to on the remote server
Return type:str
__exit__(exc_type, exc_val, exc_tb)[source]

Remove the directory containing the build artifacts on the remote server.

__init__(local_path, remote_path, runner=None)[source]

Set the local directory that contains the artifacts and the remote directory that they should be transferred to.

Both the local and remote paths should not contain trailing slashes. Any trailing slashes will be removed.

Parameters:
  • local_path (str) – Directory path on the local machine that contains the build artifacts to be transferred (without a trailing slash) or the path on the local machine of a single file.
  • remote_path (str) – Directory on the remote machine that the build artifacts should be transferred to (without a tailing slash).
  • runner (FabRunner) – Optional runner to use for executing commands to transfer artifacts.

Changed in version 0.5.0: Trailing slashes are now removed from local_path and remote_path.

class tunic.install.StaticFileInstallation(base, local_path, runner=None)[source]

Install the contents of a local directory into a remote release directory.

If the remote release directory does not already exist, it will be created during the install process.

See Design for more information about the expected directory structure for deployments.

New in version 0.5.0.

__init__(base, local_path, runner=None)[source]

Set the project base directory on the remote server and path to a directory of static content to be installed into a remote release directory.

Parameters:
  • base (str) – Absolute path to the root of the code deploy on the remote server
  • local_path (str) – Absolute or relative path to a local directory whose contents will be copied to a remote release directory.
  • runner (FabRunner) – Optional runner to use for executing remote and local commands to perform the installation.
Raises:

ValueError – If the base directory or local path isn’t specified.

install(release_id)[source]

Install the contents of the local directory into a release directory.

If the directory for the given release ID does not exist on the remote system, it will be created. The directory will be created according to the standard Tunic directory structure (see Design).

Note that the name and path of the local directory is irrelevant, only the contents of the specified directory will be transferred to the remote server. The contents will end up as children of the release directory on the remote server.

Parameters:release_id (str) – Timestamp-based identifier for this deployment. If this ID corresponds to a directory that already exists, contents of the local directory will be copied into this directory.
Returns:The results of the put command using Fabric. This return value is an iterable of the paths of all files uploaded on the remote server.
class tunic.install.VirtualEnvInstallation(base, packages, sources=None, venv_path=None, runner=None)[source]

Install one or multiple packages into a remote Python virtual environment.

If the remote virtual environment does not already exist, it will be created during the install process.

The installation can use the standard package index (PyPI) to download dependencies, or it can use one or multiple alternative installation sources (such as a local PyPI instance, Artifactory, the local file system, etc.) and ignore the default index. These two modes are mutually exclusive.

See Design for more information about the expected directory structure for deployments.

New in version 0.3.0.

__init__(base, packages, sources=None, venv_path=None, runner=None)[source]

Set the project base directory, packages to install, and optionally alternative sources from which to download dependencies and path to the virtualenv tool.

Parameters:
  • base (str) – Absolute path to the root of the code deploy on the remote server
  • packages (list) – A collection of package names to install into a remote virtual environment.
  • sources (list) – A collection of alternative sources from which to install dependencies. These sources should be strings that are either URLs or file paths. E.g. ‘http://pypi.example.com/simple/’ or ‘/tmp/build/mypackages’. Paths and URLs may be mixed in the same list of sources.
  • venv_path (str) – Optional absolute path to the virtualenv tool on the remote server. Required if the virtualenv tool is not in the PATH on the remote server.
  • runner (FabRunner) – Optional runner to use for executing remote and local commands to perform the installation.
Raises:

ValueError – If the base directory isn’t specified, if no packages are given, packages is not an iterable collection of some kind, or if sources is specified but not an iterable collection of some kind.

Changed in version 0.4.0: Allow the path to the virtualenv script on the remote server to be specified.

install(release_id, upgrade=False)[source]

Install target packages into a virtual environment.

If the virtual environment for the given release ID does not exist on the remote system, it will be created. The virtual environment will be created according to the standard Tunic directory structure (see Design).

If upgrade=True is passed, packages will be updated to the most recent version if they are already installed in the virtual environment.

Parameters:
  • release_id (str) – Timestamp-based identifier for this deployment. If this ID corresponds to a virtual environment that already exists, packages will be installed into this environment.
  • upgrade (bool) – Should packages be updated if they are already installed in the virtual environment.
Returns:

The results of running the installation command using Fabric. Note that this return value is a decorated version of a string that contains additional meta data about the result of the command, in addition to the output generated.

Return type:

str