mrsk 0.0.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +193 -77
  3. data/bin/mrsk +5 -0
  4. data/lib/mrsk/cli/accessory.rb +85 -0
  5. data/lib/mrsk/cli/app.rb +123 -0
  6. data/lib/mrsk/cli/base.rb +48 -0
  7. data/lib/mrsk/cli/build.rb +53 -0
  8. data/lib/mrsk/cli/main.rb +110 -0
  9. data/lib/mrsk/cli/prune.rb +19 -0
  10. data/lib/mrsk/cli/registry.rb +18 -0
  11. data/lib/mrsk/cli/server.rb +8 -0
  12. data/lib/mrsk/cli/templates/deploy.yml +17 -0
  13. data/lib/mrsk/cli/traefik.rb +77 -0
  14. data/lib/mrsk/cli.rb +9 -0
  15. data/lib/mrsk/commander.rb +45 -5
  16. data/lib/mrsk/commands/accessory.rb +61 -0
  17. data/lib/mrsk/commands/app.rb +50 -10
  18. data/lib/mrsk/commands/base.rb +13 -9
  19. data/lib/mrsk/commands/builder/base.rb +26 -0
  20. data/lib/mrsk/commands/builder/multiarch/remote.rb +12 -4
  21. data/lib/mrsk/commands/builder/multiarch.rb +17 -9
  22. data/lib/mrsk/commands/builder/native/remote.rb +71 -0
  23. data/lib/mrsk/commands/builder/native.rb +3 -7
  24. data/lib/mrsk/commands/builder.rb +11 -7
  25. data/lib/mrsk/commands/traefik.rb +13 -3
  26. data/lib/mrsk/configuration/accessory.rb +60 -0
  27. data/lib/mrsk/configuration/role.rb +46 -14
  28. data/lib/mrsk/configuration.rb +86 -43
  29. data/lib/mrsk/sshkit_with_ext.rb +12 -0
  30. data/lib/mrsk/utils.rb +29 -0
  31. data/lib/mrsk/version.rb +1 -1
  32. data/lib/mrsk.rb +0 -1
  33. metadata +40 -18
  34. data/lib/mrsk/engine.rb +0 -4
  35. data/lib/tasks/mrsk/app.rake +0 -97
  36. data/lib/tasks/mrsk/build.rake +0 -52
  37. data/lib/tasks/mrsk/mrsk.rake +0 -37
  38. data/lib/tasks/mrsk/prune.rake +0 -18
  39. data/lib/tasks/mrsk/registry.rake +0 -16
  40. data/lib/tasks/mrsk/server.rake +0 -11
  41. data/lib/tasks/mrsk/setup.rb +0 -6
  42. data/lib/tasks/mrsk/templates/deploy.yml +0 -24
  43. data/lib/tasks/mrsk/templates/mrsk +0 -8
  44. data/lib/tasks/mrsk/traefik.rake +0 -41
@@ -15,12 +15,20 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
15
15
  end
16
16
 
17
17
  private
18
+ def builder_name
19
+ super + "-remote"
20
+ end
21
+
22
+ def builder_name_with_arch(arch)
23
+ "#{builder_name}-#{arch}"
24
+ end
25
+
18
26
  def create_local_buildx
19
- docker :buildx, :create, "--use", "--name", "mrsk", "mrsk-#{local["arch"]}", "--platform", "linux/#{local["arch"]}"
27
+ docker :buildx, :create, "--name", builder_name, builder_name_with_arch(local["arch"]), "--platform", "linux/#{local["arch"]}"
20
28
  end
21
29
 
22
30
  def append_remote_buildx
23
- docker :buildx, :create, "--append", "--name", "mrsk", "mrsk-#{remote["arch"]}", "--platform", "linux/#{remote["arch"]}"
31
+ docker :buildx, :create, "--append", "--name", builder_name, builder_name_with_arch(remote["arch"]), "--platform", "linux/#{remote["arch"]}"
24
32
  end
25
33
 
26
34
  def create_contexts
@@ -30,7 +38,7 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
30
38
  end
31
39
 
32
40
  def create_context(arch, host)
33
- docker :context, :create, "mrsk-#{arch}", "--description", "'MRSK #{arch} Native Host'", "--docker", "'host=#{host}'"
41
+ docker :context, :create, builder_name_with_arch(arch), "--description", "'#{builder_name} #{arch} native host'", "--docker", "'host=#{host}'"
34
42
  end
35
43
 
36
44
  def remove_contexts
