athlete 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 +22 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +297 -0
- data/Rakefile +2 -0
- data/athlete.gemspec +27 -0
- data/bin/athlete +5 -0
- data/lib/athlete.rb +20 -0
- data/lib/athlete/build.rb +130 -0
- data/lib/athlete/cli.rb +118 -0
- data/lib/athlete/deployment.rb +285 -0
- data/lib/athlete/logging.rb +34 -0
- data/lib/athlete/utils.rb +34 -0
- data/lib/athlete/version.rb +3 -0
- data/lib/marathon/LICENSE.txt +22 -0
- data/lib/marathon/client.rb +130 -0
- data/lib/marathon/response.rb +54 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6d3860c8ddee3f9c32fe243c211833b00ae37488
|
4
|
+
data.tar.gz: 47a5c48f169f581acb8c100b9428e69dec334778
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a0ee2dfa941b4e3c504b6530bfe344170da34a8cb6500b05cf062c49832d55c07a05c784472034f8258990e2b9169a8e09df95072d050f3e183431863e1b2a2b
|
7
|
+
data.tar.gz: 17ca485cf67f9ff3afe517b049b3c104feda65f9b30d63ab3e0e3fa8180e025cf1f3f575478f1ba63497ed64f01e59e120541e6d7265ef1448802ddf405fe32d
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
athlete
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Andy Sykes
|
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,297 @@
|
|
1
|
+
# Athlete
|
2
|
+
|
3
|
+
Athlete is a Capistrano-like deployment tool for deploying Docker
|
4
|
+
containers into [Marathon](https://mesosphere.github.io/marathon/).
|
5
|
+
|
6
|
+
Warning: Athlete is at best a beta. It may not understand all Marathon responses, it
|
7
|
+
lacks some features, and it doesn't do some basic error checking. Use at your own risk.
|
8
|
+
Pull requests welcomed. YMMV.
|
9
|
+
|
10
|
+
## Why Athlete exists
|
11
|
+
|
12
|
+
If you're a Ruby developer, Capistrano makes things so fantastically easy that you miss it when
|
13
|
+
you start to package apps as Docker containers.
|
14
|
+
|
15
|
+
Athlete was written to become, internally, a simple Capistrano-like tool that allows developers
|
16
|
+
to quickly and easily deploy to our Marathon cluster.
|
17
|
+
|
18
|
+
## Features
|
19
|
+
|
20
|
+
- Simple DSL for defining Docker builds and deployments
|
21
|
+
- Detects deployment failures
|
22
|
+
- Simple (~750 LoC)
|
23
|
+
- Allows Marathon properties to be set outside deployments or forced
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
Add these lines to your application's Gemfile, in the `:development` group:
|
28
|
+
|
29
|
+
group :development do
|
30
|
+
... some other gems ...
|
31
|
+
gem 'athlete'
|
32
|
+
end
|
33
|
+
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
bundle install --binstubs
|
37
|
+
|
38
|
+
Athlete isn't required at runtime.
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
Athlete performs two actions: building, and deploying.
|
43
|
+
|
44
|
+
An Athlete build runs `docker build`, tags the image appropriately
|
45
|
+
(including the registry name if you're using a private registry),
|
46
|
+
and the pushes it to the registry. This push step can be skipped.
|
47
|
+
|
48
|
+
An Athlete deploy uses Marathon's REST API to deploy one of the Docker
|
49
|
+
containers built in the build step or any arbitrary Docker container -
|
50
|
+
you are not limited to only deploying containers you built.
|
51
|
+
|
52
|
+
### Command line usage
|
53
|
+
|
54
|
+
(You may want to read the configuration section first, since you
|
55
|
+
need a configuration before you can do anything.)
|
56
|
+
|
57
|
+
To get help with the CLI:
|
58
|
+
|
59
|
+
bin/athlete help
|
60
|
+
|
61
|
+
To build all builds in the configuration file:
|
62
|
+
|
63
|
+
bin/athlete build
|
64
|
+
|
65
|
+
To build all builds put not push them:
|
66
|
+
|
67
|
+
bin/athlete build --no-push
|
68
|
+
|
69
|
+
To deploy all deployments in the configuration file:
|
70
|
+
|
71
|
+
bin/athlete deploy
|
72
|
+
|
73
|
+
### Configuration
|
74
|
+
|
75
|
+
Athlete is configured using a simple DSL.
|
76
|
+
|
77
|
+
By default, it expects the configuration file to be called `athlete.rb` and
|
78
|
+
to be placed in the `config` directory relative to the base of your app.
|
79
|
+
|
80
|
+
__Todo: write a command to produce a template athlete.rb file__
|
81
|
+
|
82
|
+
A build takes some information about the name you want to give your
|
83
|
+
container, how it should be versioned, and what registry it should be pushed to.
|
84
|
+
|
85
|
+
A deployment takes some information about where to deploy to, how many
|
86
|
+
instances to run, how much CPU and memory resource to allocate, and so on.
|
87
|
+
|
88
|
+
Here's an example of a simple image build and deploy:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
Athlete::Build.define('my-image') do
|
92
|
+
registry 'my-registry:5000'
|
93
|
+
version '1'
|
94
|
+
end
|
95
|
+
|
96
|
+
Athlete::Deployment.define('my-app') do
|
97
|
+
marathon_url 'http://marathon:8080'
|
98
|
+
# image_name 'ubuntu:12.04'
|
99
|
+
# command ['/bin/sleep', '600']
|
100
|
+
# arguments ['something']
|
101
|
+
# environment_variables {'RACK_ENV' => 'production'}
|
102
|
+
build_name 'my-image'
|
103
|
+
cpus 1, :override
|
104
|
+
memory 128, :inherit
|
105
|
+
instances 1, :override
|
106
|
+
minimum_health_capacity 0.5, :inherit
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
This will build an image tagged `my-registry:5000/my-image:1`, remembering
|
111
|
+
that the Docker image conventions are: `registry_url:registry_port/image_name:image_version`.
|
112
|
+
|
113
|
+
Once built, it will deploy a container based on that image to the Marathon host
|
114
|
+
at `http://marathon:8080`. It will request 1 CPU and 128MB of RAM from Marathon,
|
115
|
+
and run one instance of the container. See below for details of what the property
|
116
|
+
`minimum_health_capacity` does.
|
117
|
+
|
118
|
+
#### Build DSL reference
|
119
|
+
|
120
|
+
| Property | Required | Description |
|
121
|
+
| -------- | -------- | ----------- |
|
122
|
+
| registry | no | The Docker registry to push to - if unspecified, we use the Docker Hub. |
|
123
|
+
| version | yes | How to version the image; this can be any stringifiable object, or the symbol `:git`, which will version using the output of `git rev-parse HEAD` |
|
124
|
+
|
125
|
+
#### Deployment DSL reference
|
126
|
+
|
127
|
+
Some properties are defined with an extra parameter which is either
|
128
|
+
`:override` or `:inherit` - in the above example, `instances 1, :override`
|
129
|
+
is specified with `:override`, and `memory 128, :inherit` is specified with
|
130
|
+
`:inherit`.
|
131
|
+
|
132
|
+
These properties are ones that can be varied in Marathon through other means.
|
133
|
+
For example, you may have a separate 'scaling' system that changes the number
|
134
|
+
of instances of a container in response to some parameter. Let's say that it
|
135
|
+
has acted to increase the number of instances to 5, and our `athlete.rb` has
|
136
|
+
this line in the deployment section:
|
137
|
+
|
138
|
+
instances 1, :override
|
139
|
+
|
140
|
+
When you deploy, Athlete will see that Marathon's currently running value for
|
141
|
+
instances of the app is 5, and that you set it to 1 in your deployment configuration
|
142
|
+
with `:override`, and it will _force_ there to be only 1 instance after the deployment.
|
143
|
+
|
144
|
+
This would be non-ideal, since your scaling system is 'authoritative' for this
|
145
|
+
property - it decides how many instances should run. Resetting it when you deploy
|
146
|
+
could break production!
|
147
|
+
|
148
|
+
If you had set the instances property to be `:inherit`, like so:
|
149
|
+
|
150
|
+
instances 1, :inherit
|
151
|
+
|
152
|
+
Then when you run a deploy, Athlete will completely ignore the instance value set in
|
153
|
+
the configuration file, and just trust whatever is currently set in Marathon.
|
154
|
+
|
155
|
+
The only time _all parameters_ will be sent to Marathon is when an app
|
156
|
+
does not already exist. In that case, we have to supply some initial values to get the app going.
|
157
|
+
|
158
|
+
##### `marathon_url`
|
159
|
+
|
160
|
+
__required__: yes
|
161
|
+
__override/inherit__: no
|
162
|
+
|
163
|
+
The URL to the Marathon REST API endpoint you're using.
|
164
|
+
|
165
|
+
##### `build_name`
|
166
|
+
|
167
|
+
__required__: yes (if not supplying `image_name`)
|
168
|
+
__override/inherit__: no
|
169
|
+
|
170
|
+
The build name to get Docker image information from. You must
|
171
|
+
reference a build defined earlier in the `athlete.rb` file. The name of a build
|
172
|
+
is the string supplied to the `define` call. E.g.
|
173
|
+
|
174
|
+
Athlete::Build.define('my-image') do
|
175
|
+
registry 'my-registry:5000'
|
176
|
+
version '1'
|
177
|
+
end
|
178
|
+
|
179
|
+
You would reference this by setting:
|
180
|
+
|
181
|
+
build_name 'my-image'
|
182
|
+
|
183
|
+
in your deployment definition.
|
184
|
+
|
185
|
+
It is required if you are not specifying `image_name`.
|
186
|
+
|
187
|
+
##### `image_name`
|
188
|
+
|
189
|
+
__required__: yes (if not supplying `build_name`)
|
190
|
+
__override/inherit__: no
|
191
|
+
|
192
|
+
The Docker image name to deploy. You must specify the entire image name,
|
193
|
+
including whatever tagged version you want. E.g. `ubuntu:12.04`.
|
194
|
+
|
195
|
+
It is required if you are not specifying `build_name`.
|
196
|
+
|
197
|
+
##### `command`
|
198
|
+
|
199
|
+
__required__: no
|
200
|
+
__override/inherit__: no
|
201
|
+
|
202
|
+
The command to run inside the Docker container. This will override
|
203
|
+
the `CMD` section of the Dockerfile.
|
204
|
+
|
205
|
+
##### `arguments`
|
206
|
+
|
207
|
+
__required__: no
|
208
|
+
__override/inherit__: no
|
209
|
+
|
210
|
+
Arguments to supply to the container's ENTRYPOINT. This should be
|
211
|
+
an array of strings.
|
212
|
+
|
213
|
+
##### `cpus`
|
214
|
+
|
215
|
+
__required__: yes (on a cold deploy)
|
216
|
+
__override/inherit__: yes
|
217
|
+
|
218
|
+
CPU resource to request for this app. This can be a fractional value (e.g. 0.1).
|
219
|
+
|
220
|
+
##### `memory`
|
221
|
+
|
222
|
+
__required__: yes (on a cold deploy)
|
223
|
+
__override/inherit__: yes
|
224
|
+
|
225
|
+
Memory to request for this app in MB.
|
226
|
+
|
227
|
+
##### `environment_variables`
|
228
|
+
|
229
|
+
__required__: no
|
230
|
+
__override/inherit__: no
|
231
|
+
|
232
|
+
Environment variables to pass into the container at startup - must be specified
|
233
|
+
as a hash of `ENV_VAR_NAME => ENV_VAR_VALUE`.
|
234
|
+
|
235
|
+
##### `instances`
|
236
|
+
|
237
|
+
__required__: no
|
238
|
+
__override/inherit__: yes
|
239
|
+
|
240
|
+
Number of instances of the container to run.
|
241
|
+
|
242
|
+
##### `minimum_health_capacity`
|
243
|
+
|
244
|
+
__required__: no
|
245
|
+
__override/inherit__: yes
|
246
|
+
|
247
|
+
This description is taken from the
|
248
|
+
[Marathon documentation](https://mesosphere.github.io/marathon/docs/rest-api.html#post-/v2/apps).
|
249
|
+
|
250
|
+
> During an upgrade all instances of an application get replaced by a new version.
|
251
|
+
> The minimumHealthCapacity defines the minimum number of healthy nodes, that do not sacrifice
|
252
|
+
> overall application purpose. It is a number between 0 and 1 which is multiplied with the
|
253
|
+
> instance count. The default minimumHealthCapacity is 1, which means no old instance can be stopped,
|
254
|
+
> before all new instances are deployed. A value of 0.5 means that an upgrade can be deployed side by side,
|
255
|
+
> by taking half of the instances down in the first step, deploy half of the new version and
|
256
|
+
> then take the other half down and deploy the rest. A value of 0 means take all instances down
|
257
|
+
> immediately and replace with the new application.
|
258
|
+
|
259
|
+
## Contributing
|
260
|
+
|
261
|
+
1. Fork it ( https://github.com/forward3d/athlete/fork )
|
262
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
263
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
264
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
265
|
+
5. Create a new pull request
|
266
|
+
|
267
|
+
## Acknowledgements
|
268
|
+
|
269
|
+
This repository includes code from the [marathon_client gem](https://github.com/mesosphere/marathon_client).
|
270
|
+
It is included with Athlete as Athlete requires some unreleased functionality, and some additional
|
271
|
+
functionality, and it is not possible (rightly!) to make gems dependent on git repositories.
|
272
|
+
|
273
|
+
In accordance with the MIT license, the license information from marathon_client is included here,
|
274
|
+
and in the `lib/marathon` directory, which are files covered by the below license:
|
275
|
+
|
276
|
+
Copyright (c) 2013 Tobi Knaup
|
277
|
+
|
278
|
+
MIT License
|
279
|
+
|
280
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
281
|
+
a copy of this software and associated documentation files (the
|
282
|
+
"Software"), to deal in the Software without restriction, including
|
283
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
284
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
285
|
+
permit persons to whom the Software is furnished to do so, subject to
|
286
|
+
the following conditions:
|
287
|
+
|
288
|
+
The above copyright notice and this permission notice shall be
|
289
|
+
included in all copies or substantial portions of the Software.
|
290
|
+
|
291
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
292
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
293
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
294
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
295
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
296
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
297
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/athlete.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'athlete/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "athlete"
|
8
|
+
spec.version = Athlete::VERSION
|
9
|
+
spec.authors = ["Andy Sykes"]
|
10
|
+
spec.email = ["github@tinycat.co.uk"]
|
11
|
+
spec.summary = %q{A deployment tool for Marathon and Mesos}
|
12
|
+
spec.description = %q{A deployment tool for building Docker containers for Marathon and Mesos}
|
13
|
+
spec.homepage = "https://github.com/forward3d/athlete"
|
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_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
|
24
|
+
spec.add_dependency "thor", "~> 0.19"
|
25
|
+
spec.add_dependency "httparty", "~> 0.13"
|
26
|
+
spec.add_dependency "multi_json", "~> 1.10"
|
27
|
+
end
|
data/bin/athlete
ADDED
data/lib/athlete.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'open3'
|
3
|
+
require 'httparty'
|
4
|
+
require 'multi_json'
|
5
|
+
require_relative 'marathon/client'
|
6
|
+
require_relative 'marathon/response'
|
7
|
+
|
8
|
+
require_relative "athlete/version"
|
9
|
+
require_relative "athlete/logging"
|
10
|
+
require_relative "athlete/utils"
|
11
|
+
require_relative "athlete/build"
|
12
|
+
require_relative "athlete/cli"
|
13
|
+
require_relative "athlete/deployment"
|
14
|
+
|
15
|
+
module Athlete
|
16
|
+
class BuildConfigurationInvalid < Exception; end
|
17
|
+
class BuildFailedException < Exception; end
|
18
|
+
class CommandExecutionFailed < Exception; end
|
19
|
+
class ConfigurationInvalidException < Exception; end
|
20
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Athlete
|
2
|
+
class Build
|
3
|
+
include Logging
|
4
|
+
|
5
|
+
@builds = {}
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :builds
|
9
|
+
end
|
10
|
+
|
11
|
+
# Define valid properties
|
12
|
+
@@valid_properties = %w{
|
13
|
+
name
|
14
|
+
registry
|
15
|
+
version
|
16
|
+
}
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@@valid_properties.each do |property|
|
20
|
+
self.class.class_eval {
|
21
|
+
define_method(property) do |arg|
|
22
|
+
instance_variable_set("@#{property}", arg)
|
23
|
+
self.class.class_eval{attr_reader property.to_sym}
|
24
|
+
end
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup_dsl_methods
|
30
|
+
@@valid_properties.each do |property|
|
31
|
+
self.class.class_eval {
|
32
|
+
define_method(property) do |arg|
|
33
|
+
instance_variable_set("@#{property}", arg)
|
34
|
+
self.class.class_eval{attr_reader property.to_sym}
|
35
|
+
end
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.define(name, &block)
|
41
|
+
build = Athlete::Build.new
|
42
|
+
build.name name
|
43
|
+
build.instance_eval(&block)
|
44
|
+
build.fill_default_values
|
45
|
+
@builds[build.name] = build
|
46
|
+
end
|
47
|
+
|
48
|
+
def fill_default_values
|
49
|
+
@version_method ||= :git_head
|
50
|
+
end
|
51
|
+
|
52
|
+
def final_image_name
|
53
|
+
@final_image_name ||= @registry.nil? ? "#{@name}:#{determined_version}" : "#{@registry}/#{@name}:#{determined_version}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def determined_version
|
57
|
+
case @version
|
58
|
+
when :git_head
|
59
|
+
return git_tag
|
60
|
+
else
|
61
|
+
return @version.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Figure out the short hash of the current HEAD
|
66
|
+
def git_tag
|
67
|
+
return @git_tag if @git_tag
|
68
|
+
@git_tag = `git rev-parse --short HEAD 2>&1`.chomp
|
69
|
+
if $? != 0
|
70
|
+
raise Athlete::BuildFailedException, "Could not determine git hash of HEAD, output was: #{@git_tag}"
|
71
|
+
end
|
72
|
+
@git_tag
|
73
|
+
end
|
74
|
+
|
75
|
+
# Create the image name with a specified git tag
|
76
|
+
def image_name_with_specified_version(version)
|
77
|
+
@registry.nil? ? "#{@name}:#{version}" : "#{@registry}/#{@name}:#{version}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def perform(should_push)
|
81
|
+
build
|
82
|
+
if should_push
|
83
|
+
push
|
84
|
+
else
|
85
|
+
info "Skipping push of image as --no-push was specified"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Build the Docker image
|
90
|
+
def build
|
91
|
+
info "Building with image name as: '#{final_image_name}', tagged #{determined_version}"
|
92
|
+
command = "docker build -t #{final_image_name} ."
|
93
|
+
logged_command = get_loglevel == Logger::INFO ? 'docker build' : command
|
94
|
+
retval = Utils::Subprocess.run command do |stdout, stderr, thread|
|
95
|
+
info "[#{logged_command}] [stdout] #{stdout}"
|
96
|
+
info "[#{logged_command}] [stderr] #{stderr}" if stderr != nil
|
97
|
+
end
|
98
|
+
if retval.exitstatus != 0
|
99
|
+
raise Athlete::CommandExecutionFailed, "The command #{command} exited with non-zero status #{retval.exitstatus}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Push image to remote registry (Docker Hub or private registry)
|
104
|
+
def push
|
105
|
+
if @registry.nil?
|
106
|
+
info "Preparing to push image to the Docker Hub"
|
107
|
+
else
|
108
|
+
info "Preparing to push image to '#{@registry}'"
|
109
|
+
end
|
110
|
+
|
111
|
+
command = "docker push #{final_image_name}"
|
112
|
+
retval = Utils::Subprocess.run "docker push #{final_image_name}" do |stdout, stderr, thread|
|
113
|
+
info "[#{logged_command}] [stdout] #{stdout}"
|
114
|
+
info "[#{logged_command}] [stderr] #{stderr}" if stderr != nil
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
def readable_output
|
120
|
+
lines = []
|
121
|
+
lines << " Build name: #{@name}"
|
122
|
+
@@valid_properties.sort.each do |property|
|
123
|
+
next if property == 'name'
|
124
|
+
lines << sprintf(" %-10s: %s", property, instance_variable_get("@#{property}")) if instance_variable_get("@#{property}")
|
125
|
+
end
|
126
|
+
puts lines.join("\n")
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|