minke 1.10.0 → 1.11.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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- Mzg1Y2JlMzZhZmM1YjYwNjgzOGNmMjhiNDZkNTMyMGE0NGMzMGU1OA==
4
+ ZjYxZTYwNDkzZDQwOTQ0OTJhYjRjZjBmYzViNDE5OWQ0YmYxOTNhMg==
5
5
  data.tar.gz: !binary |-
6
- NzZlMDAxMzNmN2E2NTJiZTA4ZGMyZGRhYjIyMzZkODBmYjZlYmYwYg==
6
+ NGFhMWY0MTY5MDBlMGQ1ZDM1YzVmNjUyNjQwYWE2MmI5ZjRkNzAyZA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YTY2ZDlmZTQyNzI5ZjAyOWM2ZmZkOWNlZWFhMGIzNGVkMDA5NWEyYzRkOTk3
10
- NGIzMjdiYzk1NDFmOWViODQ3ZjQ4YWFmNzk2NzA3MWUyY2RhM2RiOWMyOTJh
11
- YTAwZDlmYTY3ZjQ3NDEwMmRlMTMzOWVjODFjY2M0NzcyNzZlOWU=
9
+ NDRkZmEwNzMzZDI2MjM4ZmFiMDJjZjM4ZjEyMDI3MTkwMjE0NmUyMGYwYmU3
10
+ M2Y1NjU4NjRhMjllNDdlYTMyODJjM2NlNDQ5N2ZmNTQyODUxNzRhY2ViOGQ3
11
+ NDc3MGQ3NjA2YWMxYjg5NzQ5MWY0Mzc1NGI5NGE3MzhmYzBmZTA=
12
12
  data.tar.gz: !binary |-
13
- MGEyZDMyNzc1MmQ5MzAwMTAxNTdhMWQ3MjVhNDZkYTZiZTdjZTlhMWY4NmI2
14
- ZmViMTI5NGVmMmNjYjlhZGMxYTVkODAzNzY2OTMzODkyY2JmMmY0OWM2NWNm
15
- YmI5YzE4NjMxYzA5ZTliZmQ4MDZlYjcxMmNiNDg2MzYzM2E1YjM=
13
+ YTExMTAzZDUxNmRmNjQ2MzZhODM2Y2UxMzQzZTY3MzQxZjEyN2E4ZmMxMDMz
14
+ ZjljNWFjNWRhOWRmZTY2YWUwMTFkZTRjMjczNDBiMGUxZDRlNzJiNmEzYmIw
15
+ MjJlM2E3ODVmODk4ZTE2ZTY4ZDBiMTVhYjJhYmQ3N2Y2MDRhZmQ=
@@ -200,6 +200,20 @@ module Minke
200
200
  ##
201
201
  # Task encapsulates the configuration for the various rake tasks like build, run, etc.
202
202
  class Task
203
+ ##
204
+ # consul_loader will specify that the given config file is loaded into Consul.
205
+ # instance of Minke::Config::ConsulLoader
206
+ #
207
+ # [Optional]
208
+ attr_accessor :consul_loader
209
+
210
+ ##
211
+ # health_check is the string representation of a url to check before continuing with the rest of the
212
+ # task a successfull 200 response from the endpoint is required to contine.
213
+ #
214
+ # [Optional]
215
+ attr_accessor :health_check
216
+
203
217
  ##
204
218
  # pre tasks will run before the main task executes.
205
219
  # instance of Minke::Config::TaskRunSettings
@@ -239,20 +253,6 @@ module Minke
239
253
  # [Optional]
240
254
  attr_accessor :tasks
241
255
 
242
- ##
243
- # consul_loader will specify that the given config file is loaded into Consul.
244
- # instance of Minke::Config::ConsulLoader
245
- #
246
- # [Optional]
247
- attr_accessor :consul_loader
248
-
249
- ##
250
- # health_check is the string representation of a url to check before continuing with the rest of the
251
- # task a successfull 200 response from the endpoint is required to contine.
252
- #
253
- # [Optional]
254
- attr_accessor :health_check
255
-
256
256
  ##
257
257
  # copy is an array of Copy instances which will be copied before the task continues.
258
258
  # instance of Minke::Config::Copy
@@ -49,18 +49,18 @@ module Minke
49
49
 
50
50
  def read_task_section section, docker_config
51
51
  Task.new.tap do |t|
52
- t.docker = read_docker_section section['docker'] unless section['docker'] == nil
53
- t.pre = read_pre_post_section section['pre'] unless section['pre'] == nil
54
- t.post = read_pre_post_section section['post'] unless section['post'] == nil
52
+ t.consul_loader = read_consul_loader_section section['consul_loader'] unless section['consul_loader'] == nil
53
+ t.health_check = read_url section['health_check'] unless section['health_check'] == nil
54
+ t.docker = read_docker_section section['docker'] unless section['docker'] == nil
55
+ t.pre = read_pre_post_section section['pre'] unless section['pre'] == nil
56
+ t.post = read_pre_post_section section['post'] unless section['post'] == nil
55
57
  end
56
58
  end
57
59
 
58
60
  def read_pre_post_section section
59
61
  TaskRunSettings.new.tap do |tr|
60
- tr.tasks = section['tasks'] unless section['tasks'] == nil
61
- tr.copy = read_copy_section section['copy'] unless section['copy'] == nil
62
- tr.consul_loader = read_consul_loader_section section['consul_loader'] unless section['consul_loader'] == nil
63
- tr.health_check = read_url section['health_check'] unless section['health_check'] == nil
62
+ tr.tasks = section['tasks'] unless section['tasks'] == nil
63
+ tr.copy = read_copy_section section['copy'] unless section['copy'] == nil
64
64
  end
65
65
  end
66
66
 