@@ -40,7 +48,7 @@ class Mrsk::Commands::Builder::Multiarch::Remote < Mrsk::Commands::Builder::Mult
40
48
  end
41
49
 
42
50
  def remove_context(arch)
43
- docker :context, :rm, "mrsk-#{arch}"
51
+ docker :context, :rm, builder_name_with_arch(arch)
44
52
  end
45
53
 
46
54
  def local
@@ -1,20 +1,23 @@
1
- require "mrsk/commands/base"
1
+ require "mrsk/commands/builder/base"
2
2
 
3
- class Mrsk::Commands::Builder::Multiarch < Mrsk::Commands::Base
3
+ class Mrsk::Commands::Builder::Multiarch < Mrsk::Commands::Builder::Base
4
4
  def create
5
- docker :buildx, :create, "--use", "--name", "mrsk"
5
+ docker :buildx, :create, "--use", "--name", builder_name
6
6
  end
7
7
 
8
8
  def remove
9
- docker :buildx, :rm, "mrsk"
9
+ docker :buildx, :rm, builder_name
10
10
  end
11
11
 
12
12
  def push
13
- docker :buildx, :build, "--push", "--platform linux/amd64,linux/arm64", "-t", config.absolute_image, "."
14
- end
15
-
16
- def pull
17
- docker :pull, config.absolute_image
13
+ docker :buildx, :build,
14
+ "--push",
15
+ "--platform", "linux/amd64,linux/arm64",
16
+ "--builder", builder_name,
17
+ "-t", config.absolute_image,
18
+ *build_args,
19
+ *build_secrets,
20
+ "."
18
21
  end
19
22
 
20
23
  def info
@@ -22,4 +25,9 @@ class Mrsk::Commands::Builder::Multiarch < Mrsk::Commands::Base
22
25
  docker(:context, :ls),
23
26
  docker(:buildx, :ls)
24
27
  end
28
+
29
+ private
30
+ def builder_name
31
+ "mrsk-#{config.service}-multiarch"
32
+ end
25
33
  end
@@ -0,0 +1,71 @@
1
+ require "mrsk/commands/builder/native"
2
+
3
+ class Mrsk::Commands::Builder::Native::Remote < Mrsk::Commands::Builder::Native
4
+ def create
5
+ combine \
6
+ create_context,
7
+ create_buildx
8
+ end
9
+
10
+ def remove
11
+ combine \
12
+ remove_context,
13
+ remove_buildx
14
+ end
15
+
16
+ def push
17
+ docker :buildx, :build,
18
+ "--push",
19
+ "--platform", platform,
20
+ "--builder", builder_name,
21
+ "-t", config.absolute_image,
22
+ *build_args,
23
+ *build_secrets,
24
+ "."
25
+ end
26
+
27
+ def info
28
+ combine \
29
+ docker(:context, :ls),
30
+ docker(:buildx, :ls)
31
+ end
32
+
33
+
34
+ private
35
+ def arch
36
+ config.builder["remote"]["arch"]
37
+ end
38
+
39
+ def host
40
+ config.builder["remote"]["host"]
41
+ end
42
+
43
+ def builder_name
44
+ "mrsk-#{config.service}-native-remote"
45
+ end
46
+
47
+ def builder_name_with_arch
48
+ "#{builder_name}-#{arch}"
49
+ end
50
+
51
+ def platform
52
+ "linux/#{arch}"
53
+ end
54
+
55
+ def create_context
56
+ docker :context, :create,
57
+ builder_name_with_arch, "--description", "'#{builder_name} #{arch} native host'", "--docker", "'host=#{host}'"
58
+ end
59
+
60
+ def remove_context
61
+ docker :context, :rm, builder_name_with_arch
62
+ end
63
+
64
+ def create_buildx
65
+ docker :buildx, :create, "--name", builder_name, builder_name_with_arch, "--platform", platform
66
+ end
67
+
68
+ def remove_buildx
69
+ docker :buildx, :rm, builder_name
70
+ end
71
+ end
@@ -1,6 +1,6 @@
1
- require "mrsk/commands/base"
1
+ require "mrsk/commands/builder/base"
2
2
 
3
- class Mrsk::Commands::Builder::Native < Mrsk::Commands::Base
3
+ class Mrsk::Commands::Builder::Native < Mrsk::Commands::Builder::Base
4
4
  def create
5
5
  # No-op on native
6
6
  end
@@ -11,14 +11,10 @@ class Mrsk::Commands::Builder::Native < Mrsk::Commands::Base
11
11
 
