kuber_kit 0.1.5 → 0.2.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +4 -2
  3. data/README.md +16 -3
  4. data/TODO.md +5 -4
  5. data/example/app_data/env_file.yml +10 -0
  6. data/example/configurations/review.rb +2 -1
  7. data/example/images/app_sources/Dockerfile +1 -1
  8. data/example/images/ruby_app/image.rb +4 -4
  9. data/example/infrastructure/build_servers.rb +8 -0
  10. data/example/infrastructure/templates.rb +5 -0
  11. data/example/services/env_file.rb +6 -0
  12. data/kuber_kit.gemspec +1 -0
  13. data/lib/kuber_kit.rb +51 -23
  14. data/lib/kuber_kit/actions/configuration_loader.rb +11 -2
  15. data/lib/kuber_kit/actions/env_file_reader.rb +8 -5
  16. data/lib/kuber_kit/actions/image_compiler.rb +18 -22
  17. data/lib/kuber_kit/actions/kubectl_applier.rb +6 -1
  18. data/lib/kuber_kit/actions/kubectl_attacher.rb +19 -0
  19. data/lib/kuber_kit/actions/service_deployer.rb +13 -3
  20. data/lib/kuber_kit/actions/service_reader.rb +9 -6
  21. data/lib/kuber_kit/actions/template_reader.rb +5 -0
  22. data/lib/kuber_kit/cli.rb +51 -20
  23. data/lib/kuber_kit/configs.rb +24 -22
  24. data/lib/kuber_kit/container.rb +43 -19
  25. data/lib/kuber_kit/core/artifacts/artifact_store.rb +12 -23
  26. data/lib/kuber_kit/core/build_servers/abstract_build_server.rb +21 -0
  27. data/lib/kuber_kit/core/build_servers/build_server.rb +24 -0
  28. data/lib/kuber_kit/core/build_servers/build_server_store.rb +18 -0
  29. data/lib/kuber_kit/core/configuration.rb +14 -4
  30. data/lib/kuber_kit/core/configuration_definition.rb +22 -1
  31. data/lib/kuber_kit/core/configuration_factory.rb +11 -1
  32. data/lib/kuber_kit/core/configuration_store.rb +14 -24
  33. data/lib/kuber_kit/core/context_helper/base_helper.rb +12 -7
  34. data/lib/kuber_kit/core/context_helper/context_helper_factory.rb +11 -8
  35. data/lib/kuber_kit/core/context_helper/service_helper.rb +7 -6
  36. data/lib/kuber_kit/core/env_files/env_file_store.rb +8 -23
  37. data/lib/kuber_kit/core/image_store.rb +8 -18
  38. data/lib/kuber_kit/core/registries/registry_store.rb +8 -23
  39. data/lib/kuber_kit/core/service.rb +6 -2
  40. data/lib/kuber_kit/core/service_factory.rb +4 -1
  41. data/lib/kuber_kit/core/service_store.rb +13 -23
  42. data/lib/kuber_kit/core/store.rb +48 -0
  43. data/lib/kuber_kit/core/templates/template_store.rb +12 -23
  44. data/lib/kuber_kit/env_file_reader/action_handler.rb +12 -0
  45. data/lib/kuber_kit/env_file_reader/reader.rb +4 -4
  46. data/lib/kuber_kit/env_file_reader/{abstract_env_file_reader.rb → strategies/abstract.rb} +1 -1
  47. data/lib/kuber_kit/env_file_reader/{artifact_file_reader.rb → strategies/artifact_file.rb} +1 -1
  48. data/lib/kuber_kit/image_compiler/action_handler.rb +21 -0
  49. data/lib/kuber_kit/image_compiler/build_server_pool.rb +30 -0
  50. data/lib/kuber_kit/image_compiler/build_server_pool_factory.rb +13 -0
  51. data/lib/kuber_kit/image_compiler/compiler.rb +2 -5
  52. data/lib/kuber_kit/image_compiler/image_build_dir_creator.rb +13 -7
  53. data/lib/kuber_kit/image_compiler/image_dependency_resolver.rb +25 -5
  54. data/lib/kuber_kit/preprocessing/file_preprocessor.rb +5 -4
  55. data/lib/kuber_kit/preprocessing/text_preprocessor.rb +1 -1
  56. data/lib/kuber_kit/service_deployer/action_handler.rb +16 -0
  57. data/lib/kuber_kit/service_deployer/deployer.rb +28 -6
  58. data/lib/kuber_kit/service_deployer/strategies/abstract.rb +1 -1
  59. data/lib/kuber_kit/service_deployer/strategies/kubernetes.rb +9 -4
  60. data/lib/kuber_kit/service_deployer/strategy_detector.rb +6 -0
  61. data/lib/kuber_kit/service_reader/action_handler.rb +13 -0
  62. data/lib/kuber_kit/{service_deployer/service_reader.rb → service_reader/reader.rb} +1 -1
  63. data/lib/kuber_kit/shell/abstract_shell.rb +4 -0
  64. data/lib/kuber_kit/shell/{bash_commands.rb → commands/bash_commands.rb} +1 -1
  65. data/lib/kuber_kit/shell/{docker_commands.rb → commands/docker_commands.rb} +1 -1
  66. data/lib/kuber_kit/shell/{git_commands.rb → commands/git_commands.rb} +1 -1
  67. data/lib/kuber_kit/shell/{kubectl_commands.rb → commands/kubectl_commands.rb} +25 -1
  68. data/lib/kuber_kit/shell/commands/rsync_commands.rb +32 -0
  69. data/lib/kuber_kit/shell/local_shell.rb +24 -5
  70. data/lib/kuber_kit/shell/ssh_session.rb +60 -0
  71. data/lib/kuber_kit/shell/ssh_shell.rb +77 -0
  72. data/lib/kuber_kit/tools/file_presence_checker.rb +6 -2
  73. data/lib/kuber_kit/ui/interactive.rb +8 -0
  74. data/lib/kuber_kit/ui/simple.rb +6 -0
  75. data/lib/kuber_kit/version.rb +2 -2
  76. metadata +41 -13
  77. data/lib/kuber_kit/preprocessing/dir_preprocessor.rb +0 -19
  78. data/lib/kuber_kit/service_deployer/service_restarter.rb +0 -37
  79. data/lib/kuber_kit/shell/rsync_commands.rb +0 -20
  80. data/lib/kuber_kit/tools/files_sync.rb +0 -10