@@ -0,0 +1,57 @@
1
+ module Minke
2
+ module Docker
3
+ class Consul
4
+ def initialize health_check, service_discovery, consul_loader, docker_runner, network, project_name
5
+ @health_check = health_check
6
+ @service_discovery = service_discovery
7
+ @consul_loader = consul_loader
8
+ @docker_runner = docker_runner
9
+ @network = network
10
+ @project_name = project_name
11
+ end
12
+
13
+ ##
14
+ # start_and_load_data config
15
+ def start_and_load_data consul_config
16
+ start
17
+ wait_for_startup consul_config.url
18
+ load_data consul_config.url, consul_config.config_file
19
+ end
20
+
21
+ ##
22
+ # stop consul
23
+ def stop
24
+ @docker_runner.stop_container @container
25
+ @docker_runner.delete_container @container
26
+ end
27
+
28
+ private
29
+ def start
30
+ @docker_runner.pull_image 'progrium/consul:latest' unless @docker_runner.find_image 'progrium/consul:latest'
31
+ @container, success = @docker_runner.create_and_run_container(
32
+ {
33
+ :image => 'progrium/consul',
34
+ :network => @network,
35
+ :command => '-server -bootstrap -ui-dir /ui',
36
+ :name => "/#{@project_name}_consul_1",
37
+ :deamon => true
38
+ }
39
+ )
40
+
41
+ puts @container
42
+ end
43
+
44
+ def wait_for_startup url
45
+ server = @service_discovery.build_address(url)
46
+ @health_check.wait_for_HTTPOK "#{server}/v1/status/leader"
47
+ end
48
+
49
+ ##
50
+ # Loads consul data into the given server
51
+ def load_data url, config_file
52
+ server = @service_discovery.build_address(url)
53
+ @consul_loader.load_config config_file, server
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,23 +1,25 @@
1
1
  module Minke
2
2
  module Docker
3
3
  class DockerComposeFactory
4
- def initialize system_runner, project_name
4
+ def initialize system_runner, project_name, docker_network = nil
5
5
  @project_name = project_name
6
6
  @system_runner = system_runner
7
+ @docker_network = docker_network
7
8
  end
8
9
 
9
10
  def create compose_file
10
- Minke::Docker::DockerCompose.new compose_file, @system_runner, @project_name
11
+ Minke::Docker::DockerCompose.new compose_file, @system_runner, @project_name, @docker_network
11
12
  end
12
13
  end
13
14
 
14
15
  class DockerCompose
15
16
  @compose_file = nil
16
17
 
17
- def initialize compose_file, system_runner, project_name
18
+ def initialize compose_file, system_runner, project_name, docker_network = nil
18
19
  @project_name = project_name
19
20
  @compose_file = compose_file
20
21
  @system_runner = system_runner
22
+ @docker_network = docker_network ||= 'bridge'
21
23
  end
22
24
 
23
25
  ##
@@ -45,33 +47,44 @@ module Minke
45
47
  execute_command 'logs -f'
46
48
  end
47
49
 
48
- ##
49
- # return the local address and port of a containers private port
50
- def public_address container, private_port
51
- @system_runner.execute_and_return "docker-compose -f #{@compose_file} port #{container} #{private_port}"
52
- end
53
-
54
50
  def execute_command command
55
- unless ENV['DOCKER_NETWORK'].to_s.empty?
56
- directory = create_compose_network_file
51
+ hash = create_compose
57
52
 
58
- @system_runner.execute "docker-compose -f #{@compose_file} -f #{directory + '/docker-compose.yml'} -p #{@project_name} #{command}"
59
- @system_runner.remove_entry_secure directory
60
- else
61
- @system_runner.execute "docker-compose -f #{@compose_file} -p #{@project_name} #{command}"
53
+ unless @docker_network == nil
54
+ hash.merge!(create_compose_network)
62
55
  end
63
- end
64
-
65
- def create_compose_network_file
66
- content = { 'version' => '2'.to_s, 'networks' => {'default' => { 'external' => { 'name' => ENV['DOCKER_NETWORK'] } } } }
67
56
 
68
57
  directory = @system_runner.mktmpdir
69
58
 
70
59
  temp_file = directory + '/docker-compose.yml'
71
- @system_runner.write_file temp_file, YAML.dump(content)
60
+ puts temp_file
61
+ @system_runner.write_file temp_file, YAML.dump(hash)
62
+
63
+ ex = "docker-compose -f #{temp_file} -p #{@project_name} #{command}"
64
+ puts ex
72
65
 
73
- directory
66
+ @system_runner.execute ex
67
+ @system_runner.remove_entry_secure directory
74
68
  end
69
+
70
+ def create_compose_network
71
+ { 'networks' => {'default' => { 'external' => { 'name' => @docker_network } } } }
72
+ end
73
+
74
+ def create_compose
75
+ existing = YAML.load(File.read(@compose_file))
76
+ services = {}
77
+
78
+ existing['services'].keys.each do |key|
79
+ newservice = existing['services'][key].merge({'external_links' => ["#{@project_name}_consul_1:consul"]})
80
+ services[key] = newservice
81
+ end
82
+
83
+ compose = { 'version' => 2.to_s, 'services' => services }
84
+
85
+ compose
86
+ end
87
+
75
88
  end
76
89
  end
77
90
  end
@@ -1,6 +1,10 @@
1
1
  module Minke
2
2
  module Docker
3
3
  class DockerRunner
4
+ def initialize network = nil
5
+ @network = network ||= 'bridge'
6
+ end
7
+
4
8
  ##
5
9
  # returns the ip address that docker is running on
6
10
  def get_docker_ip_address
@@ -39,6 +43,7 @@ module Minke
39
43
  # pull_image pulls a new copy of the given image from the registry
40
44
  def pull_image image_name
41
45
  puts "Pulling Image: #{image_name}"
