aggkit 0.2.5

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +20 -0
  3. data/.gitignore +109 -0
  4. data/.gitlab-ci.yml +66 -0
  5. data/.rspec +4 -0
  6. data/.rubocop.yml +98 -0
  7. data/.travis.yml +30 -0
  8. data/Gemfile +12 -0
  9. data/Gemfile.lock +55 -0
  10. data/README.md +96 -0
  11. data/aggkit.gemspec +38 -0
  12. data/bin/agg +167 -0
  13. data/bin/aggconsul +222 -0
  14. data/bin/agglock +71 -0
  15. data/bin/aggmerge +118 -0
  16. data/bin/aggwait +262 -0
  17. data/bin/consul.rb +222 -0
  18. data/bin/locker.rb +71 -0
  19. data/bin/merger.rb +118 -0
  20. data/bin/terminator.rb +71 -0
  21. data/bin/waiter.rb +262 -0
  22. data/docker/Dockerfile +112 -0
  23. data/docker/docker-compose.yml +12 -0
  24. data/docker/down.sh +4 -0
  25. data/docker/run_tests.sh +23 -0
  26. data/lib/aggkit/childprocess/abstract_io.rb +38 -0
  27. data/lib/aggkit/childprocess/abstract_process.rb +194 -0
  28. data/lib/aggkit/childprocess/errors.rb +28 -0
  29. data/lib/aggkit/childprocess/jruby/io.rb +17 -0
  30. data/lib/aggkit/childprocess/jruby/process.rb +161 -0
  31. data/lib/aggkit/childprocess/jruby/pump.rb +55 -0
  32. data/lib/aggkit/childprocess/jruby.rb +58 -0
  33. data/lib/aggkit/childprocess/tools/generator.rb +148 -0
  34. data/lib/aggkit/childprocess/unix/fork_exec_process.rb +72 -0
  35. data/lib/aggkit/childprocess/unix/io.rb +22 -0
  36. data/lib/aggkit/childprocess/unix/lib.rb +188 -0
  37. data/lib/aggkit/childprocess/unix/platform/i386-linux.rb +14 -0
  38. data/lib/aggkit/childprocess/unix/platform/i386-solaris.rb +13 -0
  39. data/lib/aggkit/childprocess/unix/platform/x86_64-linux.rb +14 -0
  40. data/lib/aggkit/childprocess/unix/platform/x86_64-macosx.rb +13 -0
  41. data/lib/aggkit/childprocess/unix/posix_spawn_process.rb +135 -0
  42. data/lib/aggkit/childprocess/unix/process.rb +91 -0
  43. data/lib/aggkit/childprocess/unix.rb +11 -0
  44. data/lib/aggkit/childprocess/version.rb +5 -0
  45. data/lib/aggkit/childprocess/windows/handle.rb +93 -0
  46. data/lib/aggkit/childprocess/windows/io.rb +25 -0
  47. data/lib/aggkit/childprocess/windows/lib.rb +418 -0
  48. data/lib/aggkit/childprocess/windows/process.rb +132 -0
  49. data/lib/aggkit/childprocess/windows/process_builder.rb +177 -0
  50. data/lib/aggkit/childprocess/windows/structs.rb +151 -0
  51. data/lib/aggkit/childprocess/windows.rb +35 -0
  52. data/lib/aggkit/childprocess.rb +213 -0
  53. data/lib/aggkit/env.rb +219 -0
  54. data/lib/aggkit/runner.rb +80 -0
  55. data/lib/aggkit/version.rb +5 -0
  56. data/lib/aggkit/watcher.rb +239 -0
  57. data/lib/aggkit.rb +15 -0
  58. metadata +196 -0
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.load(config == '-' ? STDIN.read : File.read(config))
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/locker.rb ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'diplomat'
5
+
6
+ @opts = {
7
+ url: 'http://localhost:8500',
8
+ timeout: 10,
9
+ ttl: 30 * 60
10
+ }
11
+
12
+ parser = OptionParser.new do |o|
13
+ o.banner = 'Usage: locker.rb [options]'
14
+
15
+ o.on("--consul url=#{@opts[:url]}", 'Set up a custom Consul URL') do |url|
16
+ Diplomat.configure do |config|
17
+ config.url = url.strip
18
+ end
19
+ end
20
+
21
+ o.on('--lock resource', 'resource name to lock with Consul') do |resource|
22
+ @opts[:lock] = resource.strip
23
+ end
24
+
25
+ o.on("--ttl seconds=#{@opts[:ttl]}", 'TTL to set when session created') do |seconds|
26
+ @opts[:ttl] = Integer(seconds.strip)
27
+ end
28
+
29
+ o.on('--unlock session', 'session name from previous call lock') do |session|
30
+ @opts[:unlock] = session.strip
31
+ end
32
+
33
+ o.on("--timeout seconds=#{@opts[:timeout]}", 'timeout to wait lock') do |seconds|
34
+ @opts[:timeout] = Integer(seconds.strip)
35
+ end
36
+ end
37
+ parser.parse!
38
+
39
+
40
+ def lock(session, locker, timeout)
41
+ Timeout.timeout(timeout) do
42
+ return Diplomat::Lock.wait_to_acquire("resource/#{locker[:resource]}/lock", session, locker.to_json, 10)
43
+ end
44
+ rescue Timeout::Error => e
45
+ false
46
+ end
47
+
48
+
49
+ if resource = @opts[:lock]
50
+ locker = {
51
+ Name: "#{resource}_locker_#{rand(999_999)}",
52
+ Behavior: 'delete',
53
+ TTL: "#{@opts[:ttl]}s",
54
+ resource: resource
55
+ }
56
+ sessionid = Diplomat::Session.create(locker)
57
+
58
+ if lock(sessionid, locker, @opts[:timeout])
59
+ puts sessionid
60
+ exit 0
61
+ else
62
+ STDERR.puts "Failed to lock resource: #{resource}"
63
+ exit 1
64
+ end
65
+
66
+ elsif session = @opts[:unlock]
67
+ Diplomat::Session.destroy(session)
68
+ else
69
+ STDERR.puts parser.help
70
+ exit 1
71
+ end
data/bin/merger.rb ADDED
@@ -0,0 +1,118 @@
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 or more 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
+ file_to_load = if File.exist?(dirname + '/' + file)
79
+ dirname + '/' + file
80
+ else
81
+ file
82
+ end
83
+
84
+ tmp = process_compose_hash(YAML.load(File.read(file_to_load)), File.dirname(file_to_load), service)
85
+
86
+ begin
87
+ (tmp['services'][ext['service']] || {})
88
+ rescue StandardError
89
+ {}
90
+ end
91
+ else
92
+ yml['services'][ext['service']]
93
+ end.deep_dup
94
+
95
+ service.delete 'extends'
96
+
97
+ yml['services'][name] = extend_hash(base, service)
98
+ end
99
+ yml
100
+ end
101
+
102
+ if File.basename($PROGRAM_NAME) == File.basename(__FILE__)
103
+ result = ENV['COMPOSE_FILE'].split(':').reduce({}) do |parent, file|
104
+ yml = process_compose_hash(YAML.load(File.read(file)), File.dirname(file), parent)
105
+ if yml['version'] && parent['version'] && yml['version'] != parent['version']
106
+ raise "version mismatch: #{file}"
107
+ end
108
+ ret = extend_hash(parent.deep_dup, yml)
109
+ ret
110
+ end
111
+
112
+ if ARGV[0].nil? || ARGV[0].strip == '-'
113
+ puts YAML.dump(result)
114
+ else
115
+ File.write(ARGV[0].strip, YAML.dump(result))
116
+ end
117
+
118
+ end
data/bin/terminator.rb ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'English'
4
+
5
+ STDOUT.sync = true
6
+ STDERR.sync = true
7
+
8
+ @opts = {
9
+ code: 0,
10
+ sleep: 1,
11
+ term_code: 0
12
+ }
13
+
14
+ def log(msg)
15
+ puts "[terminator]: #{msg}"
16
+ end
17
+
18
+ log "started: #{ARGV.inspect}"
19
+
20
+
21
+ parser = OptionParser.new do |o|
22
+ o.banner = 'Usage: term.rb [options]'
23
+
24
+ o.on("--exit code=#{@opts[:code]}", 'set exit code') do |code|
25
+ @opts[:code] = code.to_i
26
+ end
27
+
28
+ o.on("--sleep sec=#{@opts[:sleep]}", 'Sleep before exit') do |sec|
29
+ @opts[:sleep] = sec.to_i
30
+ end
31
+
32
+ o.on('--term', 'SIGTERM self') do
33
+ @opts[:term] = true
34
+ end
35
+
36
+ o.on("--term-code=#{@opts[:term_code]}", 'exit code when SIGTERM catched') do |code|
37
+ @opts[:term_code] = code.to_i
38
+ end
39
+
40
+ o.on('--kill', 'SIGKILL self') do
41
+ @opts[:kill] = true
42
+ end
43
+ end
44
+ parser.parse!
45
+
46
+
47
+
48
+
49
+ %w[INT TERM].each do |sig|
50
+ trap(sig) do
51
+ log "signal: #{sig}. exit: #{@opts[:term_code]}"
52
+ exit(@opts[:term_code])
53
+ end
54
+ end
55
+
56
+ log 'sleep...'
57
+ sleep @opts[:sleep]
58
+
59
+ log 'go'
60
+ if @opts[:kill]
61
+ log 'kill self'
62
+ ::Process.kill('KILL', $PROCESS_ID)
63
+ end
64
+
65
+ if @opts[:term]
66
+ log 'term self'
67
+ ::Process.kill('TERM', $PROCESS_ID)
68
+ end
69
+
70
+ log "normal exit with: #{@opts[:code]}"
71
+ exit @opts[:code]