docker-app 0.2.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 +11 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docker-app.gemspec +36 -0
- data/exe/docker-app +20 -0
- data/lib/docker_app.rb +23 -0
- data/lib/docker_app/builder/packer.rb +105 -0
- data/lib/docker_app/chef/.chef/knife.rb +118 -0
- data/lib/docker_app/chef/chef_build_image.rb +55 -0
- data/lib/docker_app/chef/chef_destroy_container.rb +13 -0
- data/lib/docker_app/chef/chef_destroy_image.rb +17 -0
- data/lib/docker_app/chef/chef_exec_container.rb +16 -0
- data/lib/docker_app/chef/chef_run_container.rb +64 -0
- data/lib/docker_app/chef/install_container_service.rb +14 -0
- data/lib/docker_app/cli.rb +502 -0
- data/lib/docker_app/command.rb +16 -0
- data/lib/docker_app/config.rb +249 -0
- data/lib/docker_app/config/dsl.rb +64 -0
- data/lib/docker_app/config/helpers.rb +99 -0
- data/lib/docker_app/manager_container.rb +376 -0
- data/lib/docker_app/manager_image.rb +119 -0
- data/lib/docker_app/manager_swarm.rb +66 -0
- data/lib/docker_app/provisioner/base.rb +179 -0
- data/lib/docker_app/provisioner/chef.rb +93 -0
- data/lib/docker_app/server_settings.rb +361 -0
- data/lib/docker_app/version.rb +3 -0
- data/lib/templates/example-chef/.chef/knife.rb +5 -0
- data/lib/templates/example-chef/config.rb.erb +18 -0
- data/lib/templates/example-chef/servers/server1/.chef/knife.rb +8 -0
- data/lib/templates/example-chef/servers/server1/config.rb.erb +54 -0
- data/lib/templates/example-chef/servers/server1/cookbooks/server1/README.md +1 -0
- data/lib/templates/example-chef/servers/server1/cookbooks/server1/metadata.rb.erb +8 -0
- data/lib/templates/example-chef/servers/server1/cookbooks/server1/recipes/build.rb +10 -0
- data/lib/templates/example-chef/servers/server1/cookbooks/server1/recipes/install.rb +36 -0
- data/lib/templates/example-chef/servers/server1/cookbooks/server1/recipes/install_host.rb +9 -0
- data/lib/templates/example-chef/servers/server1/cookbooks/server1/templates/index.html.erb +5 -0
- data/lib/templates/example-chef/servers/server1/cookbooks/server1/templates/nginx-sites/default.conf.erb +45 -0
- data/readme.md +853 -0
- data/readme_developers.md +54 -0
- metadata +129 -0
@@ -0,0 +1,249 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'docker_app/config/dsl'
|
3
|
+
require 'docker_app/config/helpers'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
module DockerApp
|
8
|
+
module Config
|
9
|
+
#class Error < DockerApp::Error; end
|
10
|
+
|
11
|
+
DEFAULTS = {
|
12
|
+
:config_file => 'config.rb',
|
13
|
+
:tmp_path => 'temp'
|
14
|
+
}
|
15
|
+
|
16
|
+
class << self
|
17
|
+
#include Utilities::Helpers
|
18
|
+
|
19
|
+
attr_reader :servers, :options,
|
20
|
+
:root_path, :config_file, :tmp_path
|
21
|
+
|
22
|
+
|
23
|
+
# Define on self, since it's a class method
|
24
|
+
def method_missing(method_sym, *arguments, &block)
|
25
|
+
# the first argument is a Symbol, so you need to_s it if you want to pattern match
|
26
|
+
if options.has_key?(method_sym)
|
27
|
+
return options[method_sym]
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
#if method_sym.to_s =~ /^find_by_(.*)$/
|
32
|
+
# find($1.to_sym => arguments.first)
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
# Loads the user's +config.rb+ and all model files.
|
39
|
+
def load(opts = {})
|
40
|
+
update(opts) # from the command line
|
41
|
+
|
42
|
+
#config_file = 'temp_config.rb'
|
43
|
+
|
44
|
+
puts "config file: #{config_file}"
|
45
|
+
|
46
|
+
unless File.exist?(config_file)
|
47
|
+
#raise Error, "Could not find configuration file: '#{config_file}'."
|
48
|
+
raise "Could not find configuration file: '#{config_file}'."
|
49
|
+
end
|
50
|
+
|
51
|
+
text_config = File.read(config_file)
|
52
|
+
|
53
|
+
dsl = DSL.new
|
54
|
+
dsl.instance_eval(text_config, config_file)
|
55
|
+
|
56
|
+
# set options from dsl object
|
57
|
+
update(dsl._config_options) # from config.rb
|
58
|
+
# command line takes precedence
|
59
|
+
update(opts)
|
60
|
+
|
61
|
+
#Dir[File.join(File.dirname(config_file), 'models', '*.rb')].each do |model|
|
62
|
+
# dsl.instance_eval(File.read(model), model)
|
63
|
+
#end
|
64
|
+
|
65
|
+
# servers
|
66
|
+
# Identify all servers
|
67
|
+
if @options['server']
|
68
|
+
srv_name = @options['server'] || @options[:server]
|
69
|
+
# one server
|
70
|
+
@servers = {srv_name => dsl._config_servers[srv_name]}
|
71
|
+
else
|
72
|
+
# all servers
|
73
|
+
@servers = dsl._config_servers
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
@servers.each do |name, sc|
|
78
|
+
# from common config
|
79
|
+
sc.common_config = self
|
80
|
+
sc.properties['name'] ||= name
|
81
|
+
#sc.properties['common'] = Config.options[:common]
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def dir_gem_root
|
90
|
+
return @dir_gem_root unless @dir_gem_root.nil?
|
91
|
+
|
92
|
+
#
|
93
|
+
spec = Gem::Specification.find_by_name("docker-app")
|
94
|
+
@dir_gem_root = spec.gem_dir
|
95
|
+
|
96
|
+
@dir_gem_root
|
97
|
+
end
|
98
|
+
|
99
|
+
def options
|
100
|
+
return @options unless @options.nil?
|
101
|
+
|
102
|
+
@options = {}
|
103
|
+
@options
|
104
|
+
end
|
105
|
+
|
106
|
+
#def servers
|
107
|
+
#options[:servers]
|
108
|
+
#@_servers || []
|
109
|
+
#end
|
110
|
+
|
111
|
+
|
112
|
+
### NOT USED
|
113
|
+
## TODO: refactor
|
114
|
+
def self.load_settings_for_server(name, opts={})
|
115
|
+
settings = ServerSettings.new
|
116
|
+
|
117
|
+
settings.set 'name', name
|
118
|
+
|
119
|
+
# set from main Config
|
120
|
+
Config.servers[name].each do |k,v|
|
121
|
+
settings.properties[k]=v
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
#puts "current=#{File.dirname(__FILE__)}"
|
126
|
+
#puts "ff=#{file_base_settings}"
|
127
|
+
|
128
|
+
#
|
129
|
+
#t = File.read(file_base_settings) rescue ''
|
130
|
+
#eval(t, settings.get_binding)
|
131
|
+
|
132
|
+
|
133
|
+
#
|
134
|
+
f = file_settings_for_server(name)
|
135
|
+
t = File.read(f) rescue ''
|
136
|
+
eval(t, settings.get_binding)
|
137
|
+
|
138
|
+
#
|
139
|
+
settings.properties['name'] ||= name
|
140
|
+
|
141
|
+
# from common config
|
142
|
+
settings.properties['common'] = Config.options[:common]
|
143
|
+
|
144
|
+
settings
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
### helpers
|
149
|
+
|
150
|
+
def self.file_settings_for_server(name)
|
151
|
+
#File.join(File.dirname(__FILE__), '..', 'config', "#{name}.rb")
|
152
|
+
File.join(Config.root_path, 'servers', name, 'config.rb')
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.file_server_base_settings
|
156
|
+
File.join(File.dirname(__FILE__), '..', 'config' ,'common.rb')
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
# If :root_path is set in the options, all paths will be updated.
|
163
|
+
# Otherwise, only the paths given will be updated.
|
164
|
+
def update(opts = {})
|
165
|
+
#puts "update. opts=#{opts}"
|
166
|
+
|
167
|
+
# root_path
|
168
|
+
root_path = opts[:root_path].to_s.strip
|
169
|
+
|
170
|
+
#puts "root from opts = #{root_path}"
|
171
|
+
|
172
|
+
if root_path.empty?
|
173
|
+
root_path = File.path(Dir.getwd)
|
174
|
+
end
|
175
|
+
|
176
|
+
new_root = root_path.empty? ? false : set_root_path(root_path)
|
177
|
+
|
178
|
+
DEFAULTS.each do |name, ending|
|
179
|
+
set_path_variable(name, options[name], ending, new_root)
|
180
|
+
end
|
181
|
+
|
182
|
+
# options
|
183
|
+
opts.each do |name, v|
|
184
|
+
set_variable(name, v)
|
185
|
+
end
|
186
|
+
|
187
|
+
# config file
|
188
|
+
set_path_variable("config_file", options['config_file'], DEFAULTS['config_file'], new_root)
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
# Sets the @root_path to the given +path+ and returns it.
|
193
|
+
# Raises an error if the given +path+ does not exist.
|
194
|
+
def set_root_path(path)
|
195
|
+
# allows #reset! to set the default @root_path,
|
196
|
+
# then use #update to set all other paths,
|
197
|
+
# without requiring that @root_path exist.
|
198
|
+
return @root_path if path == @root_path
|
199
|
+
|
200
|
+
path = File.expand_path(path)
|
201
|
+
|
202
|
+
unless File.directory?(path)
|
203
|
+
raise Error, <<-EOS
|
204
|
+
Root Path Not Found
|
205
|
+
When specifying a --root-path, the path must exist.
|
206
|
+
Path was: #{ path }
|
207
|
+
EOS
|
208
|
+
end
|
209
|
+
@root_path = path
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
|
214
|
+
def set_variable(name, v)
|
215
|
+
#instance_variable_set(:"@#{name}", v) if v
|
216
|
+
options[name] = v
|
217
|
+
end
|
218
|
+
|
219
|
+
def set_path_variable(name, path, ending, root_path)
|
220
|
+
# strip any trailing '/' in case the user supplied this as part of
|
221
|
+
# an absolute path, so we can match it against File.expand_path()
|
222
|
+
path = path.to_s.sub(/\/\s*$/, '').lstrip
|
223
|
+
new_path = false
|
224
|
+
# If no path is given, the variable will not be set/updated
|
225
|
+
# unless a root_path was given. In which case the value will
|
226
|
+
# be updated with our default ending.
|
227
|
+
if path.empty?
|
228
|
+
new_path = File.join(root_path, ending) if root_path
|
229
|
+
else
|
230
|
+
# When a path is given, the variable will be set/updated.
|
231
|
+
# If the path is relative, it will be joined with root_path (if given),
|
232
|
+
# or expanded relative to PWD.
|
233
|
+
new_path = File.expand_path(path)
|
234
|
+
unless path == new_path
|
235
|
+
new_path = File.join(root_path, path) if root_path
|
236
|
+
end
|
237
|
+
end
|
238
|
+
instance_variable_set(:"@#{name}", new_path) if new_path
|
239
|
+
end
|
240
|
+
|
241
|
+
#def reset!
|
242
|
+
# @root_path = File.join(File.expand_path(ENV['HOME'] || ''), 'DockerApp')
|
243
|
+
# update(:root_path => @root_path)
|
244
|
+
#end
|
245
|
+
end
|
246
|
+
|
247
|
+
#reset! # set defaults on load
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module DockerApp
|
4
|
+
module Config
|
5
|
+
# Context for loading user config.rb and model files.
|
6
|
+
class DSL
|
7
|
+
#class Error < Backup::Error; end
|
8
|
+
#Server = DockerApp::Server
|
9
|
+
|
10
|
+
attr_reader :_config_options
|
11
|
+
attr_reader :_config_servers
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@_config_options = {}
|
15
|
+
@_config_servers = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
# Allow users to set command line path options in config.rb
|
19
|
+
[:root_path, :tmp_path].each do |name|
|
20
|
+
define_method name, lambda {|path| _config_options[name] = path }
|
21
|
+
end
|
22
|
+
|
23
|
+
# options - common
|
24
|
+
[
|
25
|
+
:prefix, :image_prefix, :container_prefix, :service_prefix,
|
26
|
+
:dir_data
|
27
|
+
].each do |name|
|
28
|
+
define_method name, lambda {|path| _config_options[name] = path }
|
29
|
+
end
|
30
|
+
|
31
|
+
# allowed options
|
32
|
+
[:common, :base].each do |name|
|
33
|
+
define_method name, lambda {|v| _config_options[name] = v }
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def server(server_name, &block)
|
38
|
+
sc = ServerSettings.new
|
39
|
+
block.call(sc)
|
40
|
+
#sc.instance_eval(&block)
|
41
|
+
_config_servers[server_name] = sc
|
42
|
+
end
|
43
|
+
|
44
|
+
# Allows users to create preconfigured models.
|
45
|
+
=begin
|
46
|
+
def preconfigure(name, &block)
|
47
|
+
unless name.is_a?(String) && name =~ /^[A-Z]/
|
48
|
+
raise Error, "Preconfigured model names must be given as a string " +
|
49
|
+
"and start with a capital letter."
|
50
|
+
end
|
51
|
+
|
52
|
+
if DSL.const_defined?(name)
|
53
|
+
raise Error, "'#{ name }' is already in use " +
|
54
|
+
"and can not be used for a preconfigured model."
|
55
|
+
end
|
56
|
+
|
57
|
+
DSL.const_set(name, Class.new(Model))
|
58
|
+
DSL.const_get(name).preconfigure(&block)
|
59
|
+
end
|
60
|
+
=end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module DockerApp
|
5
|
+
module Config
|
6
|
+
module Helpers
|
7
|
+
|
8
|
+
def self.included(klass)
|
9
|
+
klass.extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
def defaults
|
15
|
+
@defaults ||= Config::Defaults.new
|
16
|
+
|
17
|
+
if block_given?
|
18
|
+
yield @defaults
|
19
|
+
else
|
20
|
+
@defaults
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Used only within the specs
|
25
|
+
def clear_defaults!
|
26
|
+
defaults.reset!
|
27
|
+
end
|
28
|
+
|
29
|
+
def deprecations
|
30
|
+
@deprecations ||= {}
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
end # ClassMethods
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
##
|
42
|
+
# Sets any pre-configured default values.
|
43
|
+
# If a default value was set for an invalid accessor,
|
44
|
+
# this will raise a NameError.
|
45
|
+
def load_defaults!
|
46
|
+
self.class.defaults._attributes.each do |name|
|
47
|
+
val = self.class.defaults.send(name)
|
48
|
+
val = val.dup rescue val
|
49
|
+
send(:"#{ name }=", val)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Check missing methods for deprecated attribute accessors.
|
55
|
+
#
|
56
|
+
# If a value is set on an accessor that has been deprecated
|
57
|
+
# using #attr_deprecate, a warning will be issued and any
|
58
|
+
# :action (Proc) specified will be called with a reference to
|
59
|
+
# the class instance and the value set on the deprecated accessor.
|
60
|
+
# See #attr_deprecate and #log_deprecation_warning
|
61
|
+
#
|
62
|
+
# Note that OpenStruct (used for setting defaults) does not allow
|
63
|
+
# multiple arguments when assigning values for members.
|
64
|
+
# So, we won't allow it here either, even though an attr_accessor
|
65
|
+
# will accept and convert them into an Array. Therefore, setting
|
66
|
+
# an option value using multiple values, whether as a default or
|
67
|
+
# directly on the class' accessor, should not be supported.
|
68
|
+
# i.e. if an option will accept being set as an Array, then it
|
69
|
+
# should be explicitly set as such. e.g. option = [val1, val2]
|
70
|
+
#
|
71
|
+
def method_missing(name, *args)
|
72
|
+
if method = name.to_s.chomp!('=')
|
73
|
+
if (len = args.count) != 1
|
74
|
+
raise ArgumentError,
|
75
|
+
"wrong number of arguments (#{ len } for 1)", caller(1)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
end # Helpers
|
83
|
+
|
84
|
+
# Store for pre-configured defaults.
|
85
|
+
class Defaults < OpenStruct
|
86
|
+
# Returns an Array of all attribute method names
|
87
|
+
# that default values were set for.
|
88
|
+
def _attributes
|
89
|
+
@table.keys
|
90
|
+
end
|
91
|
+
|
92
|
+
# Used only within the specs
|
93
|
+
def reset!
|
94
|
+
@table.clear
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,376 @@
|
|
1
|
+
module DockerApp
|
2
|
+
class ManagerContainer
|
3
|
+
|
4
|
+
def self.save_chef_config(settings)
|
5
|
+
require 'json'
|
6
|
+
filename = settings.filename_chef_config
|
7
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
8
|
+
File.open(filename,"w+") do |f|
|
9
|
+
f.write(settings.all_attributes.to_json)
|
10
|
+
end
|
11
|
+
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def self.save_config_json(settings)
|
17
|
+
require 'json'
|
18
|
+
filename = settings.filename_config_json
|
19
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
20
|
+
File.open(filename,"w+") do |f|
|
21
|
+
f.write(settings.all_attributes.to_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
### run
|
31
|
+
|
32
|
+
def self.run_container(server_name, settings={})
|
33
|
+
puts "creating and running container.."
|
34
|
+
#settings = load_settings(server_name)
|
35
|
+
|
36
|
+
# generate config
|
37
|
+
save_config_json(settings)
|
38
|
+
|
39
|
+
|
40
|
+
# destroy
|
41
|
+
destroy_container(server_name, settings)
|
42
|
+
|
43
|
+
# create
|
44
|
+
create_container(settings)
|
45
|
+
|
46
|
+
|
47
|
+
# START && run provision after start
|
48
|
+
start_container(name, settings)
|
49
|
+
|
50
|
+
|
51
|
+
# TODO: systemd service
|
52
|
+
#res_service = _install_service_container(settings)
|
53
|
+
|
54
|
+
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.create_container(settings)
|
59
|
+
# create
|
60
|
+
net_options = ""
|
61
|
+
networks = settings['docker'].fetch('network', {}).fetch('networks', [])
|
62
|
+
if networks && networks[0]
|
63
|
+
network = networks[0]
|
64
|
+
#puts "network=#{network}"
|
65
|
+
net_options << "--net #{network['net']} "
|
66
|
+
net_options << "--ip #{network['ip']} " if network['ip']
|
67
|
+
net_options << "--mac-address #{network['mac_address']} " if network['mac_address']
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
cmd %Q(docker create --name #{settings.container_name} #{net_options} #{settings.docker_ports_string} #{settings.docker_volumes_string} #{settings.docker_volumes_from_string} #{settings.docker_links_string} #{settings.run_extra_options_string} #{settings.run_env_variables_string} #{settings.image_name} #{settings['docker']['command']} #{settings['docker']['run_options']})
|
72
|
+
|
73
|
+
# network
|
74
|
+
setup_network(settings)
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def self.setup_network(settings)
|
79
|
+
container_name = settings.container_name
|
80
|
+
|
81
|
+
# networks
|
82
|
+
networks = settings['docker'].fetch('network', {}).fetch('networks', [])
|
83
|
+
if networks
|
84
|
+
ind = 0
|
85
|
+
networks.each do |net|
|
86
|
+
ind = ind + 1
|
87
|
+
|
88
|
+
#
|
89
|
+
next if net['action']=='remove'
|
90
|
+
|
91
|
+
# skip first network
|
92
|
+
next if ind==1
|
93
|
+
|
94
|
+
# connect
|
95
|
+
ip = net['ip']
|
96
|
+
s_ip = "--ip #{ip}" if ip
|
97
|
+
#puts %Q(docker network connect #{s_ip} #{net['net']} #{settings.container_name})
|
98
|
+
cmd %Q(docker network connect #{s_ip} #{net['net']} #{settings.container_name})
|
99
|
+
end
|
100
|
+
|
101
|
+
# remove
|
102
|
+
networks.each do |net|
|
103
|
+
next unless net['action']=='remove'
|
104
|
+
cmd %Q(docker network disconnect #{net['net']} #{settings.container_name})
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
def self.start_container(name, settings)
|
113
|
+
### BEFORE START
|
114
|
+
# run setup provision scripts
|
115
|
+
DockerApp::Provisioner::Base.run_provision_scripts_setup(settings)
|
116
|
+
|
117
|
+
|
118
|
+
### start
|
119
|
+
cmd %Q(docker start #{settings.container_name})
|
120
|
+
|
121
|
+
# wait
|
122
|
+
wait_until_running(settings.container_name)
|
123
|
+
|
124
|
+
### AFTER START
|
125
|
+
|
126
|
+
# setup
|
127
|
+
setup_container_after_start(settings)
|
128
|
+
|
129
|
+
# provision after start
|
130
|
+
# run bootstrap provision scripts
|
131
|
+
DockerApp::Provisioner::Base.run_provision_scripts_bootstrap(settings)
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def self.wait_until_running(container_name)
|
137
|
+
retries = 10
|
138
|
+
until system("docker exec #{container_name} true") || retries < 0
|
139
|
+
sleep 1
|
140
|
+
retries = retries - 1
|
141
|
+
end
|
142
|
+
|
143
|
+
assert_container_running(container_name)
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.assert_container_running(container_name)
|
147
|
+
res = system("docker exec #{container_name} true")
|
148
|
+
assert res, "Container #{container_name} is not running"
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
=begin
|
153
|
+
def self._prepare_provision_before_start_chef(settings, script)
|
154
|
+
puts "_prepare_provision_before_start_chef"
|
155
|
+
|
156
|
+
require_relative '../../lib/docker_app/provisioner/provisioner_chef'
|
157
|
+
|
158
|
+
provisioner = DockerApp::Provisioner::Chef.new(settings)
|
159
|
+
provisioner.copy_config_file
|
160
|
+
|
161
|
+
end
|
162
|
+
=end
|
163
|
+
|
164
|
+
def self.setup_container_after_start(settings)
|
165
|
+
|
166
|
+
# default gateway
|
167
|
+
network = settings['docker']['network']
|
168
|
+
if network
|
169
|
+
gateway = network['default_gateway']
|
170
|
+
|
171
|
+
if gateway
|
172
|
+
# fix default gateway
|
173
|
+
#cmd %Q(docker exec #{settings.container_name} ip route change default via #{gateway} dev eth1)
|
174
|
+
cmd %Q(docker exec #{settings.container_name} ip route change default via #{gateway})
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
# fix hosts
|
181
|
+
container_hosts = settings['docker']['hosts'] || []
|
182
|
+
container_hosts.each do |r|
|
183
|
+
#cmd %Q(docker exec #{settings.container_name} bash -c 'echo "#{r[0]} #{r[1]}" >> /etc/hosts')
|
184
|
+
cmd %Q(docker exec #{settings.container_name} sh -c 'echo "#{r[0]} #{r[1]}" >> /etc/hosts')
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
|
192
|
+
|
193
|
+
### systemd service
|
194
|
+
|
195
|
+
def self._install_service_container(settings)
|
196
|
+
# not work
|
197
|
+
#cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} install_container_service.rb )
|
198
|
+
|
199
|
+
# work
|
200
|
+
#cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} -j config_run_install_container_service.json )
|
201
|
+
|
202
|
+
# work
|
203
|
+
#cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} --override-runlist 'recipe[server-api::install_container_service]' )
|
204
|
+
|
205
|
+
#
|
206
|
+
cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} -j config/config-#{settings.name}.json --override-runlist 'recipe[server-api::install_container_service]' )
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
def self._remove_service_container(settings)
|
211
|
+
cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} -j config/config-#{settings.name}.json --override-runlist 'recipe[server-api::remove_container_service]' )
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
|
216
|
+
=begin
|
217
|
+
def self._run_container_chef(settings)
|
218
|
+
# generate json config for chef
|
219
|
+
save_chef_config(settings)
|
220
|
+
|
221
|
+
# run chef
|
222
|
+
#s_run = %Q(cd #{settings.name} && chef-client -z -j config.json -c ../.chef/knife.rb -N #{settings.name} ../lib/chef_container_run.rb)
|
223
|
+
|
224
|
+
# good - 2016-nov-19
|
225
|
+
#cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} chef_run_container.rb)
|
226
|
+
|
227
|
+
#
|
228
|
+
res_chef = run_chef_recipe(settings, 'chef_run_container.rb')
|
229
|
+
|
230
|
+
res_chef
|
231
|
+
end
|
232
|
+
|
233
|
+
=end
|
234
|
+
|
235
|
+
|
236
|
+
|
237
|
+
|
238
|
+
###
|
239
|
+
|
240
|
+
def self.destroy_container(server_name, settings)
|
241
|
+
puts "destroying container #{server_name}..."
|
242
|
+
|
243
|
+
# TODO: stop, remove systemd service
|
244
|
+
#res_service = _remove_service_container(settings)
|
245
|
+
|
246
|
+
#
|
247
|
+
cmd %Q(docker rm -f #{settings.container_name} )
|
248
|
+
|
249
|
+
|
250
|
+
|
251
|
+
# if chef
|
252
|
+
if settings['build']['build_type']=='chef'
|
253
|
+
return destroy_container_chef(settings)
|
254
|
+
end
|
255
|
+
|
256
|
+
#
|
257
|
+
return true
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
def self.destroy_container_chef(settings)
|
262
|
+
# destroy temp container
|
263
|
+
cmd %Q(docker rm -f chef-converge.#{settings.image_name} )
|
264
|
+
|
265
|
+
#
|
266
|
+
res_chef = run_chef_recipe(settings, 'chef_destroy_container.rb')
|
267
|
+
#cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} chef_destroy_container.rb)
|
268
|
+
|
269
|
+
#
|
270
|
+
chef_remove_data(settings)
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
|
276
|
+
|
277
|
+
### stop container
|
278
|
+
|
279
|
+
def self.stop_container(server_name, settings)
|
280
|
+
puts "stopping container #{server_name}..."
|
281
|
+
|
282
|
+
#
|
283
|
+
cmd %Q(docker stop #{settings.container_name} )
|
284
|
+
|
285
|
+
#
|
286
|
+
return true
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
### run task on running container
|
291
|
+
def self.exec_task(server_name, recipe_name)
|
292
|
+
#raise 'not implemented'
|
293
|
+
|
294
|
+
settings = load_settings(server_name)
|
295
|
+
|
296
|
+
# check script exists
|
297
|
+
script_path = "#{settings.name}/cookbooks/#{settings.name}/recipes/#{recipe_name}.rb"
|
298
|
+
f = File.expand_path('.', script_path)
|
299
|
+
|
300
|
+
if !File.exists?(f)
|
301
|
+
puts "script not found: #{f}. Skipping"
|
302
|
+
return false
|
303
|
+
end
|
304
|
+
|
305
|
+
#
|
306
|
+
cmd %Q(SERVER_NAME=#{settings.name} chef-client -z --override-runlist 'recipe[server-api::exec_container]' )
|
307
|
+
#cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} --override-runlist 'recipe[#{settings.name}::#{recipe_name}]' )
|
308
|
+
#cmd %Q(SERVER_NAME=#{settings.name} chef-client -z -N #{settings.name} chef_exec_container.rb )
|
309
|
+
|
310
|
+
return true
|
311
|
+
end
|
312
|
+
|
313
|
+
|
314
|
+
###
|
315
|
+
def self.clear_cache(name, settings)
|
316
|
+
# common cache
|
317
|
+
cmd("rm -rf ~/.chef/cache")
|
318
|
+
cmd("rm -rf ~/.chef/local-mode-cache")
|
319
|
+
|
320
|
+
# cache for server
|
321
|
+
cmd("rm -rf #{settings.dir_server_root}/.chef/local-mode-cache")
|
322
|
+
#cmd("rm -rf ~/.chef/package-cache")
|
323
|
+
|
324
|
+
# cache in gem
|
325
|
+
cmd("rm -rf #{Config.dir_gem_root}/lib/docker_app/.chef/local-mode-cache")
|
326
|
+
|
327
|
+
|
328
|
+
end
|
329
|
+
|
330
|
+
###
|
331
|
+
|
332
|
+
def self.cmd(s)
|
333
|
+
Command.cmd(s)
|
334
|
+
end
|
335
|
+
|
336
|
+
|
337
|
+
|
338
|
+
### helpers - chef
|
339
|
+
|
340
|
+
def self.run_chef_recipe(settings, recipe_rb)
|
341
|
+
cmd %Q(cd #{Config.root_path} && SERVER_NAME=#{settings.name} SERVER_PATH=#{settings.dir_server_root} chef exec chef-client -z -N #{settings.container_name} -j #{settings.filename_config_json} -c #{chef_config_knife_path} #{chef_recipe_path(recipe_rb)} )
|
342
|
+
end
|
343
|
+
|
344
|
+
def self.run_chef_recipe_server_recipe(settings, server_recipe)
|
345
|
+
cmd %Q(cd #{Config.root_path} && SERVER_NAME=#{settings.name} SERVER_PATH=#{settings.dir_server_root} chef exec chef-client -z -N #{settings.container_name} -c #{chef_config_knife_path} --override-runlist 'recipe[#{settings.name}::#{server_recipe}]' )
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
def self.chef_config_knife_path
|
350
|
+
"#{Config.dir_gem_root}/lib/docker_app/chef/.chef/knife.rb"
|
351
|
+
end
|
352
|
+
|
353
|
+
def self.chef_recipe_path(p)
|
354
|
+
"#{Config.dir_gem_root}/lib/docker_app/chef/#{p}"
|
355
|
+
end
|
356
|
+
|
357
|
+
|
358
|
+
def self.chef_remove_data(settings)
|
359
|
+
#
|
360
|
+
cmd %Q(cd #{Config.root_path} && chef exec knife node delete #{settings.chef_node_name} -y -c #{chef_config_knife_path})
|
361
|
+
|
362
|
+
# clean chef client, node
|
363
|
+
cmd %Q(cd #{Config.root_path} && rm -f #{settings.filename_chef_node_json} )
|
364
|
+
cmd %Q(cd #{Config.root_path} && rm -f #{settings.filename_chef_client_json} )
|
365
|
+
end
|
366
|
+
|
367
|
+
|
368
|
+
### common helpers
|
369
|
+
def self.assert(expression, string = "Assert failed")
|
370
|
+
unless expression
|
371
|
+
throw Exception.new string
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
end
|
376
|
+
end
|