46
+ ::Docker.options = {:chunk_size => 1, :read_timeout => 3600}
42
47
  ::Docker::Image.create('fromImage' => image_name)
43
48
  end
44
49
 
@@ -58,39 +63,42 @@ module Minke
58
63
  # Returns:
59
64
  # - Docker::Container
60
65
  # - sucess (true if command succeded without error)
61
- def create_and_run_container image, volumes, environment, working_directory, cmd
66
+ def create_and_run_container args
62
67
  # update the timeout for the Excon Http Client
63
68
  # set the chunk size to enable streaming of log files
64
- #puts working_directory
65
- puts volumes
66
- #puts environment
67
-
68
69
  ::Docker.options = {:chunk_size => 1, :read_timeout => 3600}
69
70
  container = ::Docker::Container.create(
70
- 'Image' => image,
71
- 'Cmd' => cmd,
72
- "Binds" => volumes,
73
- "Env" => environment,
74
- 'WorkingDir' => working_directory)
71
+ 'Image' => args[:image],
72
+ 'Cmd' => args[:command],
73
+ "Binds" => args[:volumes],
74
+ "Env" => args[:environment],
75
+ 'WorkingDir' => args[:working_directory],
76
+ 'NetworkMode' => @network,
77
+ 'name' => args[:name],
78
+ 'PublishAllPorts' => true
79
+ )
75
80
 
76
81
  success = true
77
82
 
78
- thread = Thread.new do
79
- container.attach(:stream => true, :stdin => nil, :stdout => true, :stderr => true, :logs => false, :tty => false) do
80
- |stream, chunk|
81
- stream.to_s == 'stdout' ? color = :green : color = :red
82
- puts "#{chunk.strip}".colorize(color)
83
-
84
- if stream.to_s == "stderr"
85
- success = false
86
- else
87
- success = true
88
- end
83
+ unless args[:deamon] == true
84
+ thread = Thread.new do
85
+ container.attach(:stream => true, :stdin => nil, :stdout => true, :stderr => true, :logs => false, :tty => false) do
86
+ |stream, chunk|
87
+ stream.to_s == 'stdout' ? color = :green : color = :red
88
+ puts "#{chunk.strip}".colorize(color)
89
+
90
+ if stream.to_s == "stderr"
91
+ success = false
92
+ else
93
+ success = true
94
+ end
95
+ end
89
96
  end
90
97
  end
91
98
 
92
99
  container.start
93
- thread.join
100
+
101
+ thread.join unless args[:deamon] == true
94
102
 
95
103
  return container, success
96
104
  end
@@ -98,6 +106,8 @@ module Minke
98
106
  ##
99
107
  # build_image creates a new image from the given Dockerfile and name
100
108
  def build_image dockerfile_dir, name
109
+ puts dockerfile_dir
110
+ puts name
101
111
  ::Docker.options = {:read_timeout => 6200}
102
112
  begin
103
113
  ::Docker::Image.build_from_dir(dockerfile_dir, {:t => name}) do |v|
@@ -106,17 +116,22 @@ module Minke
106
116
  $stdout.puts data unless data == nil
107
117
  end
108
118
  rescue => e
119
+ puts e
109
120
  message = /.*{"message":"(.*?)"}/.match(e.to_s)
110
121
  puts "Error: #{message[1]}" unless message == nil || message.length < 1
111
122
  end
112
123
  end
113
124
 
125
+ def stop_container container
126
+ container.stop()
127
+ end
128
+
114
129
  def delete_container container
115
130
  if container != nil
116
131
  begin
117
132
  container.delete()
118
133
  rescue => e
119
- puts "Error: Unable to delete container"
134
+ puts "Error: Unable to delete container: #{e}"
120
135
  end
121
136
  end
122
137
  end
@@ -0,0 +1,61 @@
1
+ module Minke
2
+ module Docker
3
+ ##
4
+ # HealthCheck checks health of a running container
5
+ class HealthCheck
6
+
7
+ def initialize count=nil, pause=nil
8
+ @count = count ||= 180
9
+ @pause = pause ||= 1
10
+ @successes = 2
11
+ end
12
+
13
+ ##
14
+ # waits until a 200 response is received from the given url
15
+ def wait_for_HTTPOK url
16
+ puts "Waiting for server #{url} to start #{@count} attempts left"
17
+
18
+ begin
19
+ response = RestClient.send('get', url)
20
+ rescue
21
+ puts 'Invalid response from server'
22
+ end
23
+
24
+ check_response response, url
25
+ end
26
+
27
+ private
28
+ def check_response response, url
29
+ if response == nil || !response.code.to_i == 200
30
+ check_failed url
31
+ else
32
+ check_success url
33
+ end
34
+ end
35
+
36
+ def check_failed url
37
+ @count -= 1
38
+ sleep @pause
39
+
40
+ if @count > 0
41
+ wait_for_HTTPOK url
42
+ else
43
+ raise 'Server failed to start'
44
+ end
45
+ end
46
+
47
+ def check_success url
48
+ if @successes > 0
49
+ puts "Server: #{url} passed health check, #{@successes} checks to go..."
50
+
51
+ @successes -= 1
52
+ sleep @pause
53
+ wait_for_HTTPOK url
54
+ else
55
+ puts "Server: #{url} healthy"
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,23 @@
1
+ module Minke
2
+ module Docker
3
+ class Network
4
+ def initialize network_name, shell_runner
5
+ @network_name = network_name
6
+ @shell_runner = shell_runner
7
+ end
8
+
9
+ def create
10
+ @shell_runner.execute("docker network create #{@network_name}") if find_network.to_s == ''
11
+ end
12
+
13
+ def remove
14
+ @shell_runner.execute("docker network rm #{@network_name}") unless find_network.to_s == ''
15
+ end
16
+
17
+ private
18
+ def find_network
19
+ @shell_runner.execute_and_return("docker network ls | grep #{@network_name}")
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,9 +3,10 @@ module Minke
3
3
  ##