@@ -1,19 +1,6 @@
1
1
  class KuberKit::Core::Registries::RegistryStore
2
- NotFoundError = Class.new(KuberKit::NotFoundError)
3
- AlreadyAddedError = Class.new(KuberKit::Error)
4
-
5
2
  def add(registry)
6
- @@registries ||= {}
7
-
8
- if !registry.is_a?(KuberKit::Core::Registries::AbstractRegistry)
9
- raise ArgumentError.new("should be an instance of KuberKit::Core::Registries::AbstractRegistry, got: #{registry.inspect}")
10
- end
11
-
12
- unless @@registries[registry.name].nil?
13
- raise AlreadyAddedError, "registry #{registry.name} was already added"
14
- end
15
-
16
- @@registries[registry.name] = registry
3
+ store.add(registry.name, registry)
17
4
  end
18
5
 
19
6
  def get(registry_name)
@@ -24,14 +11,7 @@ class KuberKit::Core::Registries::RegistryStore
24
11
  end
25
12
 
26
13
  def get_global(registry_name)
27
- @@registries ||= {}
28
- registry = @@registries[registry_name]
29
-
30
- if registry.nil?
31
- raise NotFoundError, "registry '#{registry_name}' not found"
32
- end
33
-
34
- registry
14
+ store.get(registry_name)
35
15
  end
36
16
 
37
17
  def get_from_configuration(registry_name)
@@ -44,6 +24,11 @@ class KuberKit::Core::Registries::RegistryStore
44
24
  end
45
25
 
46
26
  def reset!
47
- @@registries = {}
27
+ store.reset!
48
28
  end
29
+
30
+ private
31
+ def store
32
+ @@store ||= KuberKit::Core::Store.new(KuberKit::Core::Registries::AbstractRegistry)
33
+ end
49
34
  end
