docker_toolkit 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8bed7bfd3321be850470d15839c3e4516c030ef2fd85a5cb893719e69651235c
4
+ data.tar.gz: bca92e12468219f060491956acc7d1867c198e43b9f933a08351ee0929fd5ffd
5
+ SHA512:
6
+ metadata.gz: 5146180b05f18e8ba0a42da96465c3aefaf3a671b3d9b396dabb184eda42023c86df8ba6320f279962711f743eb16ea7e4fdfa781ac4caa60065199d1dea8ebd
7
+ data.tar.gz: a6776d22bbc35be6b0283cb0ee730c8eb9addb16063e8acdb3d8258d95f75f78ebb13fa62178f46a25f3744e46d9ebe187074556882d1d74fe71aadafd1f97ee
data/.dockerignore ADDED
@@ -0,0 +1,20 @@
1
+ .git
2
+ log/*
3
+ tmp/*
4
+ doc/*
5
+ envs/*
6
+ Dockerfile
7
+ /node_modules
8
+ config/keys/*
9
+ config/database.yml
10
+ config/secrets.yml
11
+
12
+ .gitignore
13
+ .gitlab-ci.yml
14
+ base-service.yml
15
+ common-services.yml
16
+
17
+ vendor/cache
18
+
19
+ ca/db
20
+
data/.gitignore ADDED
@@ -0,0 +1,109 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # bundler state
8
+ /.bundle
9
+ vendor/cache
10
+ vendor/bundle
11
+ /vendor/ruby/
12
+
13
+ # minimal Rails specific artifacts
14
+ db/*.sqlite3
15
+ /db/*.sqlite3-journal
16
+ /log/*
17
+ /tmp/*
18
+
19
+ # add /config/database.yml if it contains passwords
20
+ # /config/database.yml
21
+
22
+ # various artifacts
23
+ **.war
24
+ *.rbc
25
+ *.sassc
26
+ .redcar/
27
+ .sass-cache
28
+ /config/config.yml
29
+ /coverage.data
30
+ /coverage/
31
+ /db/*.javadb/
32
+ /db/*.sqlite3
33
+ /config/database.yml
34
+ /config/secrets.yml
35
+ oxymoron.js
36
+ /doc/api/
37
+ /doc/app/
38
+ /doc/features.html
39
+ /doc/specs.html
40
+ /public/cache
41
+ /public/uploads
42
+ /public/stylesheets/compiled
43
+ /public/system/*
44
+ /spec/tmp/*
45
+ /cache
46
+ /capybara*
47
+ /capybara-*.html
48
+ /gems
49
+ /specifications
50
+ app/assets/fonts/disp-preview.html
51
+ rerun.txt
52
+ pickle-email-*.html
53
+ *.sublime-project
54
+ *.sublime-workspace
55
+ .zeus.sock
56
+ .byebug_history
57
+
58
+ #test
59
+ /docs
60
+
61
+
62
+ # If you find yourself ignoring temporary files generated by your text editor
63
+ # or operating system, you probably want to add a global ignore instead:
64
+ # git config --global core.excludesfile ~/.gitignore_global
65
+ #
66
+ # Here are some files you may want to ignore globally:
67
+
68
+ # scm revert files
69
+ **.orig
70
+
71
+ # Mac finder artifacts
72
+ .DS_Store
73
+
74
+ # Netbeans project directory
75
+ /nbproject/
76
+
77
+ # RubyMine project files
78
+ .idea
79
+
80
+ # Textmate project files
81
+ /*.tmproj
82
+
83
+ # vim artifacts
84
+ **.swp
85
+
86
+ # Environment files that may contain sensitive data
87
+ .env
88
+ .powenv
89
+
90
+ # tilde files are usually backup files from a text editor
91
+ *~
92
+ public/assets/
93
+ config/keys
94
+ .ruby-gemset
95
+ .ruby-version
96
+ spec/reports/
97
+ app/assets/javascripts/oxymoron.js
98
+
99
+ !/log/.keep
100
+ !/tmp/.keep
101
+
102
+ /node_modules
103
+ /yarn-error.log
104
+
105
+ .byebug_history
106
+ /public/packs
107
+ /public/packs-test
108
+ /node_modules
109
+ passenger.*.pid.lock
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --tty
3
+ --format documentation
4
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,89 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
3
+ Exclude:
4
+ - 'storage/**/*'
5
+ - 'docker/**/*'
6
+
7
+ Style/AsciiComments:
8
+ Enabled: false
9
+
10
+ Style/RedundantBegin:
11
+ Enabled: false
12
+
13
+ Style/GlobalVars:
14
+ AllowedVariables: ['$logger', '$root']
15
+
16
+ Metrics/BlockLength:
17
+ Exclude:
18
+ - 'spec/**/*.rb'
19
+
20
+ Metrics/MethodLength:
21
+ Max: 20
22
+
23
+ Style/ClassAndModuleChildren:
24
+ EnforcedStyle: compact
25
+ Enabled: false
26
+
27
+ Style/Documentation:
28
+ Enabled: false
29
+
30
+ Style/Lambda:
31
+ Enabled: false
32
+
33
+
34
+ Style/RaiseArgs:
35
+ EnforcedStyle: compact
36
+
37
+ Metrics/LineLength:
38
+ Max: 100
39
+
40
+ #Layout/IndentationWidth:
41
+ # Enabled: true
42
+
43
+ #Layout/IndentAssignment:
44
+ # Enabled: false
45
+ # IndentationWidth: false
46
+
47
+ #Layout/ElseAlignment:
48
+ # Enabled: false
49
+
50
+ #Layout/EndAlignment:
51
+ # Enabled: false
52
+
53
+ #Lint/AssignmentInCondition:
54
+ # Enabled: false
55
+
56
+ Layout/IndentationConsistency:
57
+ EnforcedStyle: rails
58
+
59
+ Layout/EmptyLines:
60
+ Enabled: false
61
+
62
+ Layout/EmptyLinesAroundClassBody:
63
+ EnforcedStyle: empty_lines
64
+
65
+ Layout/EmptyLinesAroundModuleBody:
66
+ EnforcedStyle: empty_lines
67
+
68
+ Layout/SpaceInsideBlockBraces:
69
+ EnforcedStyle: space
70
+ SpaceBeforeBlockParameters: false
71
+
72
+ Layout/SpaceAroundBlockParameters:
73
+ EnforcedStyleInsidePipes: no_space
74
+
75
+ Layout/SpaceBeforeBlockBraces:
76
+ Enabled: false
77
+
78
+ Style/NumericPredicate:
79
+ Enabled: false
80
+
81
+ Style/FrozenStringLiteralComment:
82
+ Enabled: false
83
+
84
+ Style/DoubleNegation:
85
+ Enabled: false
86
+
87
+ Style/SymbolArray:
88
+ Enabled: false
89
+
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1
4
+ - 2.5
5
+
6
+ services:
7
+ - docker
8
+
9
+ stage: test
10
+
11
+ script:
12
+ - cd docker && ./run_tests.sh
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in aggredator.gemspec
4
+ gemspec
5
+
6
+
7
+ group :test do
8
+ gem 'awesome_print'
9
+ gem 'faker'
10
+ gem 'faker-russian'
11
+ gem 'rspec'
12
+ gem 'rspec-retry'
13
+ gem 'rspec-set'
14
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,59 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ docker_toolkit (0.1.0)
5
+ diplomat
6
+ json
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ awesome_print (1.8.0)
12
+ concurrent-ruby (1.0.5)
13
+ diff-lcs (1.3)
14
+ diplomat (2.0.2)
15
+ faraday (~> 0.9)
16
+ json
17
+ faker (1.9.1)
18
+ i18n (>= 0.7)
19
+ faker-russian (0.0.6)
20
+ faraday (0.15.2)
21
+ multipart-post (>= 1.2, < 3)
22
+ i18n (1.0.1)
23
+ concurrent-ruby (~> 1.0)
24
+ json (2.1.0)
25
+ multipart-post (2.0.0)
26
+ rake (10.5.0)
27
+ rspec (3.7.0)
28
+ rspec-core (~> 3.7.0)
29
+ rspec-expectations (~> 3.7.0)
30
+ rspec-mocks (~> 3.7.0)
31
+ rspec-core (3.7.1)
32
+ rspec-support (~> 3.7.0)
33
+ rspec-expectations (3.7.0)
34
+ diff-lcs (>= 1.2.0, < 2.0)
35
+ rspec-support (~> 3.7.0)
36
+ rspec-mocks (3.7.0)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.7.0)
39
+ rspec-retry (0.6.1)
40
+ rspec-core (> 3.3)
41
+ rspec-set (0.1.3)
42
+ rspec-support (3.7.1)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ awesome_print
49
+ bundler (~> 1.14)
50
+ docker_toolkit!
51
+ faker
52
+ faker-russian
53
+ rake (~> 10.0)
54
+ rspec
55
+ rspec-retry
56
+ rspec-set
57
+
58
+ BUNDLED WITH
59
+ 1.16.1
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ # docker_toolkit
2
+ Helper tools for work with docker and consul
3
+
4
+ [![Build Status](https://travis-ci.com/RnD-Soft/docker_toolkit.svg?branch=master)](https://travis-ci.com/RnD-Soft/docker_toolkit)
data/bin/consul.rb ADDED
@@ -0,0 +1,222 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'diplomat'
4
+ require 'optparse'
5
+ require 'English'
6
+ require 'yaml'
7
+
8
+ STDOUT.sync = true
9
+ STDERR.sync = true
10
+
11
+ @opts = {}
12
+
13
+ @opts[:exec] = (begin
14
+ ARGV.join(' ').split(' -- ')[1].strip
15
+ rescue StandardError
16
+ nil
17
+ end)
18
+
19
+ parser = OptionParser.new do |o|
20
+ o.banner = 'Usage: consul.rb [options] -- exec'
21
+
22
+ o.on('--consul url', 'Set up a custom Consul URL') do |url|
23
+ Diplomat.configure do |config|
24
+ config.url = url.strip
25
+ end
26
+ end
27
+
28
+ o.on('--token token', 'Connect into consul with custom access token (ACL)') do |token|
29
+ Diplomat.configure do |config|
30
+ config.acl_token = token.strip
31
+ end
32
+ end
33
+
34
+ o.on('--init [service]', 'Initialize Consul services from config') do |service|
35
+ @opts[:service] = service
36
+ @opts[:init] = true
37
+ end
38
+
39
+ o.on('--config file', 'Read service configulation from file') do |file|
40
+ @opts[:config] = file.strip
41
+ end
42
+
43
+ o.on('--upload', 'Upload files to variables') do
44
+ @opts[:upload] = true
45
+ end
46
+
47
+ o.on('--show [service]', 'Show service configulation from Consul') do |service|
48
+ @opts[:service] = service
49
+ @opts[:show] = true
50
+ end
51
+
52
+ o.on('--override', 'override existed keys') do
53
+ @opts[:override] = true
54
+ end
55
+
56
+ o.on('-d', '--dereference', 'dereference consul values in form of "consul://key/subkey"') do
57
+ @opts[:dereference] = true
58
+ end
59
+
60
+ o.on('--env prefix', 'export KV values from prefix as env varaibles') do |prefix|
61
+ @opts[:env] = (prefix + '/').gsub('//', '/')
62
+ end
63
+
64
+ o.on('--export', 'add export to --env output') do
65
+ @opts[:export] = true
66
+ end
67
+
68
+ o.on('--pristine', "not include the parent processes' environment when exec child process") do
69
+ @opts[:pristine] = true
70
+ end
71
+
72
+ o.on('--put path:value', 'put value to path') do |path|
73
+ @opts[:put] = path.strip
74
+ end
75
+
76
+ o.on('--get path', 'get value from') do |path|
77
+ @opts[:get] = path.strip
78
+ end
79
+ end
80
+ parser.parse!
81
+
82
+ def die(message)
83
+ STDERR.puts "Error: #{message}"
84
+ exit 1
85
+ end
86
+
87
+ def key_to_consul(key)
88
+ key.downcase.gsub(/[^0-9a-z]/i, '_')
89
+ end
90
+
91
+ def key_to_env(key)
92
+ key.upcase.gsub(/[^0-9a-z]/i, '_')
93
+ end
94
+
95
+ def dereferenced_value(value)
96
+ if @opts[:dereference] && value && value[/^consul:\/\//]
97
+ reference_path = value.gsub(/^consul:\/\//, '')
98
+ dereferenced_value(Diplomat::Kv.get(reference_path))
99
+ else
100
+ value
101
+ end
102
+ end
103
+
104
+ if config = @opts[:config]
105
+ @opts[:config] = YAML.safe_load(config == '-' ? STDIN.read : File.read(config), [], [], true)
106
+ end
107
+
108
+ if @opts[:init]
109
+ raise OptionParser::MissingArgument.new('config') unless @opts[:config]
110
+
111
+ services = if service = @opts[:service]
112
+ {
113
+ service => @opts[:config][service]
114
+ }
115
+ else
116
+ @opts[:config]
117
+ end
118
+
119
+ services.each_pair do |service, config|
120
+ next unless config
121
+ next if service[/^\./] # skip hidden keys
122
+
123
+ path = "services/env/#{service}"
124
+ config.each_pair do |env, item|
125
+ key = "#{path}/#{key_to_consul(env)}"
126
+ value = if @opts[:upload] && item['file']
127
+ File.read(item['file'])
128
+ else
129
+ item['value'] || item['default'] || item['file']
130
+ end
131
+
132
+ empty = begin
133
+ Diplomat::Kv.get(key)
134
+ false
135
+ rescue Diplomat::KeyNotFound
136
+ true
137
+ end
138
+
139
+ Diplomat::Kv.put(key, value.to_s.strip) || die("Can't put #{key} to Consul") if empty || @opts[:override]
140
+ end
141
+ end
142
+
143
+ exit 0
144
+ end
145
+
146
+ if @opts[:show]
147
+ config = {}
148
+
149
+ path = if service = @opts[:service]
150
+ "services/env/#{service}/"
151
+ else
152
+ 'services/env/'
153
+ end
154
+
155
+ answer = Diplomat::Kv.get(path, recurse: true, convert_to_hash: true) || die("Can't get #{path} from Consul")
156
+ answer['services']['env'].each_pair do |service, env|
157
+ cfg = config[service] ||= {}
158
+
159
+ env.each_pair do |key, value|
160
+ value = dereferenced_value(value)
161
+
162
+ cfg[key_to_env(key)] = {
163
+ env: key_to_env(key),
164
+ value: value
165
+ }
166
+ end
167
+ end
168
+
169
+ STDOUT.puts JSON.parse(config.to_json).to_yaml
170
+
171
+ exit 0
172
+ end
173
+
174
+ if put = @opts[:put]
175
+ path, *value = put.split(':').map(&:strip)
176
+ value = value.join(':')
177
+ value = File.read(value) if @opts[:upload] && value && File.exist?(value)
178
+
179
+ Diplomat::Kv.put(path, value.to_s.strip) || die("Can't put #{path} to Consul")
180
+
181
+ exit 0
182
+ end
183
+
184
+ if path = @opts[:get]
185
+ value = dereferenced_value(Diplomat::Kv.get(path))
186
+
187
+ STDOUT.puts value.to_s.strip
188
+
189
+ exit 0
190
+ end
191
+
192
+ if prefix = @opts[:env]
193
+ keys = begin
194
+ Diplomat::Kv.get(prefix, keys: true)
195
+ rescue Diplomat::KeyNotFound => e
196
+ []
197
+ rescue StandardError
198
+ die("Can't get keys at #{prefix} from Consul")
199
+ end
200
+
201
+ env = keys.reduce({}) do |e, key|
202
+ value = dereferenced_value(Diplomat::Kv.get(key))
203
+
204
+ e.merge(key_to_env(key.gsub(prefix, '')) => value)
205
+ end
206
+
207
+ if cmd = @opts[:exec]
208
+ env = ENV.to_h.merge(env) unless @opts[:pristine]
209
+
210
+ exec(env, cmd, unsetenv_others: true)
211
+ else
212
+ env.each_pair do |k, v|
213
+ STDOUT.puts "#{@opts[:export] ? 'export ' : ''}#{k}=\"#{v}\""
214
+ end
215
+ end
216
+
217
+
218
+ exit 0
219
+ end
220
+
221
+ STDOUT.puts parser.help
222
+ exit 1
data/bin/merger.rb ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'English'
4
+ require 'yaml'
5
+
6
+ if File.basename($PROGRAM_NAME) == File.basename(__FILE__)
7
+ unless ENV['COMPOSE_FILE']
8
+ STDERR.puts 'COMPOSE_FILE environment must point to one on mo files'
9
+ exit 1
10
+ end
11
+ end
12
+
13
+
14
+ class Hash
15
+
16
+ def deep_dup
17
+ Marshal.load(Marshal.dump(self))
18
+ end
19
+
20
+ end
21
+
22
+ class Array
23
+
24
+ def deep_dup
25
+ Marshal.load(Marshal.dump(self))
26
+ end
27
+
28
+ end
29
+
30
+
31
+
32
+ def extend_hash(first, second)
33
+ raise ArgumentError.new('First and second args equal nil') if [first, second].all? &:nil?
34
+ return second if first.nil?
35
+ return first if second.nil?
36
+
37
+ first.each_pair do |fk, fv|
38
+ next unless second.key?(fk)
39
+
40
+ sv = second[fk]
41
+ raise "Types of values not match(#{fv.class}, #{sv.class})" if fv.class != sv.class
42
+
43
+ # Специальный случай потому что command не мерджится а заменяется
44
+ if fk == 'command'
45
+ first[fk] = sv
46
+ elsif fv.is_a? Hash
47
+ extend_hash(fv, sv)
48
+ elsif fv.is_a? Array
49
+ fv |= sv
50
+ first[fk] = fv
51
+ else
52
+ first[fk] = sv
53
+ end
54
+ end
55
+
56
+ second.each_pair do |sk, sv|
57
+ next if first.key?(sk)
58
+
59
+ first[sk] = sv
60
+ end
61
+
62
+ first
63
+ end
64
+
65
+ def process_compose_hash(yml, dirname, parent = {})
66
+ (yml['services'] || {}).each_pair do |name, service|
67
+ next unless ext = service['extends']
68
+ base = if ext.is_a? String
69
+ template = yml['services'][ext]
70
+ parent_service = (parent['services'] || {})[ext] || {}
71
+ extend_hash(parent_service.deep_dup, template)
72
+ elsif file = ext['file']
73
+ ENV.each_pair do |k, v|
74
+ file.gsub!("$#{k}", v)
75
+ file.gsub!("${#{k}}", v)
76
+ end
77
+
78
+ tmp = if File.exist?(dirname + '/' + file)
79
+ YAML.safe_load(File.read(dirname + '/' + file))
80
+ else
81
+ YAML.safe_load(File.read(file))
82
+ end
83
+
84
+ begin
85
+ (tmp['services'][ext['service']] || {})
86
+ rescue StandardError
87
+ {}
88
+ end
89
+ else
90
+ yml['services'][ext['service']]
91
+ end.deep_dup
92
+
93
+ service.delete 'extends'
94
+
95
+ yml['services'][name] = extend_hash(base, service)
96
+ end
97
+ yml
98
+ end
99
+
100
+ if File.basename($PROGRAM_NAME) == File.basename(__FILE__)
101
+ result = ENV['COMPOSE_FILE'].split(':').reduce({}) do |parent, file|
102
+ yml = process_compose_hash(YAML.safe_load(File.read(file)), File.dirname(file), parent)
103
+ if yml['version'] && parent['version'] && yml['version'] != parent['version']
104
+ raise "version mismatch: #{file}"
105
+ end
106
+ ret = extend_hash(parent.deep_dup, yml)
107
+ ret
108
+ end
109
+
110
+ if ARGV[0].nil? || ARGV[0].strip == '-'
111
+ puts YAML.dump(result)
112
+ else
113
+ File.write(ARGV[0].strip, YAML.dump(result))
114
+ end
115
+
116
+ end
data/bin/waiter.rb ADDED
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'securerandom'
5
+ require 'English'
6
+ require 'openssl'
7
+ require 'tempfile'
8
+
9
+ STDOUT.sync = true
10
+ STDERR.sync = true
11
+
12
+ TIMEOUT = 15
13
+ INTERVAL = 3
14
+
15
+ @opts = {}
16
+
17
+ @opts[:exec] = (begin
18
+ ARGV.join(' ').split(' -- ')[1].strip
19
+ rescue StandardError
20
+ nil
21
+ end)
22
+ @opts[:timeout] = TIMEOUT
23
+ @opts[:interval] = INTERVAL
24
+ @opts[:consul_addr] = 'http://localhost:8500'
25
+
26
+
27
+ OptionParser.new do |o|
28
+ o.banner = 'Usage: waiter.rb [options] -- exec'
29
+
30
+ o.on('--tcp host:port', 'Wait for tcp accepts on host:port') do |addr|
31
+ host, port = addr.split(':')
32
+ @opts[:tcp] = addr.strip
33
+ @opts[:host] = host.strip
34
+ @opts[:port] = port.strip
35
+ end
36
+
37
+ o.on('--db dbname', 'Wait for PG database exists. Using --tcp to conenct PG') do |db|
38
+ @opts[:db] = db.strip
39
+ end
40
+
41
+ o.on('--tb tablename', 'Wait for PG table exists. Using --tcp to conenct PG') do |tb|
42
+ @opts[:tb] = tb.strip
43
+ end
44
+
45
+ o.on('-f', '--file filename', 'Wait for file exists.') do |file|
46
+ @opts[:file] = file.strip
47
+ end
48
+
49
+ o.on("--consul-addr addr=#{@opts[:consul_addr]}", 'HTTP addres to connect to consul') do |addr|
50
+ @opts[:consul_addr] = addr.strip
51
+ end
52
+
53
+ o.on('--consul', 'Wait for local consul agent to be ready') do
54
+ @opts[:consul] = true
55
+ end
56
+
57
+ o.on('--consul-service service', 'Wait for service appear in consul') do |service|
58
+ @opts[:consul_service] = service
59
+ end
60
+
61
+ o.on('--user user', 'username') do |user|
62
+ @opts[:user] = user.strip
63
+ end
64
+
65
+ o.on('--pass pass', 'password') do |pass|
66
+ @opts[:pass] = pass.strip
67
+ end
68
+
69
+ o.on('-t', '--timeout secs=15', 'Total timeout') do |timeout|
70
+ @opts[:timeout] = timeout.to_i
71
+ end
72
+
73
+ o.on('-i', '--interval secs=2', 'Interval between attempts') do |interval|
74
+ @opts[:interval] = interval.to_i
75
+ end
76
+
77
+ o.on('-q', '--quiet', 'Do not output any status messages') do
78
+ @opts[:quiet] = true
79
+ end
80
+ end.parse!
81
+
82
+ def log(message)
83
+ puts message unless @opts[:quiet]
84
+ end
85
+
86
+ @opts[:timeout] = @opts[:timeout].to_i
87
+ @opts[:interval] = @opts[:interval].to_i
88
+
89
+ if @opts[:db]
90
+ @pg = {}
91
+ @pg[:db] = "-d #{@opts[:db]}"
92
+ @pg[:user] = "-U #{@opts[:user]}" if @opts[:user]
93
+ @pg[:pass] = if @opts[:pass] && !@opts[:pass].empty?
94
+ "-W #{@opts[:pass]}"
95
+ else
96
+ '-w'
97
+ end
98
+
99
+ @pg[:host] = "-h #{@opts[:host]}" if @opts[:host]
100
+ @pg[:port] = "-p #{@opts[:port]}" if @opts[:port]
101
+
102
+ @pg[:tb] = @opts[:tb] if @opts[:tb]
103
+ end
104
+
105
+ def wait_for(timeout)
106
+ starttime = Time.now
107
+ loop do
108
+ success = yield
109
+
110
+ return success if success
111
+
112
+ return false if (Time.now - starttime) > timeout
113
+ sleep @opts[:interval]
114
+ end
115
+
116
+ false
117
+ end
118
+
119
+ def complete!(success)
120
+ if success
121
+ if @opts[:exec]
122
+ exec @opts[:exec]
123
+ else
124
+ exit 0
125
+ end
126
+ end
127
+
128
+ STDERR.puts 'Operation timed out'
129
+ exit 1
130
+ end
131
+
132
+ def wait_for_consul
133
+ log('Waiting for consul...')
134
+ ret = wait_for @opts[:timeout] do
135
+ cmd = "consul operator raft list-peers -http-addr=#{@opts[:consul_addr]} > /dev/null 2>&1"
136
+ system(cmd)
137
+ $CHILD_STATUS.success?
138
+ end
139
+
140
+ yield(ret)
141
+ end
142
+
143
+ def wait_for_consul_service(service)
144
+ log("Waiting for consul service #{service}...")
145
+ ret = wait_for @opts[:timeout] do
146
+ cmd = "curl -s #{@opts[:consul_addr]}/v1/health/service/#{service}?passing | wc -c"
147
+ bytes = `#{cmd}`.to_i
148
+ bytes > 10
149
+ end
150
+
151
+ yield(ret)
152
+ end
153
+
154
+ def wait_for_tcp
155
+ log("Waiting for TCP: #{@opts[:host]}:#{@opts[:port]}...")
156
+ ret = wait_for @opts[:timeout] do
157
+ cmd = "nc -z #{@opts[:host]} #{@opts[:port]} > /dev/null 2>&1"
158
+ system(cmd)
159
+ $CHILD_STATUS.success?
160
+ end
161
+
162
+ yield(ret)
163
+ end
164
+
165
+ def wait_for_db
166
+ log("Waiting for DB: pg://#{@opts[:user]}:#{@opts[:pass]}@#{@opts[:host]}:#{@opts[:port]}/#{@opts[:db]}...")
167
+ ret = wait_for @opts[:timeout] do
168
+ cmd = "psql -lqt #{@pg[:user]} #{@pg[:pass]} #{@pg[:host]} #{@pg[:port]} #{@pg[:db]} 2>/dev/null | cut -d \\| -f 1 | grep -qw #{@opts[:db]} > /dev/null 2>&1"
169
+ system(cmd)
170
+ $CHILD_STATUS.success?
171
+ end
172
+
173
+ yield(ret)
174
+ end
175
+
176
+ def wait_for_tb
177
+ log("Waiting for TABLE: pg://#{@opts[:user]}:#{@opts[:pass]}@#{@opts[:host]}:#{@opts[:port]}/#{@opts[:db]}##{@opts[:tb]}...")
178
+ ret = wait_for @opts[:timeout] do
179
+ cmd = "echo \"\\dt\" | psql -qt #{@pg[:user]} #{@pg[:pass]} #{@pg[:host]} #{@pg[:port]} #{@pg[:db]} 2>/dev/null | cut -d \\| -f 2 | grep -qw #{@pg[:tb]} > /dev/null 2>&1"
180
+ system(cmd)
181
+ $CHILD_STATUS.success?
182
+ end
183
+
184
+ yield(ret)
185
+ end
186
+
187
+ def wait_for_file(file = @opts[:file], timeout = @opts[:timeout])
188
+ log("Waiting for FILE: #{file}")
189
+ ret = wait_for timeout do
190
+ File.exist? file
191
+ end
192
+ yield(ret)
193
+ end
194
+
195
+ if @opts[:tb]
196
+ wait_for_tcp do |success|
197
+ if success
198
+ wait_for_db do |success|
199
+ if success
200
+ wait_for_tb do |success|
201
+ complete!(success)
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ complete!(false)
208
+ end
209
+ end
210
+
211
+ if @opts[:db]
212
+ wait_for_tcp do |success|
213
+ if success
214
+ wait_for_db do |success|
215
+ complete!(success)
216
+ end
217
+ end
218
+
219
+ complete!(false)
220
+ end
221
+ end
222
+
223
+
224
+ if @opts[:consul]
225
+ wait_for_consul do |success|
226
+ complete!(success)
227
+ end
228
+ end
229
+
230
+ if @opts[:consul_service]
231
+ wait_for_consul_service(@opts[:consul_service]) do |success|
232
+ complete!(success)
233
+ end
234
+ end
235
+
236
+ if @opts[:tcp]
237
+ wait_for_tcp do |success|
238
+ complete!(success)
239
+ end
240
+ end
241
+
242
+ if @opts[:file]
243
+ wait_for_file(@opts[:file], @opts[:timeout]) do |success|
244
+ complete!(success)
245
+ end
246
+ end
data/docker/Dockerfile ADDED
@@ -0,0 +1,53 @@
1
+ FROM ruby:2.5.0-alpine
2
+ MAINTAINER Firmhouse "kinnalru@gmail.com"
3
+
4
+ WORKDIR /home/app
5
+
6
+ RUN mkdir -p ~/.ssh && echo -e "Host * \
7
+ \n StrictHostKeyChecking no \
8
+ \n UserKnownHostsFile=/dev/null\n" >> ~/.ssh/config
9
+
10
+ RUN set -ex \
11
+ && apk add --no-cache \
12
+ bash \
13
+ libstdc++ \
14
+ libxml2 \
15
+ ruby-libs \
16
+ wget \
17
+ curl \
18
+ libcurl \
19
+ ruby \
20
+ git \
21
+ tzdata
22
+
23
+ RUN set -ex \
24
+ && curl -sSLo /tmp/consul.zip https://releases.hashicorp.com/consul/1.2.1/consul_1.2.1_linux_amd64.zip \
25
+ && unzip -d /bin /tmp/consul.zip \
26
+ && rm -rf /tmp/consul.zip \
27
+ && addgroup consul \
28
+ && adduser -D -g "" -s /bin/sh -G consul consul \
29
+ && mkdir -p /tmp/consul \
30
+ && chown -R consul:consul /tmp/consul
31
+
32
+ RUN set -ex \
33
+ && curl -so envconsul.tgz https://releases.hashicorp.com/envconsul/0.7.3/envconsul_0.7.3_linux_amd64.tgz \
34
+ && tar -xvzf envconsul.tgz \
35
+ && rm -rf envconsul.tgz \
36
+ && mv envconsul /bin/envconsul \
37
+ && chmod +x /bin/envconsul
38
+
39
+ ADD Gemfile Gemfile.lock docker_toolkit.gemspec /home/app/
40
+ ADD lib/ /home/app/lib
41
+
42
+ RUN set -ex \
43
+ && bundle install \
44
+ && cd / \
45
+ && rm -rf /usr/src/ruby
46
+
47
+ ADD . /home/app
48
+
49
+
50
+
51
+ SHELL ["/bin/sh", "-c", "-l"]
52
+
53
+
@@ -0,0 +1,12 @@
1
+ version: "2"
2
+ services:
3
+ tests:
4
+ build:
5
+ context: ../
6
+ dockerfile: docker/Dockerfile
7
+ image: docker_toolkit_tests:latest
8
+ working_dir: /home/app
9
+ command: ["tail", "-f", "/dev/null"]
10
+
11
+
12
+
data/docker/down.sh ADDED
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ docker-compose down -v || true
3
+
4
+
@@ -0,0 +1,17 @@
1
+ #!/bin/sh
2
+ SELF=$(readlink -f $0)
3
+ export ENV_ROOT=$(dirname "${SELF}")
4
+
5
+ trap '$ENV_ROOT/down.sh' EXIT
6
+
7
+ cd $ENV_ROOT
8
+
9
+ docker-compose up -d --force-recreate --build || exit 1
10
+ docker-compose exec -T tests bundle exec rspec $@
11
+
12
+ code=$?
13
+ if [ $code -ne 0 ]; then
14
+ docker-compose logs
15
+ fi
16
+
17
+ exit $code
@@ -0,0 +1,33 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'docker_toolkit/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'docker_toolkit'
7
+ spec.version = DockerToolkit::VERSION
8
+ spec.authors = ['Godko Ivan', 'Samoilenko Yuri']
9
+ spec.email = ['igodko@rnds.pro', 'kinnalru@gmail.com']
10
+ spec.homepage = 'https://github.com/RnD-Soft/docker_toolkit'
11
+ spec.required_ruby_version = '>= 2.1.0'
12
+
13
+ spec.summary = 'Helper scripts for work with docker and consul'
14
+ spec.description = 'Advanced docker and consul control scripts'
15
+
16
+ spec.bindir = 'bin'
17
+ spec.require_paths = ['lib']
18
+
19
+ if File.exist?(File.join(__dir__, '/', '.git'))
20
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
21
+ f.match(%r{^(test|spec|features)/})
22
+ end
23
+
24
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f) }
25
+ end
26
+
27
+
28
+ spec.add_dependency 'diplomat'
29
+ spec.add_dependency 'json'
30
+
31
+ spec.add_development_dependency 'bundler', '~> 1.14'
32
+ spec.add_development_dependency 'rake', '~> 10.0'
33
+ end
@@ -0,0 +1,5 @@
1
+ module DockerToolkit
2
+
3
+ VERSION = '0.1.0'.freeze
4
+
5
+ end
@@ -0,0 +1,10 @@
1
+ require 'diplomat'
2
+ require 'English'
3
+ require 'optparse'
4
+
5
+ require 'docker_toolkit/version'
6
+
7
+ module DockerToolkit
8
+
9
+
10
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: docker_toolkit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Godko Ivan
8
+ - Samoilenko Yuri
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2018-08-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: diplomat
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.14'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.14'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '10.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '10.0'
70
+ description: Advanced docker and consul control scripts
71
+ email:
72
+ - igodko@rnds.pro
73
+ - kinnalru@gmail.com
74
+ executables:
75
+ - consul.rb
76
+ - merger.rb
77
+ - waiter.rb
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - ".dockerignore"
82
+ - ".gitignore"
83
+ - ".rspec"
84
+ - ".rubocop.yml"
85
+ - ".travis.yml"
86
+ - Gemfile
87
+ - Gemfile.lock
88
+ - README.md
89
+ - bin/consul.rb
90
+ - bin/merger.rb
91
+ - bin/waiter.rb
92
+ - docker/Dockerfile
93
+ - docker/docker-compose.yml
94
+ - docker/down.sh
95
+ - docker/run_tests.sh
96
+ - docker_toolkit.gemspec
97
+ - lib/docker_toolkit.rb
98
+ - lib/docker_toolkit/version.rb
99
+ homepage: https://github.com/RnD-Soft/docker_toolkit
100
+ licenses: []
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 2.1.0
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.7.3
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Helper scripts for work with docker and consul
122
+ test_files: []