4
4
  # ServiceDiscovery allows you to look up the publicly accessible address and port for a server
5
5
  class ServiceDiscovery
6
- def initialize project_name, docker_runner
6
+ def initialize project_name, docker_runner, docker_network = nil
7
7
  @project_name = project_name
8
8
  @docker_runner = docker_runner
9
+ @docker_network = docker_network
9
10
  end
10
11
 
11
12
  ##
@@ -47,7 +48,21 @@ module Minke
47
48
  return "#{ip}:#{private_port}"
48
49
  end
49
50
 
50
- :private
51
+ ##
52
+ # builds an address for the given url
53
+ def build_address url
54
+ if url.type == 'external'
55
+ "#{url.protocol}://#{url.address}:#{url.port}#{url.path}"
56
+ elsif url.type == 'bridge'
57
+ address = bridge_address_for @docker_network, url.address, url.port
58
+ "#{url.protocol}://#{address}#{url.path}"
59
+ elsif url.type == 'public'
60
+ address = public_address_for url.address, url.port
61
+ "#{url.protocol}://#{address}#{url.path}"
62
+ end
63
+ end
64
+
65
+ private
51
66
  def find_container_by_name name
52
67
  containers = @docker_runner.running_containers
53
68
  containers.select { |c| c.info['Names'].include?(name) }
@@ -0,0 +1,17 @@
1
+ module Minke
2
+ module Helpers
3
+ class Copy
4
+ ##
5
+ # copy assets from one location to another
6
+ def copy_assets from, to
7
+ directory = to
8
+ if File.directory?(to)
9
+ directory = File.dirname(to)
10
+ end
11
+
12
+ Dir.mkdir directory unless Dir.exist? to
13
+ FileUtils.cp_r from, to
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module Minke
2
+ module Helpers
3
+ class Error
4
+ ##
5
+ # fatal_error aborts the current execute with the given message
6
+ def fatal_error message
7
+ abort message
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module Minke
2
+ module Helpers
3
+ class Logger
4
+ def log message, level
5
+ ## implement logger implementation
6
+ case level
7
+ when :error
8
+ @logger.error message
9
+ when :info
10
+ @logger.info message
11
+ when :debug
12
+ @logger.debug message
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module Minke
2
+ module Helpers
3
+ class Rake
4
+ ##
5
+ # invoke a rake task
6
+ def invoke_task task
7
+ Rake::Task[task].invoke
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,7 +1,8 @@
1
1
  module Minke
2
- module Docker
3
- class SystemRunner
4
-
2
+ module Helpers
3
+ class Shell
4
+ ##
5
+ # Executes a shell command and returns the return status
5
6
  def execute command
6
7
  system("#{command}")
7
8
  end
@@ -22,7 +23,6 @@ module Minke
22
23
  def write_file filename, data
23
24
  File.open(filename, 'w') { |file| file.write(data) }
24
25
  end
25
-
26
26
  end
27
27
  end
28
- end
28
+ end
@@ -1,52 +1,46 @@
1
- namespace :app do
1
+ require 'minke'
2
+
3
+ reader = Minke::Config::Reader.new
4
+ @config = reader.read './config.yml'
2
5
 
6
+ namespace :app do
3
7
  desc "fetch dependent packages"
4
8
  task :fetch => ['config:set_docker_env'] do
5
- create_dependencies
6
-
7
9
  if @config.fetch != nil
8
10
  puts 'run fetch'
9
- runner = Minke::Tasks::Fetch.new @config, :fetch, @generator_config, @docker_runner, @docker_compose_factory, @service_discovery, @logger, @helper, @system_runner
11
+ runner = Minke::Tasks::Fetch.new create_dependencies :fetch
10
12
  runner.run
11
13
  end
12
14
  end
13
15
 
14
16
  desc "build application"
15
17
  task :build => [:fetch] do
16
- create_dependencies
17
-
18
18
  if @config.build != nil
19
- runner = Minke::Tasks::Build.new @config, :build, @generator_config, @docker_runner, @docker_compose_factory, @service_discovery, @logger, @helper, @system_runner
19
+ runner = Minke::Tasks::Build.new create_dependencies :build
20
20
  runner.run
21
21
  end
22
22
  end
23
23
 
24
24
  desc "run unit tests"
25
25
  task :test => [:build] do
26
- create_dependencies
27
-
28
26
  if @config.test != nil
29
- runner = Minke::Tasks::Test.new @config, :test, @generator_config, @docker_runner, @docker_compose_factory, @service_discovery, @logger, @helper, @system_runner
27
+ runner = Minke::Tasks::Test.new create_dependencies :test
30
28
  runner.run
31
29
  end
32
30
  end
33
31
 
34
32
  desc "build Docker image for application"
35
33
  task :build_image => [:test] do
36
- create_dependencies
37
-
38
34
  if @config.build != nil
39
- runner = Minke::Tasks::BuildImage.new @config, :build, @generator_config, @docker_runner, @docker_compose_factory, @service_discovery, @logger, @helper, @system_runner
35
+ runner = Minke::Tasks::BuildImage.new create_dependencies :build
40
36
  runner.run
41
37
  end
42
38
  end
43
39
 
44
40
  desc "run application with Docker Compose"
45
41
  task :run => ['config:set_docker_env'] do
46
- create_dependencies
47
-
48
42
  if @config.run != nil
49
- runner = Minke::Tasks::Run.new @config, :run, @generator_config, @docker_runner, @docker_compose_factory, @service_discovery, @logger, @helper, @system_runner
43
+ runner = Minke::Tasks::Run.new create_dependencies :run
50
44
  runner.run