@@ -22,11 +22,15 @@ class KuberKit::Core::Service
22
22
  name.to_s.gsub("_", "-")
23
23
  end
24
24
 
25
- def attribute(attribute_name)
26
- unless attributes.has_key?(attribute_name.to_sym)
25
+ def attribute(attribute_name, default: nil)
26
+ if !attributes.has_key?(attribute_name.to_sym) && default.nil?
27
27
  raise AttributeNotSet, "attribute #{attribute_name} was not set"
28
28
  end
29
29
 
30
+ if !attributes.has_key?(attribute_name.to_sym) && !default.nil?
31
+ return default
32
+ end
33
+
30
34
  attributes[attribute_name.to_sym]
31
35
  end
32
36
  end
@@ -8,12 +8,15 @@ class KuberKit::Core::ServiceFactory
8
8
  raise AttributeNotSetError, "Please set template for service using #template method"
9
9
  end
10
10
 
11
+ configuration_attributes = KuberKit.current_configuration.service_attributes(service_attrs.name)
12
+ attributes = (service_attrs.attributes || {}).merge(configuration_attributes)
13
+
11
14
  KuberKit::Core::Service.new(
12
15
  name: service_attrs.name,
13
16
  template_name: service_attrs.template_name,
14
17
  tags: service_attrs.tags,
15
18
  images: service_attrs.images,
16
- attributes: service_attrs.attributes || {}
19
+ attributes: attributes
17
20
  )
18
21
  end
19
22
  end
@@ -1,7 +1,4 @@
1
1
  class KuberKit::Core::ServiceStore
