Compare commits

...

22 Commits
0.0.1 ... 0.0.2

Author SHA1 Message Date
Ben Firshman
e0a21e3df4 Bump version to 0.0.2 2014-01-02 21:30:28 +00:00
Ben Firshman
45b7bd4361 Readme tweaks 2014-01-02 21:23:47 +00:00
Ben Firshman
36002f95ed Try connecting to localdocker:4243
See https://github.com/noplay/docker-osx/pull/22
2014-01-02 20:51:35 +00:00
Ben Firshman
0a92cbfa4d Fix readme formatting 2014-01-02 20:19:00 +00:00
Ben Firshman
5b1fd64708 Add getting started guide to readme 2014-01-02 20:08:01 +00:00
Ben Firshman
9b289b6f3b Stop "fig up" containers gracefully
With double ctrl-c force.
2014-01-02 19:18:08 +00:00
Ben Firshman
6d0702e607 Send log output to stderr 2014-01-02 18:31:00 +00:00
Aanand Prasad
38478ea504 Full fig.yml and environment variable reference 2014-01-02 17:01:27 +00:00
Ben Firshman
a39db86651 Add "fig build" command 2014-01-02 15:28:33 +00:00
Ben Firshman
853d8ad280 Namespace tests inside a project
So it doesn't delete all your containers for every test. Cool.
2014-01-02 15:27:51 +00:00
Ben Firshman
17c6ae067a Rewrite readme intro 2014-01-02 15:03:30 +00:00
Ben Firshman
770e78fdce Make usage alphabetical 2014-01-02 15:00:16 +00:00
Aanand Prasad
e5065bed16 Expand the intro a bit 2013-12-31 16:31:40 +00:00
Aanand Prasad
c0676e3fa3 Add confirmation prompt to 'fig rm' 2013-12-31 13:42:58 +00:00
Aanand Prasad
d4f3ed1840 Fix 'fig up' behaviour
- For each service, creates a container if there are none (stopped OR
  started)
