dockistrano 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +101 -0
- data/Rakefile +1 -0
- data/bin/doc +13 -0
- data/bin/docker +0 -0
- data/dockistrano.gemspec +32 -0
- data/lib/dockistrano/cli.rb +220 -0
- data/lib/dockistrano/command_line.rb +28 -0
- data/lib/dockistrano/docker.rb +188 -0
- data/lib/dockistrano/git.rb +27 -0
- data/lib/dockistrano/hipache.rb +62 -0
- data/lib/dockistrano/registry.rb +48 -0
- data/lib/dockistrano/service.rb +331 -0
- data/lib/dockistrano/service_dependency.rb +114 -0
- data/lib/dockistrano/version.rb +3 -0
- data/lib/dockistrano.rb +14 -0
- data/spec/dockistrano/cli_spec.rb +296 -0
- data/spec/dockistrano/command_line_spec.rb +27 -0
- data/spec/dockistrano/docker_spec.rb +242 -0
- data/spec/dockistrano/git_spec.rb +48 -0
- data/spec/dockistrano/hipache_spec.rb +81 -0
- data/spec/dockistrano/registry_spec.rb +56 -0
- data/spec/dockistrano/service_dependency_spec.rb +154 -0
- data/spec/dockistrano/service_spec.rb +536 -0
- data/spec/fixtures/project_1/Dockerfile +0 -0
- data/spec/fixtures/project_1/config/dockistrano.yml +8 -0
- data/spec/spec_helper.rb +21 -0
- metadata +242 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 031a5bef368643972d84782c3fe8aec9f9a83cdc
|
4
|
+
data.tar.gz: d2f202905234e891b5a2ad5c07b453365d9aec1c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d60c0c8983b6c70f78dca0a130f7db92fd0613117b11e3bb2859eb8b00dd9bfa1df6a81d8f9660978fdeeee7748974adffc60c8e45a2fd098b28d4b3f5501c8a
|
7
|
+
data.tar.gz: a341da5a23a8f8cadaed99e1d1febf57f69a5922c497b8732a1d4eb21651c7c425446a129245a77197428a9ade403f49b97dc5b7d5b77dad15b03ee346416b84
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Edwin Vlieg
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# Dockistrano
|
2
|
+
|
3
|
+
Dockistrano uses docker to create a development and testing environment for applications. It is inspired by Capistrano, because booting a container should be as easy as doing a `cap deploy`. The approach has a lot of conventions and as little as configuration as possible.
|
4
|
+
|
5
|
+
## Current status
|
6
|
+
|
7
|
+
Dockistrano is actively used for software development at [MoneyBird](http://www.moneybird.com), but is still very immature. Feel free to play around and provide us feedback. A pull request with tested code is the best way to help us improve the software!
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'dockistrano'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install dockistrano
|
22
|
+
|
23
|
+
## Preparing your application
|
24
|
+
|
25
|
+
To use Dockistrano for your application, two files should be created:
|
26
|
+
|
27
|
+
### `Dockerfile`
|
28
|
+
|
29
|
+
The `Dockerfile` describes the container that is created for the application and should contain all dependencies. Example:
|
30
|
+
|
31
|
+
```
|
32
|
+
FROM ubuntu
|
33
|
+
RUN apt-get update
|
34
|
+
RUN apt-get install mydependency
|
35
|
+
ADD ./ ./
|
36
|
+
EXPOSE 8000
|
37
|
+
CMD ["webserver", "start"]
|
38
|
+
```
|
39
|
+
|
40
|
+
For more information about writing Dockerfiles, see [the documentation on docker.io](http://docs.docker.io/en/latest/use/builder/).
|
41
|
+
|
42
|
+
### `config/dockistrano.yml`
|
43
|
+
|
44
|
+
The configuration file contains information about the registry, dependencies, ports and environment variables.
|
45
|
+
|
46
|
+
```
|
47
|
+
---
|
48
|
+
registry: my.privateregistry.com:5000
|
49
|
+
dependencies:
|
50
|
+
postgresql:
|
51
|
+
database: "my_databasename"
|
52
|
+
redis:
|
53
|
+
environment:
|
54
|
+
rails_env: development
|
55
|
+
```
|
56
|
+
|
57
|
+
## Usage
|
58
|
+
|
59
|
+
Dockistrano provides a range of commands to create containers and run commands in containers:
|
60
|
+
|
61
|
+
### `doc build`
|
62
|
+
|
63
|
+
Builds the current container by using the `Dockerfile`. The resulting container will be tagged with the registry name, name of the image and tag of the current git branch.
|
64
|
+
|
65
|
+
When building is successfull, the container will be tested by running the `test_command` provided in the config. When tests are successfull, the container is pushes to the registry.
|
66
|
+
|
67
|
+
### `doc start` and `doc start-services`
|
68
|
+
|
69
|
+
Starts the container by running the default command. Environment variables from dependencies are automatically added to the run command. Optionally the backing services can be started seperatly with `doc start-services`
|
70
|
+
|
71
|
+
### `doc stop` and `doc stop-all`
|
72
|
+
|
73
|
+
Stops the current container or stops all containers, including the backing services.
|
74
|
+
|
75
|
+
### `doc logs [NAME]`
|
76
|
+
|
77
|
+
Prints logs for the container or for a backing service when a name of the service is provided. When the container is running a `docker attach` is used, otherwise a `docker logs`.
|
78
|
+
|
79
|
+
### `doc exec COMMAND`
|
80
|
+
|
81
|
+
Executes the command in the container, printing the result in the console.
|
82
|
+
|
83
|
+
### `doc console [CONSOLE]`
|
84
|
+
|
85
|
+
Starts a console in the container, by default /bin/bash is started. Optionally a console can be provided, for example `doc console rails console` to start a Rails console.
|
86
|
+
|
87
|
+
### `doc ps`
|
88
|
+
|
89
|
+
Prints all running processes on Docker
|
90
|
+
|
91
|
+
### `doc clean`
|
92
|
+
|
93
|
+
Cleans unused containers and images from Docker
|
94
|
+
|
95
|
+
### `doc status`
|
96
|
+
|
97
|
+
Prints information about the current container and lists environment variables that are provided to the container when started.
|
98
|
+
|
99
|
+
### `doc pull`
|
100
|
+
|
101
|
+
Pulls new versions of containers from the registry
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/doc
ADDED
data/bin/docker
ADDED
Binary file
|
data/dockistrano.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dockistrano/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dockistrano"
|
8
|
+
spec.version = Dockistrano::VERSION
|
9
|
+
spec.authors = ["Edwin Vlieg"]
|
10
|
+
spec.email = ["edwin@moneybird.com"]
|
11
|
+
spec.summary = %q{Manage Docker containers for a development workflow}
|
12
|
+
spec.homepage = "http://github.com/moneybird/dockistrano"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "thor"
|
21
|
+
spec.add_dependency "cocaine"
|
22
|
+
spec.add_dependency "multi_json"
|
23
|
+
spec.add_dependency "redis"
|
24
|
+
spec.add_dependency "dotenv"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "guard"
|
29
|
+
spec.add_development_dependency "guard-rspec"
|
30
|
+
spec.add_development_dependency "terminal-notifier-guard"
|
31
|
+
spec.add_development_dependency "webmock"
|
32
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require "dotenv"
|
3
|
+
Dotenv.load(".dockistrano")
|
4
|
+
ENV["DOCKISTRANO_ENVIRONMENT"] ||= "default"
|
5
|
+
ENV["DOCKER_HOST_IP"] ||= "127.0.0.1"
|
6
|
+
ENV["DOCKER_BINARY"] ||= begin
|
7
|
+
if RUBY_PLATFORM =~ /darwin|mac os/
|
8
|
+
bin_dir = File.expand_path(File.dirname(__FILE__) + "/../../bin")
|
9
|
+
"#{bin_dir}/docker"
|
10
|
+
else
|
11
|
+
"docker"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Dockistrano
|
16
|
+
|
17
|
+
class Cli < ::Thor
|
18
|
+
|
19
|
+
desc "ps", "List all running containers in docker"
|
20
|
+
def ps
|
21
|
+
puts Docker.ps
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "setup", "Sets up a host for starting the application"
|
25
|
+
method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
|
26
|
+
def setup
|
27
|
+
say "Please execute the following command on the host to setup", :green
|
28
|
+
say "\tmkdir -p #{current_service.directories_required_on_host.join(" ")}"
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "status", "Status of the application"
|
32
|
+
method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
|
33
|
+
def status
|
34
|
+
say "DOCKISTRANO_ENVIRONMENT: #{options["environment"]}", :green
|
35
|
+
say "DOCKER_HOST_IP: #{ENV['DOCKER_HOST_IP']}", :green
|
36
|
+
say "DOCKER_BINARY: #{ENV['DOCKER_BINARY']}", :green
|
37
|
+
say ""
|
38
|
+
say "Current application", :blue
|
39
|
+
say " registry: #{current_service.registry}"
|
40
|
+
say " image name: #{current_service.image_name}"
|
41
|
+
say " tag: #{current_service.tag}"
|
42
|
+
say " volumes:"
|
43
|
+
current_service.volumes.each do |volume|
|
44
|
+
say " #{volume}"
|
45
|
+
end
|
46
|
+
say ""
|
47
|
+
say "Dependencies", :blue
|
48
|
+
current_service.backing_services.each do |name, service|
|
49
|
+
say " #{service.full_image_name}"
|
50
|
+
end
|
51
|
+
say ""
|
52
|
+
say "Environment", :blue
|
53
|
+
current_service.environment_variables.each do |key, value|
|
54
|
+
say " #{key}=#{value}"
|
55
|
+
end
|
56
|
+
say ""
|
57
|
+
say "Hipache", :blue
|
58
|
+
Hipache.new(ENV["DOCKER_HOST_IP"]).status.each do |host, ips|
|
59
|
+
say " #{host}: #{ips.join(", ")}"
|
60
|
+
end
|
61
|
+
say ""
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "build", "Build and test a new application container"
|
65
|
+
def build
|
66
|
+
if current_service.build
|
67
|
+
say_status "built", current_service.image_name
|
68
|
+
if current_service.test
|
69
|
+
say_status "tests passed", current_service.image_name
|
70
|
+
current_service.push
|
71
|
+
say_status "pushed", current_service.image_name
|
72
|
+
else
|
73
|
+
say_status "tests failed", current_service.image_name
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
else
|
77
|
+
say_status "failed", current_service.image_name, :red
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "pull", "Pull new versions of dependencies"
|
83
|
+
def pull
|
84
|
+
current_service.backing_services.each do |name, service|
|
85
|
+
if service.newer_version_available?
|
86
|
+
service.pull
|
87
|
+
say_status "Pulled", name
|
88
|
+
else
|
89
|
+
say_status "Uptodate", name, :white
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if current_service.newer_version_available?
|
94
|
+
current_service.pull
|
95
|
+
say_status "Pulled", current_service.image_name
|
96
|
+
else
|
97
|
+
say_status "Uptodate", current_service.image_name, :white
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
desc "push", "Pushes a new version of this container"
|
102
|
+
def push
|
103
|
+
current_service.push
|
104
|
+
end
|
105
|
+
|
106
|
+
desc "start-services", "Starts the backing services"
|
107
|
+
method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
|
108
|
+
def start_services
|
109
|
+
current_service.backing_services.each do |name, service|
|
110
|
+
if service.running?
|
111
|
+
say_status("Running", name, :white)
|
112
|
+
else
|
113
|
+
service.start
|
114
|
+
say_status("Started", name)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
desc "stop-all", "Stops the backing services"
|
120
|
+
def stop_all
|
121
|
+
current_service.stop
|
122
|
+
say_status("Stopped", current_service.image_name)
|
123
|
+
current_service.backing_services.each do |name, service|
|
124
|
+
if service.running?
|
125
|
+
service.stop
|
126
|
+
say_status("Stopped", name)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
desc "start", "Starts the application"
|
132
|
+
method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
|
133
|
+
def start
|
134
|
+
if current_service.running?
|
135
|
+
say_status("Running", current_service.image_name, :white)
|
136
|
+
else
|
137
|
+
current_service.start(options)
|
138
|
+
say_status("Started", current_service.image_name)
|
139
|
+
end
|
140
|
+
rescue Dockistrano::Service::EnvironmentVariablesMissing => e
|
141
|
+
say e.message, :red
|
142
|
+
end
|
143
|
+
|
144
|
+
desc "stop [ID]", "Stops the application or container with specified ID"
|
145
|
+
def stop(id=nil)
|
146
|
+
if id
|
147
|
+
Docker.stop(id)
|
148
|
+
say_status("Stopped", id, :green)
|
149
|
+
else
|
150
|
+
current_service.stop
|
151
|
+
say_status("Stopped", current_service.image_name, :green)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
desc "restart", "Restarts the application"
|
156
|
+
method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
|
157
|
+
def restart
|
158
|
+
current_service.stop
|
159
|
+
say_status("Stopped", current_service.image_name)
|
160
|
+
current_service.start(options)
|
161
|
+
say_status("Started", current_service.image_name)
|
162
|
+
end
|
163
|
+
|
164
|
+
desc "exec COMMAND", "Executes a command in the application and returns"
|
165
|
+
method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
|
166
|
+
def exec(*command)
|
167
|
+
current_service.exec(command.join(" "), options)
|
168
|
+
rescue Dockistrano::Service::EnvironmentVariablesMissing => e
|
169
|
+
say e.message, :red
|
170
|
+
end
|
171
|
+
|
172
|
+
desc "console [COMMAND]", "Starts an interactive shell in the application"
|
173
|
+
method_option "environment", aliases: "-e", default: ENV["DOCKISTRANO_ENVIRONMENT"], type: :string, desc: "Environment to start the container in"
|
174
|
+
def console(*command)
|
175
|
+
command = ["/bin/bash"] if command.empty?
|
176
|
+
current_service.console(command.join(" "), options)
|
177
|
+
rescue Dockistrano::Service::EnvironmentVariablesMissing => e
|
178
|
+
say e.message, :red
|
179
|
+
end
|
180
|
+
|
181
|
+
desc "clean", "Cleans images and containers from docker"
|
182
|
+
def clean
|
183
|
+
Docker.clean
|
184
|
+
Dockistrano::ServiceDependency.clear_cache
|
185
|
+
end
|
186
|
+
|
187
|
+
desc "logs [NAME]", "Prints the logs for the service"
|
188
|
+
def logs(name=nil)
|
189
|
+
service = name ? current_service.backing_services[name] : current_service
|
190
|
+
if service.running?
|
191
|
+
say "Container #{service.image_name} running, attaching to output", :blue
|
192
|
+
service.attach
|
193
|
+
else
|
194
|
+
say "Container #{service.image_name} stopped, printing logs of last run", :blue
|
195
|
+
service.logs
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def method_missing(*args)
|
200
|
+
command = args[0]
|
201
|
+
if command and current_service.config["aliases"] and current_service.config["aliases"][command.to_s]
|
202
|
+
args.shift
|
203
|
+
Kernel.exec("doc #{current_service.config["aliases"][command.to_s]} #{args.join(" ")}")
|
204
|
+
else
|
205
|
+
super
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
# Returns the current service
|
212
|
+
def current_service
|
213
|
+
@service ||= Service.factory(Dir.pwd, options["environment"])
|
214
|
+
rescue Dockistrano::Service::ConfigurationFileMissing
|
215
|
+
say "No configuration file found in current directory. config/dockistrano.yml missing", :red
|
216
|
+
exit 1
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Dockistrano
|
2
|
+
|
3
|
+
class CommandLine
|
4
|
+
|
5
|
+
def self.command_with_result(command)
|
6
|
+
debug(command)
|
7
|
+
`#{command}`
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.command_with_stream(command)
|
11
|
+
debug(command)
|
12
|
+
begin
|
13
|
+
Kernel.system(command)
|
14
|
+
rescue Interrupt
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.command_with_interaction(command)
|
19
|
+
debug(command)
|
20
|
+
Kernel.exec(command)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.debug(command)
|
24
|
+
puts "$ #{command}" if false
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'cocaine'
|
2
|
+
require 'multi_json'
|
3
|
+
|
4
|
+
module Dockistrano
|
5
|
+
|
6
|
+
# Class for communication with Docker. Uses two means of communication:
|
7
|
+
#
|
8
|
+
# - Actions on containers are executed by calling the docker binary with an
|
9
|
+
# ip address of the Docker location. The docker command line client is best
|
10
|
+
# capable of executing the actions for building images, running containers and
|
11
|
+
# managing containers.
|
12
|
+
# - Queries are executed using the HTTP API of docker. This API is exposed via HTTP
|
13
|
+
# and returns JSON. This allows us to easily parse and return the information.
|
14
|
+
#
|
15
|
+
# This class uses two environment variables:
|
16
|
+
#
|
17
|
+
# DOCKER_BINARY - Location of the docker binary on your system
|
18
|
+
# DOCKER_HOST_IP - IP address or host of the docker server
|
19
|
+
#
|
20
|
+
class Docker
|
21
|
+
|
22
|
+
class EnvironmentVariableMissing < StandardError
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the docker command as a string: 'docker -H 127.0.0.1'
|
26
|
+
def self.docker_command
|
27
|
+
raise EnvironmentVariableMissing.new("Missing DOCKER_BINARY in environment, please provide the location of the docker binary") unless ENV["DOCKER_BINARY"]
|
28
|
+
raise EnvironmentVariableMissing.new("Missing DOCKER_HOST_IP in environment, please provide the host or ip address of the docker server") unless ENV["DOCKER_HOST_IP"]
|
29
|
+
"#{ENV['DOCKER_BINARY']} -H #{ENV['DOCKER_HOST_IP']}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Executes the given command on the command line
|
33
|
+
def self.execute(command, mode=:string_result)
|
34
|
+
case mode
|
35
|
+
when :string_result
|
36
|
+
Dockistrano::CommandLine.command_with_result("#{docker_command} #{command.collect { |c| c.kind_of?(String) ? c : arguments(c) }.join(" ")}".strip)
|
37
|
+
when :stream
|
38
|
+
Dockistrano::CommandLine.command_with_stream("#{docker_command} #{command.collect { |c| c.kind_of?(String) ? c : arguments(c) }.join(" ")}".strip)
|
39
|
+
else
|
40
|
+
Dockistrano::CommandLine.command_with_interaction("#{docker_command} #{command.collect { |c| c.kind_of?(String) ? c : arguments(c) }.join(" ")}".strip)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.ps(options={})
|
45
|
+
execute(["ps", options])
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.stop(id)
|
49
|
+
execute(["stop", id])
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.run(full_image_name, options={})
|
53
|
+
if (command = options.delete(:command))
|
54
|
+
execute(["run", options, full_image_name, command])
|
55
|
+
else
|
56
|
+
execute(["run", options, full_image_name])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.exec(full_image_name, options={})
|
61
|
+
if (command = options.delete(:command))
|
62
|
+
execute(["run", options, full_image_name, command], :stream)
|
63
|
+
else
|
64
|
+
execute(["run", options, full_image_name], :stream)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.console(full_image_name, options={})
|
69
|
+
options["t"] = true
|
70
|
+
options["i"] = true
|
71
|
+
if (command = options.delete(:command))
|
72
|
+
execute(["run", options, full_image_name, command], :interaction)
|
73
|
+
else
|
74
|
+
execute(["run", options, full_image_name], :interaction)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.build(full_image_name)
|
79
|
+
execute(["build", { t: full_image_name }, "."], :stream)
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.pull(full_image_name, tag)
|
83
|
+
execute(["pull", { t: tag }, full_image_name])
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.push(image_name, tag)
|
87
|
+
execute(["push", image_name, tag], :stream)
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.logs(id)
|
91
|
+
execute(["logs", id], :stream)
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.attach(id)
|
95
|
+
execute(["attach", id], :stream)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.clean
|
99
|
+
Dockistrano::CommandLine.command_with_stream("#{docker_command} rmi $(#{docker_command} images -a | grep \"^<none>\" | awk '{print $3}')")
|
100
|
+
Dockistrano::CommandLine.command_with_stream("#{docker_command} rm $(#{docker_command} ps -a -q)")
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.running_container_id(full_image_name)
|
104
|
+
request(["containers", "json"]).each do |container|
|
105
|
+
return container["Id"] if container["Image"] == full_image_name
|
106
|
+
end
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns the id of the last container with an error
|
111
|
+
def self.last_run_container_id(full_image_name)
|
112
|
+
request(["containers", "json?all=1"]).each do |container|
|
113
|
+
return container["Id"] if container["Image"] == full_image_name and container["Command"] != "cat /dockistrano.yml"
|
114
|
+
end
|
115
|
+
nil
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.image_id(full_image_name)
|
119
|
+
inspect_image(full_image_name)["id"]
|
120
|
+
end
|
121
|
+
|
122
|
+
class ImageNotFound < StandardError
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.inspect_image(full_image_name)
|
126
|
+
response = request(["images", full_image_name, "json"])
|
127
|
+
rescue ResourceNotFound => e
|
128
|
+
raise ImageNotFound.new(e.message)
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.inspect_container(id)
|
132
|
+
request(["containers", id, "json"])
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.stop_all_containers_from_image(full_image_name)
|
136
|
+
containers = request(["containers", "json"])
|
137
|
+
containers.each do |container|
|
138
|
+
execute(["stop", container["Id"]]) if container["Image"] == full_image_name
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.tags_for_image(image_name)
|
143
|
+
images = request(["images", "json"])
|
144
|
+
[].tap do |tags|
|
145
|
+
images.each do |image|
|
146
|
+
tags << image["Tag"] if image["Repository"] == image_name
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def self.request(path)
|
154
|
+
uri = URI.parse("http://#{ENV['DOCKER_HOST_IP']}:4243/#{path.join("/")}")
|
155
|
+
response = Net::HTTP.get_response(uri)
|
156
|
+
if response.kind_of?(Net::HTTPNotFound)
|
157
|
+
raise ResourceNotFound.new("Could not find #{path.join("/")}: #{response.body}")
|
158
|
+
end
|
159
|
+
|
160
|
+
MultiJson.load(response.body)
|
161
|
+
end
|
162
|
+
|
163
|
+
class ResourceNotFound < StandardError
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.arguments(options)
|
167
|
+
options.collect do |k,v|
|
168
|
+
case v
|
169
|
+
when TrueClass
|
170
|
+
"-#{k}"
|
171
|
+
when Array
|
172
|
+
v.collect { |av| "-#{k} #{av}" }.join(" ").strip
|
173
|
+
when Hash
|
174
|
+
v.collect { |ak, av|
|
175
|
+
if av
|
176
|
+
"-#{k} #{ak}='#{av}'"
|
177
|
+
else
|
178
|
+
""
|
179
|
+
end
|
180
|
+
}.join(" ").strip
|
181
|
+
else
|
182
|
+
"-#{k} #{v}"
|
183
|
+
end
|
184
|
+
end.join(" ").strip
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Dockistrano
|
2
|
+
|
3
|
+
class Git
|
4
|
+
|
5
|
+
def self.repository_name
|
6
|
+
git_url = Cocaine::CommandLine.new("git config --get remote.origin.url").run.strip
|
7
|
+
|
8
|
+
if git_url =~ /^[A-z0-9]+@[A-z0-9.:\-]+\/([A-z0-9\-_\.]+)(\.git)?$/
|
9
|
+
$1.gsub(/\.git$/, "")
|
10
|
+
elsif git_url =~ /^https?:\/\/[a-z\-\.]+\/[a-z\-\.]+\/([A-z0-9.\-\_]+)$/
|
11
|
+
$1
|
12
|
+
else
|
13
|
+
raise "Unknown git url '#{git_url}'"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.branch
|
18
|
+
if ENV['JANKY_BRANCH']
|
19
|
+
ENV['JANKY_BRANCH'].gsub("/", "-")
|
20
|
+
else
|
21
|
+
branch = Cocaine::CommandLine.new("git rev-parse --abbrev-ref HEAD").run.strip
|
22
|
+
branch.gsub("/", "-")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|