kuber_kit 0.3.8 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +35 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/TODO.md +2 -1
  6. data/example/infrastructure/artifacts.rb +1 -1
  7. data/example/services/docker_app.rb +12 -0
  8. data/lib/kuber_kit.rb +6 -4
  9. data/lib/kuber_kit/actions/configuration_loader.rb +12 -19
  10. data/lib/kuber_kit/actions/env_file_reader.rb +1 -0
  11. data/lib/kuber_kit/actions/image_compiler.rb +10 -6
  12. data/lib/kuber_kit/actions/service_deployer.rb +10 -7
  13. data/lib/kuber_kit/actions/template_reader.rb +1 -0
  14. data/lib/kuber_kit/artifacts_sync/artifacts_updater.rb +3 -2
  15. data/lib/kuber_kit/cli.rb +38 -25
  16. data/lib/kuber_kit/configs.rb +2 -1
  17. data/lib/kuber_kit/container.rb +6 -2
  18. data/lib/kuber_kit/core/configuration_store.rb +2 -2
  19. data/lib/kuber_kit/core/image_store.rb +2 -2
  20. data/lib/kuber_kit/core/service.rb +5 -5
  21. data/lib/kuber_kit/core/service_factory.rb +0 -6
  22. data/lib/kuber_kit/core/service_store.rb +2 -2
  23. data/lib/kuber_kit/image_compiler/compiler.rb +3 -1
  24. data/lib/kuber_kit/image_compiler/image_builder.rb +9 -1
  25. data/lib/kuber_kit/service_deployer/strategies/docker.rb +26 -9
  26. data/lib/kuber_kit/service_deployer/strategies/docker_compose.rb +3 -0
  27. data/lib/kuber_kit/service_deployer/strategies/kubernetes.rb +3 -1
  28. data/lib/kuber_kit/service_reader/reader.rb +6 -0
  29. data/lib/kuber_kit/shell/commands/docker_commands.rb +59 -14
  30. data/lib/kuber_kit/shell/commands/docker_compose_commands.rb +4 -5
  31. data/lib/kuber_kit/shell/local_shell.rb +6 -6
  32. data/lib/kuber_kit/shell/ssh_shell.rb +4 -4
  33. data/lib/kuber_kit/tools/logger_factory.rb +7 -3
  34. data/lib/kuber_kit/ui/api.rb +48 -0
  35. data/lib/kuber_kit/ui/debug.rb +31 -0
  36. data/lib/kuber_kit/ui/interactive.rb +15 -0
  37. data/lib/kuber_kit/ui/simple.rb +34 -5
  38. data/lib/kuber_kit/version.rb +1 -1
  39. metadata +10 -6
@@ -5,7 +5,7 @@ class KuberKit::Configs
5
5
  :image_dockerfile_name, :image_build_context_dir, :image_tag, :docker_ignore_list, :image_compile_dir,
6
6
  :kuber_kit_dirname, :kuber_kit_min_version, :images_dirname, :services_dirname, :infra_dirname, :configurations_dirname,
7
7
  :artifact_clone_dir, :service_config_dir, :deployer_strategy, :compile_simultaneous_limit,
8
- :additional_images_paths, :deprecation_warnings_disabled
8
+ :additional_images_paths, :deprecation_warnings_disabled, :log_file_path
9
9
  ]
10
10
  DOCKER_IGNORE_LIST = [
11
11
  'Dockerfile',
@@ -51,6 +51,7 @@ class KuberKit::Configs
51
51
  set :compile_simultaneous_limit, 5
52
52
  set :additional_images_paths, []
53
53
  set :deprecation_warnings_disabled, false
54
+ set :log_file_path, "/tmp/kuber_kit.log"
54
55
  end
55
56
 
56
57
  def items
@@ -114,7 +114,7 @@ class KuberKit::Container
114
114
  end
115
115
 
116
116
  register "tools.logger" do
117
- KuberKit::Container["tools.logger_factory"].create("/tmp/kuber_kit.log")
117
+ KuberKit::Container["tools.logger_factory"].create()
118
118
  end
119
119
 
120
120
  register "shell.bash_commands" do
@@ -258,8 +258,12 @@ class KuberKit::Container
258
258
  end
259
259
 
260
260
  register "ui" do
261
- if KuberKit.debug_mode?
261
+ if KuberKit.ui_mode == :debug
262
+ KuberKit::UI::Debug.new
263
+ elsif KuberKit.ui_mode == :simple
262
264
  KuberKit::UI::Simple.new
265
+ elsif KuberKit.ui_mode == :api
266
+ KuberKit::UI::Api.new
263
267
  else
264
268
  KuberKit::UI::Interactive.new
265
269
  end
@@ -3,7 +3,7 @@ class KuberKit::Core::ConfigurationStore
3
3
  "core.configuration_factory",
4
4
  "core.configuration_definition_factory",
5
5
  "shell.local_shell",
6
- "tools.logger"
6
+ "ui"
7
7
  ]