2
- NotFoundError = Class.new(KuberKit::Error)
3
- AlreadyAddedError = Class.new(KuberKit::Error)
4
-
5
2
  include KuberKit::Import[
6
3
  "core.service_factory",
7
4
  "core.service_definition_factory",
@@ -16,24 +13,12 @@ class KuberKit::Core::ServiceStore
16
13
  end
17
14
 
18
15
  def add_definition(service_definition)
19
- @@service_definitions ||= {}
20
-
21
- unless @@service_definitions[service_definition.service_name].nil?
22
- raise AlreadyAddedError, "service #{service_definition.service_name} was already added"
23
- end
24
-
25
- @@service_definitions[service_definition.service_name] = service_definition
16
+ definitions_store.add(service_definition.service_name, service_definition)
26
17
  end
27
18
 
28
19
  Contract Symbol => Any
29
20
  def get_definition(service_name)
30
- @@service_definitions ||= {}
31
-
32
- if @@service_definitions[service_name].nil?
33
- raise NotFoundError, "service '#{service_name}' not found"
34
- end
35
-
36
- @@service_definitions[service_name]
21
+ definitions_store.get(service_name)
37
22
  end
38
23
 
39
24
  Contract Symbol => Any
@@ -57,18 +42,23 @@ class KuberKit::Core::ServiceStore
57
42
  end
58
43
 
59
44
  def reset!
60
- @@service_definitions = {}
45
+ definitions_store.reset!
61
46
  end
62
47
 
63
- def all_definitions
64
- @@service_definitions ||= {}
48
+ def count
49
+ definitions_store.size
65
50
  end
66
51
 
67
- def count
68
- all_definitions.count
52
+ def all_definitions
53
+ definitions_store.items
69
54
  end
70
55
 
71
56
  def exists?(service_name)
72
- !all_definitions[service_name].nil?
57
+ definitions_store.exists?(service_name)
73
58
  end
59
+
60
+ private
61
+ def definitions_store
62
+ @@definitions_store ||= KuberKit::Core::Store.new(KuberKit::Core::ServiceDefinition)
63
+ end
74
64
  end
@@ -0,0 +1,48 @@
1
+ class KuberKit::Core::Store
2
+ NotFoundError = Class.new(KuberKit::NotFoundError)
3
+ AlreadyAddedError = Class.new(KuberKit::Error)
4
+
5
+ attr_reader :object_class_name
6
+
7
+ def initialize(object_class_name)
8
+ @object_class_name = object_class_name
9
+ end
10
+
11
+ def add(item_name, item)
12
+ unless item.is_a?(object_class_name)
13
+ raise ArgumentError.new("#{self.object_class_name}: should be an instance of #{object_class_name}, got: #{item.inspect}")
14
+ end
15
+
16
+ unless items[item_name].nil?
17
+ raise AlreadyAddedError, "#{self.object_class_name}: item with name #{item_name} was already added"
18
+ end
19
+
20
+ items[item_name] = item
21
+ end
22
+
23
+ def get(item_name)
24
+ item = items[item_name]
25
+
26
+ if item.nil?
27
+ raise NotFoundError, "#{self.object_class_name}: item '#{item_name}' not found"
28
+ end
29
+
30
+ item
31
+ end
32
+
33
+ def items
34
+ @items ||= {}
35
+ end
36
+
37
+ def reset!
38
+ @items = {}
39
+ end
40
+
41
+ def size
42
+ items.count
43
+ end
44
+
45
+ def exists?(name)
46
+ !items[name].nil?
47
+ end
48
+ end
@@ -1,19 +1,6 @@
1
1
  class KuberKit::Core::Templates::TemplateStore
2
- NotFoundError = Class.new(KuberKit::NotFoundError)
3
- AlreadyAddedError = Class.new(KuberKit::Error)
4
-
5
2
  def add(template)
6
- @@templates ||= {}
7
-
8
- if !template.is_a?(KuberKit::Core::Templates::AbstractTemplate)
9
- raise ArgumentError.new("should be an instance of KuberKit::Core::Templates::AbstractTemplate, got: #{template.inspect}")
10
- end
11
-
12
- unless @@templates[template.name].nil?
13
- raise AlreadyAddedError, "template #{template.name} was already added"
14
- end
15
-
16
- @@templates[template.name] = template
3
+ store.add(template.name, template)
17
4
  end
18
5
 
19
6
  def get(template_name)
@@ -24,14 +11,7 @@ class KuberKit::Core::Templates::TemplateStore
24
11
  end
25
12
 
26
13
  def get_global(template_name)
27
- @@templates ||= {}
28
- template = @@templates[template_name]
29
-
30
- if template.nil?
31
- raise NotFoundError, "template '#{template_name}' not found"
32
- end
33
-
34
- template
14
+ store.get(template_name)
35
15
  end
36
16
 
37
17
  def get_from_configuration(template_name)
@@ -40,6 +20,15 @@ class KuberKit::Core::Templates::TemplateStore
40
20
  end
41
21
 
42
22
  def reset!
43
- @@templates = {}
23
+ store.reset!
24
+ end
25
+
26
+ def exists?(template_name)
27
+ store.exists?(template_name)
44
28
  end
29
+
30
+ private
31
+ def store
32
+ @@store ||= KuberKit::Core::Store.new(KuberKit::Core::Templates::AbstractTemplate)
33
+ end
45
34
  end
@@ -0,0 +1,12 @@
1
+ class KuberKit::EnvFileReader::ActionHandler
2
+ include KuberKit::Import[
3
+ "env_file_reader.reader",
4
+ "core.env_file_store",
5
+ ]
6
+
7
+ Contract KuberKit::Shell::AbstractShell, Symbol => Any
8
+ def call(shell, env_file_name)
9
+ env_file = env_file_store.get(env_file_name)
10
+ reader.read(shell, env_file)
11
+ end
12
+ end
@@ -2,14 +2,14 @@ class KuberKit::EnvFileReader::Reader
2
2
  ReaderNotFoundError = Class.new(KuberKit::NotFoundError)
3
3
 
4
4
  include KuberKit::Import[
5
- "env_file_reader.artifact_file_reader",
5
+ "env_file_reader.strategies.artifact_file",
6
6
  ]
7
7
 
8
8
  def use_reader(env_file_reader, env_file_class:)
9
9
  @@readers ||= {}
10
10
 
11
- if !env_file_reader.is_a?(KuberKit::EnvFileReader::AbstractEnvFileReader)
12
- raise ArgumentError.new("should be an instance of KuberKit::EnvFileReader::AbstractEnvFileReader, got: #{env_file_reader.inspect}")
11
+ if !env_file_reader.is_a?(KuberKit::EnvFileReader::Strategies::Abstract)
12
+ raise ArgumentError.new("should be an instance of KuberKit::EnvFileReader::Strategies::Abstract, got: #{env_file_reader.inspect}")
13
13
  end
14
14
 
15
15
  @@readers[env_file_class] = env_file_reader
@@ -26,7 +26,7 @@ class KuberKit::EnvFileReader::Reader
26
26
  end
27
27
 
28
28
  def add_default_readers
29
- use_reader(artifact_file_reader, env_file_class: KuberKit::Core::EnvFiles::ArtifactFile)
29
+ use_reader(artifact_file, env_file_class: KuberKit::Core::EnvFiles::ArtifactFile)
30
30
  end
31
31
 
32
32
  def reset!
@@ -1,4 +1,4 @@
1
- class KuberKit::EnvFileReader::AbstractEnvFileReader
1
+ class KuberKit::EnvFileReader::Strategies::Abstract
2
2
  def read(shell, env_file)
3
3
  raise KuberKit::NotImplementedError, "must be implemented"
4
4
  end
@@ -1,4 +1,4 @@
1
- class KuberKit::EnvFileReader::ArtifactFileReader < KuberKit::EnvFileReader::AbstractEnvFileReader
1
+ class KuberKit::EnvFileReader::Strategies::ArtifactFile < KuberKit::EnvFileReader::Strategies::Abstract
2
2
  include KuberKit::Import[
3
3
  "core.artifact_store"
4
4
  ]
@@ -0,0 +1,21 @@
1
+ class KuberKit::ImageCompiler::ActionHandler
2
+ include KuberKit::Import[
3
+ "image_compiler.compiler",
4
+ "core.image_store",
5
+ "configs",
6
+ ]
7
+
8
+ Contract KuberKit::Shell::AbstractShell, Symbol, String => Any
9
+ def call(shell, image_name, build_id)
10
+ image = image_store.get_image(image_name)
11
+
12
+ compile_dir = generate_compile_dir(build_id: build_id)
13
+
14
+ compiler.compile(shell, image, compile_dir)
15
+ end
16
+
17
+ private
18
+ def generate_compile_dir(build_id:)
19
+ File.join(configs.image_compile_dir, build_id)
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ class KuberKit::ImageCompiler::BuildServerPool
2
+ attr_reader :ssh_shells, :local_shell
3
+
4
+ def initialize(local_shell:, build_servers:, ssh_shell_class:)
5
+ @local_shell = local_shell
6
+ @ssh_shell_class = ssh_shell_class
7
+ @ssh_shells = connect_to_ssh_shells(build_servers)
8
+ end
9
+
10
+ def get_shell
11
+ if @ssh_shells.any?
12
+ @ssh_shells.sample
13
+ else
14
+ @local_shell
15
+ end
16
+ end
17
+
18
+ def disconnect_all
19
+ @ssh_shells.each(&:disconnect)
20
+ end
21
+
22
+ private
23
+ def connect_to_ssh_shells(build_servers)
24
+ build_servers.map do |bs|
25
+ shell = @ssh_shell_class.new
26
+ shell.connect(host: bs.host, user: bs.user, port: bs.port)
27
+ shell
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ class KuberKit::ImageCompiler::BuildServerPoolFactory
2
+ include KuberKit::Import[
3
+ "shell.local_shell",
4
+ ]
5
+
6
+ def create(ssh_shell_class: KuberKit::Shell::SshShell)
7
+ KuberKit::ImageCompiler::BuildServerPool.new(
8
+ local_shell: local_shell,
9
+ build_servers: KuberKit.current_configuration.build_servers,
10
+ ssh_shell_class: ssh_shell_class,
11
+ )
12
+ end
13
+ end
@@ -3,13 +3,10 @@ class KuberKit::ImageCompiler::Compiler
3
3
  "image_compiler.image_build_dir_creator",
4
4
  "image_compiler.image_builder",
5
5
  "core.context_helper_factory",
6
- "core.image_store"
7
6
  ]
