docker-spec 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ec716d228a4a5a27638c2ae5c4e86589f055366b
4
- data.tar.gz: f625a53beed83758039e2766db7dac9fb1106809
3
+ metadata.gz: a736a70e119ee3d55295140138d5f220f382fd4e
4
+ data.tar.gz: 7945ce843581eb476e90346fc40f63cde87db0a5
5
5
  SHA512:
6
- metadata.gz: 6be64c5bd2f787f1440b9127e334e43599f4f23679129df9b2ae7e9d32ba00fa2f3755042075793d6f182a55570b393ace9c710edb0f1c58e7711ee19b6f0d84
7
- data.tar.gz: 7ce469a66bfa79a12f2f9dac5827cdaec2b2216edd7a79a716626bdf0327ce8e3468ed1bab9edf9a97d616c78233f344a669ab260c06cfae965d690dba795a90
6
+ metadata.gz: a3af787003c12260f552e08fdf2a23a80f6377c8c5e243cae6e06abd954643f6918f28cc80262f138510cb20f4c69f5d471c666f531c4f00a7107da83dd82dfe
7
+ data.tar.gz: 88d4133cfb8a0a4b2e2946e0cb80a8d401a763b473f0c23b9a2eae4b18ff3a435ac99f0d27632ddc0e3f5cb6c95369b79fdc962d319b7116a6211b2abc7d2d2d
data/.gitignore CHANGED
@@ -7,3 +7,6 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+
11
+ # Vim files
12
+ *.sw?
data/README.md CHANGED
@@ -35,3 +35,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERN
35
35
 
36
36
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
37
37
 
38
+ # TODO: Finish the integration with push
data/docker-spec.gemspec CHANGED
@@ -21,4 +21,14 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.10"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+ spec.add_dependency 'serverspec'
26
+ spec.add_dependency 'docker-api'
27
+ spec.add_dependency 'pry'
28
+ spec.add_dependency 'timeout'
29
+ spec.add_dependency 'highline'
30
+ spec.add_dependency 'popen4'
31
+ spec.add_dependency 'colorize'
32
+ spec.add_dependency 'logger'
33
+ spec.add_dependency 'moneta'
24
34
  end
data/lib/docker/spec.rb CHANGED
@@ -1,7 +1,182 @@
1
- require "docker/spec/version"
1
+ require 'docker/spec/version'
2
+ require 'docker/spec/docker'
3
+ require 'serverspec'
4
+ require 'docker'
5
+ require 'pry'
6
+ require 'timeout'
7
+ require 'highline/import'
8
+ require 'popen4'
9
+ require 'colorize'
10
+ require 'yaml'
11
+ require 'logger'
12
+ require 'moneta'
13
+ require 'pp'
2
14
 
