kuby-core 0.16.1 → 0.17.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5cbd792443dc33de6a20d02f6969f6d59d535f1b68fb75c9a8945615fd870a28
4
- data.tar.gz: 3add1ef85d6758a2590d35d7aa0bfb4fffaeae55ef6567a34cf3b7557a56e55a
3
+ metadata.gz: 06ed279a1b0ecaac0daed1b868610bac67e6564611360de4cd841a24827438e2
4
+ data.tar.gz: f8616a5b0ab87c4fb71afa3afba0e001760b3c0855b7670b976013de3c1db5d6
5
5
  SHA512:
6
- metadata.gz: 7d855f57aae01d93c2fa44e285ee417ebcc00f12de6f9c4b989a39626ec9ec13a4659eafe0b8924592de5d860666158376e5adbf69c70373703eb2a9074ca75d
7
- data.tar.gz: dc553aa0b22e5ab262fa18fa1a60bebb421862eab7e747e06c63907fefe8f5371be56415d0bde2e959ffa775140b624aee3aa53006f1dbee272122c87bf53cc6
6
+ metadata.gz: d75bf991f55a97798152449606740b2d94c9a012ad7c17ea0b9b940c9ca9b3aad0e31baa4635ffeeec584144492d967054cdbfffa386c05c7427f1e90ac58e8f
7
+ data.tar.gz: 73b7718181d0e43ab1382c70a4a22da1835da30c887c2f42bc67bcce15d811aa0efab93df3a5fd6d28e2b2ce6d6dc3a73154a4cacdadcfeb9641ca0b2ba5604c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.17.1
2
+ * Allow storage class to be customized when using the built-in bare metal provider.
3
+ * Fix a bug where the assets image would be built using the previous app image instead of the current one.
4
+ * Centralize the lookup of the Rails master key (not user-facing).
5
+ * Add descriptions to numerous CLI commands and their arguments.
6
+ * CLI now accepts multiple `--only` flags passed to subcommands like `build`, `push`, etc.
7
+ * Allow running setup steps for individual plugins.
8
+
1
9
  ## 0.16.1
2
10
  * Fix a few bugs caused by leaving `continue-on-error: true` in the GitHub actions config 🤦
3
11
  - Docker builds would fail if no previous images existed in the registry.
data/lib/kuby/commands.rb CHANGED
@@ -62,12 +62,22 @@ module Kuby
62
62
  true
63
63
  end
64
64
 
65
- desc 'Builds the Docker image.'
65
+ desc 'Builds Docker images.'
66
66
  command :build do |c|
67
+ c.desc 'Docker build argument.'
67
68
  c.flag [:a, :arg], required: false, multiple: true
69
+
70
+ c.desc 'When enabled, ignores missing build arguments.'
68
71
  c.switch [:'ignore-missing-args'], required: false, default: false
69
- c.flag [:only], required: false
72
+
73
+ c.desc 'Build only the images associated with the specified identifier(s). '\
74
+ 'Run `kuby images` for a list of all valid identifiers (note that '\
75
+ 'identifiers can be associated with more than one image).'
76
+ c.flag [:only], required: false, multiple: true
77
+
78
+ c.desc 'The directory to use as the Docker build context.'
70
79
  c.flag [:c, :context], required: false
80
+
71
81
  c.action do |global_options, options, docker_args|
72
82
  build_args = {}.tap do |build_args|
73
83
  (options[:arg] || []).each do |a|
@@ -86,9 +96,12 @@ module Kuby
86
96
  end
87
97
  end
88
98
 
89
- desc 'Pushes the Docker image to the configured registry.'
99
+ desc 'Pushes Docker images to their associated registries.'
90
100
  command :push do |c|
91
- c.flag [:only], required: false
101
+ c.desc 'Push only the images associated with the specified identifier(s). '\
102
+ 'Run `kuby images` for a list of all valid identifiers (note that '\
103
+ 'identifiers can be associated with more than one image).'
104
+ c.flag [:only], required: false, multiple: true
92
105
  c.action do |global_options, options, args|
93
106
  tasks.push(only: options[:only])
94
107
  end
@@ -96,14 +109,18 @@ module Kuby
96
109
 
97
110
  desc 'Gets your Kubernetes cluster ready to run your Rails app.'
98
111
  command :setup do |c|