8
7
 
9
- Contract KuberKit::Shell::AbstractShell, Symbol, String => Any
10
- def compile(shell, image_name, builds_dir)
11
- image = image_store.get_image(image_name)
12
-
8
+ Contract KuberKit::Shell::AbstractShell, KuberKit::Core::Image, String => Any
9
+ def compile(shell, image, builds_dir)
13
10
  image_build_dir = File.join(builds_dir, image.name.to_s)
14
11
 
15
12
  context_helper = context_helper_factory.build_image_context(shell)
@@ -1,8 +1,8 @@
1
1
  class KuberKit::ImageCompiler::ImageBuildDirCreator
2
2
  include KuberKit::Import[
3
- "preprocessing.dir_preprocessor",
4
3
  "preprocessing.file_preprocessor",
5
4
  "shell.bash_commands",
5
+ "shell.local_shell",
6
6
  "configs"
7
7
  ]
8
8
 
@@ -14,16 +14,22 @@ class KuberKit::ImageCompiler::ImageBuildDirCreator
14
14
  bash_commands.mkdir_p(shell, build_dir)
15
15
 
16
16
  if image.build_context_dir
17
- dir_preprocessor.compile(
18
- shell, image.build_context_dir, build_dir,
19
- context_helper: context_helper
20
- )
17
+ # Sync build context and then preprocess
18
+ shell.sync(image.build_context_dir, build_dir)
19
+
20
+ shell.recursive_list_files(build_dir).each do |file_path|
21
+ file_preprocessor.compile(
22
+ shell, file_path,
23
+ context_helper: context_helper
24
+ )
25
+ end
21
26
  end
