baha 0.0.1 → 0.1.0
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 +8 -8
- data/.travis.yml +4 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -0
- data/README.md +75 -17
- data/baha.gemspec +4 -3
- data/example/example.yml +5 -0
- data/example/memcached/Dockerfile +24 -0
- data/lib/baha/builder.rb +29 -2
- data/lib/baha/cli.rb +53 -0
- data/lib/baha/config.rb +13 -0
- data/lib/baha/container_options/exposed_ports.rb +6 -2
- data/lib/baha/dockerfile.rb +150 -0
- data/lib/baha/image.rb +2 -1
- data/lib/baha/version.rb +1 -1
- data/spec/builder_spec.rb +15 -2
- data/spec/config_spec.rb +17 -1
- data/spec/dockerfile_spec.rb +38 -0
- data/spec/fixtures/Dockerfile +33 -0
- data/spec/fixtures/Dockerfile.invalid +4 -0
- data/spec/fixtures/config_build.yml +4 -1
- data/spec/fixtures/config_build_image.yml +3 -1
- data/spec/fixtures/config_dockerfile.yml +9 -0
- data/spec/fixtures/config_eachimage.yml +7 -1
- data/spec/spec_helper.rb +14 -0
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YTUxODZmMWUzYTBhNzI5YTIzZWU0NjAwNzUyMjRiMTMzY2VjNjkyOA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MzU1Nzg5YjQ3Y2RiNzMwYTIzMmU2ZTQ5ZjQ5ZmVmMDMxNWQ0ZDIwZA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NGZiYmFmMTY5ZGRmNDQ1MGJkMzIzMmYyYmIyYjAwZjJkZGY3ZTg5OTExN2Rh
|
10
|
+
NzRkZjY0MDI3NmQ5MTU2NTg1MjUwMmYwN2ZmNjFiY2RlOWEzMDk4NTJlMmI0
|
11
|
+
YjZkMjJlYTJiYTk0ZTk1ODI5M2JmNjMyYzQ3OTczZmQ3YTM5NGM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YWYzZmFlNjMzMjZkOTgzNjA2N2JhZjNiNTQ4MjRjZTBhNzg1OTFhMzJjZmEw
|
14
|
+
MTg1NjYzZjVkNWUwZWI2ZjUxZDU4ZjM1Yzk2MmQ1ZmM5NTkzZDk4ZTIyNDI0
|
15
|
+
NDY0ZDE3ZTQyZDRiMzhiYjg2MTcyYWM0YTNkM2Y5YmQ3YmZiYzc=
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,12 +3,13 @@ Baha
|
|
3
3
|
|
4
4
|
[](http://badge.fury.io/rb/baha)
|
5
5
|
[](https://travis-ci.org/justenwalker/baha)
|
6
|
+
[](https://codeclimate.com/github/justenwalker/baha)
|
6
7
|
|
7
8
|
Introduction
|
8
9
|
------------
|
9
10
|
|
10
11
|
Baha is a command-line utility that assists in the creation of docker images.
|
11
|
-
It addresses some of
|
12
|
+
It addresses some of Dockerfiles shortcomings and encourages smaller, reusable, tagged images.
|
12
13
|
|
13
14
|
Why not Dockerfiles?
|
14
15
|
--------------------
|
@@ -18,9 +19,11 @@ Dockerfiles are simple. They are an easy way to make a docker image without need
|
|
18
19
|
So why would I use Baha?
|
19
20
|
------------------------
|
20
21
|
|
22
|
+
Baha attempts to address the shortcomings of Dockerfiles by factoring out redundancies and providing a modular interface for creating suites of dependent images.
|
23
|
+
|
21
24
|
### 1. Baha forbids more than 1 layer per image
|
22
25
|
|
23
|
-
If you split statements across multiple RUN statements, each of these results in a new layer.
|
26
|
+
If you split statements across multiple `RUN` statements, each of these results in a new layer.
|
24
27
|
The more commands you run, the more layers you create. If you want to *minimize the number of layers* (See [Official Recommendations](https://docs.docker.com/articles/dockerfile_best-practices/))
|
25
28
|
then you must ensure that all statements can be condensed into one line - sacrificing maintainability in the process.
|
26
29
|
|
@@ -30,25 +33,25 @@ Baha encourages using scripts instead of `RUN` statements to ensure that only on
|
|
30
33
|
|
31
34
|
The nature of the way the dockerfiles are processed means that each command you run commits a new image.
|
32
35
|
This means, that if you have a `RUN` statement that downloads packages for installation.
|
33
|
-
This will commit a layer with the installation files. Later on if you clean up these files with further RUN commands, they will still exist in your image lineage - thus having no space savings. Without proper precautions, you'll end up having unnecessarily large images.
|
36
|
+
This will commit a layer with the installation files. Later on if you clean up these files with further `RUN` commands, they will still exist in your image lineage - thus having no space savings. Without proper precautions, you'll end up having unnecessarily large images.
|
34
37
|
|
35
38
|
Baha ensures that all setup tasks happen in a single commit - so you can write cleanup statements and be assured that they will indeed be absent in the resulting images.
|
36
39
|
|
37
40
|
### 3. Baha understands the bigger picture
|
38
41
|
|
39
|
-
Another best practice (2
|
42
|
+
Another best practice ([2](http://crosbymichael.com/dockerfile-best-practices-take-2.html): #7) recommends that you use your own base image.
|
40
43
|
Dockerfiles make it simple to create your own 'base' image, but how about updates?
|
41
44
|
|
42
45
|
If you were to just rebuild all of your Dockerfiles, you would create an entirely new tree - even if nothing changed.
|
43
46
|
|
44
|
-
Baha will rebuild your entire lineage if the base
|
47
|
+
Baha will rebuild your entire lineage if the base image changes, but will not rebuild base images if only the children change.
|
45
48
|
|
46
|
-
**Caveat
|
49
|
+
**Caveat**
|
47
50
|
|
48
51
|
Baha relies on tagging your releases, noticing when the tag has changed, and treating tags as immutable.
|
49
52
|
This is analogous to how **git** treats tags.
|
50
53
|
|
51
|
-
Tagging your images is another best-practice (2
|
54
|
+
Tagging your images is another best-practice ([2](http://crosbymichael.com/dockerfile-best-practices-take-2.html): #5) anyway, so this is encouraged by design.
|
52
55
|
|
53
56
|
Bottom line is: If you change your image, you should change the tag/version.
|
54
57
|
|
@@ -62,8 +65,8 @@ This workspace is made available to the image via a bind mount during build-time
|
|
62
65
|
|
63
66
|
**References**
|
64
67
|
|
65
|
-
1. [Official Dockerfile Best Practices](https://docs.docker.com/articles/dockerfile_best-practices/)
|
66
|
-
2. [Dockerfile Best Practices - take 2, by Michael Crosby](http://crosbymichael.com/dockerfile-best-practices-take-2.html)
|
68
|
+
1. [Official Dockerfile Best Practices](https://docs.docker.com/articles/dockerfile_best-practices/)
|
69
|
+
2. [Dockerfile Best Practices - take 2, by Michael Crosby](http://crosbymichael.com/dockerfile-best-practices-take-2.html)
|
67
70
|
|
68
71
|
Disclaimer
|
69
72
|
----------
|
@@ -83,16 +86,16 @@ Installation
|
|
83
86
|
```
|
84
87
|
$ gem install baha
|
85
88
|
```
|
86
|
-
### gem install baha
|
87
89
|
|
88
90
|
Usage
|
89
91
|
-----
|
90
92
|
|
91
93
|
```
|
92
94
|
Baha Commands:
|
93
|
-
baha build [options] CONFIG
|
94
|
-
baha
|
95
|
-
baha
|
95
|
+
baha build [options] CONFIG # Builds all docker images based on the given config
|
96
|
+
baha convert DOCKERFILE n, --name=NAME # Converts an existing dockerfile to a Baha-compatible image.yml
|
97
|
+
baha help [COMMAND] # Describe available commands or one specific command
|
98
|
+
baha version # Print version and exit
|
96
99
|
```
|
97
100
|
|
98
101
|
**build**
|
@@ -111,7 +114,50 @@ Description:
|
|
111
114
|
Reads the CONFIG file and builds all of the docker images in the order they appear.
|
112
115
|
```
|
113
116
|
|
114
|
-
|
117
|
+
**convert**
|
118
|
+
|
119
|
+
```
|
120
|
+
Usage:
|
121
|
+
baha convert DOCKERFILE n, --name=NAME
|
122
|
+
|
123
|
+
Options:
|
124
|
+
n, --name=NAME # The target image name
|
125
|
+
t, [--tag=TAG] # The target image tag
|
126
|
+
# Default: latest
|
127
|
+
o, [--output=OUTPUT] # Target output file
|
128
|
+
# Default: STDOUT
|
129
|
+
|
130
|
+
Description:
|
131
|
+
Reads the given Dockerfile and outputs a Baha-compatible image.yml
|
132
|
+
which can be included or embedded within a CONFIG
|
133
|
+
```
|
134
|
+
|
135
|
+
Example
|
136
|
+
-------
|
137
|
+
|
138
|
+
Check out the **example** directory for a sample CONFIG.
|
139
|
+
|
140
|
+
To run the example build
|
141
|
+
|
142
|
+
```
|
143
|
+
### 1.
|
144
|
+
### If necessary (using boot2docker) export the correct environment variables
|
145
|
+
### You can find this by running boot2docker up
|
146
|
+
# export DOCKER_HOST=tcp://192.168.59.103:2376
|
147
|
+
# export DOCKER_CERT_PATH=$HOME/.boot2docker/certs/boot2docker-vm
|
148
|
+
# export DOCKER_TLS_VERIFY=1
|
149
|
+
|
150
|
+
### 2.
|
151
|
+
### Checkout baha
|
152
|
+
git clone https://github.com/justenwalker/baha.git
|
153
|
+
cd baha
|
154
|
+
|
155
|
+
### 3. Install bundle
|
156
|
+
bundle install
|
157
|
+
|
158
|
+
### 4. Run the example.yml
|
159
|
+
bundle exec baha build -d example/example.yml
|
160
|
+
```
|
115
161
|
|
116
162
|
How it works
|
117
163
|
------------
|
@@ -127,13 +173,25 @@ It will build each image in the order they appear by doing the following.
|
|
127
173
|
1. Create the workspace directory if it doesn't exist
|
128
174
|
2. Run any `pre_build` tasks to prepare dependencies
|
129
175
|
|
130
|
-
### Run the
|
176
|
+
### Run the command inside the image
|
131
177
|
1. Creates a new container and runs it with the `command` given
|
132
178
|
2. Commits the container with the run options specified in the images `config` section.
|
133
179
|
|
180
|
+
### Tags the resulting image
|
181
|
+
Adds the appropriate tags to the image as defined in the image config for both the remote registry and local repository.
|
182
|
+
|
134
183
|
How to Contribute
|
135
184
|
-----------------
|
136
185
|
|
186
|
+
Contributions are welcome! Documentation, bug-fixes, patches, or new functionality, or comments/criticism.
|
187
|
+
|
188
|
+
### Code Contributions
|
189
|
+
|
190
|
+
Start by [forking](https://github.com/justenwalker/baha/fork) the github project.
|
191
|
+
Work on a topic branch instead of master (`git checkout -b my-feature`) and submit a pull request when you are done.
|
192
|
+
|
193
|
+
Please add specs to cover the change so that we can avoid regressions and help future commits from breaking existing code.
|
194
|
+
|
137
195
|
### Running the tests
|
138
196
|
|
139
197
|
$ bundle
|
@@ -146,11 +204,11 @@ How to Contribute
|
|
146
204
|
|
147
205
|
### Reporting Issues
|
148
206
|
|
149
|
-
Please include a reproducible test case.
|
207
|
+
Please include a reproducible test case if possible. Otherwise, provide as much detail as you can.
|
150
208
|
|
151
209
|
License
|
152
210
|
-------
|
153
211
|
|
154
212
|
Copyright (c) 2014 Justen Walker.
|
155
213
|
|
156
|
-
Released under the terms of the MIT License. For further information, please see the file `LICENSE.md`.
|
214
|
+
Released under the terms of the MIT License. For further information, please see the file `LICENSE.md`.
|
data/baha.gemspec
CHANGED
@@ -8,9 +8,10 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Baha::VERSION
|
9
9
|
spec.authors = ["Justen Walker"]
|
10
10
|
spec.email = ["justen.walker+github@gmail.com"]
|
11
|
-
spec.summary = %q{Baha -
|
12
|
-
spec.description =
|
13
|
-
|
11
|
+
spec.summary = %q{Baha is a command-line utility that assists in the creation of docker images.}
|
12
|
+
spec.description = spec.summary + "\n" +
|
13
|
+
%q{It addresses some of Dockerfiles shortcomings and encourages smaller, reusable, tagged images.}
|
14
|
+
spec.homepage = "https://github.com/justenwalker/baha"
|
14
15
|
spec.license = "MIT"
|
15
16
|
|
16
17
|
spec.files = `git ls-files -z`.split("\x0")
|
data/example/example.yml
CHANGED
@@ -52,3 +52,8 @@ images:
|
|
52
52
|
### include them from another file relative to this config.
|
53
53
|
### Keep things modular and maintainable.
|
54
54
|
- include: rvm/image.yml
|
55
|
+
### You can also build an image from a Dockerfile
|
56
|
+
### Be sure to name and tag it
|
57
|
+
- dockerfile: memcached/Dockerfile
|
58
|
+
name: memcached
|
59
|
+
tag: 2.2
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Memcached
|
2
|
+
#
|
3
|
+
# VERSION 2.2
|
4
|
+
|
5
|
+
# use the ubuntu base image provided by dotCloud
|
6
|
+
FROM ubuntu
|
7
|
+
|
8
|
+
MAINTAINER Victor Coisne victor.coisne@dotcloud.com
|
9
|
+
|
10
|
+
# make sure the package repository is up to date
|
11
|
+
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
|
12
|
+
RUN apt-get update
|
13
|
+
|
14
|
+
# install memcached
|
15
|
+
RUN apt-get install -y memcached
|
16
|
+
|
17
|
+
# Launch memcached when launching the container
|
18
|
+
ENTRYPOINT ["memcached"]
|
19
|
+
|
20
|
+
# run memcached as the daemon user
|
21
|
+
USER daemon
|
22
|
+
|
23
|
+
# expose memcached port
|
24
|
+
EXPOSE 11211
|
data/lib/baha/builder.rb
CHANGED
@@ -3,6 +3,8 @@ require 'baha/image'
|
|
3
3
|
require 'baha/log'
|
4
4
|
require 'baha/pre_build'
|
5
5
|
require 'fileutils'
|
6
|
+
require 'tempfile'
|
7
|
+
require 'shellwords'
|
6
8
|
|
7
9
|
class Baha::Builder
|
8
10
|
LOG = Baha::Log.for_name("Builder")
|
@@ -47,6 +49,27 @@ class Baha::Builder
|
|
47
49
|
FileUtils.mkdir_p workspace.to_s
|
48
50
|
end
|
49
51
|
|
52
|
+
run = false
|
53
|
+
## Image Run Config
|
54
|
+
if image.run
|
55
|
+
build_log.debug { "Image has RUN commands"}
|
56
|
+
run = '.init.sh'
|
57
|
+
File.open(workspace + run,'w') do |f|
|
58
|
+
f.write("#!/bin/sh\n")
|
59
|
+
f.write("set -xe\n")
|
60
|
+
image.run.each do |cmd|
|
61
|
+
build_log.debug { "Writing command: #{cmd}"}
|
62
|
+
case cmd
|
63
|
+
when String
|
64
|
+
f.write("#{cmd}\n")
|
65
|
+
when Array
|
66
|
+
safe = Shellwords.shelljoin(cmd)
|
67
|
+
f.write("#{safe}\n")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
50
73
|
## Pre-Build tasks
|
51
74
|
build_log.info { "Building #{image.name}" }
|
52
75
|
if image.pre_build
|
@@ -58,16 +81,20 @@ class Baha::Builder
|
|
58
81
|
end
|
59
82
|
|
60
83
|
## Build Image
|
84
|
+
command = image.command
|
85
|
+
if run
|
86
|
+
command = ["/bin/sh", "#{image.bind}/#{run}"]
|
87
|
+
end
|
61
88
|
container_config = {
|
62
89
|
'Image' => image.parent_id,
|
63
|
-
'Cmd' =>
|
90
|
+
'Cmd' => command,
|
64
91
|
'Workingdir' => image.bind
|
65
92
|
}
|
66
93
|
build_log.debug { "Creating container for #{image.name} => #{container_config.inspect}" }
|
67
94
|
container = Docker::Container.create(container_config)
|
68
95
|
build_log.debug { "Created container #{container.id} "}
|
69
96
|
|
70
|
-
build_log.debug { "Running container for #{image.name}" }
|
97
|
+
build_log.debug { "Running container for #{image.name}: #{command}" }
|
71
98
|
container.start({
|
72
99
|
'Binds' => "#{image.workspace.expand_path}:#{image.bind}"
|
73
100
|
})
|
data/lib/baha/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'baha/builder'
|
3
3
|
require 'baha/log'
|
4
|
+
require 'baha/dockerfile'
|
4
5
|
|
5
6
|
class Baha::CLI < Thor
|
6
7
|
desc "build [options] CONFIG", "Builds all docker images based on the given config"
|
@@ -62,6 +63,58 @@ class Baha::CLI < Thor
|
|
62
63
|
Baha::Log.close!
|
63
64
|
end
|
64
65
|
end
|
66
|
+
desc "convert DOCKERFILE", "Converts an existing dockerfile to a Baha-compatible image.yml"
|
67
|
+
long_desc <<-LONGDESC
|
68
|
+
Reads the given Dockerfile and outputs a Baha-compatible image.yml which can be included or embedded within a CONFIG
|
69
|
+
LONGDESC
|
70
|
+
option :name, {
|
71
|
+
:aliases => :n,
|
72
|
+
:required => true,
|
73
|
+
:type => :string,
|
74
|
+
:desc => "The target image name"
|
75
|
+
}
|
76
|
+
option :tag, {
|
77
|
+
:aliases => :t,
|
78
|
+
:required => false,
|
79
|
+
:type => :string,
|
80
|
+
:default => 'latest',
|
81
|
+
:desc => 'The target image tag'
|
82
|
+
}
|
83
|
+
option :output, {
|
84
|
+
:aliases => :o,
|
85
|
+
:required => false,
|
86
|
+
:type => :string,
|
87
|
+
:default => 'STDOUT',
|
88
|
+
:desc => 'Target output file'
|
89
|
+
}
|
90
|
+
def convert(dockerfile)
|
91
|
+
file = Pathname.new(dockerfile)
|
92
|
+
out = options[:output]
|
93
|
+
name = options[:name]
|
94
|
+
tag = options[:tag]
|
95
|
+
Baha::Log.logfile = STDERR
|
96
|
+
Baha::Log.level = :info
|
97
|
+
log = Baha::Log.for_name("CLI")
|
98
|
+
begin
|
99
|
+
if file.exist?
|
100
|
+
yaml = Baha::Dockerfile.parse(dockerfile)
|
101
|
+
yaml = { 'name' => name, 'tag' => tag }.merge(yaml)
|
102
|
+
if out == 'STDOUT'
|
103
|
+
puts yaml.to_yaml
|
104
|
+
else
|
105
|
+
File.open(out,'w') do |f|
|
106
|
+
f.write yaml.to_yaml
|
107
|
+
end
|
108
|
+
end
|
109
|
+
else
|
110
|
+
log.fatal { "DOCKERFILE #{dockerfile} not found" }
|
111
|
+
exit 1
|
112
|
+
end
|
113
|
+
rescue Exception => e
|
114
|
+
log.fatal("Error encountered while building images")
|
115
|
+
log.fatal(e)
|
116
|
+
end
|
117
|
+
end
|
65
118
|
desc "version", "Print version and exit"
|
66
119
|
def version
|
67
120
|
puts "baha " + Baha::VERSION
|
data/lib/baha/config.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'pathname'
|
3
3
|
require 'baha/log'
|
4
|
+
require 'baha/dockerfile'
|
4
5
|
|
5
6
|
class Baha::Config
|
6
7
|
DEFAULTS = {
|
@@ -84,6 +85,18 @@ class Baha::Config
|
|
84
85
|
LOG.error { "Unable to find image include: #{path}"}
|
85
86
|
next
|
86
87
|
end
|
88
|
+
elsif image.has_key?('dockerfile')
|
89
|
+
path = Pathname.new(image['dockerfile'])
|
90
|
+
file = resolve_file(path)
|
91
|
+
if file
|
92
|
+
dockerfile = Baha::Dockerfile.parse(file)
|
93
|
+
dockerfile['name'] = image['name']
|
94
|
+
dockerfile['tag'] = image['tag']
|
95
|
+
yield Baha::Image.new(self,dockerfile)
|
96
|
+
else
|
97
|
+
LOG.error { "Unable to find dockerfile: #{path}"}
|
98
|
+
next
|
99
|
+
end
|
87
100
|
else
|
88
101
|
yield Baha::Image.new(self,image)
|
89
102
|
end
|
@@ -15,7 +15,11 @@ module Baha
|
|
15
15
|
when Fixnum
|
16
16
|
config['ExposedPorts']["#{port}/tcp"] = {}
|
17
17
|
when String
|
18
|
-
|
18
|
+
if port.match(/^\d+$/)
|
19
|
+
config['ExposedPorts']["#{port}/tcp"] = {}
|
20
|
+
else
|
21
|
+
config['ExposedPorts'][port] = {}
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
@@ -24,7 +28,7 @@ module Baha
|
|
24
28
|
raise ERROR("should be an array") unless @value.kind_of?(Array)
|
25
29
|
@value.each_with_index do |item,index|
|
26
30
|
if item.kind_of?(String)
|
27
|
-
unless /(\d+)\/(tcp|udp)
|
31
|
+
unless /(\d+)(\/(tcp|udp))?/ =~ item
|
28
32
|
raise ERROR("#{index}: '#{item}' should be in the form 8080/tcp")
|
29
33
|
end
|
30
34
|
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'docker'
|
2
|
+
require 'baha/container_options'
|
3
|
+
require 'baha/log'
|
4
|
+
require 'set'
|
5
|
+
require 'json'
|
6
|
+
require 'csv'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
module Baha
|
10
|
+
class DockerfileParseError < RuntimeError
|
11
|
+
attr_reader :file, :line, :text
|
12
|
+
def initialize(file,line, text)
|
13
|
+
super("Unable to parse Dockerfile #{file}:#{line}\n#{text}")
|
14
|
+
@file = file
|
15
|
+
@line = line
|
16
|
+
@text = text
|
17
|
+
end
|
18
|
+
end
|
19
|
+
class Dockerfile
|
20
|
+
LOG = Baha::Log.for_name("Dockerfile")
|
21
|
+
class << self
|
22
|
+
def parse(file)
|
23
|
+
LOG.info { "Parsing Dockerfile: #{file}" }
|
24
|
+
linenum = 0
|
25
|
+
image = {
|
26
|
+
'run' => [],
|
27
|
+
'pre_build' => [],
|
28
|
+
'config' => {}
|
29
|
+
}
|
30
|
+
multiline = []
|
31
|
+
f = File.open(file, "r")
|
32
|
+
begin
|
33
|
+
f.each_line do |rawline|
|
34
|
+
linenum = linenum + 1
|
35
|
+
line = rawline.chomp.gsub(/^\s*/,'')
|
36
|
+
# Skip empty lines
|
37
|
+
next if line.empty?
|
38
|
+
# Skip comments
|
39
|
+
next if line.match(/^#/)
|
40
|
+
|
41
|
+
# Buffer multi-lines
|
42
|
+
if line.match(/\\$/)
|
43
|
+
multiline << line.chop
|
44
|
+
next
|
45
|
+
end
|
46
|
+
multiline << line
|
47
|
+
|
48
|
+
|
49
|
+
line_to_parse = multiline.join("\n")
|
50
|
+
LOG.debug { "Parsing #{linenum}: #{line_to_parse}" }
|
51
|
+
unless parse_line(image,line_to_parse)
|
52
|
+
raise DockerfileParseError.new(file,linenum, line_to_parse)
|
53
|
+
end
|
54
|
+
multiline = []
|
55
|
+
end
|
56
|
+
ensure
|
57
|
+
f.close
|
58
|
+
end
|
59
|
+
image
|
60
|
+
end
|
61
|
+
|
62
|
+
def as_array(args)
|
63
|
+
begin
|
64
|
+
return JSON.parse(args)
|
65
|
+
rescue
|
66
|
+
return CSV.parse_line(args,{:col_sep => " ", })
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def as_cmd(cmd)
|
71
|
+
begin
|
72
|
+
return JSON.parse(cmd)
|
73
|
+
rescue
|
74
|
+
cmd
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def append_attr(image,key,value)
|
79
|
+
image[key] = [] unless image.has_key?(key)
|
80
|
+
case value
|
81
|
+
when Array
|
82
|
+
image[key].concat(value)
|
83
|
+
else
|
84
|
+
image[key].push(value)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Resolve environment variables in the string
|
89
|
+
def resolve_env(image,value)
|
90
|
+
if image['config'].has_key?('env')
|
91
|
+
env = image['config']['env']
|
92
|
+
env.keys.reduce(value) do |v,k|
|
93
|
+
r = Regexp.new("(?<!\\\\)[$](?:\\{#{k}\\}|#{k})")
|
94
|
+
v.gsub(r,env[k])
|
95
|
+
end
|
96
|
+
else
|
97
|
+
value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Sets the workdir on the image config
|
102
|
+
def set_workdir(image,value)
|
103
|
+
wd = image['config']['workingdir']
|
104
|
+
if wd
|
105
|
+
wd = (Pathname.new(wd) + value).to_s
|
106
|
+
else
|
107
|
+
wd = value
|
108
|
+
end
|
109
|
+
image['config']['workingdir'] = resolve_env(image,wd)
|
110
|
+
end
|
111
|
+
|
112
|
+
def set_env(image,value)
|
113
|
+
k,v = value.split(/\s+/,2)
|
114
|
+
image['config']['env'] ||= {}
|
115
|
+
image['config']['env'][k] = v
|
116
|
+
end
|
117
|
+
|
118
|
+
# Parse a line and configure the image
|
119
|
+
def parse_line(image,line)
|
120
|
+
cmd, args = line.split(/\s+/,2)
|
121
|
+
cmd = cmd.downcase.to_sym
|
122
|
+
case cmd
|
123
|
+
when :from
|
124
|
+
image['parent'] = args
|
125
|
+
when :maintainer
|
126
|
+
image['maintainer'] = args
|
127
|
+
when :expose
|
128
|
+
append_attr(image['config'],'exposedports',resolve_env(image,args))
|
129
|
+
when :volume
|
130
|
+
append_attr(image['config'],'volumes',as_array(resolve_env(image,args)))
|
131
|
+
when :entrypoint
|
132
|
+
image['config']['entrypoint'] = as_cmd(args)
|
133
|
+
when :cmd
|
134
|
+
image['config']['cmd'] = as_cmd(args)
|
135
|
+
when :run
|
136
|
+
image['run'] << as_cmd(args)
|
137
|
+
when :user
|
138
|
+
image['config']['user'] = resolve_env(image,args)
|
139
|
+
when :workdir
|
140
|
+
set_workdir(image,args)
|
141
|
+
when :env
|
142
|
+
set_env(image,resolve_env(image,args))
|
143
|
+
else
|
144
|
+
return false
|
145
|
+
end
|
146
|
+
true
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/lib/baha/image.rb
CHANGED
@@ -65,7 +65,7 @@ module Baha
|
|
65
65
|
end
|
66
66
|
|
67
67
|
end
|
68
|
-
attr_reader :parent, :image, :maintainer, :options, :pre_build, :bind, :command, :timeout, :workspace, :name, :tags
|
68
|
+
attr_reader :parent, :image, :maintainer, :options, :pre_build, :bind, :command, :timeout, :workspace, :name, :tags, :run
|
69
69
|
|
70
70
|
def initialize(config,image)
|
71
71
|
@parent = Baha::Image.parse_with_default(image['parent'] || config.defaults[:parent], config.defaults[:repository])
|
@@ -76,6 +76,7 @@ module Baha
|
|
76
76
|
@pre_build = image['pre_build']
|
77
77
|
@bind = image['bind'] || config.defaults[:bind]
|
78
78
|
@command = image['command'] || config.defaults[:command]
|
79
|
+
@run = image['run']
|
79
80
|
@timeout = image['timeout'] || config.defaults[:timeout]
|
80
81
|
@workspace = config.workspace + (image['workspace'] || @image[:name])
|
81
82
|
@name = @image[:name]
|
data/lib/baha/version.rb
CHANGED
data/spec/builder_spec.rb
CHANGED
@@ -44,10 +44,15 @@ describe Baha::Builder do
|
|
44
44
|
let(:image2) {
|
45
45
|
double('image2')
|
46
46
|
}
|
47
|
+
let (:init) {
|
48
|
+
double('init.sh')
|
49
|
+
}
|
47
50
|
before do
|
48
51
|
allow_any_instance_of(Baha::Image).to receive(:needs_update?).and_return(true)
|
49
52
|
allow_any_instance_of(Baha::Image).to receive(:parent_id).and_return('AAAA')
|
50
53
|
allow(Docker::Container).to receive(:create).and_return(container)
|
54
|
+
allow(File).to receive(:open).and_call_original
|
55
|
+
allow(File).to receive(:open).with(pathname_matching(/init.sh$/),'w').and_yield(init)
|
51
56
|
allow(container).to receive(:start)
|
52
57
|
allow(container).to receive(:stop)
|
53
58
|
allow(container).to receive(:streaming_logs).with({"stdout"=>true, "stderr"=>true, "follow"=>true, "timestamps"=>false}).and_yield(:stdout,"console message").and_yield(:stderr,"error line")
|
@@ -57,22 +62,30 @@ describe Baha::Builder do
|
|
57
62
|
allow(Docker::Image).to receive(:get).with('BBBB').and_return(image)
|
58
63
|
allow(image).to receive(:tag)
|
59
64
|
allow(container).to receive(:remove)
|
65
|
+
allow(init).to receive(:write)
|
60
66
|
end
|
61
67
|
it 'executes pre_build step' do
|
62
68
|
subject.build!
|
63
69
|
expect(Baha::PreBuild::Module).to have_received(:execute).twice.with(hash_including('download' => "http://www.google.com"))
|
64
70
|
end
|
71
|
+
it 'write run script' do
|
72
|
+
subject.build!
|
73
|
+
expect(init).to have_received(:write).with("#!/bin/sh\n").ordered
|
74
|
+
expect(init).to have_received(:write).with("set -xe\n").ordered
|
75
|
+
expect(init).to have_received(:write).with("echo \"Hello\"\n").ordered
|
76
|
+
expect(init).to have_received(:write).with("/bin/echo World\n").ordered
|
77
|
+
end
|
65
78
|
it 'creates containers' do
|
66
79
|
subject.build!
|
67
80
|
expect(Docker::Container).to have_received(:create).twice.with({"Image"=>"AAAA", "Cmd"=>["/bin/bash", "./init.sh"], "Workingdir"=>"/.baha"})
|
68
81
|
end
|
69
82
|
it 'starts containers' do
|
70
83
|
subject.build!
|
71
|
-
expect(container).to have_received(:start).
|
84
|
+
expect(container).to have_received(:start).exactly(3).times
|
72
85
|
end
|
73
86
|
it 'commits containers' do
|
74
87
|
subject.build!
|
75
|
-
expect(container).to have_received(:commit).with({"run"=>{"ExposedPorts"=>{"8080/tcp"=>{}}}}).ordered
|
88
|
+
expect(container).to have_received(:commit).with({"run"=>{"ExposedPorts"=>{"8080/tcp"=>{}, "8081/tcp"=>{}, "8009/tcp"=>{}}}}).ordered
|
76
89
|
expect(container).to have_received(:commit).with({'run' => {}}).ordered
|
77
90
|
end
|
78
91
|
it 'tags image' do
|
data/spec/config_spec.rb
CHANGED
@@ -39,6 +39,22 @@ describe Baha::Config do
|
|
39
39
|
its(:configdir) { should eq(fixture_path) }
|
40
40
|
its(:workspace) { should eq(fixture_path + 'workspace') }
|
41
41
|
end
|
42
|
+
context "with dockerfile" do
|
43
|
+
subject { Baha::Config.load(fixture('config_dockerfile.yml')) }
|
44
|
+
its(:defaults) { should eq(
|
45
|
+
{
|
46
|
+
:parent=>"ubuntu:14.04.1",
|
47
|
+
:bind=>"/.baha",
|
48
|
+
:repository=>'docker.example.com/baha',
|
49
|
+
:maintainer => "Ishmael <ishmael@example.com>",
|
50
|
+
:command => ['/bin/bash','./init.sh'],
|
51
|
+
:timeout => 1200
|
52
|
+
})
|
53
|
+
}
|
54
|
+
its(:options) { should eq({}) }
|
55
|
+
its(:configdir) { should eq(fixture_path) }
|
56
|
+
its(:workspace) { should eq(fixture_path + 'workspace') }
|
57
|
+
end
|
42
58
|
context "with DOCKER_CERT_PATH set" do
|
43
59
|
subject { Baha::Config.load(fixture('config_embedded.yml')) }
|
44
60
|
before do
|
@@ -87,7 +103,7 @@ describe Baha::Config do
|
|
87
103
|
subject.each_image do |image|
|
88
104
|
images << image
|
89
105
|
end
|
90
|
-
expect(images.size).to eq(
|
106
|
+
expect(images.size).to eq(3)
|
91
107
|
end
|
92
108
|
end
|
93
109
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'baha/config'
|
3
|
+
|
4
|
+
describe Baha::Config do
|
5
|
+
before do
|
6
|
+
ENV['DOCKER_CERT_PATH'] = nil
|
7
|
+
ENV['DOCKER_TLS_VERIFY'] = nil
|
8
|
+
end
|
9
|
+
describe "#parse" do
|
10
|
+
context "with valid Dockerfile" do
|
11
|
+
subject { Baha::Dockerfile.parse(fixture('Dockerfile')) }
|
12
|
+
its(['parent']) { should eq('ubuntu:14.04.1')}
|
13
|
+
its(['run']) { should eq([
|
14
|
+
"echo \"Hello\"",
|
15
|
+
["/bin/echo", "World"],
|
16
|
+
"echo Hello \nworld \nmultiline"])}
|
17
|
+
its(['config']) { should eq({
|
18
|
+
"entrypoint"=>["/bin/bash"],
|
19
|
+
"exposedports"=>["8080", "8081", "8009"],
|
20
|
+
"env"=>{
|
21
|
+
"HOME"=>"/home/user",
|
22
|
+
"BIN_DIR"=>"bin",
|
23
|
+
"HOME2"=>"/home/user/two",
|
24
|
+
"USER"=>"daemon"},
|
25
|
+
"workingdir"=>"/home/user/bin/b/c",
|
26
|
+
"cmd"=>"-l",
|
27
|
+
"user"=>"daemon",
|
28
|
+
"volumes"=>[
|
29
|
+
"/home/user",
|
30
|
+
"/logs",
|
31
|
+
"/home/user/logs",
|
32
|
+
"/data"]})}
|
33
|
+
end
|
34
|
+
context "with invalid Dockerfile" do
|
35
|
+
it { expect { Baha::Dockerfile.parse(fixture('Dockerfile.invalid')) }.to raise_error(Baha::DockerfileParseError) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Comment
|
2
|
+
FROM ubuntu:14.04.1
|
3
|
+
|
4
|
+
MAINTAINER "Captain Ahab" <ahab@example.com>
|
5
|
+
|
6
|
+
RUN echo "Hello"
|
7
|
+
RUN ["/bin/echo", "World"]
|
8
|
+
RUN echo Hello \
|
9
|
+
world \
|
10
|
+
multiline
|
11
|
+
|
12
|
+
ENTRYPOINT ["/bin/bash"]
|
13
|
+
|
14
|
+
EXPOSE 8080
|
15
|
+
EXPOSE 8081
|
16
|
+
EXPOSE 8009
|
17
|
+
|
18
|
+
ENV HOME /home/user
|
19
|
+
ENV BIN_DIR bin
|
20
|
+
ENV HOME2 $HOME/two
|
21
|
+
ENV USER daemon
|
22
|
+
|
23
|
+
WORKDIR ${HOME}
|
24
|
+
WORKDIR $BIN_DIR
|
25
|
+
WORKDIR b
|
26
|
+
WORKDIR c
|
27
|
+
|
28
|
+
CMD -l
|
29
|
+
|
30
|
+
USER ${USER}
|
31
|
+
|
32
|
+
VOLUME $HOME /logs
|
33
|
+
VOLUME ["$HOME/logs", "/data"]
|
@@ -9,4 +9,10 @@ images:
|
|
9
9
|
- parent: 'ubuntu:14.04.1'
|
10
10
|
name: base
|
11
11
|
tag: 1.0.0
|
12
|
-
maintainer: '"Captain Ahab" <ahab@example.com>'
|
12
|
+
maintainer: '"Captain Ahab" <ahab@example.com>'
|
13
|
+
- dockerfile: Dockerfile
|
14
|
+
name: dockerfile
|
15
|
+
tag: 1.0.0
|
16
|
+
- dockerfile: no such dockerfile
|
17
|
+
name: invalid
|
18
|
+
tag: 1.0.0
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require "codeclimate-test-reporter"
|
2
|
+
CodeClimate::TestReporter.start
|
3
|
+
|
1
4
|
require 'simplecov'
|
2
5
|
SimpleCov.start do
|
3
6
|
add_filter '/spec/'
|
@@ -36,4 +39,15 @@ RSpec.configure do |config|
|
|
36
39
|
config.before(:each) do
|
37
40
|
Baha::Log.logfile = StringIO.new
|
38
41
|
end
|
42
|
+
end
|
43
|
+
|
44
|
+
RSpec::Matchers.define :pathname_matching do |expected|
|
45
|
+
match do |actual|
|
46
|
+
case expected
|
47
|
+
when Regexp
|
48
|
+
expected.match(actual.to_s) != nil
|
49
|
+
else
|
50
|
+
expected == actual
|
51
|
+
end
|
52
|
+
end
|
39
53
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: baha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justen Walker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -136,7 +136,11 @@ dependencies:
|
|
136
136
|
- - ~>
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.9.1
|
139
|
-
description: Baha -
|
139
|
+
description: ! 'Baha is a command-line utility that assists in the creation of docker
|
140
|
+
images.
|
141
|
+
|
142
|
+
It addresses some of Dockerfiles shortcomings and encourages smaller, reusable,
|
143
|
+
tagged images.'
|
140
144
|
email:
|
141
145
|
- justen.walker+github@gmail.com
|
142
146
|
executables:
|
@@ -146,6 +150,7 @@ extra_rdoc_files: []
|
|
146
150
|
files:
|
147
151
|
- .gitignore
|
148
152
|
- .travis.yml
|
153
|
+
- CHANGELOG.md
|
149
154
|
- Gemfile
|
150
155
|
- LICENSE.txt
|
151
156
|
- README.md
|
@@ -156,6 +161,7 @@ files:
|
|
156
161
|
- example/base/init.sh.erb
|
157
162
|
- example/base/test-template.erb
|
158
163
|
- example/example.yml
|
164
|
+
- example/memcached/Dockerfile
|
159
165
|
- example/rvm/image.yml
|
160
166
|
- example/rvm/init.sh.erb
|
161
167
|
- lib/baha.rb
|
@@ -170,6 +176,7 @@ files:
|
|
170
176
|
- lib/baha/container_options/invalid_option_error.rb
|
171
177
|
- lib/baha/container_options/option.rb
|
172
178
|
- lib/baha/container_options/volumes.rb
|
179
|
+
- lib/baha/dockerfile.rb
|
173
180
|
- lib/baha/image.rb
|
174
181
|
- lib/baha/log.rb
|
175
182
|
- lib/baha/pre_build.rb
|
@@ -186,9 +193,13 @@ files:
|
|
186
193
|
- spec/container_options/exposed_ports_spec.rb
|
187
194
|
- spec/container_options/option_spec.rb
|
188
195
|
- spec/container_options/volumes_spec.rb
|
196
|
+
- spec/dockerfile_spec.rb
|
197
|
+
- spec/fixtures/Dockerfile
|
198
|
+
- spec/fixtures/Dockerfile.invalid
|
189
199
|
- spec/fixtures/base_image.yml
|
190
200
|
- spec/fixtures/config_build.yml
|
191
201
|
- spec/fixtures/config_build_image.yml
|
202
|
+
- spec/fixtures/config_dockerfile.yml
|
192
203
|
- spec/fixtures/config_eachimage.yml
|
193
204
|
- spec/fixtures/config_embedded.yml
|
194
205
|
- spec/fixtures/config_include.yml
|
@@ -203,7 +214,7 @@ files:
|
|
203
214
|
- spec/pre_build/template_spec.rb
|
204
215
|
- spec/pre_build_spec.rb
|
205
216
|
- spec/spec_helper.rb
|
206
|
-
homepage:
|
217
|
+
homepage: https://github.com/justenwalker/baha
|
207
218
|
licenses:
|
208
219
|
- MIT
|
209
220
|
metadata: {}
|
@@ -226,7 +237,7 @@ rubyforge_project:
|
|
226
237
|
rubygems_version: 2.1.11
|
227
238
|
signing_key:
|
228
239
|
specification_version: 4
|
229
|
-
summary: Baha -
|
240
|
+
summary: Baha is a command-line utility that assists in the creation of docker images.
|
230
241
|
test_files:
|
231
242
|
- spec/builder_spec.rb
|
232
243
|
- spec/config_spec.rb
|
@@ -236,9 +247,13 @@ test_files:
|
|
236
247
|
- spec/container_options/exposed_ports_spec.rb
|
237
248
|
- spec/container_options/option_spec.rb
|
238
249
|
- spec/container_options/volumes_spec.rb
|
250
|
+
- spec/dockerfile_spec.rb
|
251
|
+
- spec/fixtures/Dockerfile
|
252
|
+
- spec/fixtures/Dockerfile.invalid
|
239
253
|
- spec/fixtures/base_image.yml
|
240
254
|
- spec/fixtures/config_build.yml
|
241
255
|
- spec/fixtures/config_build_image.yml
|
256
|
+
- spec/fixtures/config_dockerfile.yml
|
242
257
|
- spec/fixtures/config_eachimage.yml
|
243
258
|
- spec/fixtures/config_embedded.yml
|
244
259
|
- spec/fixtures/config_include.yml
|