51
45
  end
52
46
  end
@@ -56,49 +50,69 @@ namespace :app do
56
50
 
57
51
  desc "run end to end Cucumber tests USAGE: rake app:cucumber[@tag]"
58
52
  task :cucumber, [:feature] => ['config:set_docker_env'] do |t, args|
59
- create_dependencies
60
-
61
53
  if @config.cucumber != nil
62
- runner = Minke::Tasks::Cucumber.new @config, :cucumber, @generator_config, @docker_runner, @docker_compose_factory, @service_discovery, @logger, @helper, @system_runner
54
+ runner = Minke::Tasks::Cucumber.new create_dependencies :cucumber
63
55
  runner.run
64
56
  end
65
57
  end
66
58
 
67
59
  desc "push built image to Docker registry"
68
60
  task :push do
69
- create_dependencies
70
- runner = Minke::Tasks::Push.new @config, :cucumber, @generator_config, @docker_runner, @docker_compose_factory, @service_discovery, @logger, @helper, @system_runner
61
+ runner = Minke::Tasks::Push.new create_dependencies :push
71
62
  runner.run
72
63
  end
73
64
 
74
- def create_dependencies
75
- @project_name = "minke#{SecureRandom.urlsafe_base64(12)}".downcase.gsub('-', '')
76
- ENV["DOCKER_PROJECT"] = @project_name
77
-
78
- @system_runner = Minke::Docker::SystemRunner.new
79
- @docker_compose_factory ||= Minke::Docker::DockerComposeFactory.new @system_runner, @project_name
80
- @docker_runner ||= Minke::Docker::DockerRunner.new
81
- @service_discovery ||= Minke::Docker::ServiceDiscovery.new @project_name, @docker_runner
82
-
83
- if @config == nil
84
- reader = Minke::Config::Reader.new
85
- @config = reader.read './config.yml'
86
- end
87
-
88
- if @generator_config == nil
89
- variables = Minke::Generators::ConfigVariables.new.tap do |v|
90
- v.application_name = @config.application_name
91
- v.namespace = @config.namespace
92
- v.src_root = File.expand_path('../')
93
- end
94
-
95
- Minke::Generators::Processor.load_generators
96
- processor = Minke::Generators::Processor.new variables, @docker_runner
65
+ def create_dependencies task
66
+ project_name = "minke#{SecureRandom.urlsafe_base64(12)}".downcase.gsub(/[^0-9a-z ]/i, '')
67
+ network_name = ENV['DOCKER_NETWORK'] ||= "#{project_name}_default"
68
+ ENV['DOCKER_PROJECT'] = project_name
69
+ ENV['DOCKER_NETWORK'] = network_name
97
70
 
98
- @generator_config = processor.get_generator @config.generator_name
71
+ variables = Minke::Generators::ConfigVariables.new.tap do |v|
72
+ v.application_name = @config.application_name
73
+ v.namespace = @config.namespace
74
+ v.src_root = File.expand_path('../')
99
75
  end
100
76
 
101
- @logger ||= Logger.new(STDOUT)
102
- @helper ||= Minke::Helpers::Helper.new
77
+ Minke::Generators::Processor.load_generators
78
+ processor = Minke::Generators::Processor.new variables, @docker_runner
79
+
80
+ generator_config = processor.get_generator @config.generator_name
81
+
82
+ task_runner = Minke::Tasks::TaskRunner.new ({
83
+ :rake_helper => Minke::Helpers::Rake.new,
84
+ :copy_helper => Minke::Helpers::Copy.new,
85
+ :service_discovery => Minke::Docker::ServiceDiscovery.new(project_name, Minke::Docker::DockerRunner.new, network_name)
86
+ })
87
+
88
+ consul = Minke::Docker::Consul.new(
89
+ Minke::Docker::HealthCheck.new,
90
+ Minke::Docker::ServiceDiscovery.new( project_name, Minke::Docker::DockerRunner.new(network_name), network_name),
91
+ ConsulLoader::Loader.new(ConsulLoader::ConfigParser.new),
92
+ Minke::Docker::DockerRunner.new(network_name),
93
+ network_name,
94
+ project_name
95
+ )
96
+
97
+ network = Minke::Docker::Network.new(
98
+ network_name,
99
+ Minke::Helpers::Shell.new
100
+ )
101
+
102
+ return {
103
+ :config => @config,
104
+ :task_name => task,
105
+ :docker_runner => Minke::Docker::DockerRunner.new(network_name),
106
+ :task_runner => task_runner,
107
+ :error_helper => Minke::Helpers::Error.new,
108
+ :shell_helper => Minke::Helpers::Shell.new,
109
+ :logger_helper => Minke::Helpers::Logger.new,
110
+ :generator_config => generator_config,
111
+ :docker_compose_factory => Minke::Docker::DockerComposeFactory.new(Minke::Helpers::Shell.new, project_name, network_name),
112
+ :consul => consul,
113
+ :docker_network => network,
114
+ :health_check => Minke::Docker::HealthCheck.new,
115
+ :service_discovery => Minke::Docker::ServiceDiscovery.new(project_name, Minke::Docker::DockerRunner.new, network_name)
116
+ }
103
117
  end
104
118
  end
@@ -1,6 +1,6 @@
1
1
  namespace :config do
2
2
  task :set_docker_env do
3
- DOCKER_IP = Minke::Docker::DockerRunner.new.get_docker_ip_address
3
+ DOCKER_IP = Minke::Docker::DockerRunner.new(nil).get_docker_ip_address
4
4
  ENV['DOCKER_IP'] = DOCKER_IP
5
5
  end
6
6
  end
@@ -4,6 +4,7 @@ RVM_COMMAND="source /usr/local/rvm/scripts/rvm"
4
4
  ERROR="Please specify a command e.g. ./minke.sh rake app:test"
