├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── dockerrun ├── __init__.py └── client.py ├── example.py ├── script └── run-example └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.egg-info 3 | /dist 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2 2 | ADD . /code 3 | WORKDIR /code 4 | RUN python setup.py install 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Ben Firshman 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | * The names of its contributors may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dockerrun 2 | ========= 3 | 4 | dockerrun is a dead simple Python library for running Docker commands. It does the thing you normally want to do with minimal hassle. 5 | 6 | It works a bit like this: 7 | 8 | ``` 9 | >>> import dockerrun 10 | >>> client = dockerrun.from_env() 11 | 12 | >>> client.run("ubuntu", "echo hello world") 13 | 'hello world\n' 14 | 15 | >>> client.run("ubuntu", "cat missing") 16 | Traceback (most recent call last): 17 | File "", line 1, in 18 | File "dockerrun/client.py", line 54, in run 19 | self.logs(container, stdout=False, stderr=True) 20 | dockerrun.client.ProcessError: Command 'cat missing' in image 'ubuntu' returned non-zero exit status 1: cat: missing: No such file or directory 21 | 22 | >>> client.run("myapp", "tasks/reticulate-splines", detach=True) 23 | {'Id': 'ee2b9f3c6d75fc309b114b5a021bfaa0b35cb807a1af036d256d8deff503f5ba', 'Warnings': None} 24 | ``` 25 | -------------------------------------------------------------------------------- /dockerrun/__init__.py: -------------------------------------------------------------------------------- 1 | from .client import Client, from_env 2 | -------------------------------------------------------------------------------- /dockerrun/client.py: -------------------------------------------------------------------------------- 1 | import docker 2 | from docker.errors import APIError 3 | from docker.utils import kwargs_from_env 4 | 5 | class ProcessError(Exception): 6 | def __init__(self, container, exit_status, command, image, stderr): 7 | self.container = container 8 | self.exit_status = exit_status 9 | self.command = command 10 | self.image = image 11 | self.stderr = stderr 12 | super(ProcessError, self).__init__("Command '%s' in image '%s' returned non-zero exit status %s: %s" % (command, image, exit_status, stderr)) 13 | 14 | CREATE_KWARGS = ["hostname", "user", "detach", "stdin_open", "tty", "mem_limit", "ports", "environment", "dns", "volumes", "volumes_from", "network_disabled", "name", "entrypoint", "cpu_shares", "working_dir", "domainname", "memswap_limit", "cpuset", "host_config", "mac_address", "labels"] 15 | 16 | START_KWARGS = ["binds", "port_bindings", "lxc_conf", "publish_all_ports", "links", "privileged", "dns", "dns_search", "volumes_from", "network_mode", "restart_policy", "cap_add", "cap_drop", "devices", "extra_hosts", "read_only", "pid_mode", "ipc_mode", "security_opt", "ulimits"] 17 | 18 | def _dict_filter(d, keys): 19 | return dict((k, v) for k, v in d.items() if k in keys) 20 | 21 | class Client(docker.Client): 22 | def run(self, image, command=None, detach=False, stdout=True, stderr=False, **kwargs): 23 | create_kwargs = _dict_filter(kwargs, CREATE_KWARGS) 24 | start_kwargs = _dict_filter(kwargs, START_KWARGS) 25 | create_kwargs['host_config'] = self.create_host_config(**start_kwargs) 26 | try: 27 | container = self.create_container(image, command, **create_kwargs) 28 | except APIError as e: 29 | if e.response.status_code == 404 \ 30 | and e.explanation \ 31 | and 'No such image' in str(e.explanation): 32 | self.pull(image) 33 | container = self.create_container(image, command) 34 | else: 35 | raise 36 | 37 | 38 | self.start(container) 39 | 40 | if detach: 41 | return container 42 | 43 | exit_status = self.wait(container) 44 | if exit_status != 0: 45 | raise ProcessError( 46 | container, 47 | exit_status, 48 | command, 49 | image, 50 | self.logs(container, stdout=False, stderr=True) 51 | ) 52 | return self.logs(container, stdout=stdout, stderr=stderr) 53 | 54 | 55 | from_env = Client.from_env 56 | -------------------------------------------------------------------------------- /example.py: -------------------------------------------------------------------------------- 1 | import dockerrun 2 | 3 | client = dockerrun.from_env() 4 | print client.run("ubuntu", "echo hello world") 5 | -------------------------------------------------------------------------------- /script/run-example: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t dockerrun . 3 | exec docker run --rm -v /var/run/docker.sock:/var/run/docker.sock dockerrun python example.py 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import setup, find_packages 4 | 5 | setup(name='dockerrun', 6 | version='0.1.4', 7 | description='A dead simple Python library for running Docker commands', 8 | author='Ben Firshman', 9 | author_email='ben@firshman.co.uk', 10 | url='https://github.com/bfirsh/dockerrun', 11 | packages=find_packages(exclude=['tests.*', 'tests']), 12 | install_requires=['docker-py'], 13 | ) 14 | --------------------------------------------------------------------------------