12
12
  def push
13
13
  combine \
14
- docker(:build, "-t", config.absolute_image, "."),
14
+ docker(:build, "-t", *build_args, *build_secrets, config.absolute_image, "."),
15
15
  docker(:push, config.absolute_image)
16
16
  end
17
17
 
18
- def pull
19
- docker :pull, config.absolute_image
20
- end
21
-
22
18
  def info
23
19
  # No-op on native
24
20
  end
@@ -2,22 +2,21 @@ require "mrsk/commands/base"
2
2
 
3
3
  class Mrsk::Commands::Builder < Mrsk::Commands::Base
4
4
  delegate :create, :remove, :push, :pull, :info, to: :target
5
- delegate :native?, :multiarch?, :remote?, to: :name
6
5
 
7
6
  def name
8
- target.class.to_s.demodulize.downcase.inquiry
7
+ target.class.to_s.remove("Mrsk::Commands::Builder::").underscore
9
8
  end
10
9
 
11
10
  def target
12
11
  case
13
- when config.builder.nil?
14
- multiarch
15
- when config.builder["multiarch"] == false
12
+ when config.builder && config.builder["multiarch"] == false
16
13
  native
17
- when config.builder["local"] && config.builder["local"]
14
+ when config.builder && config.builder["local"] && config.builder["remote"]
18
15
  multiarch_remote
16
+ when config.builder && config.builder["remote"]
17
+ native_remote
19
18
  else
20
- raise ArgumentError, "Builder configuration incorrect: #{config.builder.inspect}"
19
+ multiarch
21
20
  end
22
21
  end
23
22
 
@@ -25,6 +24,10 @@ class Mrsk::Commands::Builder < Mrsk::Commands::Base
25
24
  @native ||= Mrsk::Commands::Builder::Native.new(config)
26
25
  end
27
26
 
27
+ def native_remote
28
+ @native ||= Mrsk::Commands::Builder::Native::Remote.new(config)
29
+ end
30
+
28
31
  def multiarch
29
32
  @multiarch ||= Mrsk::Commands::Builder::Multiarch.new(config)
30
33
  end
@@ -35,5 +38,6 @@ class Mrsk::Commands::Builder < Mrsk::Commands::Base
35
38
  end
36
39
 
37
40
  require "mrsk/commands/builder/native"
41
+ require "mrsk/commands/builder/native/remote"
38
42
  require "mrsk/commands/builder/multiarch"
39
43
  require "mrsk/commands/builder/multiarch/remote"
@@ -8,7 +8,8 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
8
8
  "-p 80:80",
9
9
  "-v /var/run/docker.sock:/var/run/docker.sock",
10
10
  "traefik",
11
- "--providers.docker"
11
+ "--providers.docker",
12
+ "--log.level=DEBUG"
12
13
  end
13
14
 
14
15
  def start
@@ -23,8 +24,17 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
23
24
  docker :ps, "--filter", "name=traefik"
24
25
  end
25
26
 
26
- def logs
27
- docker :logs, "traefik", "-n", "100", "-t"
27
+ def logs(since: nil, lines: nil, grep: nil)
28
+ pipe \
29
+ docker(:logs, "traefik", (" --since #{since}" if since), (" -n #{lines}" if lines), "-t", "2>&1"),
30
+ ("grep '#{grep}'" if grep)
31
+ end
32
+
33
+ def follow_logs(host:, grep: nil)
34
+ run_over_ssh pipe(
35
+ docker(:logs, "traefik", "-t", "-n", "10", "-f", "2>&1"),
36
+ ("grep '#{grep}'" if grep)
37
+ ).join(" "), host: host
28
38
  end
29
39
 
30
40
  def remove_container
