Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
artyomb committed Jul 24, 2024
1 parent e4bb5f8 commit dcf1c66
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 133 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
dry-stack (0.0.88)
dry-stack (0.1.0)

GEM
remote: https://rubygems.org/
Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This gem allows ...
cat simple_stack.drs | dry-stack -e to_compose | docker stack deploy -c - simple_stack
$ dry-stack
Version: 0.0.88
Version: 0.1.0
Usage:
dry-stack -s stackfile [options] COMMAND
cat stackfile | dry-stack COMMAND
Expand All @@ -16,7 +16,7 @@ Commands:
to_compose - Print stack in docker compose format
[... to_compose <deploy name>]
swarm_deploy - Call docker stack deploy & add config readme w/ description
[... swarm_deploy sd_name -- --prune --resolve-image changed]
[... swarm_deploy -- --prune --resolve-image changed]
Options:
-s, --stack STACK_NAME Stack file
Expand All @@ -27,11 +27,13 @@ Options:
Generate ingress labels
--traefik
Generate traefik labels
--traefik_tls
--traefik-tls
Generate traefik tls labels
--host_sed /from/to/
--host-sed /from/to/
Sed ingress host /\*/dev.*/
-n, --no-env Do not process env variables
-n, --no-env Deprecated
-c, --configuration name Configuration name
-x, --context-endpoint host Docker context host. Created if not exists
-h, --help
```
Expand Down
9 changes: 4 additions & 5 deletions lib/dry-stack/command_compose.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
require_relative 'command_line'

Dry::CommandLine::COMMANDS[:to_compose] = Class.new do
def run(stack, params, args, extra)
raise "none or one deploy name may be specified: #{args}" unless args.empty? || args.size == 1
def run(stack, params, _args, _extra)
_params = stack.options.merge params
stack.name = _params[:name] if _params[:name]
yaml = stack.to_compose(_params, args[0]&.to_sym ).lines[1..].join
yaml = stack.to_compose(_params ).lines[1..].join
$stdout.puts yaml

# substitute ENV variables
_params[:'no-env'] ? $stdout.puts(yaml) : system("echo \"#{yaml.gsub("`", '\\\`')}\"")
# _params[:'no-env'] ? $stdout.puts(yaml) : system("echo \"#{yaml.gsub("`", '\\\`')}\"")
end

