dip 7.4.0 → 7.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42554510aef42c0faa6c2d1ccec6be58c8997bbd1708d2a9e7008363dcc0916a
4
- data.tar.gz: c2cc4e38f8f42fed73be2f88e0b66331521176d80c04bf789dccdf1de63e4d64
3
+ metadata.gz: 077560a05e3c58c34f61f81e80a941a6bb8a88da7b8acc59cb1e8c254985467e
4
+ data.tar.gz: 8d7b121d08fb87b68bf375b8651cc60f2e27307267f813ea87faf2eee6f88870
5
5
  SHA512:
6
- metadata.gz: c9bb9b9e632a899c9cb4433a8aeece65e3f5ebd9705c80fabea87f2197b5013a95dbaa522127cdf42f875c546e897f00b5068a3d421023b2d5f9a1d54f933a51
7
- data.tar.gz: 5eee73a6bcfc1bbda1526fb04b3143dc2784be36b6b98a2b0855a376a0799113b7d79e17f48c02dd2504b577237662284f044c5cbed39e99d0a2d1fc2973720e
6
+ metadata.gz: 1a00861123026227700fcb92e3ef1fa47f702efcfdd2bbce83363aeca5bedf7d2c669428f5837828c53edcb76975958334689657f2d52df7f8dee3e3991d0a08
7
+ data.tar.gz: f2bd7865a209166096b5b9f553da6031ec7192c889f8e6e357a230fd2f9dd9c67259501f358dffde25657370a3f7cf8d628156cbad7d9524ea9505c10ff7c724
data/README.md CHANGED
@@ -38,8 +38,7 @@ After that we can type commands without `dip` prefix. For example:
38
38
  <run-command> *any-args
39
39
  compose *any-compose-arg
40
40
  up <service>
41
- build
42
- down
41
+ ktl *any-kubectl-arg
43
42
  provision
44
43
  ```
45
44
 
@@ -81,10 +80,11 @@ Also, you can check out examples at the top.
81
80
 
82
81
  ```yml
83
82
  # Required minimum dip version
84
- version: '7.1'
83
+ version: '7.5'
85
84
 
86
85
  environment:
87
86
  COMPOSE_EXT: development
87
+ STAGE: "staging"
88
88
 
89
89
  compose:
90
90
  files:
@@ -93,6 +93,9 @@ compose:
93
93
  - docker/docker-compose.$DIP_OS.yml
94
94
  project_name: bear
95
95
 
96
+ kubectl:
97
+ namespace: rocket-$STAGE
98
+
96
99
  interaction:
97
100
  shell:
98
101
  description: Open the Bash shell in app's container
@@ -129,6 +132,12 @@ interaction:
129
132
  compose:
130
133
  run_options: [service-ports, use-aliases]
131
134
 
135
+ stack:
136
+ description: Run full stack (server, workers, etc.)
137
+ runner: docker_compose
138
+ compose:
139
+ profiles: [web, workers]
140
+
132
141
  sidekiq:
133
142
  description: Run sidekiq in background
134
143
  service: worker
@@ -142,6 +151,22 @@ interaction:
142
151
  default_args: db_dev
143
152
  command: psql -h pg -U postgres
144
153
 
154
+ k:
155
+ description: Run commands in Kubernetes cluster
156
+ pod: svc/rocket-app:app-container
157
+ entrypoint: /env-entrypoint
158
+ subcommands:
159
+ bash:
160
+ description: Get a shell to the running container
161
+ command: /bin/bash
162
+ rails:
163
+ description: Run Rails commands
164
+ command: bundle exec rails
165
+ kafka-topics:
166
+ description: Manage Kafka topics
167
+ pod: svc/rocket-kafka
168
+ command: kafka-topics.sh --zookeeper zookeeper:2181
169
+
145
170
  setup_key:
146
171
  description: Copy key
147
172
  service: app
@@ -201,7 +226,13 @@ returned is `/app/sub-project-dir`.
201
226
 
202
227
  Run commands defined within the `interaction` section of dip.yml
203
228
 