22
27
 
28
+ # Sync dockerfile and then preprocess
23
29
  target_dockerfile = File.join(build_dir, configs.image_dockerfile_name)
30
+ shell.sync(image.dockerfile_path, target_dockerfile)
24
31
  file_preprocessor.compile(
25
- shell, image.dockerfile_path,
26
- destination_path: target_dockerfile,
32
+ shell, target_dockerfile,
27
33
  context_helper: context_helper
28
34
  )
29
35
 
@@ -3,20 +3,40 @@ class KuberKit::ImageCompiler::ImageDependencyResolver
3
3
  DependencyNotFoundError = Class.new(KuberKit::NotFoundError)
4
4
 
5
5
  include KuberKit::Import[
6
- "core.image_store"
6
+ "core.image_store",
7
+ "configs"
7
8
  ]
9
+
10
+ Contract Or[Symbol, ArrayOf[Symbol]], Proc => Any
11
+ def each_with_deps(image_names, &block)
12
+ compile_limit = configs.compile_simultaneous_limit
13
+
14
+ resolved_dependencies = []
15
+ next_dependencies = get_next(image_names, limit: compile_limit)
16
+
17
+ while (next_dependencies - resolved_dependencies).any?
18
+ block.call(next_dependencies)
19
+ resolved_dependencies += next_dependencies
20
+ next_dependencies = get_next(image_names, resolved: resolved_dependencies, limit: compile_limit)
21
+ end
22
+
23
+ block.call(image_names - resolved_dependencies)
24
+ end
8
25
 
9
- Contract Any, KeywordArgs[
10
- resolved: Optional[ArrayOf[Symbol]]
26
+ Contract Or[Symbol, ArrayOf[Symbol]], KeywordArgs[
27
+ resolved: Optional[ArrayOf[Symbol]],
28
+ limit: Optional[Maybe[Num]]
11
29
  ] => Any
12
- def get_next(image_names, resolved: [])
30
+ def get_next(image_names, resolved: [], limit: nil)
13
31
  deps = Array(image_names).map { |i| get_recursive_deps(i) }.flatten.uniq
14
32
 
15
33
  ready_to_resolve = deps.select do |dep_name|
16
34
  unresolved_deps = get_deps(dep_name) - resolved
17
35
  unresolved_deps.empty?
18
36
  end
19
- ready_to_resolve - resolved
37
+ unresolved_deps = ready_to_resolve - resolved
38
+ unresolved_deps = unresolved_deps.take(limit) if limit
39
+ unresolved_deps
20
40
  end
21
41
 
22
42
  def get_recursive_deps(image_name, dependency_tree: [])