@@ -0,0 +1,60 @@
1
+ class Mrsk::Configuration::Assessory
2
+ delegate :argumentize, :argumentize_env_with_secrets, to: Mrsk::Utils
3
+
4
+ attr_accessor :name, :specifics
5
+
6
+ def initialize(name, config:)
7
+ @name, @config, @specifics = name.inquiry, config, config.raw_config["accessories"][name]
8
+ end
9
+
10
+ def service_name
11
+ "#{config.service}-#{name}"
12
+ end
13
+
14
+ def image
15
+ specifics["image"]
16
+ end
17
+
18
+ def host
19
+ specifics["host"] || raise(ArgumentError, "Missing host for accessory")
20
+ end
21
+
22
+ def port
23
+ if specifics["port"].to_s.include?(":")
24
+ specifics["port"]
25
+ else
26
+ "#{specifics["port"]}:#{specifics["port"]}"
27
+ end
28
+ end
29
+
30
+ def labels
31
+ default_labels.merge(specifics["labels"] || {})
32
+ end
33
+
34
+ def label_args
35
+ argumentize "--label", labels
36
+ end
37
+
38
+ def env
39
+ specifics["env"] || {}
40
+ end
41
+
42
+ def env_args
43
+ argumentize_env_with_secrets env
44
+ end
45
+
46
+ def volumes
47
+ specifics["volumes"] || []
48
+ end
49
+
50
+ def volume_args
51
+ argumentize "--volume", volumes
52
+ end
53
+
54
+ private
55
+ attr_accessor :config
56
+
57
+ def default_labels
58
+ { "service" => service_name }
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
1
  class Mrsk::Configuration::Role
2
- delegate :argumentize, to: Mrsk::Configuration
2
+ delegate :argumentize, :argumentize_env_with_secrets, to: Mrsk::Utils
3
3
 
4
4
  attr_accessor :name
5
5
 
@@ -12,21 +12,33 @@ class Mrsk::Configuration::Role
12
12
  end
13
13
 
14
14
  def labels
15
- if name.web?
16
- default_labels.merge(traefik_labels).merge(custom_labels)
17
- else
18
- default_labels.merge(custom_labels)
19
- end
15
+ default_labels.merge(traefik_labels).merge(custom_labels)
20
16
  end
21
17
 
22
18
  def label_args
23
19
  argumentize "--label", labels
24
20
  end
25
21
 
22
+ def env
23
+ if config.env && config.env["secret"]
24
+ merged_env_with_secrets
25
+ else
26
+ merged_env
27
+ end
28
+ end
29
+
30
+ def env_args
31
+ argumentize_env_with_secrets env
32
+ end
33
+
26
34
  def cmd
27
35
  specializations["cmd"]
28
36
  end
29
37
 
38
+ def running_traefik?
39
+ name.web? || specializations["traefik"]
40
+ end
41
+
30
42
  private
31
43
  attr_accessor :config
32
44
 
@@ -44,13 +56,17 @@ class Mrsk::Configuration::Role
44
56
  end
45
57
 
46
58
  def traefik_labels
47
- {
48
- "traefik.http.routers.#{config.service}.rule" => "'PathPrefix(`/`)'",
49
- "traefik.http.services.#{config.service}.loadbalancer.healthcheck.path" => "/up",
50
- "traefik.http.services.#{config.service}.loadbalancer.healthcheck.interval" => "1s",
51
- "traefik.http.middlewares.#{config.service}.retry.attempts" => "3",
52
- "traefik.http.middlewares.#{config.service}.retry.initialinterval" => "500ms"
53
- }
59
+ if running_traefik?
60
+ {
61
+ "traefik.http.routers.#{config.service}.rule" => "'PathPrefix(`/`)'",
62
+ "traefik.http.services.#{config.service}.loadbalancer.healthcheck.path" => "/up",
63
+ "traefik.http.services.#{config.service}.loadbalancer.healthcheck.interval" => "1s",
64
+ "traefik.http.middlewares.#{config.service}.retry.attempts" => "3",
65
+ "traefik.http.middlewares.#{config.service}.retry.initialinterval" => "500ms"
66
+ }
67
+ else
68
+ {}
69
+ end
54
70
  end
55
71
 
56
72
  def custom_labels
@@ -64,7 +80,23 @@ class Mrsk::Configuration::Role
64
80
  if config.servers.is_a?(Array) || config.servers[name].is_a?(Array)
65
81
  { }
66
82
  else
67
- config.servers[name].without("hosts")
83
+ config.servers[name].except("hosts")
84
+ end
85
+ end
86
+
87
+ def specialized_env
88
+ specializations["env"] || {}
89
+ end
90
+
91
+ def merged_env
92
+ config.env&.merge(specialized_env) || {}
93
+ end
94
+
95
+ # Secrets are stored in an array, which won't merge by default, so have to do it by hand.
96
+ def merged_env_with_secrets
97
+ merged_env.tap do |new_env|
98
+ new_env["secret"] = Array(config.env["secret"]) + Array(specialized_env["secret"])
99
+ new_env["clear"] = (Array(config.env["clear"] || config.env) + Array(specialized_env["clear"] || specialized_env)).uniq
68
100
  end
69
101
  end
70
102
  end
@@ -1,26 +1,44 @@
1
1
  require "active_support/ordered_options"
