kuby-core 0.17.0 → 0.18.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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/Gemfile +6 -2
  4. data/Rakefile +5 -3
  5. data/bin/tapioca +29 -0
  6. data/kuby-core.gemspec +9 -11
  7. data/lib/kuby/basic_logger.rb +34 -34
  8. data/lib/kuby/cli_base.rb +43 -43
  9. data/lib/kuby/commands.rb +94 -11
  10. data/lib/kuby/definition.rb +12 -12
  11. data/lib/kuby/dependable.rb +20 -0
  12. data/lib/kuby/dependency.rb +14 -0
  13. data/lib/kuby/docker/alpine.rb +10 -10
  14. data/lib/kuby/docker/app_image.rb +11 -11
  15. data/lib/kuby/docker/app_phase.rb +36 -0
  16. data/lib/kuby/docker/assets_phase.rb +2 -2
  17. data/lib/kuby/docker/bundler_phase.rb +42 -40
  18. data/lib/kuby/docker/cli.rb +71 -43
  19. data/lib/kuby/docker/copy_phase.rb +7 -7
  20. data/lib/kuby/docker/credentials.rb +1 -0
  21. data/lib/kuby/docker/debian.rb +10 -10
  22. data/lib/kuby/docker/distro.rb +13 -13
  23. data/lib/kuby/docker/docker_uri.rb +20 -20
  24. data/lib/kuby/docker/dockerfile.rb +48 -39
  25. data/lib/kuby/docker/image.rb +66 -54
  26. data/lib/kuby/docker/inline_layer.rb +4 -4
  27. data/lib/kuby/docker/layer.rb +6 -6
  28. data/lib/kuby/docker/layer_stack.rb +35 -35
  29. data/lib/kuby/docker/local_tags.rb +16 -16
  30. data/lib/kuby/docker/package_list.rb +16 -16
  31. data/lib/kuby/docker/package_phase.rb +16 -16
  32. data/lib/kuby/docker/packages/managed_package.rb +13 -13
  33. data/lib/kuby/docker/packages/nodejs.rb +5 -5
  34. data/lib/kuby/docker/packages/package.rb +8 -8
  35. data/lib/kuby/docker/packages/simple_managed_package.rb +7 -7
  36. data/lib/kuby/docker/packages/yarn.rb +6 -6
  37. data/lib/kuby/docker/remote_tags.rb +16 -16
  38. data/lib/kuby/docker/setup_phase.rb +18 -20
  39. data/lib/kuby/docker/spec.rb +93 -72
  40. data/lib/kuby/docker/timestamp_tag.rb +16 -11
  41. data/lib/kuby/docker/timestamped_image.rb +59 -40
  42. data/lib/kuby/docker/webserver_phase.rb +20 -20
  43. data/lib/kuby/docker/yarn_phase.rb +29 -5
  44. data/lib/kuby/docker.rb +2 -1
  45. data/lib/kuby/kubernetes/bare_metal_provider.rb +9 -9
  46. data/lib/kuby/kubernetes/deployer.rb +22 -10
  47. data/lib/kuby/kubernetes/docker_config.rb +1 -0
  48. data/lib/kuby/kubernetes/provider.rb +1 -0
  49. data/lib/kuby/kubernetes/spec.rb +47 -7
  50. data/lib/kuby/plugin.rb +22 -1
  51. data/lib/kuby/plugins/nginx_ingress.rb +8 -6
  52. data/lib/kuby/plugins/rails_app/assets.rb +16 -4
  53. data/lib/kuby/plugins/rails_app/assets_image.rb +17 -8
  54. data/lib/kuby/plugins/rails_app/crdb/plugin.rb +473 -0
  55. data/lib/kuby/plugins/rails_app/crdb.rb +9 -0
  56. data/lib/kuby/plugins/rails_app/database.rb +12 -8
  57. data/lib/kuby/plugins/rails_app/generators/kuby.rb +17 -16
  58. data/lib/kuby/plugins/rails_app/plugin.rb +29 -18
  59. data/lib/kuby/plugins/rails_app/sqlite.rb +7 -3
  60. data/lib/kuby/plugins/rails_app/tasks.rake +25 -12
  61. data/lib/kuby/plugins/rails_app.rb +1 -0
  62. data/lib/kuby/plugins/system.rb +16 -0
  63. data/lib/kuby/plugins.rb +1 -0
  64. data/lib/kuby/railtie.rb +31 -1
  65. data/lib/kuby/tasks.rb +72 -5
  66. data/lib/kuby/trailing_hash.rb +2 -2
  67. data/lib/kuby/utils/sem_ver/constraint.rb +68 -0
  68. data/lib/kuby/utils/sem_ver/constraint_set.rb +25 -0
  69. data/lib/kuby/utils/sem_ver/version.rb +49 -0
  70. data/lib/kuby/utils/sem_ver.rb +17 -0
  71. data/lib/kuby/utils/which.rb +65 -0
  72. data/lib/kuby/utils.rb +7 -1
  73. data/lib/kuby/version.rb +1 -1
  74. data/lib/kuby.rb +37 -2
  75. data/rbi/kuby-core.rbi +2128 -0
  76. data/spec/docker/spec_spec.rb +50 -26
  77. data/spec/dummy/app/channels/application_cable/channel.rb +2 -1
  78. data/spec/dummy/app/channels/application_cable/connection.rb +2 -1
  79. data/spec/dummy/app/controllers/application_controller.rb +2 -1
  80. data/spec/dummy/app/jobs/application_job.rb +2 -1
  81. data/spec/dummy/app/mailers/application_mailer.rb +2 -1
  82. data/spec/dummy/app/models/application_record.rb +2 -1
  83. data/spec/dummy/config/application.rb +2 -1
  84. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -1
  85. data/spec/dummy/config/routes.rb +2 -1
  86. data/spec/dummy/test/application_system_test_case.rb +2 -1
  87. data/spec/dummy/test/channels/application_cable/connection_test.rb +2 -1
  88. data/spec/spec_helper.rb +13 -1
  89. metadata +44 -39
  90. data/lib/kuby/plugins/rails_app/mysql.rb +0 -158
  91. data/lib/kuby/plugins/rails_app/postgres.rb +0 -163