204
- By default, a command will be executed using [`docker compose`](https://docs.docker.com/compose/install/) command. If you are still using `docker-compose` binary (i.e., prior to Compose V2 changes), a command would be run through it. You can disable using of Compose V2 by passing an environment variable `DIP_COMPOSE_V2=false dip run`.
229
+ A command will be executed by specified runner. Dip has three types of them:
230
+
231
+ - `docker-compose` runner — used when the `service` option is defined.
232
+ - `kubectl` runner — used when the `pod` option is defined.
233
+ - `local` runner — used when the previous ones are not defined.
234
+
235
+ If you are still using `docker-compose` binary (i.e., prior to Compose V2 changes), a command would be run through it. You can disable using of Compose V2 by passing an environment variable `DIP_COMPOSE_V2=false dip run`.
205
236
 
206
237
  ```sh
207
238
  dip run rails c
@@ -254,7 +285,7 @@ Run commands each by each from `provision` section of dip.yml
254
285
 
255
286
  ### dip compose
256
287
 
257
- Run docker-compose commands that are configured according to the application's dip.yml :
288
+ Run docker-compose commands that are configured according to the application's dip.yml:
258
289
 
259
290
  ```sh
260
291
  dip compose COMMAND [OPTIONS]
@@ -262,6 +293,16 @@ dip compose COMMAND [OPTIONS]
262
293
  dip compose up -d redis
263
294
  ```
264
295
 
296
+ ### dip ktl
297
+
298
+ Run kubectl commands that are configured according to the application's dip.yml:
299
+
300
+ ```sh
301
+ dip ktl COMMAND [OPTIONS]
302
+
303
+ STAGE=some dip ktl get pods
304
+ ```
305
+
265
306
  ### dip ssh
266
307
 
267
308
  Runs ssh-agent container based on https://github.com/whilp/ssh-agent with your ~/.ssh/id_rsa.
data/lib/dip/cli.rb CHANGED
@@ -32,7 +32,7 @@ module Dip
32
32
  end
33
33
  end
34
34
 
35
- stop_on_unknown_option! :run
35
+ stop_on_unknown_option! :run, :ktl
36
36
 
37
37
  desc "version", "dip version"
38
38
  def version
@@ -78,11 +78,17 @@ module Dip
78
78
  require_relative "commands/down_all"
79
79
  Dip::Commands::DownAll.new.execute
80
80
  else
81
- compose("down", *argv)
81
+ compose("down", *argv.push("--remove-orphans"))
82
82
  end
83
83
  end
84
84
 
85
- desc "run [OPTIONS] CMD [ARGS]", "Run configured command in a docker-compose service. `run` prefix may be omitted"
85
+ desc "ktl CMD [OPTIONS]", "Run kubectl commands"
86
+ def ktl(*argv)
87
+ require_relative "commands/kubectl"
88
+ Dip::Commands::Kubectl.new(*argv).execute
89
+ end
90
+
91
+ desc "run [OPTIONS] CMD [ARGS]", "Run configured command (`run` prefix may be omitted)"
86
92
  method_option :publish, aliases: "-p", type: :string, repeatable: true,
87
93
  desc: "Publish a container's port(s) to the host"
88
94
  method_option :help, aliases: "-h", type: :boolean, desc: "Display usage information"
@@ -91,7 +97,11 @@ module Dip
91
97
  invoke :help, ["run"]
92
98
  else
93
99
  require_relative "commands/run"
94
- Dip::Commands::Run.new(*argv, publish: options[:publish]).execute
100
+
101
+ Dip::Commands::Run.new(
102
+ *argv,
103
+ **options.to_h.transform_keys!(&:to_sym)
104
+ ).execute
95
105
  end
96
106
  end
97
107
 
@@ -13,7 +13,7 @@ module Dip
13
13
  attr_reader :argv, :config, :shell
14
14
 
15
15
  def initialize(*argv, shell: true)
16
- @argv = argv
16
+ @argv = argv.compact
17
17
  @shell = shell
18
18
  @config = ::Dip.config.compose || {}
19
19
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../command"
4
+
5
+ module Dip
6
+ module Commands
7
+ class Kubectl < Dip::Command
8
+ attr_reader :argv, :config
9
+
10
+ def initialize(*argv)
11
+ @argv = argv
12
+ @config = ::Dip.config.kubectl || {}
13
+ end
14
+
15
+ def execute
16
+ k_argv = cli_options + argv
17
+
18
+ exec_program("kubectl", k_argv)
19
+ end
20
+
21
+ private
22
+
23
+ def cli_options
24
+ %i[namespace].flat_map do |name|
25
+ next unless (value = config[name])
26
+ next unless value.is_a?(String)
27
+
28
+ value = ::Dip.env.interpolate(value).delete_suffix("-")
29
+ ["--#{name.to_s.tr("_", "-")}", value]
30
+ end.compact
31
+ end
32
+ end
33
+ end
34
+ end
@@ -4,13 +4,17 @@ require "shellwords"
4
4
  require_relative "../../../lib/dip/run_vars"
5
5
  require_relative "../command"
6
6
  require_relative "../interaction_tree"
7
- require_relative "compose"
7
+ require_relative "runners/local_runner"
8
+ require_relative "runners/docker_compose_runner"
9
+ require_relative "runners/kubectl_runner"
10
+
11
+ require_relative "kubectl"
8
12
 
9
13
  module Dip
10
14
  module Commands
11
15
  class Run < Dip::Command
12
- def initialize(cmd, *argv, publish: nil)
13
- @publish = publish
16
+ def initialize(cmd, *argv, **options)
17
+ @options = options
14
18
 
15
19
  @command, @argv = InteractionTree
16
20
  .new(Dip.config.interaction)
@@ -22,75 +26,25 @@ module Dip
22
26
  end
23
27
 
24
28
  def execute
25
- if command[:service].nil?
26
- exec_program(command[:command], get_args, shell: command[:shell])
27
- else
28
- Dip::Commands::Compose.new(
29
- command[:compose][:method],
30
- *compose_arguments,
31
- shell: command[:shell]
32
- ).execute
33
- end
29
+ lookup_runner
30
+ .new(command, argv, **options)
31
+ .execute
34
32
  end
35
33
 
36
34
  private
37
35
 
38
- attr_reader :command, :argv, :publish
39
-
40
- def compose_arguments
41
- compose_argv = command[:compose][:run_options].dup
42
-
43
- if command[:compose][:method] == "run"
44
- compose_argv.concat(run_vars)
45
- compose_argv.concat(published_ports)
46
- compose_argv << "--rm"
47
- end
48
-
49
- compose_argv << command.fetch(:service)
50
-
51
- unless (cmd = command[:command]).empty?
52
- if command[:shell]
53
- compose_argv << cmd
54
- else
55
- compose_argv.concat(cmd.shellsplit)
56
- end
57
- end
58
-
59
- compose_argv.concat(get_args)
60
-
61
- compose_argv
62
- end
63
-
64
- def run_vars
65
- run_vars = Dip::RunVars.env
66
- return [] unless run_vars
67
-
68
- run_vars.map { |k, v| ["-e", "#{k}=#{Shellwords.escape(v)}"] }.flatten
69
- end
70
-
71
- def published_ports
72
- if publish.respond_to?(:each)
73
- publish.map { |p| "--publish=#{p}" }
74
- else
75
- []
76
- end
77
- end
36
+ attr_reader :command, :argv, :options
78
37
 
79
- def get_args
80
- if argv.any?
81
- if command[:shell]
82
- [argv.shelljoin]
83
- else
84
- Array(argv)
85
- end
86
- elsif !(default_args = command[:default_args]).empty?
87
- if command[:shell]
88
- default_args.shellsplit
89
- else
90
- Array(default_args)
91
- end
38
+ def lookup_runner
39
+ if (runner = command[:runner])
40
+ camelized_runner = runner.split("_").collect(&:capitalize).join
41
+ Runners.const_get("#{camelized_runner}Runner")
42
+ elsif command[:service]
43
+ Runners::DockerComposeRunner
44
+ elsif command[:pod]
45
+ Runners::KubectlRunner
92
46
  else
93
- []
47
+ Runners::LocalRunner
94
48
  end
95
49
  end
96
50
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dip
4
+ module Commands
5
+ module Runners
6
+ class Base
7
+ def initialize(command, argv, **options)
8
+ @command = command
9
+ @argv = argv
10
+ @options = options
11
+ end
12
+
13
+ def execute
14
+ raise NotImplementedError
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :command, :argv, :options
20
+
21
+ def command_args
22
+ if argv.any?
23
+ if command[:shell]
24
+ [argv.shelljoin]
25
+ else
26
+ Array(argv)
27
+ end
28
+ elsif !(default_args = command[:default_args]).empty?
29
+ if command[:shell]
30
+ default_args.shellsplit
31
+ else
32
+ Array(default_args)
33
+ end
34
+ else
35
+ []
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../compose"
5
+
6
+ module Dip
7
+ module Commands
8
+ module Runners
9
+ class DockerComposeRunner < Base
10
+ def execute
11
+ Commands::Compose.new(
12
+ *compose_profiles,
13
+ command[:compose][:method],
14
+ *compose_arguments,
15
+ shell: command[:shell]
16
+ ).execute
17
+ end
18
+
19
+ private
20
+
21
+ def compose_profiles
22
+ return [] if command[:compose][:profiles].empty?
23
+
24
+ update_command_for_profiles
25
+
26
+ command[:compose][:profiles].each_with_object([]) do |profile, argv|
27
+ argv.concat(["--profile", profile])
28
+ end
29
+ end
30
+
31
+ def compose_arguments
32
+ compose_argv = command[:compose][:run_options].dup
33
+
34
+ if command[:compose][:method] == "run"
35
+ compose_argv.concat(run_vars)
36
+ compose_argv.concat(published_ports)
37
+ compose_argv << "--rm"
38
+ end
39
+
40
+ compose_argv << command.fetch(:service)
41
+
42
+ unless (cmd = command[:command]).empty?
43
+ if command[:shell]
44
+ compose_argv << cmd
45
+ else
46
+ compose_argv.concat(cmd.shellsplit)
47
+ end
48
+ end
49
+
50
+ compose_argv.concat(command_args)
51
+
52
+ compose_argv
53
+ end
54
+
55
+ def run_vars
56
+ run_vars = Dip::RunVars.env
57
+ return [] unless run_vars
58
+
59
+ run_vars.map { |k, v| ["-e", "#{k}=#{Shellwords.escape(v)}"] }.flatten
60
+ end
61
+
62
+ def published_ports
63
+ publish = options[:publish]
64
+
65
+ if publish.respond_to?(:each)
66
+ publish.map { |p| "--publish=#{p}" }
67
+ else
68
+ []
69
+ end
70
+ end
71
+
72
+ def update_command_for_profiles
73
+ # NOTE: When using profiles, the method is always `up`.
74
+ # This is because `docker-compose` does not support profiles
75
+ # for other commands. Also, run options need to be removed
76
+ # because they are not supported by `up`.
77
+ command[:compose][:method] = "up"
78
+ command[:command] = ""
79
+ command[:compose][:run_options] = []
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../kubectl"
5
+
6
+ module Dip
7
+ module Commands
8
+ module Runners
9
+ class KubectlRunner < Base
10
+ def execute
11
+ Commands::Kubectl.new(*kubectl_arguments).execute
12
+ end
13
+
14
+ private
15
+
16
+ def kubectl_arguments
17
+ argv = ["exec", "--tty", "--stdin"]
18
+
19
+ pod, container = command.fetch(:pod).split(":")
20
+ argv.push("--container", container) unless container.nil?
21
+ argv.push(pod, "--")
22
+
23
+ unless (entrypoint = command[:entrypoint]).nil?
24
+ argv << entrypoint
25
+ end
26
+ argv << command.fetch(:command)
27
+ argv.concat(command_args)
28
+
29
+ argv
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../../command"
5
+
6
+ module Dip
7
+ module Commands
8
+ module Runners
9
+ class LocalRunner < Base
10
+ def execute
11
+ Dip::Command.exec_program(
12
+ command[:command],
13
+ command_args,
14
+ shell: command[:shell]
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
data/lib/dip/config.rb CHANGED
@@ -16,7 +16,8 @@ module Dip
16
16
  CONFIG_DEFAULTS = {
17
17
  environment: {},
18
18
  compose: {},
19
- interation: {},
19
+ kubectl: {},
20
+ interaction: {},
20
21
  provision: []
21
22
  }.freeze
22
23
 
@@ -94,7 +95,7 @@ module Dip
94
95
  config
95
96
  end
96
97
 
97
- %i[environment compose interaction provision].each do |key|
98
+ %i[environment compose kubectl interaction provision].each do |key|
98
99
  define_method(key) do
99
100
  config[key] || (raise config_missing_error(key))
100
101
  end
@@ -58,13 +58,17 @@ module Dip
58
58
  def build_command(entry)
59
59
  {
60
60
  description: entry[:description],
61
+ runner: entry[:runner],
61
62
  service: entry[:service],
63
+ pod: entry[:pod],
64
+ entrypoint: entry[:entrypoint],
62
65
  command: entry[:command].to_s.strip,
63
66
  shell: entry.fetch(:shell, true),
64
67
  default_args: entry[:default_args].to_s.strip,
65
68
  environment: entry[:environment] || {},
66
69
  compose: {
67
70
  method: entry.dig(:compose, :method) || entry[:compose_method] || "run",
71
+ profiles: Array(entry.dig(:compose, :profiles)),
68
72
  run_options: compose_run_options(entry.dig(:compose, :run_options) || entry[:compose_run_options])
69
73
  }
70
74
  }
data/lib/dip/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dip
4
- VERSION = "7.4.0"
4
+ VERSION = "7.6.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dip
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.4.0
4
+ version: 7.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - bibendi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-24 00:00:00.000000000 Z
11
+ date: 2023-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -180,10 +180,15 @@ files:
180
180
  - lib/dip/commands/console.rb
181
181
  - lib/dip/commands/dns.rb
182
182
  - lib/dip/commands/down_all.rb
183
+ - lib/dip/commands/kubectl.rb
183
184
  - lib/dip/commands/list.rb
184
185
  - lib/dip/commands/nginx.rb
185
186
  - lib/dip/commands/provision.rb
186
187
  - lib/dip/commands/run.rb
188
+ - lib/dip/commands/runners/base.rb
189
+ - lib/dip/commands/runners/docker_compose_runner.rb
190
+ - lib/dip/commands/runners/kubectl_runner.rb
191
+ - lib/dip/commands/runners/local_runner.rb
187
192
  - lib/dip/commands/ssh.rb
188
193
  - lib/dip/config.rb
189
194
  - lib/dip/environment.rb