2
2
  require "active_support/core_ext/string/inquiry"
3
+ require "active_support/core_ext/module/delegation"
4
+ require "pathname"
3
5
  require "erb"
6
+ require "mrsk/utils"
4
7
 
5
8
  class Mrsk::Configuration
6
- delegate :service, :image, :servers, :env, :labels, :registry, :builder, to: :config, allow_nil: true
9
+ delegate :service, :image, :servers, :env, :labels, :registry, :builder, to: :raw_config, allow_nil: true
10
+ delegate :argumentize, :argumentize_env_with_secrets, to: Mrsk::Utils
11
+
12
+ attr_accessor :raw_config
7
13
 
8
14
  class << self
9
- def load_file(file)
10
- if file.exist?
11
- new YAML.load(ERB.new(IO.read(file)).result).symbolize_keys
12
- else
13
- raise "Configuration file not found in #{file}"
14
- end
15
+ def create_from(base_config_file, destination: nil, version: "missing")
16
+ new(load_config_file(base_config_file).tap do |config|
17
+ if destination
18
+ config.merge! \
19
+ load_config_file destination_config_file(base_config_file, destination)
20
+ end
21
+ end, version: version)
15
22
  end
16
23
 
17
- def argumentize(argument, attributes)
18
- attributes.flat_map { |k, v| [ argument, "#{k}=#{v}" ] }
19
- end
24
+ private
25
+ def load_config_file(file)
26
+ if file.exist?
27
+ YAML.load(ERB.new(IO.read(file)).result).symbolize_keys
28
+ else
29
+ raise "Configuration file not found in #{file}"
30
+ end
31
+ end
32
+
33
+ def destination_config_file(base_config_file, destination)
34
+ dir, basename = base_config_file.split
35
+ dir.join basename.to_s.remove(".yml") + ".#{destination}.yml"
36
+ end
20
37
  end
21
38
 
22
- def initialize(config, validate: true)
23
- @config = ActiveSupport::InheritableOptions.new(config)
39
+ def initialize(raw_config, version: "missing", validate: true)
40
+ @raw_config = ActiveSupport::InheritableOptions.new(raw_config)
41
+ @version = version
24
42
  ensure_required_keys_present if validate
25
43
  end
26
44
 
@@ -33,36 +51,34 @@ class Mrsk::Configuration
33
51
  roles.detect { |r| r.name == name.to_s }
34
52
  end
35
53
 
36
- def hosts
37
- hosts =
38
- case
39
- when ENV["HOSTS"]
40
- ENV["HOSTS"].split(",")
41
- when ENV["ROLES"]
42
- role_names = ENV["ROLES"].split(",")
43
- roles.select { |r| role_names.include?(r.name) }.flat_map(&:hosts)
44
- else
45
- roles.flat_map(&:hosts)
46
- end
54
+ def accessories
55
+ @accessories ||= raw_config.accessories.keys.collect { |name| Mrsk::Configuration::Assessory.new(name, config: self) }
56
+ end
47
57
 
48
- if hosts.any?
49
- hosts
50
- else
51
- raise ArgumentError, "No hosts found"
52
- end
58
+ def accessory(name)
59
+ accessories.detect { |a| a.name == name.to_s }
60
+ end
61
+
62
+
63
+ def all_hosts
64
+ roles.flat_map(&:hosts)
53
65
  end
54
66
 
55
- def primary_host
67
+ def primary_web_host
56
68
  role(:web).hosts.first
57
69
  end
58
70
 
71
+ def traefik_hosts
72
+ roles.select(&:running_traefik?).flat_map(&:hosts)
73
+ end
74
+
59
75
 
60
76
  def version
61
- @version ||= ENV["VERSION"] || `git rev-parse HEAD`.strip
77
+ @version
62
78
  end
63
79
 
64
80
  def repository
65
- [ config.registry["server"], image ].compact.join("/")
81
+ [ raw_config.registry["server"], image ].compact.join("/")
66
82
  end
67
83
 
68
84
  def absolute_image
@@ -75,15 +91,23 @@ class Mrsk::Configuration
75
91
 
76
92
 
77
93
  def env_args
78
- if config.env.present?
79
- self.class.argumentize "-e", config.env
94
+ if raw_config.env.present?
95
+ argumentize_env_with_secrets(raw_config.env)
96
+ else
97
+ []
98
+ end
99
+ end
100
+
101
+ def volume_args
102
+ if raw_config.volumes.present?
103
+ argumentize "--volume", raw_config.volumes
80
104
  else