data/lib/kuby/docker.rb CHANGED
@@ -4,10 +4,11 @@ require 'kuby/docker/errors'
4
4
 
5
5
  module Kuby
6
6
  module Docker
7
- LATEST_TAG = T.let('latest'.freeze, String)
7
+ LATEST_TAG = 'latest'.freeze
8
8
 
9
9
  autoload :Alpine, 'kuby/docker/alpine'
10
10
  autoload :AppImage, 'kuby/docker/app_image'
11
+ autoload :AppPhase, 'kuby/docker/app_phase'
11
12
  autoload :AssetsPhase, 'kuby/docker/assets_phase'
12
13
  autoload :BundlerPhase, 'kuby/docker/bundler_phase'
13
14
  autoload :CLI, 'kuby/docker/cli'
@@ -5,9 +5,9 @@ require 'kube-dsl'
5
5
  module Kuby
6
6
  module Kubernetes
7
7
  class BareMetalProvider < Provider
8
- extend T::Sig
8
+ # extend T::Sig
9
9
 
10
- DEFAULT_STORAGE_CLASS = T.let('hostpath'.freeze, String)
10
+ DEFAULT_STORAGE_CLASS = 'hostpath'.freeze
11
11
 
12
12
  class Config
13
13
  extend ::KubeDSL::ValueFields
@@ -16,33 +16,33 @@ module Kuby
16
16
  value_fields :storage_class
17
17
  end
18
18
 
19
- sig { returns(Config) }
19
+ # T::Sig::WithoutRuntime.sig { returns(Config) }
20
20
  attr_reader :config
21
21
 
22
- sig { params(environment: Environment).void }
22
+ # T::Sig::WithoutRuntime.sig { params(environment: Environment).void }
23
23
  def initialize(environment)
24
- @config = T.let(Config.new, Config)
24
+ @config = Config.new
25
25
  super
26
26
  end
27
27
 
28
- sig { params(block: T.proc.void).void }
28
+ # T::Sig::WithoutRuntime.sig { params(block: T.proc.void).void }
29
29
  def configure(&block)
30
30
  config.instance_eval(&block) if block
31
31
  end
32
32
 
33
- sig { returns(String) }
33
+ # T::Sig::WithoutRuntime.sig { returns(String) }
34
34
  def kubeconfig_path