5
5
  COMMAND=""
6
6
  NEW_UUID=$(base64 /dev/urandom | tr -d '/+' | head -c 32 | tr '[:upper:]' '[:lower:]')
7
+ NETWORK
7
8
  GEMSET='minkegems'
8
9
  GEMSETFOLDER="/usr/local/rvm/gems/ruby-2.3.1@${GEMSET}"
9
10
 
@@ -29,5 +30,4 @@ if [[ $1 != \ -g* ]]; then
29
30
 
30
31
  eval "docker network create minke_${NEW_UUID}"
31
32
  eval "${DOCKER_RUN}"
32
- eval "docker network rm minke_${NEW_UUID}"
33
33
  fi
@@ -4,14 +4,12 @@ module Minke
4
4
 
5
5
  def run args = nil
6
6
  puts "## Build application"
7
- run_with_block do
8
- if @generator_settings.build_settings.build_commands.build != nil
9
-
10
- @generator_settings.build_settings.build_commands.build.each do |command|
7
+ if @generator_config.build_settings.build_commands.build != nil
8
+ run_with_block do
9
+ @generator_config.build_settings.build_commands.build.each do |command|
11
10
  puts command.to_s
12
- run_command_in_container command
11
+ run_command_in_container command
13
12
  end
14
-
15
13
  end
16
14
  end
17
15
  end
@@ -5,18 +5,22 @@ module Minke
5
5
  def run args = nil
6
6
  puts "## Running cucumber with tags #{args}"
7
7
 
8
- begin
9
- status = 0
10
- @compose.up
8
+ compose_file = @config.compose_file_for(@task_name)
9
+ compose_file = File.expand_path(compose_file)
10
+ compose = @docker_compose_factory.create compose_file unless compose_file == nil
11
11
 
12
- run_with_block do
13
- status = @helper.execute_shell_command "cucumber --color -f pretty #{get_features args}"
12
+ run_with_block do
13
+ status = false
14
+ begin
15
+ compose.up
16
+ server_address = @service_discovery.build_address(@task_settings.health_check)
17
+ @health_check.wait_for_HTTPOK(server_address) unless @task_settings.health_check == nil
18
+
19
+ status = @shell_helper.execute "cucumber --color -f pretty #{get_features args}"
20
+ ensure
21
+ compose.down
22
+ @error_helper.fatal_error("Cucumber steps failed") unless status == true
14
23
  end
15
-
16
- ensure
17
- @compose.down
18
-
19
- @helper.fatal_error "Cucumber steps failed" unless status == 0
20
24
  end
21
25
  end
22
26
 
@@ -6,12 +6,13 @@ module Minke
6
6
  puts "## Update dependencies"
7
7
 
8
8
  puts '### Install gems'
9
- @system_runner.execute('bundle install -j3 && bundle update')
9
+ @shell_helper.execute('bundle install -j3 && bundle update')
10
10
 
11
11
  puts '### Install generator dependencies'
12
- run_with_block do
13
- if @generator_settings.build_settings.build_commands.fetch != nil
14
- @generator_settings.build_settings.build_commands.fetch.each do |command|
12
+
13
+ if @generator_config.build_settings.build_commands.fetch != nil
14
+ run_with_block do
15
+ @generator_config.build_settings.build_commands.fetch.each do |command|
15
16
  run_command_in_container command
16
17
  end
17
18
  end
@@ -5,16 +5,18 @@ module Minke
5
5
  def run args = nil
6
6
  puts "## Run application with docker compose"
7
7
 
8
- begin
9
- @compose.up
8
+ compose_file = @config.compose_file_for(@task_name)
9
+ compose_file = File.expand_path(compose_file)
10
+ compose = @docker_compose_factory.create compose_file unless compose_file == nil
10
11
 
11
- run_with_block do
12
- @compose.logs
12
+ run_with_block do
13
+ begin
14
+ compose.up
15
+ compose.logs
16
+ ensure
17
+ compose.down
13
18
  end
14
-
15
- ensure
16
- @compose.down
17
- end
19
+ end
18
20
  end
19
21
 
20
22
  end
@@ -4,109 +4,83 @@ module Minke
4
4
  # Task is a base implementation of a rake task such as fetch, build, etc
5
5
  class Task
6
6
 
7
- def initialize config, task, generator_settings, docker_runner, docker_compose_factory, service_discovery, logger, helper, system_runner
8
- @config = config
9
- @task = task
10
- @generator_settings = generator_settings
11
- @docker_runner = docker_runner
12
- @service_discovery = service_discovery
13
- @logger = logger
14
- @helper = helper
15
- @task_settings = config.send(task)
16
- @system_runner = system_runner
17
-
18
- @build_image = @generator_settings.build_settings.docker_settings.image
19
- @build_image = config.build_image_for(task) unless config.build_image_for(task) == nil
20
-
21
- @build_file = config.build_docker_file_for(task)
22
-
23
- @compose_file = config.compose_file_for(task)
24
-
25
- @compose = docker_compose_factory.create @compose_file unless @compose_file == nil
7
+ def initialize args
8
+ @config = args[:config]
9
+ @task_name = args[:task_name]
10
+ @docker_runner = args[:docker_runner]
11
+ @task_runner = args[:task_runner]
12
+ @error_helper = args[:error_helper]
13
+ @shell_helper = args[:shell_helper]
14
+ @logger_helper = args[:logger_helper]
15
+ @generator_config = args[:generator_config]
16
+ @docker_compose_factory = args[:docker_compose_factory]
17
+ @consul = args[:consul]
18
+ @docker_network = args[:docker_network]
19
+ @health_check = args[:health_check]
20
+ @service_discovery = args[:service_discovery]
21
+ @task_settings = @config.send(@task_name)
26
22
  end
27
23
 
28
24
  ##
