dry-stack 0.0.86 → 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 +4 -4
- data/lib/dry-stack/command_compose.rb +4 -5
- data/lib/dry-stack/command_line.rb +11 -5
- data/lib/dry-stack/command_swarm_deploy.rb +14 -20
- data/lib/dry-stack/stack.rb +36 -31
- data/lib/version.rb +1 -1
- metadata +2 -5
- data/bin/stack.drs +0 -33
- data/bin/stack1.drs +0 -1
- data/bin/stack2.drs +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 571e75a339b0f3ad9ffb0c4d5816e4de8451b2ec3f7b3bf7a31030eef31dd176
|
4
|
+
data.tar.gz: 13b9b28f6d78a75f5d08e718743b89c4f466d2134e0ca36a89e268f557b46d90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32a9c2c618aeacc2efdd3892bcb1b708e3a071b6cc3a975b9e81464dbe703e374205397de4d158f6218c11898db7401d0f21f45a397878ce0153c9a9446a86d3
|
7
|
+
data.tar.gz: 5f7450cef3b2d997d1a53b0b906384282529747ccd373b9c693fbc40fae5d1e33562657833cacd7e8f0c0e60d824ae552807a3b3227333d6e4e166dd808d56d7
|
@@ -1,14 +1,13 @@
|
|
1
1
|
require_relative 'command_line'
|
2
2
|
|
3
3
|
Dry::CommandLine::COMMANDS[:to_compose] = Class.new do
|
4
|
-
def run(stack, params,
|
5
|
-
raise "none or one deploy name may be specified: #{args}" unless args.empty? || args.size == 1
|
4
|
+
def run(stack, params, _args, _extra)
|
6
5
|
_params = stack.options.merge params
|
7
|
-
|
8
|
-
|
6
|
+
yaml = stack.to_compose(_params ).lines[1..].join
|
7
|
+
$stdout.puts yaml
|
9
8
|
|
10
9
|
# substitute ENV variables
|
11
|
-
_params[:'no-env'] ? $stdout.puts(yaml) : system("echo \"#{yaml.gsub("`", '\\\`')}\"")
|
10
|
+
# _params[:'no-env'] ? $stdout.puts(yaml) : system("echo \"#{yaml.gsub("`", '\\\`')}\"")
|
12
11
|
end
|
13
12
|
|
14
13
|
def help = ['Print stack in docker compose format',
|
@@ -37,7 +37,9 @@ module Dry
|
|
37
37
|
raise 'Invalid .env file'
|
38
38
|
end
|
39
39
|
|
40
|
-
def safe_eval(
|
40
|
+
def safe_eval(drs, params)
|
41
|
+
Dry::Stack(params[:name], params[:configuration]) { eval drs, self.binding }
|
42
|
+
end
|
41
43
|
|
42
44
|
def run(args)
|
43
45
|
params = {}
|
@@ -68,9 +70,12 @@ module Dry
|
|
68
70
|
o.on('', '--name STACK_NAME', 'Define stack name')
|
69
71
|
o.on('', '--ingress', 'Generate ingress labels') { true }
|
70
72
|
o.on('', '--traefik', 'Generate traefik labels') { true }
|
71
|
-
o.on('', '--
|
72
|
-
o.on('', '--
|
73
|
-
o.on('-n', '--no-env', '
|
73
|
+
o.on('', '--traefik-tls', 'Generate traefik tls labels') { true }
|
74
|
+
o.on('', '--host-sed /from/to/', 'Sed ingress host /\\*/dev.*/')
|
75
|
+
o.on('-n', '--no-env', 'Deprecated') { $stderr.puts 'warning: deprecated option: -n' } # TODO: remove
|
76
|
+
o.on('-c', '--configuration name', 'Configuration name')
|
77
|
+
COMMANDS.values.select{_1.options(o) if _1.respond_to? :options }
|
78
|
+
|
74
79
|
o.on('-h', '--help') { puts o; exit }
|
75
80
|
o.parse! args, into: params
|
76
81
|
|
@@ -82,7 +87,8 @@ module Dry
|
|
82
87
|
stack_text = File.read(params[:stack]) if params[:stack]
|
83
88
|
stack_text ||= STDIN.read unless $stdin.tty?
|
84
89
|
|
85
|
-
|
90
|
+
|
91
|
+
safe_eval stack_text, params # isolate context
|
86
92
|
|
87
93
|
Stack.last_stack.name = params[:name] if params[:name]
|
88
94
|
COMMANDS[command.to_sym].run Stack.last_stack, params, args, extra
|
@@ -1,41 +1,35 @@
|
|
1
1
|
require_relative 'command_line'
|
2
2
|
|
3
3
|
Dry::CommandLine::COMMANDS[:swarm_deploy] = Class.new do
|
4
|
+
def options(parser)
|
5
|
+
parser.on('-x', '--context-endpoint host', 'Docker context host. Created if not exists')
|
6
|
+
end
|
7
|
+
|
4
8
|
def run(stack, params, args, extra)
|
5
|
-
unless args.empty?
|
6
|
-
c_name = args[0].to_sym
|
7
|
-
raise "deploy config not found: #{args[0]}" unless stack.swarm_deploy.key? args[0].to_sym
|
8
|
-
context = stack.swarm_deploy[args[0].to_sym]
|
9
|
-
end
|
10
9
|
_params = stack.options.merge params
|
11
10
|
stack.name = _params[:name] if _params[:name]
|
12
11
|
|
13
|
-
if context
|
14
|
-
name =
|
15
|
-
|
12
|
+
if params[:'context-endpoint']
|
13
|
+
name = params[:'context-endpoint'].gsub( /[\/.:@]/,'_').gsub( '__','_')
|
14
|
+
name = "dry-#{name}".to_sym
|
15
|
+
endpoint = params[:'context-endpoint']
|
16
16
|
contexts = {}
|
17
|
-
exec_o_lines
|
17
|
+
exec_o_lines 'docker context ls --format json' do |line|
|
18
18
|
ctx = JSON.parse line, symbolize_names: true
|
19
19
|
contexts[ctx[:Name].to_sym] = ctx # {"Current":false,"Description":"","DockerEndpoint":"ssh://root@x.x.x.x","Error":"","Name":"prod-swarm"}
|
20
20
|
end
|
21
21
|
|
22
|
-
if contexts[name] && contexts[name][:DockerEndpoint] !=
|
23
|
-
raise "context '#{name}' has different host value: #{contexts[name][:DockerEndpoint]} != #{
|
22
|
+
if contexts[name] && contexts[name][:DockerEndpoint] != endpoint
|
23
|
+
raise "context '#{name}' has different host value: #{contexts[name][:DockerEndpoint]} != #{endpoint}"
|
24
24
|
end
|
25
25
|
|
26
|
-
exec_i "docker context create #{name} --docker host=#{
|
26
|
+
exec_i "docker context create #{name} --docker host=#{endpoint}" unless contexts[name]
|
27
27
|
|
28
28
|
ENV['DOCKER_CONTEXT'] = name.to_s
|
29
|
-
stack.name = context[:stack_name] || stack.name
|
30
|
-
context[:environment].each do |k,v|
|
31
|
-
ENV[k.to_s] = v.to_s
|
32
|
-
end
|
33
29
|
end
|
34
30
|
|
35
31
|
# substitute ENV variables
|
36
|
-
yaml = stack.to_compose(_params
|
37
|
-
yaml = _params[:'no-env'] ? yaml : `echo \"#{yaml.gsub("`", '\\\`')}\"`
|
38
|
-
system " echo \"#{yaml.gsub("`", '\\\`')}\"" if _params[:v]
|
32
|
+
yaml = stack.to_compose(_params).lines[1..].join
|
39
33
|
# system " echo \"#{yaml.gsub("`", '\\\`')}\" | docker stack deploy -c - #{stack.name} --prune --resolve-image changed"
|
40
34
|
|
41
35
|
# --prune --resolve-image changed
|
@@ -48,7 +42,7 @@ Dry::CommandLine::COMMANDS[:swarm_deploy] = Class.new do
|
|
48
42
|
end
|
49
43
|
|
50
44
|
def help = ['Call docker stack deploy & add config readme w/ description',
|
51
|
-
'[... swarm_deploy
|
45
|
+
'[... swarm_deploy -- --prune --resolve-image changed]']
|
52
46
|
|
53
47
|
end.new
|
54
48
|
|
data/lib/dry-stack/stack.rb
CHANGED
@@ -39,9 +39,10 @@ module Dry
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
def Stack(name = nil, &)
|
42
|
+
def Stack(name = nil, configuration = nil, &)
|
43
43
|
Stack.last_stack = Stack.new name
|
44
44
|
Stack.last_stack.instance_exec(&) if block_given?
|
45
|
+
Stack.last_stack.apply_configuration configuration if configuration
|
45
46
|
end
|
46
47
|
|
47
48
|
class ServiceFunction
|
@@ -61,13 +62,8 @@ module Dry
|
|
61
62
|
def ingress(ing) = ((@service[:ingress] ||=[]) << ing).flatten!
|
62
63
|
end
|
63
64
|
|
64
|
-
class
|
65
|
-
def initialize(
|
66
|
-
def env(variables)= @swarm[:environment].merge! variables
|
67
|
-
def options(variables)= @swarm[:options].merge! variables
|
68
|
-
def context_host(host)= @swarm[:context_host] = host
|
69
|
-
def context_name(name)= @swarm[:context_name] = name
|
70
|
-
def stack_name(name)= @swarm[:stack_name] = name
|
65
|
+
class ConfigurationFunction
|
66
|
+
def initialize(configuration, &); @configuration = configuration; instance_exec(&) end
|
71
67
|
end
|
72
68
|
|
73
69
|
class Stack
|
@@ -75,12 +71,13 @@ module Dry
|
|
75
71
|
class << self
|
76
72
|
attr_accessor :last_stack
|
77
73
|
end
|
78
|
-
attr_accessor :name, :options, :description, :
|
74
|
+
attr_accessor :name, :options, :description, :configuration
|
79
75
|
|
80
|
-
def Stack(
|
81
|
-
|
82
|
-
|
83
|
-
|
76
|
+
def Stack(...) = Dry::Stack(...)
|
77
|
+
|
78
|
+
# def self.new(*args, &block)
|
79
|
+
# super
|
80
|
+
# end
|
84
81
|
|
85
82
|
def initialize(name)
|
86
83
|
@name = name || 'stack'
|
@@ -97,7 +94,7 @@ module Dry
|
|
97
94
|
@labels = {}
|
98
95
|
@configs = {}
|
99
96
|
@logging = {}
|
100
|
-
@
|
97
|
+
@configurations = {}
|
101
98
|
end
|
102
99
|
|
103
100
|
def expand_hash(hash)
|
@@ -123,12 +120,13 @@ module Dry
|
|
123
120
|
end
|
124
121
|
end
|
125
122
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
123
|
+
def apply_configuration(configuration)
|
124
|
+
raise "Configuration not found: #{configuration}" unless @configurations[configuration.to_sym]
|
125
|
+
@configurations[configuration.to_sym][:block_function].call @configurations[configuration.to_sym]
|
126
|
+
end
|
129
127
|
|
130
|
-
|
131
|
-
|
128
|
+
def to_compose(opts = @options)
|
129
|
+
@name = @options[:name] || @name
|
132
130
|
|
133
131
|
compose = {
|
134
132
|
# name: @name.to_s, # https://docs.docker.com/compose/compose-file/#name-top-level-element
|
@@ -146,6 +144,8 @@ module Dry
|
|
146
144
|
|
147
145
|
compose[:services].each do |name, service|
|
148
146
|
|
147
|
+
service[:image].gsub!(/:latest$/, '') # let docker swarm to create tag: :latest@sha265:0000...
|
148
|
+
|
149
149
|
ingress = [@ingress[name], service[:ingress] || [] ].flatten.compact
|
150
150
|
|
151
151
|
service[:deploy] ||= {}
|
@@ -268,15 +268,18 @@ module Dry
|
|
268
268
|
end
|
269
269
|
|
270
270
|
compose[:configs].update(compose[:configs]) do |name, config|
|
271
|
+
# total config name must be max 64 characters length. MD5 - 32 characters
|
272
|
+
short_name = name[0..30]
|
273
|
+
|
271
274
|
if config[:file_content]
|
272
275
|
md5 = Digest::MD5.hexdigest config[:file_content]
|
273
|
-
fname = "./#{@name}.config.#{name}.#{md5}" # use MD5, when
|
276
|
+
fname = "./#{@name}.config.#{name}.#{md5}" # use MD5, when run in parallel may have different content
|
274
277
|
File.write fname, config[:file_content]
|
275
|
-
{name: "#{
|
278
|
+
{name: "#{short_name}-#{md5}", file: fname}.merge config.except(:file_content)
|
276
279
|
elsif config[:file]
|
277
280
|
body = File.read config[:file] rescue ''
|
278
281
|
md5 = Digest::MD5.hexdigest body
|
279
|
-
{name: "#{
|
282
|
+
{name: "#{short_name}-#{md5}", file: fname}.merge config
|
280
283
|
else
|
281
284
|
config
|
282
285
|
end
|
@@ -318,8 +321,8 @@ module Dry
|
|
318
321
|
end
|
319
322
|
|
320
323
|
def Options(opts)
|
321
|
-
warn 'WARN: Options command is used for testing purpose.\
|
322
|
-
|
324
|
+
# warn 'WARN: Options command is used for testing purpose.\
|
325
|
+
# Not recommended in real life configurations.' unless $0 =~ /rspec/
|
323
326
|
@options.merge! opts
|
324
327
|
end
|
325
328
|
|
@@ -328,7 +331,9 @@ module Dry
|
|
328
331
|
end
|
329
332
|
|
330
333
|
def Ingress(services)
|
331
|
-
|
334
|
+
services.each do |name, ing|
|
335
|
+
@ingress[name] = ((@ingress[name] || [] ) | [ing]).flatten
|
336
|
+
end
|
332
337
|
end
|
333
338
|
|
334
339
|
def Config(name, opts)
|
@@ -377,12 +382,12 @@ module Dry
|
|
377
382
|
yield if block_given?
|
378
383
|
end
|
379
384
|
|
380
|
-
def
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
385
|
+
def Configuration(name, opts = {}, &)
|
386
|
+
configuration = @configurations[name.to_sym] ||= { }
|
387
|
+
configuration.merge! opts
|
388
|
+
configuration.merge! block_function: ->(*args){
|
389
|
+
self.instance_exec(&) if block_given?
|
390
|
+
}
|
386
391
|
end
|
387
392
|
|
388
393
|
end
|
data/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-stack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Artyom B
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -102,9 +102,6 @@ extensions: []
|
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
104
|
- bin/dry-stack
|
105
|
-
- bin/stack.drs
|
106
|
-
- bin/stack1.drs
|
107
|
-
- bin/stack2.drs
|
108
105
|
- lib/dry-stack.rb
|
109
106
|
- lib/dry-stack/apache_specific_md5.rb
|
110
107
|
- lib/dry-stack/command_compose.rb
|
data/bin/stack.drs
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
Description <<~DSC
|
2
|
-
|
3
|
-
DSC
|
4
|
-
|
5
|
-
Options name: 'stack_name', traefik: true
|
6
|
-
SwarmDeploy :sky_gates do
|
7
|
-
context_host 'ssh://root@10.0.0.1'
|
8
|
-
stack_name 'remote_stack'
|
9
|
-
env REGISTRY_HOST: '10.100.0.2:5000'
|
10
|
-
end
|
11
|
-
Ingress admin: [
|
12
|
-
{host: 'backend.*'},
|
13
|
-
{host: 'admin.*', path: '/api', port: 4000}
|
14
|
-
]
|
15
|
-
|
16
|
-
Deploy [:admin, :operator], labels: [
|
17
|
-
'traefik.http.middlewares.%{service-name}_auth.basicauth.users=admin:$$apr1$$i7hdbc9g$$Rkocxo9snhmuESvUg0TTv/',
|
18
|
-
"traefik.http.routers.%{service-name}.middlewares=%{service-name}_auth"
|
19
|
-
]
|
20
|
-
|
21
|
-
PublishPorts admin: 4000, operator: 4001, navigator: 4002, reports: 7000 # mode: ingress, protocol: tcp
|
22
|
-
|
23
|
-
Service :admin, image: 'frontend', env: {APP: 'admin'}, ports: 5000
|
24
|
-
Service :operator, image: 'frontend', env: {APP: 'operator'}, ports: 5000
|
25
|
-
Service :navigator, image: 'frontend', env: {APP: 'navigator'}, ports: 5000
|
26
|
-
|
27
|
-
Service :backend, image: 'backend', ports: 3000 do
|
28
|
-
env APP_PORT: 3000, NODE_ENV: 'development', SKIP_GZ: true, DB_URL: '$DB_URL'
|
29
|
-
end
|
30
|
-
|
31
|
-
Service :reports, image: 'reports:0.1', env: {DB_URL: '$DB_URL'}, ports: 7000
|
32
|
-
|
33
|
-
Network :default, attachable: true
|
data/bin/stack1.drs
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Service :reports, image: 'reports', ports: 7000, env: {DB_URL: '$DB_URL'}
|
data/bin/stack2.drs
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
PublishPorts reports: 7000
|
2
|
-
Ingress reports: {host: 'reports.*', protocol: :http, port: 7000}
|
3
|
-
Deploy admin: { replica: 2, 'resources.limits': { cpus: 4, memory: '500M' } }
|
4
|
-
|
5
|
-
Service :admin, image: '$REGISTRY_HOST/frontend', env: { APP: 'admin' }, ports: 5000
|
6
|
-
Service :reports, image: '$REGISTRY_HOST/reports', env: { DB_URL: '$DB_URL' }
|
7
|
-
|
8
|
-
Network :default, attachable: true
|