baha 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +156 -0
  7. data/Rakefile +21 -0
  8. data/baha.gemspec +31 -0
  9. data/bin/baha +5 -0
  10. data/example/.gitignore +1 -0
  11. data/example/base/init.sh.erb +11 -0
  12. data/example/base/test-template.erb +22 -0
  13. data/example/example.yml +54 -0
  14. data/example/rvm/image.yml +33 -0
  15. data/example/rvm/init.sh.erb +12 -0
  16. data/lib/baha/builder.rb +130 -0
  17. data/lib/baha/cli.rb +69 -0
  18. data/lib/baha/config.rb +142 -0
  19. data/lib/baha/container_options/cmd.rb +33 -0
  20. data/lib/baha/container_options/entrypoint.rb +10 -0
  21. data/lib/baha/container_options/env.rb +21 -0
  22. data/lib/baha/container_options/exposed_ports.rb +35 -0
  23. data/lib/baha/container_options/invalid_option_error.rb +15 -0
  24. data/lib/baha/container_options/option.rb +59 -0
  25. data/lib/baha/container_options/volumes.rb +24 -0
  26. data/lib/baha/container_options.rb +38 -0
  27. data/lib/baha/image.rb +154 -0
  28. data/lib/baha/log.rb +80 -0
  29. data/lib/baha/pre_build/command.rb +51 -0
  30. data/lib/baha/pre_build/download.rb +28 -0
  31. data/lib/baha/pre_build/template.rb +48 -0
  32. data/lib/baha/pre_build.rb +47 -0
  33. data/lib/baha/version.rb +3 -0
  34. data/lib/baha/workspace.rb +13 -0
  35. data/lib/baha.rb +5 -0
  36. data/spec/builder_spec.rb +103 -0
  37. data/spec/config_spec.rb +93 -0
  38. data/spec/container_options/cmd_spec.rb +46 -0
  39. data/spec/container_options/entrypoint_spec.rb +32 -0
  40. data/spec/container_options/env_spec.rb +26 -0
  41. data/spec/container_options/exposed_ports_spec.rb +32 -0
  42. data/spec/container_options/option_spec.rb +43 -0
  43. data/spec/container_options/volumes_spec.rb +25 -0
  44. data/spec/fixtures/base_image.yml +5 -0
  45. data/spec/fixtures/config_build.yml +12 -0
  46. data/spec/fixtures/config_build_image.yml +10 -0
  47. data/spec/fixtures/config_eachimage.yml +12 -0
  48. data/spec/fixtures/config_embedded.yml +11 -0
  49. data/spec/fixtures/config_include.yml +7 -0
  50. data/spec/fixtures/config_ssl.yml +13 -0
  51. data/spec/fixtures/config_sslpath.yml +11 -0
  52. data/spec/helpers/docker_helpers.rb +31 -0
  53. data/spec/image_spec.rb +167 -0
  54. data/spec/log_spec.rb +89 -0
  55. data/spec/options_spec.rb +52 -0
  56. data/spec/pre_build/command_spec.rb +69 -0
  57. data/spec/pre_build/download_spec.rb +43 -0
  58. data/spec/pre_build/template_spec.rb +55 -0
  59. data/spec/pre_build_spec.rb +29 -0
  60. data/spec/spec_helper.rb +39 -0
  61. metadata +255 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ M2E1OWQwZWYyYmQxMzc3NmM1ZjAzZGI3ZTA5NmM3NGQyYTBjZGIyOA==