29
25
  # run_with_config executes the task steps for the given
30
26
  # - block containing custom actions
31
27
  def run_with_block
32
- #TODO: Need to add some tests for this stuff
33
- run_steps @task_settings.pre unless @task_settings == nil || @task_settings.pre == nil
34
-
35
- yield if block_given?
36
-
37
- run_steps @task_settings.post unless @task_settings == nil || @task_settings.post == nil
38
- end
28
+ puts "Starting Consul"
29
+ begin
30
+ @docker_network.create
31
+ @consul.start_and_load_data @task_settings.consul_loader unless @task_settings.consul_loader == nil
32
+ @task_runner.run_steps(@task_settings.pre) unless @task_settings == nil || @task_settings.pre == nil
39
33
 
40
- ##
41
- # execute the defined steps in the given Minke::Config::TaskRunSettings
42
- def run_steps steps
43
- execute_rake_tasks steps.tasks unless steps.tasks == nil
44
- load_consul_data steps.consul_loader unless steps.consul_loader == nil
45
- wait_for_health_check steps.health_check unless steps.health_check == nil
46
- copy_assets steps.copy unless steps.copy == nil
47
- end
34
+ yield if block_given?
48
35
 
49
- ##
50
- # execute an array of rake tasks
51
- def execute_rake_tasks tasks
52
- tasks.each { |t| @helper.invoke_task t }
36
+ @task_runner.run_steps(@task_settings.post) unless @task_settings == nil || @task_settings.post == nil
37
+ ensure
38
+ puts "Stopping Consul"
39
+ @consul.stop unless @task_settings.consul_loader == nil
40
+ @docker_network.remove
41
+ end
53
42
  end
54
43
 
55
44
  ##
56
- # load consul config
57
- def load_consul_data config
58
- @helper.load_consul_data build_address(config.url), config.config_file
59
- end
60
-
61
- def wait_for_health_check url
62
- @helper.wait_for_HTTPOK build_address(url), 0, 3
63
- end
64
-
65
- def copy_assets assets
66
- assets.each { |a| @helper.copy_assets a.from, a.to }
67
- end
68
-
45
+ # runs the given command in a docker container
69
46
  def run_command_in_container command
70
47
  begin
71
- settings = @generator_settings.build_settings.docker_settings
72
- if @build_file != nil
73
- @build_image = "#{@config.application_name}-buildimage"
74
- @docker_runner.build_image @build_file, @build_image
75
- else
76
- @docker_runner.pull_image @build_image unless @docker_runner.find_image @build_image
77
- end
78
-
79
- container, success = @docker_runner.create_and_run_container @build_image, settings.binds, settings.env, settings.working_directory, command
48
+ settings = @generator_config.build_settings.docker_settings
49
+ build_image = create_container_image
50
+
51
+ args = {
52
+ :image => build_image,
53
+ :command => command,
54
+ :volumes => settings.binds,
55
+ :environment => settings.env,
56
+ :working_directory => settings.working_directory
57
+ }
58
+ container, success = @docker_runner.create_and_run_container args
80
59
 
81
60
  # throw exception if failed
82
- @helper.fatal_error "Unable to run command #{command}" unless success
61
+ @error_helper.fatal_error "Unable to run command #{command}" unless success
83
62
  ensure
84
63
  @docker_runner.delete_container container
85
64
  end
86
65
  end
87
66
 
88
- def build_address url
89
- if url.type == 'external'
90
- "#{url.protocol}://#{url.address}:#{url.port}#{url.path}"
91
- elsif url.type == 'bridge'
92
- address = @service_discovery.bridge_address_for ENV['DOCKER_NETWORK'], url.address, url.port
93
- "#{url.protocol}://#{address}#{url.path}"
94
- elsif url.type == 'public'
95
- address = @service_discovery.public_address_for url.address, url.port
96
- "#{url.protocol}://#{address}#{url.path}"
67
+ ##
68
+ # Pulls the build image for the container from the registry if one is supplied,
69
+ # if a build file is specified an image is built.
70
+ def create_container_image
71
+ build_image = @generator_config.build_settings.docker_settings.image
72
+ build_image = @config.build_image_for(@task_name) unless @config.build_image_for(@task_name) == nil
73
+
74
+ build_file = @config.build_docker_file_for(@task_name)
75
+
76
+ if build_file != nil
77
+ build_image = "#{@config.application_name}-buildimage"
78
+ @docker_runner.build_image build_file, build_image
79
+ else
80
+ @docker_runner.pull_image build_image unless @docker_runner.find_image build_image
97
81
  end
98
- end
99
82
 
100
- def log message, level
101
- ## implement logger implementation
102
- case level
103
- when :error
104
- @logger.error message
105
- when :info
106
- @logger.info message
107
- when :debug
108
- @logger.debug message
109
- end
83
+ build_image
110
84
  end
111
85
 
112
86
  end
@@ -0,0 +1,33 @@
1
+ module Minke
2
+ module Tasks
3
+ class TaskRunner
4
+
5
+ def initialize args
6
+ @rake_helper = args[:rake_helper]
7
+ @copy_helper = args[:copy_helper]
8
+ @service_discovery = args[:service_discovery]
9
+ end
10
+
11
+ ##
12
+ # execute the defined steps in the given Minke::Config::TaskRunSettings
13
+ def run_steps steps
14
+ execute_rake_tasks steps.tasks unless steps.tasks == nil
15
+ copy_assets steps.copy unless steps.copy == nil
16
+ end
17
+
18
+ private
19
+ ##
20
+ # execute an array of rake tasks
21
+ def execute_rake_tasks tasks
22
+ tasks.each { |t| @rake_helper.invoke_task t }
23
+ end
24
+
25
+ ##
26
+ # copys the assets defined in the step
27
+ def copy_assets assets
28
+ assets.each { |a| @copy_helper.copy_assets a.from, a.to }
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -6,7 +6,7 @@ module Minke
6
6
  puts "## Test application"
