dry-stack 0.0.88 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae624210dd275eb7f62eb30f4023ea37dfde7689e84b80e9f98bf4d47f5d66b4
4
- data.tar.gz: '0109ac07fea18f6f942ad66d71292fd52da1f27cc0b99c2834d1620b6bdb2c67'
3
+ metadata.gz: 8e0189d36c23f0487d26004278fd73f0d8e94410d31a7a44237ca88521edd165
4
+ data.tar.gz: a7e80baf8f3cec031ec0dcd863738301e3758ebea4dfc11c4101b3f9c1ba51a2
5
5
  SHA512:
6
- metadata.gz: 07a69b0fc65be43c138f561eabff1a38525ceea703b43c368c292bbcd350bdff283f64b74f992aef6f7b0b97761af6ff7e594ee07b634900b1780ef559bae281
7
- data.tar.gz: fc51afc785660c574d971374b300da2ba8ce67f9673b1d700822867ba7baefc89de0addba17c52e5b3da56c32bb2b2617233cf3337f3ee64ad5e925309f46b9f
6
+ metadata.gz: 0bacfd11de68b970264c5749cd38797b52ea83aa9a2b6b818232798d22e50bfc1c6a8ae243cff52af1a03a35b841165bbfd08053dfbb39e1d5cb193f20e985ac
7
+ data.tar.gz: d3e124944972e6efaccba32322bff5edc5bf9ff9855e23981488f2ebe440cd4763781a6a9930c14b7c121ed38e5895f29e55ca54f5e017b272871d4b3e9a0812
@@ -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, args, extra)
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
- stack.name = _params[:name] if _params[:name]
8
- yaml = stack.to_compose(_params, args[0]&.to_sym ).lines[1..].join
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(str) = Dry::Stack() { eval str, self.binding }
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('', '--traefik_tls', 'Generate traefik tls labels') { true }
72
- o.on('', '--host_sed /from/to/', 'Sed ingress host /\\*/dev.*/')
73
- o.on('-n', '--no-env', 'Do not process env variables') { true }
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
- safe_eval stack_text # isolate context
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 = context[:context_name]&.to_sym || args[0].to_sym
15
- host = context[:context_host]
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 "docker context ls --format json" do |line|
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] != host
23
- raise "context '#{name}' has different host value: #{contexts[name][:DockerEndpoint]} != #{host}"
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=#{host}" unless contexts[name]
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, c_name).lines[1..].join
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 sd_name -- --prune --resolve-image changed]']
45
+ '[... swarm_deploy -- --prune --resolve-image changed]']
52
46
 
53
47
  end.new
54
48
 
@@ -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
@@ -54,20 +55,15 @@ module Dry
54
55
  def command(cmd)= @service[:command] = cmd
55
56
  def entrypoint(cmd)= @service[:entrypoint] = cmd
56
57
  def deploy_label(str)= @service[:deploy][:labels] << str
57
- def config(name = nil, opts)= (@service[:configs] ||= []) << {source: name.to_s }.merge(opts)
58
+ def config(name = nil, opts)= (@service[:configs] ||= []) << {source: name.to_s}.merge(opts)
58
59
  def logging(opts) = (@service[:logging] ||= {}).merge! opts
59
60
  def user(user) = @service[:user] = user # "${UID}:${GID}", "www-data:www-data"
60
61
  def network(names) = (@service[:networks] ||= []) << names
61
62
  def ingress(ing) = ((@service[:ingress] ||=[]) << ing).flatten!
62
63
  end
63
64
 
64
- class SwarmFunction
65
- def initialize(swarm, &); @swarm = swarm; instance_exec(&) end
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, :swarm_deploy
74
+ attr_accessor :name, :options, :description, :configuration
79
75
 
80
- def Stack(name = nil, &)
81
- Stack.last_stack = Stack.new name
82
- Stack.last_stack.instance_exec(&) if block_given?
83
- end
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
- @swarm_deploy = {}
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 to_compose(opts = @options, deploy_name = nil )
127
- if deploy_name
128
- raise "Deploy not found: #{deploy_name}" unless @swarm_deploy[deploy_name]
123
+ def apply_configuration(configuration)
124
+ raise "Configuration not found: #{configuration}" unless @configurations[configuration.to_sym]
125
+ @configurations[configuration.to_sym][:block_function].call
126
+ end
129
127
 
130
- opts.merge! @swarm_deploy[deploy_name][:options]
131
- end
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
@@ -323,8 +321,8 @@ module Dry
323
321
  end
324
322
 
325
323
  def Options(opts)
326
- warn 'WARN: Options command is used for testing purpose.\
327
- Not recommended in real life configurations.' unless $0 =~ /rspec/
324
+ # warn 'WARN: Options command is used for testing purpose.\
325
+ # Not recommended in real life configurations.' unless $0 =~ /rspec/
328
326
  @options.merge! opts
329
327
  end
330
328
 
@@ -333,7 +331,9 @@ module Dry
333
331
  end
334
332
 
335
333
  def Ingress(services)
336
- @ingress.merge! services
334
+ services.each do |name, ing|
335
+ @ingress[name] = ((@ingress[name] || [] ) | [ing]).flatten
336
+ end
337
337
  end
338
338
 
339
339
  def Config(name, opts)
@@ -382,12 +382,12 @@ module Dry
382
382
  yield if block_given?
383
383
  end
384
384
 
385
- def SwarmDeploy(name, opts = {}, &)
386
- opts[:environment] = opts.delete(:env) if opts.key? :env
387
-
388
- swarm = @swarm_deploy[name.to_sym] ||= { environment: {}, options: {} }
389
- swarm.merge! opts
390
- SwarmFunction.new(swarm, &) if block_given?
385
+ def Configuration(name, opts = {}, &)
386
+ configuration = @configurations[name.to_sym] ||= {}
387
+ configuration.merge! opts
388
+ configuration.merge! block_function: -> {
389
+ instance_exec(&) if block_given? # https://rubyreferences.github.io/rubychanges/3.3.html#anonymous-parameters-forwarding-inside-blocks-are-disallowed
390
+ }
391
391
  end
392
392
 
393
393
  end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  class Stack
3
- VERSION = '0.0.88'
3
+ VERSION = '0.1.1'
4
4
  end
5
5
  end
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.88
4
+ version: 0.1.1
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-17 00:00:00.000000000 Z
11
+ date: 2024-07-28 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