3
- module Docker
4
- module Spec
5
- # Your code goes here...
15
+ # Documentation
16
+ module DockerSpec
17
+ CONTAINER_RUN_WAIT_TIMEOUT = 60
18
+ CONFIG_FILE = 'docker_spec.yml'
19
+ ROOT_DIR = 'root'
20
+ STDOUT.sync = true
21
+
22
+ def self.run
23
+ load_config
24
+ build_root if @config[:build_root]
25
+ build_docker_image
26
+ rspec_run
27
+ end
28
+
29
+ def self.push
30
+ @config[:push_container] = DockerSpec.get_config(:push_container, 'DOCKER_SPEC_PUSH_CONTAINER',
31
+ 'Push new tag? ')
32
+ if @config[:push_container]
33
+
34
+ @config[:tag_db] ||
35
+ fail('tag_db is not defined in docker_spec.yml')
36
+ @config[:dockerhub] ||
37
+ fail('dockerhub is not defined in docker_spec.yml')
38
+ @config[:dockerhub][:username] ||
39
+ fail('dockerhub->username is not defined in docker_spec.yml')
40
+ @config[:dockerhub][:password] ||
41
+ fail('dockerhub->password is not defined in docker_spec.yml')
42
+ @config[:dockerhub][:email] ||
43
+ fail('dockerhub->email is not defined in docker_spec.yml')
44
+
45
+ # Open key value store and get the current tag for this repo
46
+ store = Moneta.new(:YAML, file: @config[:tag_db])
47
+ current_tag = store.key?(@config[:image_name]) ? store[@config[:image_name]].to_i : 0
48
+ new_tag = current_tag + 1
49
+
50
+ image = Docker::Image.all.detect do |i|
51
+ i.info['RepoTags'].include?(@config[:image_name] + ':latest')
52
+ end
53
+
54
+ # Login to docker hub and push latest and new_tag
55
+ Docker.authenticate! username: @config[:dockerhub][:username],
56
+ password: @config[:dockerhub][:password],
57
+ email: @config[:dockerhub][:email]
58
+
59
+ image.tag repo: @config[:image_name], tag: new_tag, force: true
60
+ puts "\nINFO: pushing #{@config[:image_name]}:#{new_tag} to DockerHub"
61
+ image.push nil, tag: new_tag
62
+
63
+ image.tag repo: @config[:image_name], tag: 'latest', force: true
64
+ puts "INFO: pushing #{@config[:image_name]}:latest to DockerHub"
65
+ image.push nil, tag: 'latest'
66
+
67
+ # Store the new tag in the tag_db
68
+ store[@config[:image_name]] = new_tag
69
+ store.close
70
+ end
71
+ end
72
+
73
+ def self.load_config
74
+ File.exist?(CONFIG_FILE) || fail('Could not load docker_spec.yml')
75
+ @config = YAML.load(File.read(CONFIG_FILE)) ||
76
+ fail('docker_spec.yml is not a valid yml file')
77
+
78
+ @config[:name] || fail('name is not defined in docker_spec.yml')
79
+ @config[:account] || fail('account is not defined in docker_spec.yml')
80
+ @config[:image_name] = format '%s/%s', @config[:account], @config[:name]
81
+ @config[:container_name] = format 'docker_spec-%s', @config[:name]
82
+ @config[:build_root] = DockerSpec.get_config(:build_root, 'DOCKER_SPEC_BUILD_ROOT',
83
+ 'Rebuild root filesystem? ')
84
+ @config[:clear_cache] = DockerSpec.get_config(:clear_cache, 'DOCKER_SPEC_CLEAR_CACHE',
85
+ 'Clear docker cache? ')
86
+ @config
87
+ end
88
+
89
+ def self.build_root
90
+ system 'bash -ec \'sudo chown root:root -R root &&' \
91
+ '(cd root && sudo tar zcf ../root.tar.gz .) && ' \
92
+ 'sudo chown -R `id -u`:`id -g` root.tar.gz root\'' \
93
+ if Dir.exist?(ROOT_DIR)
94
+ end
95
+
96
+ def self.build_docker_image
97
+ # Rebuild the cache filesystem
98
+ build_args = ''
99
+ build_args += ' --no-cache' if @config[:clear_cache]
100
+
101
+ # Build the docker image
102
+ build_cmd = "docker build -t #{@config[:image_name]} #{build_args} ."
103
+ status = POpen4.popen4(build_cmd) do |stdout, stderr, _stdin|
104
+ stdout.each { |line| puts line }
105
+ stderr.each { |line| puts line.red }
106
+ end
107
+ fail("#{build_cmd} failed") if status.exitstatus != 0
108
+ end
109
+
110
+ def self.rspec_run
111
+ set :backend, :docker
112
+
113
+ RSpec.configure do |rc|
114
+ rc.fail_fast = true
115
+
116
+ rc.before(:suite) do
117
+ DockerSpec.delete_container
118
+ DockerSpec.start_container
119
+ end
120
+
121
+ rc.after(:suite) do
122
+ DockerSpec.clean_up
123
+ DockerSpec.push
124
+ end
125
+ end
126
+ docker_tests
127
+ end
128
+
129
+ def self.start_container
130
+ # Run the container with options
131
+ opts = {}
132
+ opts['HostConfig'] = { 'NetworkMode' => @config[:network_mode] } \
133
+ unless @config[:network_mode].nil?
134
+
135
+ opts['env'] = @config[:env] unless @config[:env].nil?
136
+ opts['Image'] = @config[:image_name]
137
+ opts['name'] = @config[:container_name]
138
+ container = Docker::Container.create(opts).start
139
+
140
+ # Check the logs, when it stops logging we can assume the container
141
+ # is fully up and running
142
+ log_size_ary = []
143
+ CONTAINER_RUN_WAIT_TIMEOUT.times do
144
+ log_size_ary << container.logs(stdout: true).size
145
+ break if log_size_ary.last(3).sort.uniq.size == 1 &&
146
+ log_size_ary.last(3).sort.uniq.last > 0
147
+ sleep 1
148
+ end
149
+ set :docker_container, container.id
150
+ end
151
+
152
+ def self.delete_container
153
+ filters = { name: [@config[:container_name]] }.to_json
154
+ Docker::Container.all(all: true, filters: filters).each do |c|
155
+ c.kill
156
+ c.delete
157
+ end
158
+ end
159
+
160
+ def self.clean_up
161
+ # Keep container running
162
+ @config[:keep_running] = DockerSpec.get_config(:keep_running, 'DOCKER_SPEC_KEEP_RUNNING',
163
+ 'Keep container running? ')
164
+ if @config[:keep_running]
165
+ puts "\nINFO: To connect to a running container: \n\n" \
166
+ "docker exec -ti #{@config[:container_name]} bash"
167
+ else
168
+ delete_container
169
+ end
170
+ end
171
+
172
+ def self.get_config(key, envvar, question)
173
+ value = to_boolean(ENV[envvar])
174
+ value ||= @config[key]
175
+ value ||= agree(question, 'n') if value.nil?
176
+ value
177
+ end
178
+
179
+ def self.to_boolean(str)
180
+ str == 'true' unless str.nil?
6
181
  end