7
7
 
8
8
  run_with_block do
9
- @generator_settings.build_settings.build_commands.test.each do |command|
9
+ @generator_config.build_settings.build_commands.test.each do |command|
10
10
  run_command_in_container command
11
11
  end
12
12
  end
data/lib/minke/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Minke
2
- VERSION = "1.10.0"
2
+ VERSION = "1.11.0"
3
3
  end
data/lib/minke.rb CHANGED
@@ -17,16 +17,23 @@ require 'sshkey'
17
17
 
18
18
  require 'minke/version'
19
19
 
20
- require 'minke/helpers/helper'
20
+ require 'minke/helpers/copy'
21
+ require 'minke/helpers/error'
22
+ require 'minke/helpers/logger'
23
+ require 'minke/helpers/rake'
24
+ require 'minke/helpers/shell'
21
25
 
22
26
  require 'minke/docker/docker_compose'
23
27
  require 'minke/docker/docker_runner'
24
- require 'minke/docker/system_runner'
25
28
  require 'minke/docker/service_discovery'
29
+ require 'minke/docker/health_check'
30
+ require 'minke/docker/consul'
31
+ require 'minke/docker/network'
26
32
 
27
33
  require 'minke/config/config'
28
34
  require 'minke/config/reader'
29
35
 
36
+ require 'minke/tasks/task_runner'
30
37
  require 'minke/tasks/task'
31
38
  require 'minke/tasks/build'
32
39
  require 'minke/tasks/cucumber'
data/minke.gemspec CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency 'rspec'
24
24
  spec.add_development_dependency 'guard'
25
25
  spec.add_development_dependency 'guard-rspec'
26
+ spec.add_development_dependency 'webmock'
26
27
 
27
28
  spec.add_runtime_dependency 'sshkey'
28
29
  spec.add_runtime_dependency 'colorize'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minke
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nic Jackson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-08 00:00:00.000000000 Z
11
+ date: 2016-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ! '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: sshkey
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -209,10 +223,12 @@ files:
209
223
  - lib/minke.rb
210
224
  - lib/minke/config/config.rb
211
225
  - lib/minke/config/reader.rb
226
+ - lib/minke/docker/consul.rb
212
227
  - lib/minke/docker/docker_compose.rb
213
228
  - lib/minke/docker/docker_runner.rb
229
+ - lib/minke/docker/health_check.rb
230
+ - lib/minke/docker/network.rb
214
231
  - lib/minke/docker/service_discovery.rb
215
- - lib/minke/docker/system_runner.rb
216
232
  - lib/minke/encryption/encryption.rb
217
233
  - lib/minke/encryption/key_locator.rb
218
234
  - lib/minke/generators/config.rb
@@ -221,7 +237,11 @@ files:
221
237
  - lib/minke/generators/processor.rb
222
238
  - lib/minke/generators/register.rb
223
239
  - lib/minke/generators/shell_script.rb
224
- - lib/minke/helpers/helper.rb
240
+ - lib/minke/helpers/copy.rb
241
+ - lib/minke/helpers/error.rb
242
+ - lib/minke/helpers/logger.rb
243
+ - lib/minke/helpers/rake.rb
244
+ - lib/minke/helpers/shell.rb
225
245
  - lib/minke/rake/app.rake
226
246
  - lib/minke/rake/config.rake
227
247
  - lib/minke/rake/docker.rake
@@ -233,6 +253,7 @@ files:
233
253
  - lib/minke/tasks/push.rb
234
254
  - lib/minke/tasks/run.rb
235
255
  - lib/minke/tasks/task.rb
256
+ - lib/minke/tasks/task_runner.rb
236
257
  - lib/minke/tasks/test.rb
237
258
  - lib/minke/version.rb
238
259
  - minke.gemspec
@@ -1,68 +0,0 @@
1
- module Minke
2
- module Helpers
3
- class Helper
4
- ##
5
- # copy assets from one location to another
6
- def copy_assets from, to
7
- directory = to
8
- if File.directory?(to)
9
- directory = File.dirname(to)
10
- end
11
-
12
- Dir.mkdir directory unless Dir.exist? to
13
- FileUtils.cp_r from, to
14
- end
15
-
16
- ##
17
- # invoke a rake task
18
- def invoke_task task
19
- Rake::Task[task].invoke
20
- end
21
-
22
- def load_consul_data server, config_file
23
- wait_for_HTTPOK "#{server}/v1/status/leader", 0, 1
24
- loader = ConsulLoader::Loader.new(ConsulLoader::ConfigParser.new)
25
- puts config_file
26
- loader.load_config config_file, server
27
- end
28
-
29
- def execute_shell_command command
30
- puts `#{command}`
31
- $?.exitstatus
32
- end
33
-
34
- def fatal_error message
35
- abort message
36
- end
37
-
38
- ##
39
- # waits until a 200 response is received from the given url
40
- def wait_for_HTTPOK url, count, successes = 3
41
- begin
42
- response = RestClient.send("get", url)
43
- rescue
44
-
45
- end
46
-
47
- if response == nil || !response.code.to_i == 200
48
- puts "Waiting for server #{url} to start"
49
- sleep 1
50
- if count < 180
51
- wait_for_HTTPOK url, count + 1
52
- else
53
- raise 'Server failed to start'
54
- end
55
- else
56
- if successes > 0
57
- puts "Server: #{url} passed health check, #{successes} checks to go..."
58
- sleep 1
59
- wait_for_HTTPOK url, count + 1, successes - 1
60
- else
61
- puts "Server: #{url} healthy"
62
- end
63
- end
64
- end
65
-
66
- end
67
- end
68
- end