8
8
 
9
9
  def define(configuration_name)
@@ -33,7 +33,7 @@ class KuberKit::Core::ConfigurationStore
33
33
  load_definition(path)
34
34
  end
35
35
  rescue KuberKit::Shell::AbstractShell::DirNotFoundError
36
- logger.warn("Directory with configurations not found: #{dir_path}")
36
+ ui.print_warning("ConfigurationStore", "Directory with configurations not found: #{dir_path}")
37
37
  []
38
38
  end
39
39
 
@@ -3,7 +3,7 @@ class KuberKit::Core::ImageStore
3
3
  "core.image_factory",
4
4
  "core.image_definition_factory",
5
5
  "shell.local_shell",
6
- "tools.logger"
6
+ "ui"
7
7
  ]
8
8
 
9
9
  def define(image_name, image_dir = nil)
@@ -33,7 +33,7 @@ class KuberKit::Core::ImageStore
33
33
  load_definition(path)
34
34
  end
35
35
  rescue KuberKit::Shell::AbstractShell::DirNotFoundError
36
- logger.warn("Directory with images not found: #{dir_path}")
36
+ ui.print_warning("ImageStore", "Directory with images not found: #{dir_path}")
37
37
  []
38
38
  end
39
39
 
@@ -4,11 +4,11 @@ class KuberKit::Core::Service
4
4
  attr_reader :name, :template_name, :tags, :images, :attributes, :deployer_strategy
5
5
 
6
6
  Contract KeywordArgs[
7
- name: Symbol,
8
- template_name: Symbol,
9
- tags: ArrayOf[Symbol],
10
- images: ArrayOf[Symbol],
11
- attributes: HashOf[Symbol => Any],
7
+ name: Symbol,
8
+ template_name: Maybe[Symbol],
9
+ tags: ArrayOf[Symbol],
10
+ images: ArrayOf[Symbol],
11
+ attributes: HashOf[Symbol => Any],
12
12
  deployer_strategy: Maybe[Symbol]
13
13
  ] => Any
14
14
  def initialize(name:, template_name:, tags:, images:, attributes:, deployer_strategy:)
@@ -1,13 +1,7 @@
1
1
  class KuberKit::Core::ServiceFactory
2
- AttributeNotSetError = Class.new(KuberKit::Error)
3
-
4
2
  def create(definition)
5
3
  service_attrs = definition.to_service_attrs
6
4
 
7
- if service_attrs.template_name.nil?
8
- raise AttributeNotSetError, "Please set template for service using #template method"
9
- end
10
-
11
5
  configuration_attributes = KuberKit.current_configuration.service_attributes(service_attrs.name)
12
6
  attributes = (service_attrs.attributes || {}).merge(configuration_attributes)
13
7
 
@@ -3,7 +3,7 @@ class KuberKit::Core::ServiceStore
3
3
  "core.service_factory",
4
4
  "core.service_definition_factory",
5
5
  "shell.local_shell",
6
- "tools.logger"
6
+ "ui",
7
7
  ]
8
8
 
9
9
  def define(service_name)
@@ -33,7 +33,7 @@ class KuberKit::Core::ServiceStore
33
33
  load_definition(path)
34
34
  end
35
35
  rescue KuberKit::Shell::AbstractShell::DirNotFoundError
36
- logger.warn("Directory with services not found: #{dir_path}")
36
+ ui.print_warning("ServiceStore", "Directory with services not found: #{dir_path}")
37
37
  []
38
38
  end
39
39
 
@@ -12,7 +12,9 @@ class KuberKit::ImageCompiler::Compiler
12
12
  context_helper = context_helper_factory.build_image_context(shell, image)
13
13
  image_build_dir_creator.create(shell, image, image_build_dir, context_helper: context_helper)
14
14
 
15
- image_builder.build(shell, image, image_build_dir, context_helper: context_helper)
15
+ result = image_builder.build(shell, image, image_build_dir, context_helper: context_helper)
16
16
  image_build_dir_creator.cleanup(shell, image_build_dir)