7
182
  end
@@ -0,0 +1,35 @@
1
+ module DockerSpec
2
+ def self.docker_tests
3
+ describe 'Running a docker container' do
4
+ before(:all) do
5
+ @config = DockerSpec.load_config
6
+ @image = Docker::Image.all.detect do |i|
7
+ i.info['RepoTags'].include?(@config[:image_name] + ':latest')
8
+ end
9
+ @container = Docker::Container.all.select do |c|
10
+ c.info["Names"] == [ "/" + @config[:container_name] ]
11
+ end.first
12
+ end
13
+
14
+ it 'should be available' do
15
+ expect(@image).to_not be_nil
16
+ end
17
+
18
+ it 'should have state running' do
19
+ expect(@container.json['State']['Running']).to be true
20
+ end
21
+
22
+ it 'Should stay running' do
23
+ expect(@container.json['State']['Running']).to be true
24
+ end
25
+
26
+ it 'Should not have exit processes' do
27
+ expect(@container.logs(stdout: true)).to_not match(/exit/)
28
+ end
29
+
30
+ it 'Services supervisor should be running' do
31
+ expect(process('supervisord')).to be_running
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,5 @@
1
1
  module Docker
2
2
  module Spec
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker-spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Breinlinger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-02-05 00:00:00.000000000 Z
11
+ date: 2016-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,132 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: serverspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: docker-api
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: timeout
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: highline
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: popen4
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: colorize
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: logger
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: moneta
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
41
167
  description: A docker spec library to build and test docker containers
42
168
  email:
43
169
  - "<juan.brein@breins.net>"
@@ -55,6 +181,7 @@ files:
55
181
  - bin/setup
56
182
  - docker-spec.gemspec
57
183
  - lib/docker/spec.rb
184
+ - lib/docker/spec/docker.rb
58
185
  - lib/docker/spec/version.rb
59
186
  homepage: https://github.com/BreinsNet/docker-spec
60
187
  licenses: