minke 1.10.0 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
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