17
+
18
+ result
17
19
  end
18
20
  end
@@ -10,7 +10,13 @@ class KuberKit::ImageCompiler::ImageBuilder
10
10
  def build(shell, image, build_dir, context_helper: nil)
11
11
  image.before_build_callback.call(context_helper, build_dir) if image.before_build_callback
12
12
 
13
- docker_commands.build(shell, build_dir, ["-t=#{image.registry_url}"])
13
+ build_options = ["-t=#{image.registry_url}"]
14
+ # use quite option for api mode ui, so it will only return built image id
15
+ if KuberKit.ui_mode == :api
16
+ build_options << "-q"
17
+ end
18
+
19
+ build_result = docker_commands.build(shell, build_dir, build_options)
14
20
 
15
21
  version_tag = version_tag_builder.get_version
16
22
  docker_commands.tag(shell, image.registry_url, version_tag)
@@ -21,5 +27,7 @@ class KuberKit::ImageCompiler::ImageBuilder
21
27
  end
22
28
 
23
29
  image.after_build_callback.call(context_helper, build_dir) if image.after_build_callback
30
+
31
+ build_result
24
32
  end
25
33
  end
@@ -9,9 +9,11 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
9
9
  :container_name,
10
10
  :image_name,
11
11
  :detached,
12
- :docker_run_args,
13
- :docker_run_command,
14
- :delete_if_exists
12
+ :command_name,
13
+ :custom_args,
14
+ :delete_if_exists,
15
+ :volumes,
16
+ :networks,
15
17
  ]
16
18
 
17
19
  Contract KuberKit::Shell::AbstractShell, KuberKit::Core::Service => Any
@@ -22,9 +24,11 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
22
24
  raise KuberKit::Error, "Unknow options for deploy strategy: #{unknown_options}. Available options: #{STRATEGY_OPTIONS}"
23
25
  end
24
26
 
25
- container_name = strategy_options.fetch(:container_name, service.uri)
26
- docker_run_args = strategy_options.fetch(:docker_run_args, nil)
27
- docker_run_command = strategy_options.fetch(:docker_run_command, nil)
27
+ container_name = strategy_options.fetch(:container_name, service.uri)
28
+ command_name = strategy_options.fetch(:command_name, "bash")
29
+ custom_args = strategy_options.fetch(:custom_args, nil)
30
+ networks = strategy_options.fetch(:networks, [])
31
+ volumes = strategy_options.fetch(:volumes, [])
28
32
 
29
33
  image_name = strategy_options.fetch(:image_name, nil)
30
34
  if image_name.nil?
@@ -37,11 +41,24 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
37
41
  docker_commands.delete_container(shell, container_name)
38
42
  end
39
43
 
44
+ custom_args = Array(custom_args)
45
+ if container_name
46
+ custom_args << "--name #{container_name}"
47
+ end
48
+ networks.each do |network|
49
+ docker_commands.create_network(shell, network)
50
+ custom_args << "--network #{network}"
51
+ end
52
+ volumes.each do |volume|
53
+ docker_commands.create_volume(shell, volume)
54
+ custom_args << "--volume #{volume}"
55
+ end
56
+
40
57
  docker_commands.run(
41
58
  shell, image.remote_registry_url,
42
- run_args: docker_run_args,
43
- run_command: docker_run_command,
44
- detached: !!strategy_options[:detached]
59
+ command: command_name,
60
+ args: custom_args,
61
+ detached: !!strategy_options[:detached]
45
62
  )
46
63
  end
47
64
  end
@@ -8,6 +8,7 @@ class KuberKit::ServiceDeployer::Strategies::DockerCompose < KuberKit::ServiceDe
8
8
  STRATEGY_OPTIONS = [
9
9
  :service_name,
10
10
  :command_name,
11
+ :custom_args,
11
12
  :detached
12
13
  ]
13
14
 
@@ -25,10 +26,12 @@ class KuberKit::ServiceDeployer::Strategies::DockerCompose < KuberKit::ServiceDe
25
26
 
26
27
  service_name = strategy_options.fetch(:service_name, service.name.to_s)
27
28
  command_name = strategy_options.fetch(:command_name, "bash")
29
+ custom_args = strategy_options.fetch(:custom_args, nil)
28
30
 
29
31
  docker_compose_commands.run(shell, config_path,
30
32
  service: service_name,
31
33
  command: command_name,
34
+ args: custom_args,
32
35
  detached: !!strategy_options[:detached]
33
36
  )
34
37
  end
@@ -39,7 +39,7 @@ class KuberKit::ServiceDeployer::Strategies::Kubernetes < KuberKit::ServiceDeplo
39
39
  kubectl_commands.delete_resource(shell, resource_type, resource_name, kubeconfig_path: kubeconfig_path, namespace: namespace)
40
40
  end
41
41
 
42
- kubectl_commands.apply_file(shell, config_path, kubeconfig_path: kubeconfig_path, namespace: namespace)
42
+ apply_result = kubectl_commands.apply_file(shell, config_path, kubeconfig_path: kubeconfig_path, namespace: namespace)
43
43
 
44
44
  restart_enabled = strategy_options.fetch(:restart_if_exists, true)
45
45
  if restart_enabled && resource_exists
@@ -48,5 +48,7 @@ class KuberKit::ServiceDeployer::Strategies::Kubernetes < KuberKit::ServiceDeplo
48
48
  kubeconfig_path: kubeconfig_path, namespace: namespace
49
49
  )
50
50
  end
51
+
52
+ apply_result
51
53
  end
52
54
  end
@@ -6,8 +6,14 @@ class KuberKit::ServiceReader::Reader
6
6
  "preprocessing.text_preprocessor"
7
7
  ]
8
8
 
9
+ AttributeNotSetError = Class.new(KuberKit::Error)
10
+
9
11
  Contract KuberKit::Shell::AbstractShell, KuberKit::Core::Service => Any
10
12
  def read(shell, service)
13
+ if service.template_name.nil?
14
+ raise AttributeNotSetError, "Please set template for service using #template method"
15
+ end
16
+
11
17
  template = template_store.get(service.template_name)
12
18
 
13
19
  context_helper = context_helper_factory.build_service_context(shell, service)
@@ -3,7 +3,7 @@ class KuberKit::Shell::Commands::DockerCommands
3
3
  default_args = ["--rm=true"]
4
4
  args_list = (default_args + args).join(" ")
5
5
 
6
- shell.exec!(%Q{docker build #{build_dir} #{args_list}})
6
+ shell.exec!(%Q{docker image build #{build_dir} #{args_list}})
7
7
  end
8
8
 
9
9
  def tag(shell, image_name, tag_name)
@@ -14,37 +14,82 @@ class KuberKit::Shell::Commands::DockerCommands
14
14
  shell.exec!(%Q{docker push #{tag_name}})
15
15
  end
16
16
 
17
- def run(shell, image_name, run_args: nil, run_command: nil, detached: false)
17
+ def run(shell, image_name, args: nil, command: nil, detached: false, interactive: false)
18
18
  command_parts = []
19
19
  command_parts << "docker run"
20
20
  command_parts << "-d" if detached
21
- command_parts << run_args if run_args
21
+ command_parts << Array(args).join(" ") if args
22
22
  command_parts << image_name
23
- command_parts << run_command if run_command
23
+ command_parts << command if command
24
24
 
25
- shell.exec!(command_parts.join(" "))
25
+ if interactive
26
+ shell.interactive!(command_parts.join(" "))
27
+ else
28
+ shell.exec!(command_parts.join(" "))
29
+ end
26
30
  end
27
31
 
28
- def container_exists?(shell, container_name)
29
- result = get_container_id(shell, container_name)
32
+ def container_exists?(shell, container_name, status: nil)
33
+ result = get_containers(shell, container_name, status: status)
30
34
  result && result != ""
31
35
  end
32
36
 
33
- def delete_container(shell, container_name)
34
- shell.exec!(%Q{docker rm -f #{container_name}})
35
- end
36
-
37
- def get_container_id(shell, container_name, only_healthy: false, status: "running")
37
+ def get_containers(shell, container_name, only_healthy: false, status: nil)
38
38
  command_parts = []
39
39
  command_parts << "docker ps -a -q"
40
40
 
41
41
  if only_healthy
42
42
  command_parts << "--filter=\"health=healthy\""
43
43
  end
44
-
45
- command_parts << "--filter=\"status=#{status}\""
44
+ if status
45
+ command_parts << "--filter=\"status=#{status}\""
46
+ end
46
47
  command_parts << "--filter=\"name=#{container_name}\""
47
48
 
48
49
  shell.exec!(command_parts.join(" "))
49
50
  end
51
+
52
+ def delete_container(shell, container_name)
53
+ shell.exec!("docker rm -f #{container_name}")
54
+ end
55
+
56
+ def create_network(shell, name)
57
+ unless network_exists?(shell, name)
58
+ shell.exec!("docker network create #{name}")
59
+ end
60
+ end
61
+
62
+ def network_exists?(shell, network_name)
63
+ result = get_networks(shell, network_name)
64
+ result && result != ""
65
+ end
66
+
67
+ def get_networks(shell, network_name)
68
+ command_parts = []
69
+ command_parts << "docker network ls"
70
+ command_parts << "--filter=\"name=#{network_name}\""
71
+ command_parts << "--format \"{{.Name}}\""
72
+
73
+ shell.exec!(command_parts.join(" "))
74
+ end
75
+
76
+ def create_volume(shell, name)
77
+ unless volume_exists?(shell, name)
78
+ shell.exec!("docker volume create #{name}")
79
+ end
80
+ end
81
+
82
+ def volume_exists?(shell, volume_name)
83
+ result = get_volumes(shell, volume_name)
84
+ result && result != ""
85
+ end
86
+
87
+ def get_volumes(shell, volume_name)
88
+ command_parts = []
89
+ command_parts << "docker volume ls"
90
+ command_parts << "--filter=\"name=#{volume_name}\""
91
+ command_parts << "--format \"{{.Name}}\""
92
+
93
+ shell.exec!(command_parts.join(" "))
94
+ end
50
95
  end
@@ -1,17 +1,16 @@
1
1
  class KuberKit::Shell::Commands::DockerComposeCommands
2
- def run(shell, path, service:, command:, interactive: false, detached: false)
2
+ def run(shell, path, service:, args: nil, command: nil, detached: false, interactive: false)
3
3
  command_parts = [
4
4
  "docker-compose",
5
5
  "-f #{path}",
6
6
  "run",
7
7
  ]
8
8
 
9
- if detached
10
- command_parts << "-d"
11
- end
12
9
 
10
+ command_parts << "-d" if detached
11
+ command_parts << Array(args).join(" ") if args
13
12
  command_parts << service
14
- command_parts << command
13
+ command_parts << command if command
15
14
 
16
15
  if interactive
17
16
  shell.interactive!(command_parts.join(" "))
@@ -2,16 +2,16 @@ require 'fileutils'
2
2
 
3
3
  class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
4
4
  include KuberKit::Import[
5
- "tools.logger",
6
5
  "shell.command_counter",
7
6
  "shell.rsync_commands",
7
+ "ui",
8
8
  ]
9
9
 
10
10
  def exec!(command, log_command: true)
11
11
  command_number = command_counter.get_number.to_s.rjust(2, "0")
12
12
 
13
13
  if log_command
14
- logger.info("Execute: [#{command_number}]: #{command.to_s.cyan}")
14
+ ui.print_debug("LocalShell", "Execute: [#{command_number}]: #{command.to_s.cyan}")
15
15
  end
16
16
 
17
17
  result = nil
@@ -20,7 +20,7 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
20
20
  end
21
21
 
22
22
  if result && result != "" && log_command
23
- logger.info("Finished [#{command_number}] with result: \n#{result.grey}")
23
+ ui.print_debug("LocalShell", "Finished [#{command_number}] with result: \n ----\n#{result.grey}\n ----")
24
24
  end
25
25
 
26
26
  if $?.exitstatus != 0
@@ -34,7 +34,7 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
34
34
  command_number = command_counter.get_number.to_s.rjust(2, "0")
35
35
 
36
36
  if log_command
37
- logger.info("Interactive: [#{command_number}]: #{command.to_s.cyan}")
37
+ ui.print_debug("LocalShell", "Interactive: [#{command_number}]: #{command.to_s.cyan}")
38
38
  end
39
39
 
40
40
  result = system(command)
@@ -57,7 +57,7 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
57
57
 
58
58
  File.write(file_path, content)
59
59
 
60
- logger.info("Created file #{file_path.to_s.cyan}\r\n#{content.grey}")
60
+ ui.print_debug("LocalShell", "Created file #{file_path.to_s.cyan}\r\n ----\r\n#{content.grey}\r\n ----")
61
61
 
62
62
  true
63
63
  end
@@ -76,7 +76,7 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
76
76
 
77
77
  def recursive_list_files(path, name: nil)
78
78
  command = %Q{find -L #{path} -type f}
79
- command += " -name #{name}" if name
79
+ command += " -name '#{name}'" if name
80
80
  exec!(command).split(/[\r\n]+/)
81
81
  rescue => e
82
82
  if e.message.include?("No such file or directory")