- Attaches to all containers (unless -d is passed)
- Starts all containers
- On ^C, kills all containers (unless -d is passed)
2013-12-31 13:02:08 +00:00
Aanand Prasad
9ed6538693 Extract docker URL logic, use it in tests as well 2013-12-31 12:37:17 +00:00
Aanand Prasad
ff65a3e1b0 Check default socket and localhost:4243 for Docker daemon 2013-12-31 12:18:27 +00:00
Aanand Prasad
ebf9bf387c Remove unused import 2013-12-31 11:51:52 +00:00
Aanand Prasad
fdc1e0f2e1 Missing article in README 2013-12-30 18:57:55 +00:00
Aanand Prasad
f3eff9a389 Add _site to .gitignore (it's generated by Jekyll in the gh-pages branch) 2013-12-30 18:57:27 +00:00
Ben Firshman
2857631e90 Add change log 2013-12-20 21:37:55 +00:00
Ben Firshman
89cd7d8db0 Remove long description 2013-12-20 21:36:06 +00:00
13 changed files with 333 additions and 240 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.egg-info
*.pyc
/dist
/_site

18
CHANGES.md Normal file
View File

@@ -0,0 +1,18 @@
Change log
==========
0.0.2 (2014-01-02)
------------------
- Improve documentation
- Try to connect to Docker on `tcp://localdocker:4243` and a UNIX socket in addition to `localhost`.
- Improve `fig up` behaviour
- Add confirmation prompt to `fig rm`
- Add `fig build` command
0.0.1 (2013-12-20)
------------------
Initial release.

271
README.md
View File

@@ -3,7 +3,7 @@ Fig
Punctual, lightweight development environments using Docker.
Fig is tool for defining and running isolated application environments. It uses simple, version-controllable YAML configuration files that look something like this:
Fig is a tool for defining and running isolated application environments. You define the services which comprise your app in a simple, version-controllable YAML configuration file that looks like this:
```yaml
web:
@@ -16,148 +16,205 @@ db:
image: orchardup/postgresql
```
Installing
----------
Then type `fig up`, and Fig will start and run your entire app:
```bash
$ sudo pip install fig
```
$ fig up
Pulling image orchardup/postgresql...
Building web...
Starting example_db_1...
Starting example_web_1...
example_db_1 | 2014-01-02 14:47:18 UTC LOG: database system is ready to accept connections
example_web_1 | * Running on http://0.0.0.0:5000/
Defining your app
-----------------
There are commands to:
Put a `fig.yml` in your app's directory. Each top-level key defines a "service", such as a web app, database or cache. For each service, Fig will start a Docker container, so at minimum it needs to know what image to use.
- start, stop and rebuild services
- view the status of running services
- tail running services' log output
- run a one-off command on a service
The simplest way to get started is to just give it an image name:
Fig is a project from [Orchard](https://orchardup.com), a Docker hosting service. [Follow us on Twitter](https://twitter.com/orchardup) to keep up to date with Fig and other Docker news.
```yaml
db:
image: orchardup/postgresql
```
You've now given Fig the minimal amount of configuration it needs to run:
Getting started
---------------
```bash
$ fig up
Pulling image orchardup/postgresql...
Starting myapp_db_1...
myapp_db_1 is running at 127.0.0.1:45678
<...output from postgresql server...>
```
Let's get a basic Python web app running on Fig. It assumes a little knowledge of Python, but the concepts should be clear if you're not familiar with it.
For each service you've defined, Fig will start a Docker container with the specified image, building or pulling it if necessary. You now have a PostgreSQL server running at `127.0.0.1:45678`.
First, install Docker. If you're on OS X, you can use [docker-osx](https://github.com/noplay/docker-osx):
By default, `fig up` will run until each container has shut down, and relay their output to the terminal. To run in the background instead, pass the `-d` flag:
$ curl https://raw.github.com/noplay/docker-osx/master/docker > /usr/local/bin/docker
$ chmod +x /usr/local/bin/docker
$ docker version
```bash
$ fig up -d
Starting myapp_db_1... done
myapp_db_1 is running at 127.0.0.1:45678
Docker has guides for [Ubuntu](http://docs.docker.io/en/latest/installation/ubuntulinux/) and [other platforms](http://docs.docker.io/en/latest/installation/) in their documentation.
$ fig ps
Name State Ports
------------------------------------
myapp_db_1 Up 5432->45678/tcp
```
Next, install Fig:
### Building services
$ sudo pip install fig
Fig can automatically build images for you if your service specifies a directory with a `Dockerfile` in it (or a Git URL, as per the `docker build` command).
(If you dont have pip installed, try `brew install python` or `apt-get install python-pip`.)
This example will build an image with `app.py` inside it:
You'll want to make a directory for the project:
#### app.py
$ mkdir figtest
$ cd figtest
Inside this directory, create `app.py`, a simple web app that uses the Flask framework and increments a value in Redis:
```python
print "Hello world!"
from flask import Flask
from redis import Redis
import os
app = Flask(__name__)
redis = Redis(
host=os.environ.get('FIGTEST_REDIS_1_PORT_6379_TCP_ADDR'),
port=int(os.environ.get('FIGTEST_REDIS_1_PORT_6379_TCP_PORT'))
)
@app.route('/')
def hello():
redis.incr('hits')
return 'Hello World! I have been seen %s times.' % redis.get('hits')
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
```
#### fig.yml
We define our Python dependencies in a file called `requirements.txt`:
```yaml
web:
build: .
```
flask
redis
#### Dockerfile
And we define how to build this into a Docker image using a file called `Dockerfile`:
FROM ubuntu:12.04
RUN apt-get install python
ADD . /opt
WORKDIR /opt
FROM stackbrew/ubuntu:13.10
RUN apt-get -qq update
RUN apt-get install -y python python-pip
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
EXPOSE 5000
CMD python app.py
That tells Docker to create an image with Python and Flask installed on it, run the command `python app.py`, and open port 5000 (the port that Flask listens on).
We then define a set of services using `fig.yml`:
web:
build: .
ports:
- 5000:5000
volumes:
- .:/code
links:
- redis
redis:
image: orchardup/redis
This defines two services:
- `web`, which is built from `Dockerfile` in the current directory. It also says to forward the exposed port 5000 on the container to port 5000 on the host machine, connect up the Redis service, and mount the current directory inside the container so we can work on code without having to rebuild the image.
- `redis`, which uses the public image [orchardup/redis](https://index.docker.io/u/orchardup/redis/).
Now if we run `fig up`, it'll pull a Redis image, build an image for our own code, and start everything up:
$ fig up
Pulling image orchardup/redis...
Building web...
Starting figtest_redis_1...
Starting figtest_web_1...
figtest_redis_1 | [8] 02 Jan 18:43:35.576 # Server started, Redis version 2.8.3
figtest_web_1 | * Running on http://0.0.0.0:5000/
Open up [http://localhost:5000](http://localhost:5000) in your browser (or [http://localdocker:5000](http://localdocker:5000) if you're using [docker-osx](https://github.com/noplay/docker-osx)) and you should see it running!
If you want to run your services in the background, you can pass the `-d` flag to `fig up` and use `fig ps` to see what is currently running:
$ fig up -d
Starting figtest_redis_1...
Starting figtest_web_1...
$ fig ps
Name Command State Ports
-------------------------------------------------------------------
figtest_redis_1 /usr/local/bin/run Up
figtest_web_1 /bin/sh -c python app.py Up 5000->5000/tcp
`fig run` allows you to run one-off commands for your services. For example, to see what environment variables are available to the `web` service:
$ fig run web env
### Getting your code in
See `fig --help` other commands that are available.
If you want to work on an application being run by Fig, you probably don't want to have to rebuild your image every time you make a change. To solve this, you can share the directory with the container using a volume so the changes are reflected immediately:
You'll probably want to stop your services when you've finished with them:
$ fig stop
That's more-or-less how Fig works. See the reference section below for full details on the commands, configuration file and environment variables. If you have any thoughts or suggestions, [open an issue on GitHub](https://github.com/orchardup/fig) or [email us](mailto:hello@orchardup.com).
Reference
---------
### fig.yml
Each service defined in `fig.yml` must specify exactly one of `image` or `build`. Other keys are optional, and are analogous to their `docker run` command-line counterparts.
As with `docker run`, options specified in the Dockerfile (e.g. `CMD`, `EXPOSE`, `VOLUME`, `ENV`) are respected by default - you don't need to specify them again in `fig.yml`.
```yaml
web:
build: .
volumes:
- .:/opt
-- Tag or partial image ID. Can be local or remote - Fig will attempt to pull if it doesn't exist locally.
image: ubuntu
image: orchardup/postgresql
image: a4bc65fd
-- Path to a directory containing a Dockerfile. Fig will build and tag it with a generated name, and use that image thereafter.
build: /path/to/build/dir
-- Override the default command.
command: bundle exec thin -p 3000
-- Link to containers in another service (see "Communicating between containers").
links:
- db
- redis
-- Expose ports. Either specify both ports (HOST:CONTAINER), or just the container port (a random host port will be chosen).
ports:
- 3000
- 8000:8000
-- Map volumes from the host machine (HOST:CONTAINER).
volumes:
- cache/:/tmp/cache
-- Add environment variables.
environment:
RACK_ENV: development
```
### Environment variables
### Communicating between containers
Fig uses [Docker links] to expose services' containers to one another. Each linked container injects a set of environment variables, each of which begins with the uppercase name of the container.
Your web app will probably need to talk to your database. You can use [Docker links](http://docs.docker.io/en/latest/use/port_redirection/#linking-a-container) to enable containers to communicate, pass in the right IP address and port via environment variables:
<b><i>name</i>\_PORT</b><br>
Full URL, e.g. `MYAPP_DB_1_PORT=tcp://172.17.0.5:5432`
```yaml
db:
image: orchardup/postgresql
<b><i>name</i>\_PORT\_<i>num</i>\_<i>protocol</i></b><br>
Full URL, e.g. `MYAPP_DB_1_PORT_5432_TCP=tcp://172.17.0.5:5432`
web:
build: .
links:
- db
```
<b><i>name</i>\_PORT\_<i>num</i>\_<i>protocol</i>\_ADDR</b><br>
Container's IP address, e.g. `MYAPP_DB_1_PORT_5432_TCP_ADDR=172.17.0.5`
This will pass an environment variable called `MYAPP_DB_1_PORT` into the web container, whose value will look like `tcp://172.17.0.4:45678`. Your web app's code can use that to connect to the database. To see all of the environment variables available, run `env` inside a container:
<b><i>name</i>\_PORT\_<i>num</i>\_<i>protocol</i>\_PORT</b><br>
Exposed port number, e.g. `MYAPP_DB_1_PORT_5432_TCP_PORT=5432`
```bash
$ fig up -d db
$ fig run web env
```
### Container configuration options
You can pass extra configuration options to a container, much like with `docker run`:
```yaml
web:
build: .
-- override the default command
command: bundle exec thin -p 3000
-- expose ports, optionally specifying both host and container ports (a random host port will be chosen otherwise)
ports:
- 3000
- 8000:8000
-- map volumes
volumes:
- cache/:/tmp/cache
-- add environment variables
environment:
RACK_ENV: development
```
Running a one-off command
-------------------------
If you want to run a management command, use `fig run` to start a one-off container:
```bash
$ fig run db createdb myapp_development
$ fig run web rake db:migrate
$ fig run web bash
```
<b><i>name</i>\_PORT\_<i>num</i>\_<i>protocol</i>\_PROTO</b><br>
Protocol (tcp or udp), e.g. `MYAPP_DB_1_PORT_5432_TCP_PROTO=tcp`
<b><i>name</i>\_NAME</b><br>
Fully qualified container name, e.g. `MYAPP_DB_1_NAME=/myapp_web_1/myapp_db_1`
[Docker links]: http://docs.docker.io/en/latest/use/port_redirection/#linking-a-container

View File

@@ -1,3 +1,3 @@
from .service import Service
__version__ = '0.0.1'
__version__ = '0.0.2'

View File

@@ -7,17 +7,14 @@ import yaml
from ..project import Project
from .docopt_command import DocoptCommand
from .formatter import Formatter
from .utils import cached_property, mkdir
from .utils import cached_property, docker_url
log = logging.getLogger(__name__)
class Command(DocoptCommand):
@cached_property
def client(self):
if os.environ.get('DOCKER_URL'):
return Client(os.environ['DOCKER_URL'])
else:
return Client()
return Client(docker_url())
@cached_property
def project(self):

View File

@@ -1,6 +1,8 @@
import logging
import sys
import re
import signal
import sys
from inspect import getdoc
@@ -9,6 +11,7 @@ from ..project import NoSuchService
from .command import Command
from .formatter import Formatter
from .log_printer import LogPrinter
from .utils import yesno
from docker.client import APIError
from .errors import UserError
@@ -19,7 +22,7 @@ log = logging.getLogger(__name__)
def main():
console_handler = logging.StreamHandler()
console_handler = logging.StreamHandler(stream=sys.stderr)
console_handler.setFormatter(logging.Formatter())
console_handler.setLevel(logging.INFO)
root_logger = logging.getLogger()
@@ -70,14 +73,15 @@ class TopLevelCommand(Command):
--version Print version and exit
Commands:
up Create and start containers
build Build or rebuild services
kill Kill containers
logs View output from containers
ps List containers
rm Remove stopped containers
run Run a one-off command
start Start services
stop Stop services
kill Kill containers
rm Remove stopped containers
up Create and start containers
"""
def docopt_options(self):
@@ -85,6 +89,32 @@ class TopLevelCommand(Command):
options['version'] = "fig %s" % __version__
return options
def build(self, options):
"""
Build or rebuild services.
Usage: build [SERVICE...]
"""
self.project.build(service_names=options['SERVICE'])
def kill(self, options):
"""
Kill containers.
Usage: kill [SERVICE...]
"""
self.project.kill(service_names=options['SERVICE'])
def logs(self, options):
"""
View output from containers.
Usage: logs [SERVICE...]
"""
containers = self.project.containers(service_names=options['SERVICE'], stopped=False)
print "Attaching to", list_containers(containers)
LogPrinter(containers, attach_params={'logs': True}).run()
def ps(self, options):
"""
List containers.
@@ -116,6 +146,22 @@ class TopLevelCommand(Command):
])
print Formatter().table(headers, rows)
def rm(self, options):
"""
Remove stopped containers
Usage: rm [SERVICE...]
"""
all_containers = self.project.containers(service_names=options['SERVICE'], stopped=True)
stopped_containers = [c for c in all_containers if not c.is_running]
if len(stopped_containers) > 0:
print "Going to remove", list_containers(stopped_containers)
if yesno("Are you sure? [yN] ", default=False):
self.project.remove_stopped(service_names=options['SERVICE'])
else:
print "No stopped containers"
def run(self, options):
"""
Run a one-off command.
@@ -145,36 +191,6 @@ class TopLevelCommand(Command):
service.start_container(container, ports=None)
c.run()
def up(self, options):
"""
Create and start containers.
Usage: up [options] [SERVICE...]
Options:
-d Detached mode: Run containers in the background, print new container names
"""
detached = options['-d']
unstarted = self.project.create_containers(service_names=options['SERVICE'])
if not detached:
to_attach = self.project.containers(service_names=options['SERVICE']) + [c for (s, c) in unstarted]
print "Attaching to", list_containers(to_attach)
log_printer = LogPrinter(to_attach, attach_params={'logs': True})
for (s, c) in unstarted:
s.start_container(c)
if detached:
for (s, c) in unstarted:
print c.name
else:
try:
log_printer.run()
finally:
self.project.kill_and_remove(unstarted)
def start(self, options):
"""
Start existing containers.
@@ -191,31 +207,37 @@ class TopLevelCommand(Command):
"""
self.project.stop(service_names=options['SERVICE'])
def kill(self, options):
def up(self, options):
"""
Kill containers.
Create and start containers.
Usage: kill [SERVICE...]
"""
self.project.kill(service_names=options['SERVICE'])
Usage: up [options] [SERVICE...]
def rm(self, options):
Options:
-d Detached mode: Run containers in the background, print new container names
"""
Remove stopped containers
detached = options['-d']
Usage: rm [SERVICE...]
"""
self.project.remove_stopped(service_names=options['SERVICE'])
self.project.create_containers(service_names=options['SERVICE'])
containers = self.project.containers(service_names=options['SERVICE'], stopped=True)
def logs(self, options):
"""
View output from containers.
if not detached:
print "Attaching to", list_containers(containers)
log_printer = LogPrinter(containers)
Usage: logs [SERVICE...]
"""
containers = self.project.containers(service_names=options['SERVICE'], stopped=False)
print "Attaching to", list_containers(containers)
LogPrinter(containers, attach_params={'logs': True}).run()
self.project.start(service_names=options['SERVICE'])
if not detached:
try:
log_printer.run()
finally:
def handler(signal, frame):
self.project.kill(service_names=options['SERVICE'])
sys.exit(0)
signal.signal(signal.SIGINT, handler)
print "Gracefully stopping... (press Ctrl+C again to force)"
self.project.stop(service_names=options['SERVICE'])
def _attach_to_container(self, container_id, interactive, logs=False, stream=True, raw=False):
stdio = self.client.attach_socket(

View File

@@ -1,5 +1,7 @@
import datetime
import os
import socket
from .errors import UserError
def cached_property(f):
@@ -74,3 +76,36 @@ def mkdir(path, permissions=0700):
os.chmod(path, permissions)
return path
def docker_url():
if os.environ.get('DOCKER_URL'):
return os.environ['DOCKER_URL']
socket_path = '/var/run/docker.sock'
tcp_hosts = [
('localdocker', 4243),
('127.0.0.1', 4243),
]
tcp_host = '127.0.0.1'
tcp_port = 4243
if os.path.exists(socket_path):
return 'unix://%s' % socket_path
for host, port in tcp_hosts:
try:
s = socket.create_connection((host, port), timeout=1)
s.close()
return 'http://%s:%s' % (host, port)
except:
pass
raise UserError("""
Couldn't find Docker daemon - tried:
unix://%s
%s
If it's running elsewhere, specify a url with DOCKER_URL.
""" % (socket_path, '\n'.join('tcp://%s:%s' % h for h in tcp_hosts)))

View File

@@ -75,19 +75,11 @@ class Project(object):
def create_containers(self, service_names=None):
"""
Returns a list of (service, container) tuples,
one for each service with no running containers.
For each service, creates a container if there are none.
"""
containers = []
for service in self.get_services(service_names):
if len(service.containers()) == 0:
containers.append((service, service.create_container()))
return containers
def kill_and_remove(self, tuples):
for (service, container) in tuples:
container.kill()
container.remove()
if len(service.containers(stopped=True)) == 0:
service.create_container()
def start(self, service_names=None, **options):
for service in self.get_services(service_names):
@@ -101,6 +93,13 @@ class Project(object):
for service in self.get_services(service_names):
service.kill(**options)
def build(self, service_names=None, **options):
for service in self.get_services(service_names):
if service.can_be_built():
service.build(**options)
else:
log.info('%s uses an image, skipping')
def remove_stopped(self, service_names=None, **options):
for service in self.get_services(service_names):
service.remove_stopped(**options)

View File

@@ -137,7 +137,7 @@ class Service(object):
if 'volumes' in container_options:
container_options['volumes'] = dict((v.split(':')[1], {}) for v in container_options['volumes'])
if 'build' in self.options:
if self.can_be_built():
if len(self.client.images(name=self._build_tag_name())) == 0:
self.build()
container_options['image'] = self._build_tag_name()
@@ -167,6 +167,9 @@ class Service(object):
return image_id
def can_be_built(self):
return 'build' in self.options
def _build_tag_name(self):
"""
The tag to give to images built for this service.

View File

@@ -24,14 +24,10 @@ def find_version(*file_paths):
with open('requirements.txt') as f:
install_requires = f.read().splitlines()
with open('README.md') as f:
long_description = f.read()
setup(
name='fig',
version=find_version("fig", "__init__.py"),
description='Punctual, lightweight development environments using Docker',
long_description=long_description,
url='https://github.com/orchardup/fig',
author='Orchard Laboratories Ltd.',
author_email='hello@orchardup.com',

View File

@@ -1,11 +1,10 @@
from fig.project import Project
from fig.service import Service
from .testcases import DockerClientTestCase
class ProjectTest(DockerClientTestCase):
def test_from_dict(self):
project = Project.from_dicts('test', [
project = Project.from_dicts('figtest', [
{
'name': 'web',
'image': 'ubuntu'
@@ -22,7 +21,7 @@ class ProjectTest(DockerClientTestCase):
self.assertEqual(project.get_service('db').options['image'], 'ubuntu')
def test_from_dict_sorts_in_dependency_order(self):
project = Project.from_dicts('test', [
project = Project.from_dicts('figtest', [
{
'name': 'web',
'image': 'ubuntu',
@@ -47,53 +46,18 @@ class ProjectTest(DockerClientTestCase):
db = self.create_service('db')
project = Project('test', [web, db], self.client)
unstarted = project.create_containers(service_names=['web'])
self.assertEqual(len(unstarted), 1)
self.assertEqual(unstarted[0][0], web)
project.create_containers(service_names=['web'])
self.assertEqual(len(web.containers(stopped=True)), 1)
self.assertEqual(len(db.containers(stopped=True)), 0)
unstarted = project.create_containers()
self.assertEqual(len(unstarted), 2)
self.assertEqual(unstarted[0][0], web)
self.assertEqual(unstarted[1][0], db)
self.assertEqual(len(web.containers(stopped=True)), 2)
project.create_containers()
self.assertEqual(len(web.containers(stopped=True)), 1)
self.assertEqual(len(db.containers(stopped=True)), 1)
def test_up(self):
web = self.create_service('web')
db = self.create_service('db')
other = self.create_service('other')
project = Project('test', [web, db, other], self.client)
web.create_container()
self.assertEqual(len(web.containers()), 0)
self.assertEqual(len(db.containers()), 0)
self.assertEqual(len(web.containers(stopped=True)), 1)
self.assertEqual(len(db.containers(stopped=True)), 0)
unstarted = project.create_containers(service_names=['web', 'db'])
self.assertEqual(len(unstarted), 2)
self.assertEqual(unstarted[0][0], web)
self.assertEqual(unstarted[1][0], db)
self.assertEqual(len(web.containers()), 0)
self.assertEqual(len(db.containers()), 0)
self.assertEqual(len(web.containers(stopped=True)), 2)
self.assertEqual(len(db.containers(stopped=True)), 1)
project.kill_and_remove(unstarted)
self.assertEqual(len(web.containers()), 0)
self.assertEqual(len(db.containers()), 0)
self.assertEqual(len(web.containers(stopped=True)), 1)
self.assertEqual(len(db.containers(stopped=True)), 0)
def test_start_stop_kill_remove(self):
web = self.create_service('web')
db = self.create_service('db')
project = Project('test', [web, db], self.client)
project = Project('figtest', [web, db], self.client)
project.start()

View File

@@ -29,7 +29,7 @@ class ServiceTest(DockerClientTestCase):
foo.start_container()
self.assertEqual(len(foo.containers()), 1)
self.assertEqual(foo.containers()[0].name, 'default_foo_1')
self.assertEqual(foo.containers()[0].name, 'figtest_foo_1')
self.assertEqual(len(bar.containers()), 0)
bar.start_container()
@@ -39,8 +39,8 @@ class ServiceTest(DockerClientTestCase):
self.assertEqual(len(bar.containers()), 2)
names = [c.name for c in bar.containers()]
self.assertIn('default_bar_1', names)
self.assertIn('default_bar_2', names)
self.assertIn('figtest_bar_1', names)
self.assertIn('figtest_bar_2', names)
def test_containers_one_off(self):
db = self.create_service('db')
@@ -49,9 +49,9 @@ class ServiceTest(DockerClientTestCase):
self.assertEqual(db.containers(one_off=True, stopped=True), [container])
def test_project_is_added_to_container_name(self):
service = self.create_service('web', project='myproject')
service = self.create_service('web')
service.start_container()
self.assertEqual(service.containers()[0].name, 'myproject_web_1')
self.assertEqual(service.containers()[0].name, 'figtest_web_1')
def test_start_stop(self):
service = self.create_service('scalingtest')
@@ -92,13 +92,13 @@ class ServiceTest(DockerClientTestCase):
def test_create_container_with_one_off(self):
db = self.create_service('db')
container = db.create_container(one_off=True)
self.assertEqual(container.name, 'default_db_run_1')
self.assertEqual(container.name, 'figtest_db_run_1')
def test_create_container_with_one_off_when_existing_container_is_running(self):
db = self.create_service('db')
db.start()
container = db.create_container(one_off=True)
self.assertEqual(container.name, 'default_db_run_1')
self.assertEqual(container.name, 'figtest_db_run_1')
def test_start_container_passes_through_options(self):
db = self.create_service('db')
@@ -115,7 +115,7 @@ class ServiceTest(DockerClientTestCase):
web = self.create_service('web', links=[db])
db.start_container()
web.start_container()
self.assertIn('default_db_1', web.containers()[0].links())
self.assertIn('figtest_db_1', web.containers()[0].links())
db.stop(timeout=1)
web.stop(timeout=1)
@@ -124,18 +124,20 @@ class ServiceTest(DockerClientTestCase):
name='test',
client=self.client,
build='tests/fixtures/simple-dockerfile',
project='figtest',
)
container = service.start_container()
container.wait()
self.assertIn('success', container.logs())
self.assertEqual(len(self.client.images(name='default_test')), 1)
self.assertEqual(len(self.client.images(name='figtest_test')), 1)
def test_start_container_uses_tagged_image_if_it_exists(self):
self.client.build('tests/fixtures/simple-dockerfile', tag='default_test')
self.client.build('tests/fixtures/simple-dockerfile', tag='figtest_test')
service = Service(
name='test',
client=self.client,
build='this/does/not/exist/and/will/throw/error',
project='figtest',
)
container = service.start_container()
container.wait()

View File

@@ -1,25 +1,24 @@
from docker import Client
from fig.service import Service
import os
from fig.cli.utils import docker_url
from unittest import TestCase
class DockerClientTestCase(TestCase):
@classmethod
def setUpClass(cls):
if os.environ.get('DOCKER_URL'):
cls.client = Client(os.environ['DOCKER_URL'])
else:
cls.client = Client()
cls.client = Client(docker_url())
cls.client.pull('ubuntu')
def setUp(self):
for c in self.client.containers(all=True):
self.client.kill(c['Id'])
self.client.remove_container(c['Id'])
if c['Names'] and 'figtest' in c['Names'][0]:
self.client.kill(c['Id'])
self.client.remove_container(c['Id'])
def create_service(self, name, **kwargs):
return Service(
project='figtest',
name=name,
client=self.client,
image="ubuntu",