35
35
  config.kubeconfig
36
36
  end
37
37
 
38
- sig { returns(String) }
38
+ # T::Sig::WithoutRuntime.sig { returns(String) }
39
39
  def storage_class_name
40
40
  config.storage_class
41
41
  end
42
42
 
43
43
  private
44
44
 
45
- sig { void }
45
+ # T::Sig::WithoutRuntime.sig { void }
46
46
  def after_initialize
47
47
  configure do
48
48
  # default kubeconfig path
@@ -8,10 +8,8 @@ require 'yaml'
8
8
  module Kuby
9
9
  module Kubernetes
10
10
  class Deployer
11
- extend T::Sig
12
-
13
11
  attr_reader :environment
14
- attr_accessor :logdev
12
+ attr_writer :logdev
15
13
 
16
14
  def initialize(environment)
17
15
  @environment = environment
@@ -19,7 +17,7 @@ module Kuby
19
17
 
20
18
  def deploy
21
19
  restart_rails_deployment_if_necessary do
22
- namespaced, global = all_resources.partition do |resource|
20
+ resource_groups = all_resources.group_by do |resource|
23
21
  # Unfortunately we can't use respond_to here because all KubeDSL
24
22
  # objects use ObjectMeta, which has a namespace field. Not sure
25
23
  # why, since it makes no sense for a namespace to have a namespace.
@@ -27,8 +25,21 @@ module Kuby
27
25
  resource.metadata.namespace
28
26
  end
29
27
 
30
- deploy_global_resources(global)
31
- deploy_namespaced_resources(namespaced)
28
+ deploy_global_resources(resource_groups[nil])
29
+
30
+ resource_groups.each_pair do |ns, resources|
31
+ next if !ns
32
+
33
+ begin
34
+ deploy_namespaced_resources(resources, ns)
35
+ rescue => e
36
+ puts e.message
37
+
38
+ if bt = e.backtrace
39
+ puts bt.join("\n")
40
+ end
41
+ end
42
+ end
32
43
  end
33
44
  end
34
45
 
@@ -69,10 +80,11 @@ module Kuby
69
80
  end
70
81
  rescue KubernetesCLI::InvalidResourceError => e
71
82
  Kuby.logger.fatal(e.message)
72
- Kuby.logger.fatal(e.resource.to_resource.to_yaml)
83
+ resource = e.resource&.to_resource
84
+ Kuby.logger.fatal(resource) if resource
73
85
  end
74
86
 
75
- def deploy_namespaced_resources(resources)
87
+ def deploy_namespaced_resources(resources, ns)
76
88
  old_kubeconfig = ENV['KUBECONFIG']
77
89
  ENV['KUBECONFIG'] = provider.kubeconfig_path
78
90
 
@@ -87,7 +99,7 @@ module Kuby
87
99
  end
88
100
 
89
101
  task = ::Kuby::Kubernetes::DeployTask.new(
90
- namespace: namespace.metadata.name,
102
+ namespace: ns,
91
103
  context: cli.current_context,
92
104
  filenames: [tmpdir]
93
105
  )
@@ -97,7 +109,7 @@ module Kuby
97
109
  task.run!(verify_result: true, prune: false)
98
110
  ensure
99
111
  ENV['KUBECONFIG'] = old_kubeconfig
100
- FileUtils.rm_rf(T.must(tmpdir))
112
+ FileUtils.rm_rf(tmpdir)
101
113
  end
102
114
 
103
115
  def restart_rails_deployment_if_necessary
@@ -1,4 +1,5 @@
1
1
  # typed: true
2
+
2
3
  require 'base64'
3
4
  require 'kube-dsl'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # typed: true
2
+
2
3
  require 'kubernetes-cli'
3
4
 
4
5
  module Kuby
@@ -1,5 +1,7 @@
1
1
  # typed: false
2
+
2
3
  require 'kube-dsl'
4
+ require 'rake'
3
5
 
4
6
  module Kuby
5
7
  module Kubernetes
@@ -13,6 +15,7 @@ module Kuby
13
15
  @plugins = TrailingHash.new
14
16
 
15
17
  # default plugins
18
+ add_plugin(:system)
16
19
  add_plugin(:rails_app)
17
20
  end
