dockistrano 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +101 -0
- data/Rakefile +1 -0
- data/bin/doc +13 -0
- data/bin/docker +0 -0
- data/dockistrano.gemspec +32 -0
- data/lib/dockistrano/cli.rb +220 -0
- data/lib/dockistrano/command_line.rb +28 -0
- data/lib/dockistrano/docker.rb +188 -0
- data/lib/dockistrano/git.rb +27 -0
- data/lib/dockistrano/hipache.rb +62 -0
- data/lib/dockistrano/registry.rb +48 -0
- data/lib/dockistrano/service.rb +331 -0
- data/lib/dockistrano/service_dependency.rb +114 -0
- data/lib/dockistrano/version.rb +3 -0
- data/lib/dockistrano.rb +14 -0
- data/spec/dockistrano/cli_spec.rb +296 -0
- data/spec/dockistrano/command_line_spec.rb +27 -0
- data/spec/dockistrano/docker_spec.rb +242 -0
- data/spec/dockistrano/git_spec.rb +48 -0
- data/spec/dockistrano/hipache_spec.rb +81 -0
- data/spec/dockistrano/registry_spec.rb +56 -0
- data/spec/dockistrano/service_dependency_spec.rb +154 -0
- data/spec/dockistrano/service_spec.rb +536 -0
- data/spec/fixtures/project_1/Dockerfile +0 -0
- data/spec/fixtures/project_1/config/dockistrano.yml +8 -0
- data/spec/spec_helper.rb +21 -0
- metadata +242 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module Dockistrano
|
4
|
+
|
5
|
+
class Hipache
|
6
|
+
|
7
|
+
def initialize(hipache_ip)
|
8
|
+
@hipache_ip = hipache_ip
|
9
|
+
end
|
10
|
+
|
11
|
+
def online?
|
12
|
+
redis.ping
|
13
|
+
rescue Redis::CannotConnectError
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def wait_for_online
|
18
|
+
tries = 0
|
19
|
+
while !online? and tries < 5
|
20
|
+
Kernel.sleep 1
|
21
|
+
tries += 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def register(container, hostname, ip_address, port)
|
26
|
+
wait_for_online
|
27
|
+
|
28
|
+
raise "Cannot connect to Redis server, registration failed" unless online?
|
29
|
+
|
30
|
+
unless redis.lrange("frontend:#{hostname}", 0, -1).empty?
|
31
|
+
redis.del("frontend:#{hostname}")
|
32
|
+
end
|
33
|
+
|
34
|
+
redis.rpush("frontend:#{hostname}", container)
|
35
|
+
redis.rpush("frontend:#{hostname}", "http://#{ip_address}:#{port}")
|
36
|
+
end
|
37
|
+
|
38
|
+
def unregister(container, hostname, ip_address, port)
|
39
|
+
if online?
|
40
|
+
redis.lrem("frontend:#{hostname}", 0, "http://#{ip_address}:#{port}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def status
|
45
|
+
mappings = {}
|
46
|
+
if online?
|
47
|
+
redis.keys("frontend:*").each do |key|
|
48
|
+
host = key.gsub(/^frontend:/, "")
|
49
|
+
mappings[host] = redis.lrange(key, 1, -1)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
mappings
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def redis
|
58
|
+
@redis ||= Redis.new(host: @hipache_ip, port: 16379)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Dockistrano
|
2
|
+
|
3
|
+
class Registry
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
@name = name
|
9
|
+
end
|
10
|
+
|
11
|
+
class RepositoryNotFoundInRegistry < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
def tags_for_image(image_name)
|
15
|
+
result = MultiJson.load(get("repositories", image_name, "tags").body)
|
16
|
+
if result["error"]
|
17
|
+
if result["error"] == "Repository not found"
|
18
|
+
raise RepositoryNotFoundInRegistry.new("Could not find repository #{image_name} in registry #{name}")
|
19
|
+
else
|
20
|
+
raise result["error"]
|
21
|
+
end
|
22
|
+
else
|
23
|
+
result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def latest_id_for_image(image_name, tag)
|
28
|
+
response = get("repositories", image_name, "tags", tag)
|
29
|
+
if response.kind_of?(Net::HTTPNotFound)
|
30
|
+
nil
|
31
|
+
else
|
32
|
+
MultiJson.load(response.body)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
name
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def get(*url)
|
43
|
+
uri = URI.parse("http://#{name}/v1/#{url.join("/")}")
|
44
|
+
Net::HTTP.get_response(uri)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,331 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Dockistrano
|
5
|
+
|
6
|
+
class Service
|
7
|
+
|
8
|
+
attr_reader :dependencies, :config, :image_name, :registry,
|
9
|
+
:tag, :test_command, :provides_env, :backing_service_env,
|
10
|
+
:data_directories, :environment, :host, :additional_commands,
|
11
|
+
:mount_src
|
12
|
+
|
13
|
+
attr_writer :tag
|
14
|
+
|
15
|
+
class ConfigurationFileMissing < StandardError
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.factory(path, environment="default")
|
19
|
+
config = if File.exists?(File.join(path, "config", "dockistrano.yml"))
|
20
|
+
YAML.load_file(File.join(path, "config", "dockistrano.yml"))
|
21
|
+
elsif File.exists?(File.join(path, "dockistrano.yml"))
|
22
|
+
YAML.load_file(File.join(path, "dockistrano.yml"))
|
23
|
+
else
|
24
|
+
raise ConfigurationFileMissing
|
25
|
+
end
|
26
|
+
|
27
|
+
environment ||= "default"
|
28
|
+
|
29
|
+
Service.new(config, environment)
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(config, environment="default")
|
33
|
+
@full_config = config
|
34
|
+
self.environment = environment
|
35
|
+
end
|
36
|
+
|
37
|
+
def config=(config)
|
38
|
+
@config = config
|
39
|
+
@dependencies = config["dependencies"] || {}
|
40
|
+
@image_name ||= config["image_name"] || Git.repository_name
|
41
|
+
@tag ||= config["tag"] || Git.branch
|
42
|
+
@registry ||= config["registry"]
|
43
|
+
@host ||= config["host"]
|
44
|
+
@test_command = config["test_command"]
|
45
|
+
@mount_src = config["mount_src"]
|
46
|
+
@provides_env = config["provides_env"] || {}
|
47
|
+
@additional_commands = config["additional_commands"] || {}
|
48
|
+
@data_directories = config["data_directories"] || []
|
49
|
+
@backing_service_env ||= {}
|
50
|
+
@backing_service_env.merge!(config["backing_service_env"] || {})
|
51
|
+
|
52
|
+
config["environment"] ||= {}
|
53
|
+
end
|
54
|
+
|
55
|
+
class EnvironmentNotFoundInConfiguration < StandardError
|
56
|
+
end
|
57
|
+
|
58
|
+
def environment=(environment)
|
59
|
+
if @full_config[environment]
|
60
|
+
self.config = @full_config[environment]
|
61
|
+
else
|
62
|
+
raise EnvironmentNotFoundInConfiguration.new("Environment '#{environment}' not found in configuration (image: #{@full_config["image_name"]}), available: #{@full_config.keys.join(", ")}")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def registry_instance
|
67
|
+
@registry_instance ||= Registry.new(registry)
|
68
|
+
end
|
69
|
+
|
70
|
+
def image_id
|
71
|
+
Docker.image_id(full_image_name)
|
72
|
+
rescue Dockistrano::Docker::ImageNotFound
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def full_image_name
|
77
|
+
"#{registry}/#{image_name}:#{tag}"
|
78
|
+
end
|
79
|
+
|
80
|
+
# Builds a new image for this service
|
81
|
+
def build
|
82
|
+
previous_image_id = image_id
|
83
|
+
Docker.build(full_image_name)
|
84
|
+
if previous_image_id == image_id
|
85
|
+
# If the image id hasn't changed the build was not successfull
|
86
|
+
false
|
87
|
+
else
|
88
|
+
true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Tests the image of this services by running a test command
|
93
|
+
def test
|
94
|
+
environment = "test"
|
95
|
+
unless test_command.nil? or test_command.empty?
|
96
|
+
ensure_backing_services
|
97
|
+
create_data_directories
|
98
|
+
Docker.exec(full_image_name, command: test_command, e: checked_environment_variables, v: volumes)
|
99
|
+
else
|
100
|
+
true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Ensures that the right backing services are running to execute this services
|
105
|
+
# When a backing services is not running it is started
|
106
|
+
def ensure_backing_services
|
107
|
+
backing_services.each do |name, service|
|
108
|
+
service.start unless service.running?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Stops the container of the current service
|
113
|
+
def stop
|
114
|
+
if !host.nil?
|
115
|
+
hipache = Hipache.new(ENV['DOCKER_HOST_IP'])
|
116
|
+
if host.kind_of?(String)
|
117
|
+
hipache.unregister(image_name, host, ip_address, port)
|
118
|
+
else
|
119
|
+
host.each do |hostname, port|
|
120
|
+
hipache.unregister(image_name, hostname, ip_address, port)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
Docker.stop_all_containers_from_image(full_image_name)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns if this service is running
|
129
|
+
def running?
|
130
|
+
Docker.running_container_id(full_image_name)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Pulls backing services for this service
|
134
|
+
def pull_backing_services
|
135
|
+
backing_services.each do |name, service|
|
136
|
+
service.pull
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Pulls the service's container
|
141
|
+
def pull
|
142
|
+
Dockistrano::Docker.pull("#{registry}/#{image_name}", tag_with_fallback)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Pushes the local image for this service to the registry
|
146
|
+
def push
|
147
|
+
Dockistrano::Docker.push("#{registry}/#{image_name}", tag)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Starts this service
|
151
|
+
def start(options={})
|
152
|
+
ensure_backing_services
|
153
|
+
create_data_directories
|
154
|
+
environment = checked_environment_variables
|
155
|
+
|
156
|
+
if additional_commands.any?
|
157
|
+
additional_commands.each do |name, command|
|
158
|
+
Docker.run(full_image_name, e: environment, v: volumes, p: ports, d: true, command: command)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
Docker.run(full_image_name, e: environment, v: volumes, p: ports, d: true)
|
163
|
+
|
164
|
+
if !host.nil?
|
165
|
+
hipache = Hipache.new(ENV['DOCKER_HOST_IP'])
|
166
|
+
if host.kind_of?(String)
|
167
|
+
hipache.register(image_name, host, ip_address, port)
|
168
|
+
else
|
169
|
+
host.each do |hostname, port|
|
170
|
+
hipache.register(image_name, hostname, ip_address, port)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Runs a command in this container
|
177
|
+
def run(command, options={})
|
178
|
+
Docker.run(full_image_name, command: command, e: environment_variables, v: volumes, p: ports)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Executes a command in this container
|
182
|
+
def exec(command, options={})
|
183
|
+
create_data_directories
|
184
|
+
Docker.exec(full_image_name, command: command, e: environment_variables, v: volumes, p: ports)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Starts a console in the docker container
|
188
|
+
def console(command, options={})
|
189
|
+
create_data_directories
|
190
|
+
Docker.console(full_image_name, command: command, e: environment_variables, v: volumes, p: ports)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Lists all backing services for this service
|
194
|
+
def backing_services
|
195
|
+
@backing_services ||= {}.tap do |hash|
|
196
|
+
dependencies.collect do |name, config|
|
197
|
+
hash[name] = ServiceDependency.factory(self, name, config)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Returns an array of environment variables
|
203
|
+
def environment_variables
|
204
|
+
vars = {}
|
205
|
+
|
206
|
+
config["environment"].each do |name, value|
|
207
|
+
vars[name.upcase] = value
|
208
|
+
end
|
209
|
+
|
210
|
+
backing_services.each do |name, backing_service|
|
211
|
+
vars["#{name.upcase}_IP"] = backing_service.ip_address
|
212
|
+
vars["#{name.upcase}_PORT"] = backing_service.port
|
213
|
+
|
214
|
+
backing_service.backing_service_env.each do |k,v|
|
215
|
+
vars["#{name.upcase}_#{k.upcase}"] = v
|
216
|
+
end
|
217
|
+
|
218
|
+
vars.merge!(backing_service.environment_variables)
|
219
|
+
end
|
220
|
+
|
221
|
+
vars.merge!(provides_env)
|
222
|
+
vars.each do |key, value|
|
223
|
+
vars.each do |replacement_key, replacement_value|
|
224
|
+
unless vars[key].nil? or replacement_value.nil?
|
225
|
+
vars[key] = vars[key].gsub('$'+replacement_key, replacement_value)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
vars
|
231
|
+
end
|
232
|
+
|
233
|
+
# Returns the mounted volumes for this service
|
234
|
+
def volumes
|
235
|
+
[].tap do |volumes|
|
236
|
+
volumes << "/dockistrano/#{image_name.gsub("-", "_")}/data:/dockistrano/data"
|
237
|
+
if mount_src and !mount_src.empty?
|
238
|
+
volumes << "/dockistrano/#{image_name.gsub("-", "_")}/src:#{mount_src}"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def directories_required_on_host
|
244
|
+
(volumes.collect { |v| v.split(":").first } + backing_services.values.map(&:directories_required_on_host)).flatten
|
245
|
+
end
|
246
|
+
|
247
|
+
# Returns a list of available tags in the registry for the image
|
248
|
+
def available_tags
|
249
|
+
@available_tags ||= begin
|
250
|
+
registry_instance.tags_for_image(full_image_name)
|
251
|
+
rescue Dockistrano::Registry::RepositoryNotFoundInRegistry
|
252
|
+
[]
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class NoTagFoundForImage < StandardError
|
257
|
+
end
|
258
|
+
|
259
|
+
# Returns the tag that is available with fallback.
|
260
|
+
def tag_with_fallback
|
261
|
+
fallback_tags = [tag, "develop", "master", "latest"]
|
262
|
+
|
263
|
+
begin
|
264
|
+
tag_suggestion = fallback_tags.shift
|
265
|
+
final_tag = tag_suggestion if available_tags.include?(tag_suggestion)
|
266
|
+
end while !final_tag and fallback_tags.any?
|
267
|
+
|
268
|
+
if final_tag
|
269
|
+
final_tag
|
270
|
+
else
|
271
|
+
raise NoTagFoundForImage.new("No tag found for image #{image_name}, available tags: #{available_tags}")
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def ip_address
|
276
|
+
container_settings["NetworkSettings"]["IPAddress"] if running?
|
277
|
+
end
|
278
|
+
|
279
|
+
def port
|
280
|
+
container_settings["NetworkSettings"]["PortMapping"]["Tcp"].keys.first if running?
|
281
|
+
end
|
282
|
+
|
283
|
+
def ports
|
284
|
+
(config["ports"] || {}).collect { |k,v| "#{k}:#{v}" }
|
285
|
+
end
|
286
|
+
|
287
|
+
def attach
|
288
|
+
Docker.attach(Docker.running_container_id(full_image_name))
|
289
|
+
end
|
290
|
+
|
291
|
+
def logs
|
292
|
+
Docker.logs(Docker.last_run_container_id(full_image_name))
|
293
|
+
end
|
294
|
+
|
295
|
+
def create_data_directories
|
296
|
+
if data_directories.any?
|
297
|
+
image_config = Docker.inspect_image(full_image_name)
|
298
|
+
image_user = image_config["container_config"]["User"]
|
299
|
+
|
300
|
+
command = "mkdir -p #{data_directories.collect { |dir| "/dockistrano/data/#{dir}"}.join(" ") }; "
|
301
|
+
command += "chown #{image_user}:#{image_user} #{data_directories.collect { |dir| "/dockistrano/data/#{dir}"}.join(" ") }"
|
302
|
+
bash_command = "/bin/bash -c '#{command}'"
|
303
|
+
Docker.run(full_image_name, command: bash_command, v: volumes, e: environment_variables, u: "root")
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def newer_version_available?
|
308
|
+
registry_image_id = registry_instance.latest_id_for_image(image_name, tag)
|
309
|
+
registry_image_id and image_id != registry_image_id
|
310
|
+
end
|
311
|
+
|
312
|
+
private
|
313
|
+
|
314
|
+
def container_settings
|
315
|
+
@container_settings ||= Docker.inspect_container(Docker.running_container_id(full_image_name))
|
316
|
+
end
|
317
|
+
|
318
|
+
class EnvironmentVariablesMissing < StandardError
|
319
|
+
end
|
320
|
+
|
321
|
+
def checked_environment_variables
|
322
|
+
vars = environment_variables
|
323
|
+
if (empty_vars = vars.select { |k,v| v.nil? }).any?
|
324
|
+
raise EnvironmentVariablesMissing.new("Unable to execute container because of missing environment variables: #{empty_vars.keys.join(", ")}")
|
325
|
+
else
|
326
|
+
vars
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
end
|
331
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Dockistrano
|
2
|
+
|
3
|
+
class ServiceDependency
|
4
|
+
|
5
|
+
# Creates a new service instance based on the name and configuration. When
|
6
|
+
# configuration is not local, the configuration is fetched from Github and
|
7
|
+
# processed.
|
8
|
+
def self.factory(service, name, config)
|
9
|
+
ServiceDependency.new(service, name, config).backing_service
|
10
|
+
end
|
11
|
+
|
12
|
+
class DefaultEnvironmentMissingInConfiguration < StandardError
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :service, :name, :config
|
16
|
+
|
17
|
+
def initialize(service, name, config)
|
18
|
+
@service = service
|
19
|
+
@name = name
|
20
|
+
@config = config
|
21
|
+
end
|
22
|
+
|
23
|
+
def backing_service
|
24
|
+
@backing_service ||= begin
|
25
|
+
backing_service = Service.new("default" => {
|
26
|
+
"registry" => service.registry,
|
27
|
+
"image_name" => name,
|
28
|
+
"tag" => service.tag,
|
29
|
+
"backing_service_env" => config
|
30
|
+
})
|
31
|
+
|
32
|
+
backing_service.tag = tag_with_fallback(service.tag)
|
33
|
+
|
34
|
+
begin
|
35
|
+
loaded_config = load_config
|
36
|
+
if loaded_config and loaded_config["default"]
|
37
|
+
backing_service.config = loaded_config["default"]
|
38
|
+
else
|
39
|
+
raise DefaultEnvironmentMissingInConfiguration.new("No 'default' configuration found in /dockistrano.yml file in #{name} container.")
|
40
|
+
end
|
41
|
+
rescue ContainerConfigurationMissing
|
42
|
+
puts "Warning: no configuration file found for service #{name}."
|
43
|
+
rescue HostDirectoriesMissing
|
44
|
+
puts "Error: missing host directory configuration for #{name}. Please execute `doc setup`"
|
45
|
+
exit 1
|
46
|
+
end
|
47
|
+
|
48
|
+
backing_service
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_config
|
53
|
+
load_from_cache || load_from_image
|
54
|
+
end
|
55
|
+
|
56
|
+
def load_from_cache
|
57
|
+
image_id = backing_service.image_id
|
58
|
+
if image_id and File.exists?("tmp/configuration_cache/#{image_id}")
|
59
|
+
YAML.load_file("tmp/configuration_cache/#{image_id}")
|
60
|
+
else
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class ContainerConfigurationMissing < StandardError
|
66
|
+
end
|
67
|
+
|
68
|
+
class HostDirectoriesMissing < StandardError
|
69
|
+
end
|
70
|
+
|
71
|
+
def load_from_image
|
72
|
+
raw_config = Docker.run(backing_service.full_image_name, command: "cat /dockistrano.yml")
|
73
|
+
if raw_config.empty? or raw_config.include?("No such file or directory")
|
74
|
+
if raw_config.include?("failed to mount")
|
75
|
+
raise HostDirectoriesMissing
|
76
|
+
else
|
77
|
+
raise ContainerConfigurationMissing
|
78
|
+
end
|
79
|
+
else
|
80
|
+
FileUtils.mkdir_p("tmp/configuration_cache")
|
81
|
+
file = File.open("tmp/configuration_cache/#{backing_service.image_id}", "w+")
|
82
|
+
file.write(raw_config)
|
83
|
+
file.close
|
84
|
+
|
85
|
+
config = YAML.load(raw_config)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class NoTagFoundForImage < StandardError
|
90
|
+
end
|
91
|
+
|
92
|
+
def tag_with_fallback(tag)
|
93
|
+
fallback_tags = [tag, "develop", "master", "latest"]
|
94
|
+
|
95
|
+
available_tags = Docker.tags_for_image("#{backing_service.registry}/#{backing_service.image_name}")
|
96
|
+
|
97
|
+
begin
|
98
|
+
tag_suggestion = fallback_tags.shift
|
99
|
+
final_tag = tag_suggestion if available_tags.include?(tag_suggestion)
|
100
|
+
end while !final_tag and fallback_tags.any?
|
101
|
+
|
102
|
+
if final_tag
|
103
|
+
final_tag
|
104
|
+
else
|
105
|
+
raise NoTagFoundForImage.new("No tag found for image #{backing_service.image_name}, locally available tags: #{available_tags} `doc pull` for more tags from repository.")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.clear_cache
|
110
|
+
`rm -rf tmp/configuration_cache/`
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
data/lib/dockistrano.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "dockistrano/cli"
|
2
|
+
require "dockistrano/docker"
|
3
|
+
require "dockistrano/command_line"
|
4
|
+
require "dockistrano/service"
|
5
|
+
require "dockistrano/service_dependency"
|
6
|
+
require "dockistrano/version"
|
7
|
+
require "dockistrano/git"
|
8
|
+
require "dockistrano/registry"
|
9
|
+
require "dockistrano/hipache"
|
10
|
+
|
11
|
+
module Dockistrano
|
12
|
+
# Your code goes here...
|
13
|
+
|
14
|
+
end
|