112
+ c.desc 'Run the setup routines for only the specified plugin identifier(s).'
113
+ c.flag [:only], required: false, multiple: true
99
114
  c.action do |global_options, options, args|
100
- tasks.setup
115
+ tasks.setup(only: options[:only])
101
116
  end
102
117
  end
103
118
 
104
119
  desc 'Prints the effective Dockerfiles used to build Docker images.'
105
120
  command :dockerfiles do |c|
106
- c.flag [:only], required: false
121
+ c.desc 'Print Dockerfiles for only the images associated with the specified '\
122
+ 'identifier(s).'
123
+ c.flag [:only], required: false, multiple: true
107
124
  c.action do |global_options, options, args|
108
125
  tasks.print_dockerfiles(only: options[:only])
109
126
  end
@@ -118,7 +135,7 @@ module Kuby
118
135
  end
119
136
  end
120
137
 
121
- desc 'Rolls back to the previous Docker tag.'
138
+ desc 'Rolls back to the previous release.'
122
139
  command :rollback do |c|
123
140
  c.action do |global_options, options, args|
124
141
  tasks.rollback
@@ -127,25 +144,37 @@ module Kuby
127
144
 
128
145
  desc 'Prints the effective Kubernetes resources that will be applied on deploy.'
129
146
  command :resources do |c|
147
+ c.desc 'Only print resources of the given kind.'
130
148
  c.flag [:K, :kind], required: false
149
+
150
+ c.desc 'Only print resources that match the given name.'
131
151
  c.flag [:N, :name], required: false
152
+
132
153
  c.action do |global_options, options, args|
133
154
  tasks.print_resources(options[:kind], options[:name])
134
155
  end
135
156
  end
136
157
 
137
- desc 'Prints out the contents of the kubeconfig Kuby is using to communicate with your cluster.'
158
+ desc 'Prints out the contents of the kubeconfig file Kuby is using to communicate '\
159
+ 'with your cluster.'
138
160
  command :kubeconfig do |c|
139
161
  c.action do |global_options, options, args|
140
162
  tasks.print_kubeconfig
141
163
  end
142
164
  end
143
165
 
166
+ desc 'Prints out the URLs to the latest Docker images in the Docker registry.'
167
+ command :images do |c|
168
+ c.action do |global_options, options, args|
169
+ tasks.print_images
170
+ end
171
+ end
172
+
144
173
  desc 'Runs an arbitrary kubectl command.'
145
174
  command :kubectl do |c|
146
175
  c.desc 'Prefixes the kubectl command with the namespace associated with '\
147
- 'the current environment. For example, if the Kuby env is "production", '\
148
- 'this option will prefix the kubectl command with "-n myapp-production".'
176
+ 'the current environment. For example, if the Kuby env is "production", '\
177
+ 'this option will prefix the kubectl command with "-n myapp-production".'
149
178
  c.switch [:N, :namespaced], default: false
150
179
  c.action do |global_options, options, args|
151
180
  if options[:namespaced]
@@ -79,8 +79,6 @@ module Kuby
79
79
  sig { params(build_args: T::Hash[String, String], docker_args: T::Array[String], context: T.nilable(String)).void }
80
80
  def build(build_args = {}, docker_args = [], context: nil)
81
81
  docker_cli.build(new_version, build_args: build_args, docker_args: docker_args, context: context)
82
- @current_version = new_version
83
- @new_version = nil
84
82
  end
85
83
 
86
84
  sig { params(tag: String).void }
@@ -7,12 +7,13 @@ module Kuby
7
7
  class BareMetalProvider < Provider
8
8
  extend T::Sig
9
9
 
10
- STORAGE_CLASS_NAME = T.let('hostpath'.freeze, String)
10
+ DEFAULT_STORAGE_CLASS = T.let('hostpath'.freeze, String)
11
11
 
12
12
  class Config
13
13
  extend ::KubeDSL::ValueFields
14
14
 
15
15
  value_fields :kubeconfig
16
+ value_fields :storage_class
16
17
  end
17
18
 
18
19
  sig { returns(Config) }
@@ -36,7 +37,7 @@ module Kuby
36
37
 
37
38
  sig { returns(String) }
38
39
  def storage_class_name
39
- STORAGE_CLASS_NAME
40
+ config.storage_class
40
41
  end
41
42
 
42
43
  private
@@ -46,6 +47,7 @@ module Kuby
46
47
  configure do
47
48
  # default kubeconfig path