18
21
 
@@ -69,17 +72,59 @@ module Kuby
69
72
  def after_configuration
70
73
  @plugins.each { |_, plg| plg.after_configuration }
71
74
  provider.after_configuration
75
+ environment.docker.after_configuration
76
+
77
+ spec = self
78
+
79
+ # this must be done _after_ docker has been configured
80
+ registry_secret do
81
+ docker_config do
82
+ registry_host spec.docker.image.image_hostname
83
+ username spec.docker.image.credentials.username
84
+ password spec.docker.image.credentials.password
85
+ email spec.docker.image.credentials.email
86
+ end
87
+ end
72
88
  end
73
89
 
74
90
  def before_deploy
75
91
  @tag ||= docker.image.current_version.main_tag
76
92
 
93
+ check_dependencies!
94
+
77
95
  provider.before_deploy(resources)
78
96
  @plugins.each { |_, plg| plg.before_deploy(resources) }
79
97
  ensure
80
98
  @tag = nil
81
99
  end
82
100
 
101
+ def check_dependencies!(plugins = @plugins)
102
+ error_messages = []
103
+
104
+ plugins.each do |plg_name, plg|
105
+ plg.class.dependencies.each do |dependency|
106
+ dependable = Kuby.dependables[dependency.name]
107
+
108
+ unless dependable
109
+ error_messages << "The #{plg_name} plugin depends on #{dependency.name}, "\
110
+ "but that dependency has not been registered."
111
+
112
+ next
113
+ end
114
+
115
+ unless dependency.satisfied_by?(dependable)
116
+ error_messages << "The #{plg_name} plugin depends on #{dependency.name} "\
117
+ "#{dependency.constraints}, but the available version is #{dependable.version}."
118
+ end
119
+ end
120
+ end
121
+
122
+ unless error_messages.empty?
123
+ error_messages.each { |msg| Kuby.logger.fatal(msg) }
124
+ exit 1
125
+ end
126
+ end
127
+
83
128
  def after_deploy
84
129
  @tag ||= docker.image.current_version.main_tag
85
130
 
@@ -98,6 +143,8 @@ module Kuby
98
143
  end
99
144
  end
100
145
 
146
+ check_dependencies!(plugins)
147
+
101
148
  if only.empty?
102
149
  provider.before_setup
103
150
  provider.setup
@@ -159,13 +206,6 @@ module Kuby
159
206
  name "#{spec.selector_app}-registry-secret"
160
207
  namespace spec.namespace.metadata.name
161
208
  end
162
-
163
- docker_config do
164
- registry_host spec.docker.image.image_hostname
165
- username spec.docker.image.credentials.username
166
- password spec.docker.image.credentials.password
167
- email spec.docker.image.credentials.email
168
- end
169
209
  end
170
210
 
171
211
  @registry_secret.instance_eval(&block) if block
data/lib/kuby/plugin.rb CHANGED
@@ -1,4 +1,5 @@
1
- # typed: true
1
+ # typed: false
2
+
2
3
  module Kuby
3
4
  class Plugin
4
5
  attr_reader :environment
@@ -8,6 +9,21 @@ module Kuby
8
9
  after_initialize
9
10
  end
10
11
 
12
+ class << self
13
+ # returns an array of directories containing .rake files
14
+ def task_dirs
15
+ []
16
+ end
17
+
18
+ def depends_on(dependable_name, *constraints)
19
+ dependencies << Kuby::Dependency.new(dependable_name, *constraints)
20
+ end
21
+
22
+ def dependencies
23
+ @dependencies ||= []
24
+ end
25
+ end
26
+
11
27
  def configure(&block)
12
28
  # do nothing by default
13
29
  end
@@ -17,6 +33,11 @@ module Kuby
17
33
  # do nothing by default
18
34
  end
19
35
 
36
+ # remove all global resources installed by #setup
37
+ def remove
38
+ # do nothing by default
39
+ end
40
+
20
41
  # additional kubernetes resources that should be deployed
21
42
  def resources
22
43
  []
@@ -1,23 +1,25 @@
1
1
  # typed: true
2
+
2
3
  require 'kube-dsl'
3
4
 
4
5
  module Kuby
5
6
  module Plugins
6
7
  class NginxIngress < ::Kuby::Plugin