5
+ data.tar.gz: !binary |-
6
+ YWJhZDkxNDNhYmNhMmYyMTBiZDNmNzliYTc2YmNmYTk4M2JmYTlmNQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MmVhNjgyMWFmOTJjZGRiYzE0Zjc1ZjdkOTBiZTlkY2YzYzhhMWRkN2I2ODdl
10
+ MzQ3N2IwMzhkMDQyNDJiZjU4ZjNmYWZkNzU3YjE0OWE3OThjNTkxZjQwMDZl
11
+ MDA2Zjg2ZTRhZjg2M2MwODZhNGRmMDM1ZjUwYmJhMDA1Y2E1ZGI=
12
+ data.tar.gz: !binary |-
13
+ MTJhOGNiYmYwOGI0YmE5NDI3Y2EwODFiZDU5MzNjYzE4ZmI4NTA0YTlkN2M0
14
+ ZTgxNmQ5Mzc1ZmZlM2M5NzJiNDg2YjkzYjdmZDlkNjkwYjA5NGUzNzE3YTQz
15
+ NGVkMTkzYTJhMzgwNGQwMDFjYzNlMWE2YzA1ZjdlZDZjYmJkMTk=
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /spec/fixtures/workspace
10
+ /tmp/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ ---
2
+ language: ruby
3
+ before_install:
4
+ - gem update --system
5
+ - gem update
6
+ script: bundle exec rake spec
7
+ rvm:
8
+ - 1.9.2
9
+ - 1.9.3
10
+ - 2.0.0
11
+ - 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in Baha.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Justen Walker
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,156 @@
1
+ Baha
2
+ =======
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/baha.png)](http://badge.fury.io/rb/baha)
5
+ [![Build Status](https://travis-ci.org/justenwalker/baha.png?branch=master)](https://travis-ci.org/justenwalker/baha)
6
+
7
+ Introduction
8
+ ------------
9
+
10
+ Baha is a command-line utility that assists in the creation of docker images.
11
+ It addresses some of `Dockerfile`'s' shortcomings and encourages smaller, reusable, tagged images.
12
+
13
+ Why not Dockerfiles?
14
+ --------------------
15
+
16
+ Dockerfiles are simple. They are an easy way to make a docker image without needing any other dependencies. However, their simplicity comes at a cost: redundancy. This redundancy is present in a few ways that make more complicated images difficult to make and maintain.
17
+
18
+ So why would I use Baha?
19
+ ------------------------
20
+
21
+ ### 1. Baha forbids more than 1 layer per image
22
+
23
+ If you split statements across multiple RUN statements, each of these results in a new layer.
24
+ 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
+ then you must ensure that all statements can be condensed into one line - sacrificing maintainability in the process.
26
+
27
+ Baha encourages using scripts instead of `RUN` statements to ensure that only one layer is created per image.
28
+
29
+ ### 2. Baha encourages smaller images
30
+
31
+ The nature of the way the dockerfiles are processed means that each command you run commits a new image.
32
+ 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.
34
+
35
+ 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
+
37
+ ### 3. Baha understands the bigger picture
38
+
39
+ Another best practice (2, #7) recommends that you use your own base image.
40
+ Dockerfiles make it simple to create your own 'base' image, but how about updates?
41
+
42
+ If you were to just rebuild all of your Dockerfiles, you would create an entirely new tree - even if nothing changed.
43
+
44
+ Baha will rebuild your entire lineage if the base images changes, but will not rebuild base images if only the children change.
45
+
46
+ **Caveat**:
47
+
48
+ Baha relies on tagging your releases, noticing when the tag has changed, and treating tags as immutable.
49
+ This is analogous to how **git** treats tags.
50
+
51
+ Tagging your images is another best-practice (2, #5) anyway, so this is encouraged by design.
52
+
53
+ Bottom line is: If you change your image, you should change the tag/version.
54
+
55
+ #### 4. Baha lets you cache build dependencies
56
+
57
+ Most of the time, dependencies are downloaded and installed in the context of the docker container itself.
58
+ This means that rebuilding an image results in redundant downloads if files haven't changed.
59
+
60
+ Baha has pre-build steps that can be used to download files and prepare scripts on host machine.
61
+ This workspace is made available to the image via a bind mount during build-time. Not only do these dependencies stick around between builds, but they do not need to be cleaned up after the image is committed, since they are never persisted to the container.
62
+
63
+ **References**
64
+
65
+ 1. [Official Dockerfile Best Practices](https://docs.docker.com/articles/dockerfile_best-practices/)<a name="r1"></a>
66
+ 2. [Dockerfile Best Practices - take 2, by Michael Crosby](http://crosbymichael.com/dockerfile-best-practices-take-2.html)<a name="r2"></a>
67
+
68
+ Disclaimer
69
+ ----------
70
+
71
+ This gem was just released (pre 1.0) and is not ready for production use yet.
72
+
73
+ During pre 1.0, things may change that break backwards compatibility between releases. Most likely these breaking
74
+ changes would be related to the YAML file syntax.
75
+
76
+ To Do
77
+ -----
78
+ See the [Issue Tracker](https://github.com/justenwalker/baha/issues)
79
+
80
+ Installation
81
+ ------------
82
+
83
+ ```
84
+ $ gem install baha
85
+ ```
86
+ ### gem install baha
87
+
88
+ Usage
89
+ -----
90
+
91
+ ```
92
+ Baha Commands:
93
+ baha build [options] CONFIG # Builds all docker images based on the given config
94
+ baha help [COMMAND] # Describe available commands or one specific command
95
+ baha version # Print version and exit
96
+ ```
97
+
98
+ **build**
99
+
100
+ ```
101
+ Usage:
102
+ baha build [options] CONFIG
103
+
104
+ Options:
105
+ [--logfile=LOGFILE] # Log output to LOGFILE. Omit to log to stdout.
106
+ d, [--debug], [--no-debug] # Toggle debug logging. Includes verbose.
107
+ v, [--verbose], [--no-verbose] # Toggle verbose logging
108
+ q, [--quiet], [--no-quiet] # Suppress all logging
109
+
110
+ Description:
111
+ Reads the CONFIG file and builds all of the docker images in the order they appear.
112
+ ```
113
+
114
+ Check out the `example` directory for a sample CONFIG file.
115
+
116
+ How it works
117
+ ------------
118
+
119
+ Baha will read a config.yml file first and load each image configuration.
120
+ It will build each image in the order they appear by doing the following.
121
+
122
+ ### Check if the image needs updating
123
+ 1. Check to see if the parent image changed
124
+ 2. Check to see if the tag does not exist in the repository
125
+
126
+ ### Prepare the image's workspace (bind mount)
127
+ 1. Create the workspace directory if it doesn't exist
128
+ 2. Run any `pre_build` tasks to prepare dependencies
129
+
130
+ ### Run the image's `command` inside the image
131
+ 1. Creates a new container and runs it with the `command` given
132
+ 2. Commits the container with the run options specified in the images `config` section.
133
+
134
+ How to Contribute
135
+ -----------------
136
+
137
+ ### Running the tests
138
+
139
+ $ bundle
140
+ $ bundle exec rake spec
141
+
142
+ ### Installing locally
143
+
144
+ $ bundle
145
+ $ [bundle exec] rake install
146
+
147
+ ### Reporting Issues
148
+
149
+ Please include a reproducible test case.
150
+
151
+ License
152
+ -------
153
+
154
+ Copyright (c) 2014 Justen Walker.
155
+
156
+ Released under the terms of the MIT License. For further information, please see the file `LICENSE.md`.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/clean'
3
+ require 'rspec/core/rake_task'
4
+
5
+ require 'rake/clean'
6
+ CLEAN.include('pkg/', 'example/workspace')
7
+ CLOBBER.include('Gemfile.lock')
8
+
9
+ RSpec::Core::RakeTask.new('spec')
10
+
11
+ desc "Run example baha build"
12
+ task :example do
13
+ require 'pathname'
14
+ exampleyml = (Pathname.pwd + 'example' + 'example.yml')
15
+ puts "Running: baha build -d #{exampleyml}"
16
+ sh('baha', 'build', '-d', exampleyml.to_s)
17
+ end
18
+
19
+ task :default do
20
+ sh %{rake -T}
21
+ end
data/baha.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'baha/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "baha"
8
+ spec.version = Baha::VERSION
9
+ spec.authors = ["Justen Walker"]
10
+ spec.email = ["justen.walker+github@gmail.com"]
11
+ spec.summary = %q{Baha - A tool for describing image builds for Docker}
12
+ spec.description = %q{Baha - A tool for describing image builds for Docker}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'thor', '~> 0.19.1'
22
+ spec.add_dependency 'docker-api', '~> 1.14.0'
23
+ spec.add_dependency 'json', '~> 1.8.1'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.7'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.1.0'
28
+ spec.add_development_dependency 'rspec-mocks', '~> 3.1.3'
29
+ spec.add_development_dependency 'rspec-its', '~> 1.1.0'
30
+ spec.add_development_dependency 'simplecov', '~> 0.9.1'
31
+ end
data/bin/baha ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'baha/cli'
4
+
5
+ Baha::CLI.start(ARGV)
@@ -0,0 +1 @@
1
+ workspace/
@@ -0,0 +1,11 @@
1
+ #! /bin/bash
2
+
3
+ ## Install required packages
4
+ apt-get update
5
+ apt-get upgrade -y
6
+ apt-get install -y curl gnupg
7
+
8
+ ## Cleanup after ourselves
9
+ apt-get autoremove -y
10
+ apt-get clean
11
+ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@@ -0,0 +1,22 @@
1
+ ### This is the parent image config
2
+ parent: <%= parent %>
3
+
4
+ ### This is the maintainer of the image
5
+ maintainer: <%= maintainer %>
6
+
7
+ ### This is the bind location for the workspace
8
+ bind: <%= bind %>
9
+
10
+ ### This is the location of the workspace on the host machine
11
+ workspace: <%= workspace %>
12
+
13
+ ### This is the image name
14
+ name: <%= name %>
15
+
16
+ ### This is the target tag/version
17
+ tag: <%= tag %>
18
+
19
+ ### The render function will render other files
20
+ ### START RENDER ###
21
+ include: <%= render "init.sh.erb" %>
22
+ ### END RENDER ###
@@ -0,0 +1,54 @@
1
+ ---
2
+ ### Docker URL. Default is unix:///var/run/docker.sock
3
+ ### You can also run Baha with the env variable:
4
+ ### DOCKER_HOST=tcp://192.168.59.103:2376
5
+ # docker_url: tcp://192.168.59.103:2376
6
+ #
7
+ defaults:
8
+ ### If an image doesn't have a parent, it will default to this one.
9
+ parent: ubuntu:14.04.1
10
+ ### When tagging an image, the name will be tagged with: {repository}/{name}
11
+ repository: docker.example.com/baha
12
+ ### Put your name and email here to claim authorship
13
+ maintainer: Ishmael <ishmael@example.com>
14
+ ### By default, the image's workspace will be mounted here inside the container
15
+ bind: '/.data'
16
+ ### If your docker is configured for SSL connections
17
+ ### You should supply the options here.
18
+ ###
19
+ ### ENV variables take precedence over the ssl config
20
+ ### - DOCKER_CERT_PATH and DOCKER_TLS_VERIFY=1
21
+ ###
22
+ ### Leave this out if your docker connection is insecure (http or unix socket)
23
+ ### Having an ssl config assumes the connection is https://
24
+ ### having a unix socket assumes the connection is insecure, this section would be ignored
25
+ ssl:
26
+ ### Path to certificates and key
27
+ ### Assumes the files are: ca.pem, cert.pem, and key.pem
28
+ ### Same as specifying DOCKER_CERT_PATH=~/.boot2docker/certs/boot2docker-vm
29
+ # cert_path: ~/.boot2docker/certs/boot2docker-vm
30
+ #
31
+ ### You can also specify them individually:
32
+ # cert: ~/.boot2docker/certs/boot2docker-vm/cert.pem
33
+ # key: ~/.boot2docker/certs/boot2docker-vm/key.pem
34
+ # ca: ~/.boot2docker/certs/boot2docker-vm/ca.pem
35
+ #
36
+ ### Verify docker host's certificate chain
37
+ verify: true
38
+ ### Each image is an element of the images array
39
+ ### The images will be built in the order they appear
40
+ images:
41
+ - name: base
42
+ tag: 1.0.0 # Tag your image with a version. If the version changes, the image will be rebuilt
43
+ ### This list of tasks will be executed in order *before* the image container is built.
44
+ ### It is meant to prepare the workspace by downloading and creating scripts to be run in the context of the container.
45
+ pre_build:
46
+ ### The template module copies/processes an ERB into the image's workspace folder
47
+ - { template: 'base/init.sh.erb', dest: 'init.sh' }
48
+ ### This template shows the available bindings
49
+ - { template: 'base/test-template.erb', dest: 'test.txt' }
50
+ command: ['/bin/bash','/.data/init.sh']
51
+ ### Instead of listing all of the image configs in the same file, you can
52
+ ### include them from another file relative to this config.
53
+ ### Keep things modular and maintainable.
54
+ - include: rvm/image.yml
@@ -0,0 +1,33 @@
1
+ ### Base on another image created before me
2
+ parent: base:1.0.0
3
+ name: rvm-test
4
+ tag: 1.9.3
5
+ ### Override default maintainer
6
+ maintainer: '"Captain Ahab" <ahab@example.com>'
7
+ ### Override default bind mount
8
+ bind: '/.rvm'
9
+ pre_build:
10
+ - { download: 'https://get.rvm.io', file: 'rvm.sh' }
11
+ - { template: 'rvm/init.sh.erb', dest: 'init.sh' }
12
+ command: ['/bin/bash','/.rvm/init.sh']
13
+ ### Specify container's run configuration here
14
+ config:
15
+ ### Takes an array of port numbers (assumes tcp)
16
+ ### Can also be in the form 9000/udp to expose UDP ports
17
+ exposedports:
18
+ - 8080
19
+ ### Register volumes. Each array item should be a path
20
+ volumes:
21
+ - '/logs'
22
+ ### Environment variables. Hash of KEY=VALUE pairs
23
+ env:
24
+ HOME: '/root'
25
+ ### Entrypoint command. Should just be 1 string
26
+ entrypoint: '/bin/bash'
27
+ ### Override the docker containers hostname
28
+ hostname: 'my.hostname.docker'
29
+ ### Override the internal username executing the command
30
+ user: 'root'
31
+ ### Options coming after the entrypoint
32
+ cmd:
33
+ - '-l'
@@ -0,0 +1,12 @@
1
+ #! /bin/bash
2
+
3
+ ## Install RVM
4
+ gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
5
+ /bin/bash /.rvm/rvm.sh stable || exit 2
6
+ source /etc/profile.d/rvm.sh
7
+ rvm install 1.9.3
8
+
9
+ ## Clean up
10
+ apt-get autoremove -y
11
+ apt-get clean
12
+ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@@ -0,0 +1,130 @@
1
+ require 'baha/config'
2
+ require 'baha/image'
3
+ require 'baha/log'
4
+ require 'baha/pre_build'
5
+ require 'fileutils'
6
+
7
+ class Baha::Builder
8
+ LOG = Baha::Log.for_name("Builder")
9
+
10
+ class BuildError < RuntimeError
11
+ attr_reader :image, :status
12
+ def initialize(status,image)
13
+ super("Unable to build image : #{image.name} -- Status: #{status.inspect}")
14
+ @image = image
15
+ @status = status
16
+ end
17
+ end
18
+
19
+ attr_reader :config
20
+
21
+ def initialize(config)
22
+ @config = case config
23
+ when Baha::Config
24
+ config
25
+ else
26
+ Baha::Config.load(config.to_s)
27
+ end
28
+ end
29
+
30
+ def build!
31
+ LOG.info("Building Images")
32
+ LOG.debug { "Config: #{@config.inspect}" }
33
+ LOG.debug { "Initializing Docker" }
34
+ @config.init_docker!
35
+
36
+ @config.each_image do |image|
37
+ build_log = Baha::Log.for_name("Builder [#{image.name}]")
38
+ unless image.needs_update?
39
+ build_log.info { "Skipped image #{image.name} - No update needed" }
40
+ next
41
+ end
42
+
43
+ ## Prepare Workspace
44
+ workspace = Pathname.new(@config.workspace) + image.name
45
+ unless workspace.exist?
46
+ build_log.debug { "Creating Workspace: #{workspace}" }
47
+ FileUtils.mkdir_p workspace.to_s
48
+ end
49
+
50
+ ## Pre-Build tasks
51
+ build_log.info { "Building #{image.name}" }
52
+ if image.pre_build
53
+ build_log.debug { "Preparing workspace for #{image.name}" }
54
+ image.pre_build.each do |task|
55
+ build_log.debug { "execute task: #{task.inspect}" }
56
+ Baha::PreBuild::Module.execute(task.merge({ :config => @config, :image => image }))
57
+ end
58
+ end
59
+
60
+ ## Build Image
61
+ container_config = {
62
+ 'Image' => image.parent_id,
63
+ 'Cmd' => image.command,
64
+ 'Workingdir' => image.bind
65
+ }
66
+ build_log.debug { "Creating container for #{image.name} => #{container_config.inspect}" }
67
+ container = Docker::Container.create(container_config)
68
+ build_log.debug { "Created container #{container.id} "}
69
+
70
+ build_log.debug { "Running container for #{image.name}" }
71
+ container.start({
72
+ 'Binds' => "#{image.workspace.expand_path}:#{image.bind}"
73
+ })
74
+
75
+ begin
76
+ ## Stream logs
77
+ container.streaming_logs({'stdout' => true, 'stderr' => true, 'follow' => true, 'timestamps' => false }) do |out,msg|
78
+ case out
79
+ when :stdout
80
+ build_log.info { "++ #{msg.chomp}" }
81
+ when :stderr
82
+ build_log.warn { "++ #{msg.chomp}" }
83
+ end
84
+ end
85
+ ## Wait for finish
86
+ build_log.debug { "Waiting #{image.timeout} seconds for container #{container.id} to finish building" }
87
+ status = container.wait(image.timeout)
88
+ rescue Exception => e
89
+ build_log.error { "Error building image #{image.name}" }
90
+ build_log.error { e }
91
+ build_log.info { "Removing container #{container.id}" }
92
+ container.stop
93
+ container.remove
94
+ raise BuildError.new("Interrupted",image)
95
+ end
96
+
97
+ if status['StatusCode'] != 0
98
+ build_log.error { "Error building image #{image.name}" }
99
+ build_log.info { "Removing container #{container.id}" }
100
+ container.remove
101
+ raise BuildError.new(status,image)
102
+ end
103
+
104
+ ## Commit Image
105
+ build_log.debug { "Committing Container #{container.id}" }
106
+ build_log.debug { "Run Config: #{image.commit_config}" }
107
+ build_image = container.commit({'run'=>image.commit_config})
108
+
109
+ build_log.info { "New Image created: #{build_image.id}"}
110
+ build_image = Docker::Image.get(build_image.id)
111
+
112
+ image.tags.each do |tag|
113
+ build_log.debug { "Tagging as #{tag}"}
114
+ t = tag.split(/:/)
115
+ build_image.tag(:repo => t[0], :tag => t[1])
116
+ end
117
+
118
+ ## Cleanup container
119
+ container.remove
120
+ end
121
+ end
122
+
123
+ def inspect
124
+ <<-eos.gsub(/\n?\s{2,}/,'')
125
+ #{self.class.name}<
126
+ @config=#{@config.inspect}
127
+ >
128
+ eos
129
+ end
130
+ end
data/lib/baha/cli.rb ADDED
@@ -0,0 +1,69 @@
1
+ require 'thor'
2
+ require 'baha/builder'
3
+ require 'baha/log'
4
+
5
+ class Baha::CLI < Thor
6
+ desc "build [options] CONFIG", "Builds all docker images based on the given config"
7
+ long_desc <<-LONGDESC
8
+ Reads the CONFIG file and builds all of the docker images in the order they appear.
9
+ LONGDESC
10
+ option :logfile, {
11
+ :required => false,
12
+ :type => :string,
13
+ :desc => "Log output to LOGFILE. Omit to log to stdout."
14
+ }
15
+ option :debug, {
16
+ :aliases => :d,
17
+ :required => false,
18
+ :type => :boolean,
19
+ :default => false,
20
+ :desc => 'Toggle debug logging. Includes verbose.'
21
+ }
22
+ option :verbose, {
23
+ :aliases => :v,
24
+ :required => false,
25
+ :type => :boolean,
26
+ :default => false,
27
+ :desc => 'Toggle verbose logging'
28
+ }
29
+ option :quiet, {
30
+ :aliases => :q,
31
+ :required => false,
32
+ :type => :boolean,
33
+ :default => false,
34
+ :desc => 'Surpress all logging'
35
+ }
36
+ def build(config)
37
+ quiet = options[:quiet]
38
+ unless quiet
39
+ if options[:logfile].nil? or options[:logfile] == 'STDOUT'
40
+ Baha::Log.logfile = STDOUT
41
+ else
42
+ Baha::Log.logfile = STDOUT
43
+ end
44
+ if options[:debug]
45
+ Baha::Log.level = :debug
46
+ elsif options[:verbose]
47
+ Baha::Log.level = :info
48
+ else
49
+ Baha::Log.level = :error
50
+ end
51
+ end
52
+ begin
53
+ builder = Baha::Builder.new(config)
54
+ builder.build!
55
+ rescue Exception => e
56
+ unless quiet
57
+ Baha::Log.for_name("CLI").fatal("Error encountered while building images")
58
+ Baha::Log.for_name("CLI").fatal(e)
59
+ end
60
+ exit 1
61
+ ensure
62
+ Baha::Log.close!
63
+ end
64
+ end
65
+ desc "version", "Print version and exit"
66
+ def version
67
+ puts "baha " + Baha::VERSION
68
+ end
69
+ end