48
49
  kubeconfig File.join(ENV['HOME'], '.kube', 'config')
50
+ storage_class DEFAULT_STORAGE_CLASS
49
51
  end
50
52
  end
51
53
  end
@@ -89,13 +89,23 @@ module Kuby
89
89
  @tag = nil
90
90
  end
91
91
 
92
- def setup
93
- provider.before_setup
94
- provider.setup
92
+ def setup(only: [])
93
+ plugins = if only.empty?
94
+ @plugins
95
+ else
96
+ @plugins.each_with_object({}) do |(name, plg), memo|
97
+ memo[name] = plg if only.include?(name)
98
+ end
99
+ end
100
+
101
+ if only.empty?
102
+ provider.before_setup
103
+ provider.setup
104
+ end
95
105
 
96
- @plugins.each { |_, plg| plg.before_setup }
97
- @plugins.each { |_, plg| plg.setup }
98
- @plugins.each { |_, plg| plg.after_setup }
106
+ plugins.each { |_, plg| plg.before_setup }
107
+ plugins.each { |_, plg| plg.setup }
108
+ plugins.each { |_, plg| plg.after_setup }
99
109
 
100
110
  provider.after_setup
101
111
  end
data/lib/kuby/plugin.rb CHANGED
@@ -12,6 +12,7 @@ module Kuby
12
12
  # do nothing by default
13
13
  end
14
14
 
15
+ # install any global resources like operators, etc
15
16
  def setup
16
17
  # do nothing by default
17
18
  end
@@ -1,6 +1,8 @@
1
1
  # typed: false
2
2
  module Kuby
3
3
  class PluginRegistry
4
+ include Enumerable
5
+
4
6
  ANY = 'any'.freeze
5
7
 
6
8
  def register(plugin_name, plugin_klass, environment: ANY)
@@ -19,6 +21,19 @@ module Kuby
19
21
  plugins_by_env[environment] || plugins_by_env[ANY]
20
22
  end
21
23
 
24
+ def each(&block)
25
+ return to_enum(__method__) unless block
26
+
27
+ @plugins.each_pair do |plugin_name, plugins_by_env|
28
+ plugins_by_env.each_pair do |env, plugin_klass|
29
+ case env
30
+ when ANY, Kuby.env
31
+ yield plugin_name, plugin_klass
32
+ end
33
+ end
34
+ end
35
+ end
36
+
22
37
  private
23
38
 
24
39
  def plugins
@@ -11,9 +11,11 @@ module Kuby
11
11
  end
12
12
 
13
13
  def new_version
14
- # Asset images track the base image, so return the current version
14
+ # Asset images track the base image, so return the new version
15
15
  # here. There can be no asset image without a base image.
16
- current_version
16
+ @new_version ||= duplicate_with_annotated_tags(
17
+ base_image.new_version
18
+ )
17
19
  end
18
20
 
19
21
  def current_version
@@ -29,7 +31,7 @@ module Kuby
29
31
  end
30
32
 
31
33
  def build(build_args = {}, docker_args = [], context: nil)
32
- docker_cli.build(current_version, build_args: build_args, docker_args: docker_args, context: context)
34
+ docker_cli.build(new_version, build_args: build_args, docker_args: docker_args, context: context)
33
35
  end
34
36
 
35
37
  def push(tag)
@@ -209,15 +209,7 @@ module Kuby
209
209
  type 'Opaque'
210
210
 
211
211
  data do
212
- if master_key = ENV[MASTER_KEY_VAR]
213
- add MASTER_KEY_VAR.to_sym, master_key
214
- else
215
- master_key_path = File.join(spec.root, 'config', 'master.key')
216
-
217
- if File.exist?(master_key_path)
218
- add MASTER_KEY_VAR.to_sym, File.read(master_key_path).strip
219
- end
220
- end
212
+ add MASTER_KEY_VAR.to_sym, spec.master_key
221
213
  end
222
214
  end
223
215
 
@@ -434,6 +426,13 @@ module Kuby
434
426
  def namespace
435
427
  environment.kubernetes.namespace
436
428
  end
429
+
430
+ def master_key
431
+ @master_key ||= ENV[MASTER_KEY_VAR] || begin
432
+ master_key_path = File.join(root, 'config', 'master.key')
433
+ File.read(master_key_path).strip if File.exist?(master_key_path)
434
+ end
435
+ end
437
436
  end