def help = ['Print stack in docker compose format',
Expand Down
16 changes: 11 additions & 5 deletions lib/dry-stack/command_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ def load_env
raise 'Invalid .env file'
end

def safe_eval(str) = Dry::Stack() { eval str, self.binding }
def safe_eval(drs, params)
Dry::Stack(params[:name], params[:configuration]) { eval drs, self.binding }
end

def run(args)
params = {}
Expand Down Expand Up @@ -68,9 +70,12 @@ def run(args)
o.on('', '--name STACK_NAME', 'Define stack name')
o.on('', '--ingress', 'Generate ingress labels') { true }
o.on('', '--traefik', 'Generate traefik labels') { true }
o.on('', '--traefik_tls', 'Generate traefik tls labels') { true }
o.on('', '--host_sed /from/to/', 'Sed ingress host /\\*/dev.*/')
o.on('-n', '--no-env', 'Do not process env variables') { true }
o.on('', '--traefik-tls', 'Generate traefik tls labels') { true }
o.on('', '--host-sed /from/to/', 'Sed ingress host /\\*/dev.*/')
o.on('-n', '--no-env', 'Deprecated') { $stderr.puts 'warning: deprecated option: -n' } # TODO: remove
o.on('-c', '--configuration name', 'Configuration name')
COMMANDS.values.select{_1.options(o) if _1.respond_to? :options }

o.on('-h', '--help') { puts o; exit }
o.parse! args, into: params

Expand All @@ -82,7 +87,8 @@ def run(args)
stack_text = File.read(params[:stack]) if params[:stack]
stack_text ||= STDIN.read unless $stdin.tty?

safe_eval stack_text # isolate context

safe_eval stack_text, params # isolate context

Stack.last_stack.name = params[:name] if params[:name]
COMMANDS[command.to_sym].run Stack.last_stack, params, args, extra
Expand Down
34 changes: 14 additions & 20 deletions lib/dry-stack/command_swarm_deploy.rb
Original file line number Diff line number Diff line change
@@ -1,41 +1,35 @@
require_relative 'command_line'

Dry::CommandLine::COMMANDS[:swarm_deploy] = Class.new do
def options(parser)
parser.on('-x', '--context-endpoint host', 'Docker context host. Created if not exists')
end

def run(stack, params, args, extra)
unless args.empty?
c_name = args[0].to_sym
raise "deploy config not found: #{args[0]}" unless stack.swarm_deploy.key? args[0].to_sym
context = stack.swarm_deploy[args[0].to_sym]
end
_params = stack.options.merge params
stack.name = _params[:name] if _params[:name]

if context
name = context[:context_name]&.to_sym || args[0].to_sym
host = context[:context_host]
if params[:'context-endpoint']
name = params[:'context-endpoint'].gsub( /[\/.:@]/,'_').gsub( '__','_')
name = "dry-#{name}".to_sym
endpoint = params[:'context-endpoint']
contexts = {}
exec_o_lines "docker context ls --format json" do |line|
exec_o_lines 'docker context ls --format json' do |line|
ctx = JSON.parse line, symbolize_names: true
contexts[ctx[:Name].to_sym] = ctx # {"Current":false,"Description":"","DockerEndpoint":"ssh://[email protected]","Error":"","Name":"prod-swarm"}
end

if contexts[name] && contexts[name][:DockerEndpoint] != host
raise "context '#{name}' has different host value: #{contexts[name][:DockerEndpoint]} != #{host}"
if contexts[name] && contexts[name][:DockerEndpoint] != endpoint
raise "context '#{name}' has different host value: #{contexts[name][:DockerEndpoint]} != #{endpoint}"
end

exec_i "docker context create #{name} --docker host=#{host}" unless contexts[name]
exec_i "docker context create #{name} --docker host=#{endpoint}" unless contexts[name]

ENV['DOCKER_CONTEXT'] = name.to_s
stack.name = context[:stack_name] || stack.name
context[:environment].each do |k,v|
ENV[k.to_s] = v.to_s
end
end

# substitute ENV variables
yaml = stack.to_compose(_params, c_name).lines[1..].join
yaml = _params[:'no-env'] ? yaml : `echo \"#{yaml.gsub("`", '\\\`')}\"`
system " echo \"#{yaml.gsub("`", '\\\`')}\"" if _params[:v]
yaml = stack.to_compose(_params).lines[1..].join
# system " echo \"#{yaml.gsub("`", '\\\`')}\" | docker stack deploy -c - #{stack.name} --prune --resolve-image changed"

# --prune --resolve-image changed
Expand All @@ -48,7 +42,7 @@ def run(stack, params, args, extra)
end

def help = ['Call docker stack deploy & add config readme w/ description',
'[... swarm_deploy sd_name -- --prune --resolve-image changed]']
'[... swarm_deploy -- --prune --resolve-image changed]']

end.new