81
105
  []
82
106
  end
83
107
  end
84
108
 
85
109
  def ssh_user
86
- config.ssh_user || "root"
110
+ raw_config.ssh_user || "root"
87
111
  end
88
112
 
89
113
  def ssh_options
@@ -91,26 +115,45 @@ class Mrsk::Configuration
91
115
  end
92
116
 
93
117
  def master_key
94
- ENV["RAILS_MASTER_KEY"] || File.read(Rails.root.join("config/master.key"))
118
+ ENV["RAILS_MASTER_KEY"] || File.read(Pathname.new(File.expand_path("config/master.key")))
95
119
  end
96
120
 
121
+ def to_h
122
+ {
123
+ roles: role_names,
124
+ hosts: all_hosts,
125
+ primary_host: primary_web_host,
126
+ version: version,
127
+ repository: repository,
128
+ absolute_image: absolute_image,
129
+ service_with_version: service_with_version,
130
+ env_args: env_args,
131
+ volume_args: volume_args,
132
+ ssh_options: ssh_options,
133
+ builder: raw_config.builder
134
+ }.compact
135
+ end
97
136
 
98
- private
99
- attr_accessor :config
100
137
 
138
+ private
101
139
  def ensure_required_keys_present
102
- %i[ service image registry ].each do |key|
103
- raise ArgumentError, "Missing required configuration for #{key}" unless config[key].present?
140
+ %i[ service image registry servers ].each do |key|
141
+ raise ArgumentError, "Missing required configuration for #{key}" unless raw_config[key].present?
104
142
  end
105
143
 
106
- %w[ username password ].each do |key|
107
- raise ArgumentError, "Missing required configuration for registry/#{key}" unless config.registry[key].present?
108
- end
144
+ if raw_config.registry["username"].blank?
145
+ raise ArgumentError, "You must specify a username for the registry in config/deploy.yml"
146
+ end
147
+
148
+ if raw_config.registry["password"].blank?
149
+ raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
150
+ end
109
151
  end
110
152
 
111
153
  def role_names
112
- config.servers.is_a?(Array) ? [ "web" ] : config.servers.keys.sort
154
+ raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
113
155
  end
114
156
  end
115
157
 
116
158
  require "mrsk/configuration/role"
159
+ require "mrsk/configuration/accessory"
@@ -0,0 +1,12 @@
1
+ require "sshkit"
2
+ require "sshkit/dsl"
3
+
4
+ class SSHKit::Backend::Abstract
5
+ def capture_with_info(*args)
6
+ capture(*args, verbosity: Logger::INFO)
7
+ end
8
+
9
+ def puts_by_host(host, output, type: "App")
10
+ puts "#{type} Host: #{host}\n#{output}\n\n"
11
+ end
12
+ end
data/lib/mrsk/utils.rb ADDED
@@ -0,0 +1,29 @@
1
+ module Mrsk::Utils
2
+ extend self
3
+
4
+ # Return a list of shell arguments using the same named argument against the passed attributes (hash or array).
5
+ def argumentize(argument, attributes, redacted: false)
6
+ Array(attributes).flat_map do |k, v|
7
+ if v.present?
8
+ [ argument, redacted ? redact("#{k}=#{v}") : "#{k}=#{v}" ]
9
+ else
10
+ [ argument, k ]
11
+ end
12
+ end
13
+ end
14
+
15
+ # Return a list of shell arguments using the same named argument against the passed attributes,
16
+ # but redacts and expands secrets.
17
+ def argumentize_env_with_secrets(env)
18
+ if (secrets = env["secret"]).present?
19
+ argumentize("-e", secrets.to_h { |key| [ key, ENV.fetch(key) ] }, redacted: true) + argumentize("-e", env["clear"])
20
+ else
21
+ argumentize "-e", env
22
+ end
23
+ end
24
+
25
+ # Copied from SSHKit::Backend::Abstract#redact to be available inside Commands classes
26
+ def redact(arg) # Used in execute_command to hide redact() args a user passes in
27
+ arg.to_s.extend(SSHKit::Redaction) # to_s due to our inability to extend Integer, etc
28
+ end
29
+ end
data/lib/mrsk/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mrsk
2
- VERSION = "0.0.3"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/mrsk.rb CHANGED
@@ -2,5 +2,4 @@ module Mrsk
2
2
  end
3
3
 
4
4
  require "mrsk/version"
5
- require "mrsk/engine"
6
5
  require "mrsk/commander"