438
437
  end
439
438
  end
data/lib/kuby/tasks.rb CHANGED
@@ -24,23 +24,19 @@ module Kuby
24
24
  end
25
25
  end
26
26
 
27
- def setup
28
- environment.kubernetes.setup
27
+ def setup(only: [])
28
+ environment.kubernetes.setup(only: only.map(&:to_sym))
29
29
  end
30
30
 
31
- def build(build_args = {}, docker_args = [], only: nil, ignore_missing_args: false, context: nil)
31
+ def build(build_args = {}, docker_args = [], only: [], ignore_missing_args: false, context: nil)
32
32
  check_platform(docker_args)
33
33
 
34
- build_args['RAILS_MASTER_KEY'] ||= ENV['RAILS_MASTER_KEY'] || begin
35
- master_key_file = File.join('config', 'master.key')
36
- File.exist?(master_key_file) ? File.read(master_key_file).strip : nil
37
- end
34
+ build_args['RAILS_MASTER_KEY'] ||= rails_app.master_key
38
35
 
39
36
  check_build_args(build_args) unless ignore_missing_args
40
37
 
41
38
  kubernetes.docker_images.each do |image|
42
- next if only && image.identifier != only
43
-
39
+ next unless only.empty? || only.include?(image.identifier)
44
40
  return unless perform_docker_login_if_necessary(image)
45
41
 
46
42
  image = image.new_version
@@ -49,9 +45,9 @@ module Kuby
49
45
  end
50
46
  end
51
47
 
52
- def push(only: nil)
48
+ def push(only: [])
53
49
  kubernetes.docker_images.each do |image|
54
- next if only && image.identifier != only
50
+ next unless only.empty? || only.include?(image.identifier)
55
51
 
56
52
  image = image.current_version
57
53
  Kuby.logger.info("Pushing image #{image.image_url} with tags #{image.tags.join(', ')}")
@@ -101,6 +97,18 @@ module Kuby
101
97
  puts File.read(path)
102
98
  end
103
99
 
100
+ def print_images
101
+ rows = kubernetes.docker_images.flat_map do |image|
102
+ image = image.current_version
103
+
104
+ image.tags.map do |tag|
105
+ [image.identifier, "#{image.image_url}:#{tag}"]
106
+ end
107
+ end
108
+
109
+ puts Kuby::Utils::Table.new(%w(IDENTIFIER URL), rows).to_s
110
+ end
111
+
104
112
  def kubectl(*cmd)
105
113
  kubernetes_cli.run_cmd(cmd)
106
114
  end
@@ -0,0 +1,35 @@
1
+ module Kuby
2
+ module Utils
3
+ class Table
4
+ attr_reader :headers, :rows
5
+
6
+ def initialize(headers, rows)
7
+ @headers = headers
8
+ @rows = rows
9
+ end
10
+
11
+ def to_s
12
+ [headers, *rows].map { |vals| make_row(vals) }.join("\n")
13
+ end
14
+
15
+ private
16
+
17
+ def make_row(values)
18
+ columns = values.each_with_index.map do |value, idx|
19
+ col_width = col_width_at(idx) + 2
20
+ value.ljust(col_width, ' ')
21
+ end
22
+
23
+ columns.join
24
+ end
25
+
26
+ def col_width_at(idx)
27
+ col_widths[idx] ||= [headers[idx].size, *rows.map { |r| r[idx].size }].max
28
+ end
29
+
30
+ def col_widths
31
+ @col_widths ||= {}
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/kuby/utils.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Kuby
2
+ module Utils
3
+ autoload :Table, 'kuby/utils/table'
4
+ end
5
+ end
data/lib/kuby/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # typed: true
2
2
 
3
3
  module Kuby
4
- VERSION = '0.16.1'.freeze
4
+ VERSION = '0.17.0'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kuby-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.1
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Dutro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-05 00:00:00.000000000 Z
11
+ date: 2022-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -285,6 +285,8 @@ files:
285
285
  - lib/kuby/railtie.rb
286
286
  - lib/kuby/tasks.rb
287
287
  - lib/kuby/trailing_hash.rb
288
+ - lib/kuby/utils.rb
289
+ - lib/kuby/utils/table.rb
288
290
  - lib/kuby/version.rb
289
291
  - spec/docker/spec_spec.rb
290
292
  - spec/docker/timestamp_tag_spec.rb