Expand Down
56 changes: 28 additions & 28 deletions lib/dry-stack/stack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ def each_recursive(parent, each_ =-> { _1.respond_to?(:each) ? _1.each : [] }, p
end
end

def Stack(name = nil, &)
def Stack(name = nil, configuration = nil, &)
Stack.last_stack = Stack.new name
Stack.last_stack.instance_exec(&) if block_given?
Stack.last_stack.apply_configuration configuration if configuration
end

class ServiceFunction
Expand All @@ -61,26 +62,22 @@ def network(names) = (@service[:networks] ||= []) << names
def ingress(ing) = ((@service[:ingress] ||=[]) << ing).flatten!
end

class SwarmFunction
def initialize(swarm, &); @swarm = swarm; instance_exec(&) end
def env(variables)= @swarm[:environment].merge! variables
def options(variables)= @swarm[:options].merge! variables
def context_host(host)= @swarm[:context_host] = host
def context_name(name)= @swarm[:context_name] = name
def stack_name(name)= @swarm[:stack_name] = name
class ConfigurationFunction
def initialize(configuration, &); @configuration = configuration; instance_exec(&) end
end

class Stack
COMPOSE_VERSION = '3.8'
class << self
attr_accessor :last_stack
end
attr_accessor :name, :options, :description, :swarm_deploy
attr_accessor :name, :options, :description, :configuration

def Stack(name = nil, &)
Stack.last_stack = Stack.new name
Stack.last_stack.instance_exec(&) if block_given?
end
def Stack(...) = Dry::Stack(...)

# def self.new(*args, &block)
# super
# end

def initialize(name)
@name = name || 'stack'
Expand All @@ -97,7 +94,7 @@ def initialize(name)
@labels = {}
@configs = {}
@logging = {}
@swarm_deploy = {}
@configurations = {}
end

def expand_hash(hash)
Expand All @@ -123,12 +120,13 @@ def nginx_host2regexp(str)
end
end

def to_compose(opts = @options, deploy_name = nil )
if deploy_name
raise "Deploy not found: #{deploy_name}" unless @swarm_deploy[deploy_name]
def apply_configuration(configuration)
raise "Configuration not found: #{configuration}" unless @configurations[configuration.to_sym]
@configurations[configuration.to_sym][:block_function].call @configurations[configuration.to_sym]
end

opts.merge! @swarm_deploy[deploy_name][:options]
end
def to_compose(opts = @options)
@name = @options[:name] || @name

compose = {
# name: @name.to_s, # https://docs.docker.com/compose/compose-file/#name-top-level-element
Expand Down Expand Up @@ -323,8 +321,8 @@ def Description(string)
end

def Options(opts)
warn 'WARN: Options command is used for testing purpose.\
Not recommended in real life configurations.' unless $0 =~ /rspec/
# warn 'WARN: Options command is used for testing purpose.\
# Not recommended in real life configurations.' unless $0 =~ /rspec/
@options.merge! opts
end

Expand All @@ -333,7 +331,9 @@ def Labels(labels)
end

def Ingress(services)
@ingress.merge! services
services.each do |name, ing|
@ingress[name] = ((@ingress[name] || [] ) | [ing]).flatten
end
end

def Config(name, opts)
Expand Down Expand Up @@ -382,12 +382,12 @@ def Volume(name, opts = {})
yield if block_given?
end

def SwarmDeploy(name, opts = {}, &)
opts[:environment] = opts.delete(:env) if opts.key? :env

swarm = @swarm_deploy[name.to_sym] ||= { environment: {}, options: {} }
swarm.merge! opts
SwarmFunction.new(swarm, &) if block_given?
def Configuration(name, opts = {}, &)
configuration = @configurations[name.to_sym] ||= { }
configuration.merge! opts
configuration.merge! block_function: ->(*args){
self.instance_exec(&) if block_given?
}
end

end
Expand Down
2 changes: 1 addition & 1 deletion lib/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Dry
class Stack
VERSION = '0.0.88'
VERSION = '0.1.0'
end
end
26 changes: 26 additions & 0 deletions spec/data/stack13-compose-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
version: '3.8'
services:
admin:
environment:
APP: admin
STACK_NAME: stack_name_dev
STACK_SERVICE_NAME: admin
deploy:
labels:
- traefik.enable=true
- traefik.http.routers.stack_name_dev_admin-0.service=stack_name_dev_admin-0
- traefik.http.services.stack_name_dev_admin-0.loadbalancer.server.port=5000
- traefik.http.routers.stack_name_dev_admin-0.rule=HostRegexp(`{name:admin1\..*}`)
- traefik.http.routers.stack_name_dev_admin-1.service=stack_name_dev_admin-1
- traefik.http.services.stack_name_dev_admin-1.loadbalancer.server.port=4000
- traefik.http.routers.stack_name_dev_admin-1.rule=HostRegexp(`{name:admin2\..*}`)
&& PathPrefix(`/api`)
image: frontend
networks:
- default
- ingress_routing
networks:
ingress_routing:
external: true
name: ingress-routing
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ services:
- traefik.http.routers.stack_name_admin-1.tls.domains[0].main=admin2.swarm_x.com
- traefik.http.routers.stack_name_admin-1.rule=HostRegexp(`{name:admin2\..*}`)
&& PathPrefix(`/api`)
- traefik.http.routers.stack_name_admin-2.service=stack_name_admin-2
- traefik.http.services.stack_name_admin-2.loadbalancer.server.port=5000
- traefik.http.routers.stack_name_admin-2.tls=true
- traefik.http.routers.stack_name_admin-2.tls.certresolver=le
- traefik.http.routers.stack_name_admin-2.tls.domains[0].main=prod_admin.swarm_x.com
- traefik.http.routers.stack_name_admin-2.rule=HostRegexp(`{name:prod_admin\..*}`)
image: frontend
networks:
- default
Expand Down
26 changes: 0 additions & 26 deletions spec/data/stack13-compose-swarm1.yml

This file was deleted.

26 changes: 0 additions & 26 deletions spec/data/stack13-compose-swarm2.yml

This file was deleted.

Loading

0 comments on commit dcf1c66

Please sign in to comment.