8
+ depends_on :kubernetes, '>= 1.20'
9
+
7
10
  class Config
8
11
  extend ::KubeDSL::ValueFields
9
12
 
10
13
  value_fields :provider
11
14
  end
12
15
 
13
- VERSION = '0.27.1'.freeze
14
- DEFAULT_PROVIDER = 'cloud-generic'.freeze
16
+ VERSION = '1.1.1'.freeze
17
+ DEFAULT_PROVIDER = 'cloud'.freeze
15
18
  NAMESPACE = 'ingress-nginx'.freeze
16
- SERVICE_NAME = 'ingress-nginx'.freeze
19
+ SERVICE_NAME = 'ingress-nginx-controller'.freeze
17
20
 
18
21
  SETUP_RESOURCES = [
19
- "https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-#{VERSION}/deploy/static/mandatory.yaml",
20
- "https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-#{VERSION}/deploy/static/provider/%{provider}.yaml"
22
+ "https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v#{VERSION}/deploy/static/provider/%{provider}/deploy.yaml"
21
23
  ].freeze
22
24
 
23
25
  def configure(&block)
@@ -54,7 +56,7 @@ module Kuby
54
56
  private
55
57
 
56
58
  def already_deployed?
57
- kubernetes_cli.get_object('Service', 'ingress-nginx', 'ingress-nginx')
59
+ kubernetes_cli.get_object('Service', NAMESPACE, SERVICE_NAME)
58
60
  true
59
61
  rescue KubernetesCLI::GetResourceError
60
62
  return false
@@ -28,19 +28,31 @@ module Kuby
28
28
  http do
29
29
  path do
30
30
  path spec.asset_url
31
+ path_type 'Prefix'
31
32
 
32
33
  backend do
33
- service_name spec.service.metadata.name
34
- service_port spec.service.spec.ports.first.port
34
+ service do
35
+ name spec.service.metadata.name
36
+
37
+ port do
38
+ name spec.service.spec.ports.first.name
39
+ end
40
+ end
35
41
  end
36
42
  end
37
43
 
38
44
  path do
39
45
  path spec.packs_url
46
+ path_type 'Prefix'
40
47
 
41
48
  backend do
42
- service_name spec.service.metadata.name
43
- service_port spec.service.spec.ports.first.port
49
+ service do
50
+ name spec.service.metadata.name
51
+
52
+ port do
53
+ name spec.service.spec.ports.first.name
54
+ end
55
+ end
44
56
  end
45
57
  end
46
58
  end
@@ -11,33 +11,42 @@ module Kuby
11
11
  end
12
12
 
13
13
  def new_version
14
- # Asset images track the base image, so return the new version
15
- # here. There can be no asset image without a base image.
16
- @new_version ||= duplicate_with_annotated_tags(
17
- base_image.new_version
14
+ # asset images track the app image
15
+ duplicate_with_annotated_tags(
16
+ base_image.new_version.exists? ? base_image.new_version : base_image.current_version
18
17
  )
19
18
  end
20
19
 
21
20
  def current_version
22
- @current_version ||= duplicate_with_annotated_tags(
21
+ duplicate_with_annotated_tags(
23
22
  base_image.current_version
24
23
  )
25
24
  end
26
25
 
27
26
  def previous_version
28
- @previous_version ||= duplicate_with_annotated_tags(
27
+ duplicate_with_annotated_tags(
29
28
  base_image.previous_version
30
29
  )
31
30
  end
32
31
 
33
- def build(build_args = {}, docker_args = [], context: nil)
34
- docker_cli.build(new_version, build_args: build_args, docker_args: docker_args, context: context)
32
+ def build(build_args = {}, docker_args = [], context: nil, cache_from: nil)
33
+ docker_cli.build(
34
+ self,
35
+ build_args: build_args,
36
+ docker_args: docker_args,
37
+ context: context,
38
+ cache_from: cache_from
39
+ )
35
40
  end
36
41
 
37
42
  def push(tag)
38
43
  docker_cli.push(image_url, tag)
39
44
  end
40
45
 
46
+ def pull(tag)
47
+ docker_cli.pull(image_url, tag)
48
+ end
49
+
41
50
  private
42
51
 
43
52
  def duplicate_with_annotated_tags(image)