kuber_kit 0.5.6 → 0.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: 185201d6f305a1e69b2d5ec982288234454404bb9b87501130f159fb58a3b97a
4
- data.tar.gz: e411255031c65afe38e7b0faa20e9b578b2d3eca93a3bb9dc013766a59c7d2b1
3
+ metadata.gz: 32c19efd73a0f79e6dd009a9e6700c184b78eacde4be6c7eb3e9571a6aa5977d
4
+ data.tar.gz: 6c66868a7a280ecaccc6dcb44ee75a929ecbb057545f412dab2f57e4e8c45bc9
5
5
  SHA512:
6
- metadata.gz: 936fd6032488908db1fffe95f736dd05042c499f2995be2bc28566b2f65d9d5b35150acc0cf08de50442c16408d56d623292bb8e051215bfc15b8aba804266cc
7
- data.tar.gz: c81b1a227cf5690d675b0b8d269382f0bb6d13ed71cfc3442679e1bd7471b995e02e7177b6c93bfb6955792bd591708c0ea017f9ea52291992bbbd0e5b33c0e2
6
+ metadata.gz: 8b1316dd6e65c9f81db7450c4e86c398357cd429054965ddff80634744f1ab5b1acedb638cd51c9c65040edd0c09c67429d5f884eef6c443ddb0e6bf558bd878
7
+ data.tar.gz: dac99cdc86d70f8f9424f6cb9aee0e7f5630e5407f878266c6373740015a5664c3ea6c27a29c9f39985b738bc7665281f9f9ced846436f251598da16bc6517f8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ **0.6.0**
2
+ - Cleanup old image build dirs
3
+ - Add rotation to deployment log file
4
+
5
+ **0.5.10**
6
+ - Fix a regression when deployment result would not be properly returned as json.
7
+
8
+ **0.5.9**
9
+ - Added an ability to set custom user
10
+ - Allow setting environment variable in docker strategy
11
+ - Properly stop deployment if image compilation is failed
12
+
13
+ **0.5.8**
14
+ - Update gemspec to support ruby 2.5
15
+
16
+ **0.5.7**
17
+ - Look for kuber_kit root path in parent folders, so kit command will work in sub-folders
18
+
1
19
  **0.5.6**
2
20
  - Pre-process env file if it has .erb extension
3
21
  - Allow attaching env file from configuration to docker container
data/Gemfile.lock CHANGED
@@ -1,10 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kuber_kit (0.5.6)
4
+ kuber_kit (0.6.0)
5
5
  cli-ui
6
6
  contracts-lite
7
- dry-auto_inject
7
+ dry-auto_inject (~> 0.7.0)
8
+ dry-container (~> 0.7.2)
8
9
  net-ssh
9
10
  thor
10
11
  tty-prompt
data/TODO.md CHANGED
@@ -1,8 +1,5 @@
1
- - add kit get method for more interactive kubernetes
2
1
  - env files should use a separate deployment method (with change detection)
3
2
  - add automatical confirmation support for service deployer
4
3
  - template should be able to set default attributes
5
4
  - template should be able to depend on image?
6
- - cleanup image builds older than some date
7
- - add some rotation for deploy log
8
5
  - kit status should show the list of services and their status, with ability to select & view logs
@@ -3,7 +3,8 @@ apiVersion: apps/v1
3
3
  kind: Deployment
4
4
  metadata:
5
5
  labels:
6
- app: <%= service_uri %>
6
+ app: <%= service_uri %>
7
+ user: <%= KuberKit.user %>
7
8
  name: <%= service_uri %>
8
9
  spec:
9
10
  replicas: 1
@@ -0,0 +1,5 @@
1
+ FROM <%= image_url(:ruby) %>
2
+
3
+ RUN not_existing_command
4
+
5
+ CMD ["tail", "-f", "/dev/null"]
@@ -0,0 +1,4 @@
1
+ KuberKit
2
+ .define_image(:failing_app)
3
+ .registry(:default)
4
+ .depends_on(:ruby, :app_sources)
@@ -0,0 +1,6 @@
1
+ KuberKit
2
+ .define_service(:failing_app)
3
+ .depends_on(:env_file)
4
+ .template(:service)
5
+ .images(:failing_app)
6
+ .tags("app", "minimal")
data/kuber_kit.gemspec CHANGED
@@ -24,11 +24,12 @@ Gem::Specification.new do |spec|
24
24
  spec.require_paths = ["lib"]
25
25
 
26
26
  spec.add_dependency "contracts-lite"
27
- spec.add_dependency "dry-auto_inject"
27
+ spec.add_dependency "dry-auto_inject", "~> 0.7.0"
28
28
  spec.add_dependency "thor"
29
29
  spec.add_dependency "cli-ui"
30
30
  spec.add_dependency "net-ssh"
31
31
  spec.add_dependency "tty-prompt"
32
+ spec.add_dependency "dry-container", "~> 0.7.2"
32
33
 
33
34
  spec.add_development_dependency "bundler", "~> 1.17"
34
35
  spec.add_development_dependency "rake", "~> 10.0"
data/lib/kuber_kit.rb CHANGED
@@ -79,9 +79,11 @@ module KuberKit
79
79
  end
80
80
 
81
81
  module Tools
82
+ autoload :BuildDirCleaner, 'tools/build_dir_cleaner'
82
83
  autoload :FilePresenceChecker, 'tools/file_presence_checker'
83
84
  autoload :LoggerFactory, 'tools/logger_factory'
84
85
  autoload :ProcessCleaner, 'tools/process_cleaner'
86
+ autoload :WorkdirDetector, 'tools/workdir_detector'
85
87
  end
86
88
 
87
89
  module Shell
@@ -152,6 +154,7 @@ module KuberKit
152
154
  autoload :ActionHandler, 'service_deployer/action_handler'
153
155
  autoload :StrategyDetector, 'service_deployer/strategy_detector'
154
156
  autoload :Deployer, 'service_deployer/deployer'
157
+ autoload :DeploymentOptionsSelector, 'service_deployer/deployment_options_selector'
155
158
  autoload :ServiceListResolver, 'service_deployer/service_list_resolver'
156
159
  autoload :ServiceDependencyResolver, 'service_deployer/service_dependency_resolver'
157
160
 
@@ -169,6 +172,7 @@ module KuberKit
169
172
  end
170
173
 
171
174
  module Actions
175
+ autoload :ActionResult, 'actions/action_result'
172
176
  autoload :ImageCompiler, 'actions/image_compiler'
173
177
  autoload :EnvFileReader, 'actions/env_file_reader'
174
178
  autoload :TemplateReader, 'actions/template_reader'
@@ -274,6 +278,11 @@ module KuberKit
274
278
  KuberKit::Core::ContextHelper::BaseHelper.class_exec(&proc)
275
279
  end
276
280
 
281
+ def set_user(value)
282
+ @user = value
283
+ @user_id = nil
284
+ end
285
+
277
286
  def user
278
287
  @user ||= ENV["KUBER_KIT_USERNAME"] || `whoami`.chomp
279
288
  end
@@ -0,0 +1,32 @@
1
+ class KuberKit::Actions::ActionResult
2
+ attr_reader :finished_tasks, :all_results, :error
3
+
4
+ def initialize()
5
+ @all_results = {}
6
+ @started_tasks = []
7
+ @finished_tasks = []
8
+ @mutex = Mutex.new
9
+ end
10
+
11
+ def start_task(task)
12
+ @mutex.synchronize do
13
+ @started_tasks.push(task)
14
+ end
15
+ end
16
+
17
+ def finish_task(task, result = nil)
18
+ @mutex.synchronize do
19
+ @started_tasks.delete(task)
20
+ @finished_tasks.push(task)
21
+ @all_results[task] = result
22
+ end
23
+ end
24
+
25
+ def failed!(error)
26
+ @error = error
27
+ end
28
+
29
+ def succeeded?
30
+ @error.nil? && @started_tasks.empty?
31
+ end
32
+ end
@@ -4,6 +4,7 @@ class KuberKit::Actions::ConfigurationLoader
4
4
  "core.image_store",
5
5
  "core.service_store",
6
6
  "core.configuration_store",
7
+ "tools.workdir_detector",
7
8
  "artifacts_sync.artifacts_updater",
8
9
  "shell.local_shell",
9
10
  "ui",
@@ -12,7 +13,7 @@ class KuberKit::Actions::ConfigurationLoader
12
13
 
13
14
  Contract Hash => Any
14
15
  def call(options)
15
- root_path = options[:path] || File.join(Dir.pwd, configs.kuber_kit_dirname)
16
+ root_path = workdir_detector.call(options)
16
17
  images_path = options[:images_path] || File.join(root_path, configs.images_dirname)
17
18
  services_path = options[:services_path] || File.join(root_path, configs.services_dirname)
18
19
  infra_path = options[:infra_path] || File.join(root_path, configs.infra_dirname)
@@ -10,38 +10,40 @@ class KuberKit::Actions::ImageCompiler
10
10
 
11
11
  Contract ArrayOf[Symbol], Hash => Any
12
12
  def call(image_names, options)
13
+ compilation_result = KuberKit::Actions::ActionResult.new()
14
+
13
15
  build_id = generate_build_id
14
16
  build_server_pool = build_server_pool_factory.create()
15
17
 
16
- compiled_images = []
17
- compilation_result = {}
18
18
  image_dependency_resolver.each_with_deps(image_names) do |dep_image_names|
19
19
  ui.print_debug("ImageCompiler", "Scheduling to compile: #{dep_image_names.inspect}. Limit: #{configs.compile_simultaneous_limit}")
20
- result = compile_simultaneously(dep_image_names, build_id, build_server_pool)
21
- compiled_images += dep_image_names
22
- compilation_result = compilation_result.merge(result)
20
+
21
+ if compilation_result.succeeded?
22
+ compile_simultaneously(dep_image_names, build_id, build_server_pool, compilation_result)
23
+ end
23
24
  end
24
25
 
25
26
  build_server_pool.disconnect_all
26
27
 
27
- { images: compiled_images, compilation: compilation_result }
28
+ compilation_result
28
29
  rescue KuberKit::Error => e
29
30
  ui.print_error("Error", e.message)
30
31
 
32
+ compilation_result.failed!(e.message)
33
+
31
34
  false
32
35
  end
33
36
 
34
37
  private
35
- def compile_simultaneously(image_names, build_id, build_server_pool)
38
+ def compile_simultaneously(image_names, build_id, build_server_pool, compilation_result)
36
39
  task_group = ui.create_task_group
37
- compiler_result = {}
38
40
  image_names.map do |image_name|
39
41
 
40
42
  ui.print_debug("ImageCompiler", "Started compiling: #{image_name.to_s.green}")
41
43
  task_group.add("Compiling #{image_name.to_s.yellow}") do |task|
42
- shell = build_server_pool.get_shell
43
-
44
- compiler_result[image_name] = image_compiler.call(shell, image_name, build_id)
44
+ compilation_result.start_task(image_name)
45
+ image_result = compile_one(image_name, build_id, build_server_pool)
46
+ compilation_result.finish_task(image_name, image_result)
45
47
 
46
48
  task.update_title("Compiled #{image_name.to_s.green}")
47
49
  ui.print_debug("ImageCompiler", "Finished compiling: #{image_name}")
@@ -49,7 +51,11 @@ class KuberKit::Actions::ImageCompiler
49
51
 
50
52
  end
51
53
  task_group.wait
52
- compiler_result
54
+ end
55
+
56
+ def compile_one(image_name, build_id, build_server_pool)
57
+ shell = build_server_pool.get_shell
58
+ image_compiler.call(shell, image_name, build_id)
53
59
  end
54
60
 
55
61
  def generate_build_id
@@ -3,6 +3,7 @@ class KuberKit::Actions::ServiceDeployer
3
3
  "actions.image_compiler",
4
4
  "service_deployer.service_list_resolver",
5
5
  "service_deployer.service_dependency_resolver",
6
+ "service_deployer.deployment_options_selector",
6
7
  "core.service_store",
7
8
  "shell.local_shell",
8
9
  "tools.process_cleaner",
@@ -19,13 +20,13 @@ class KuberKit::Actions::ServiceDeployer
19
20
  require_confirmation: Maybe[Bool],
20
21
  ] => Any
21
22
  def call(services:, tags:, skip_services: nil, skip_compile: false, require_confirmation: false)
23
+ deployment_result = KuberKit::Actions::ActionResult.new()
22
24
  current_configuration = KuberKit.current_configuration
23
25
 
24
26
  if services.empty? && tags.empty?
25
- services, tags = show_tags_selection
27
+ services, tags = deployment_options_selector.call()
26
28
  end
27
29
 
28
-
29
30
  disabled_services = current_configuration.disabled_services.map(&:to_s)
30
31
  disabled_services += skip_services if skip_services
31
32
 
@@ -44,54 +45,50 @@ class KuberKit::Actions::ServiceDeployer
44
45
  return false
45
46
  end
46
47
 
47
- services_list = all_service_names.map(&:to_s).map(&:yellow).join(", ")
48
- ui.print_info "ServiceDeployer", "The following services will be deployed: #{services_list}"
49
-
50
- if require_confirmation
51
- result = ui.prompt("Please confirm to continue deployment", ["confirm".green, "cancel".red])
52
- return false unless ["confirm".green, "confirm", "yes"].include?(result)
53
- end
54
-
55
- services = all_service_names.map do |service_name|
56
- service_store.get_service(service_name.to_sym)
48
+ unless allow_deployment?(require_confirmation: require_confirmation, service_names: all_service_names)
49
+ return false
57
50
  end
58
51
 
59
- images_names = services.map(&:images).flatten.uniq
60
-
52
+ # Compile images for all services and dependencies
53
+ images_names = get_image_names(service_names: all_service_names)
61
54
  unless skip_compile
62
- compile_result = compile_images(images_names)
63
- return false unless compile_result
55
+ compilation_result = compile_images(images_names)
56
+
57
+ return false unless compilation_result && compilation_result.succeeded?
64
58
  end
65
59
 
66
- deployed_services = []
67
- deployment_result = {}
68
60
  service_dependency_resolver.each_with_deps(service_names) do |dep_service_names|
69
61
  ui.print_debug("ServiceDeployer", "Scheduling to compile: #{dep_service_names.inspect}. Limit: #{configs.deploy_simultaneous_limit}")
70
- result = deploy_simultaneously(dep_service_names)
71
- deployed_services += dep_service_names
72
- deployment_result = deployment_result.merge(result)
62
+
63
+ if deployment_result.succeeded?
64
+ deploy_simultaneously(dep_service_names, deployment_result)
65
+ end
73
66
  end
74
67
 
75
- { services: all_service_names, deployment: deployment_result }
68
+ deployment_result
76
69
  rescue KuberKit::Error => e
77
70
  ui.print_error("Error", e.message)
78
71
 
72
+ deployment_result.failed!(e.message)
73
+
79
74
  false
80
75
  rescue Interrupt => e
81
76
  process_cleaner.clean
77
+
78
+ false
82
79
  end
83
80
 
84
81
  private
85
- def deploy_simultaneously(service_names)
82
+ def deploy_simultaneously(service_names, deployment_result)
86
83
  task_group = ui.create_task_group
87
84
 
88
- deployer_result = {}
89
-
90
85
  service_names.each do |service_name|
91
86
 
92
87
  ui.print_debug("ServiceDeployer", "Started deploying: #{service_name.to_s.green}")
93
88
  task_group.add("Deploying #{service_name.to_s.yellow}") do |task|
94
- deployer_result[service_name] = service_deployer.call(local_shell, service_name.to_sym)
89
+ deployment_result.start_task(service_name)
90
+ service_result = service_deployer.call(local_shell, service_name.to_sym)
91
+ deployment_result.finish_task(service_name, service_result)
95
92
 
96
93
  task.update_title("Deployed #{service_name.to_s.green}")
97
94
  ui.print_debug("ServiceDeployer", "Finished deploying: #{service_name.to_s.green}")
@@ -99,55 +96,30 @@ class KuberKit::Actions::ServiceDeployer
99
96
  end
100
97
 
101
98
  task_group.wait
102
-
103
- deployer_result
104
99
  end
105
100
 
106
101
  def compile_images(images_names)
107
- return true if images_names.empty?
102
+ return KuberKit::Actions::ActionResult.new if images_names.empty?
108
103
  image_compiler.call(images_names, {})
109
104
  end
110
105
 
111
- def show_tags_selection()
112
- specific_service_option = "deploy specific service"
113
- all_services_option = "deploy all services"
114
-
115
- tags = [specific_service_option, all_services_option]
116
- tags += service_store
117
- .all_definitions
118
- .values
119
- .map(&:to_service_attrs)
120
- .map(&:tags)
121
- .flatten
122
- .uniq
123
- .sort
124
- .map(&:to_s)
125
-
126
- selected_tag = ui.prompt("Please select which tag to deploy", tags)
127
-
128
- if selected_tag == specific_service_option
129
- show_service_selection
130
- elsif selected_tag == all_services_option
131
- [["*"], []]
132
- else
133
- [[], [selected_tag]]
106
+ def get_image_names(service_names:)
107
+ services = service_names.map do |service_name|
108
+ service_store.get_service(service_name.to_sym)
134
109
  end
110
+
111
+ services.map(&:images).flatten.uniq
135
112
  end
136
113
 
137
- def show_service_selection()
138
- services = service_store
139
- .all_definitions
140
- .values
141
- .map(&:service_name)
142
- .uniq
143
- .sort
144
- .map(&:to_s)
145
-
146
- if services.empty?
147
- return [[], []]
114
+ def allow_deployment?(require_confirmation:, service_names:)
115
+ services_list = service_names.map(&:to_s).map(&:yellow).join(", ")
116
+ ui.print_info "ServiceDeployer", "The following services will be deployed: #{services_list}"
117
+
118
+ unless require_confirmation
119
+ return true
148
120
  end
149
121
 
150
- selected_service = ui.prompt("Please select which service to deploy", services)
151
- [[selected_service], []]
122
+ result = ui.prompt("Please confirm to continue deployment", ["confirm".green, "cancel".red])
123
+ return ["confirm".green, "confirm", "yes"].include?(result)
152
124
  end
153
125
  end
data/lib/kuber_kit/cli.rb CHANGED
@@ -10,6 +10,7 @@ class KuberKit::CLI < Thor
10
10
  class_option :ui, :type => :string, :desc => "UI mode (interactive|debug|simple)"
11
11
  class_option :debug, :type => :boolean, aliases: ["-d"]
12
12
  class_option :configuration, :type => :string, aliases: ["-C"]
13
+ class_option :user, :type => :string, aliases: ["-u"]
13
14
 
14
15
  desc "compile IMAGE_NAMES", "Compile image with IMAGE_NAMES (comma-separated)"
15
16
  def compile(image_names_str)
@@ -19,12 +20,15 @@ class KuberKit::CLI < Thor
19
20
  image_names = image_names_str.split(",").map(&:strip).map(&:to_sym)
20
21
 
21
22
  if KuberKit::Container['actions.configuration_loader'].call(options)
22
- result = KuberKit::Container['actions.image_compiler'].call(image_names, options)
23
+ action_result = KuberKit::Container['actions.image_compiler'].call(image_names, options)
23
24
  end
24
25
 
25
- if result
26
+ if action_result && action_result.succeeded?
26
27
  time = (Time.now.to_i - started_at)
27
- print_result("Image compilation finished! (#{time}s)", result: result)
28
+ print_result("Image compilation finished! (#{time}s)", result: {
29
+ images: action_result.finished_tasks,
30
+ compilation: action_result.all_results
31
+ })
28
32
  else
29
33
  exit 1
30
34
  end
@@ -44,7 +48,7 @@ class KuberKit::CLI < Thor
44
48
  KuberKit.current_configuration.deployer_require_confirimation ||
45
49
  false
46
50
  started_at = Time.now.to_i
47
- result = KuberKit::Container['actions.service_deployer'].call(
51
+ action_result = KuberKit::Container['actions.service_deployer'].call(
48
52
  services: (options[:services] || []).flatten.uniq,
49
53
  tags: (options[:tags] || []).flatten.uniq,
50
54
  skip_services: (options[:skip_services] || []).flatten.uniq,
@@ -53,9 +57,12 @@ class KuberKit::CLI < Thor
53
57
  )
54
58
  end
55
59
 
56
- if result
60
+ if action_result && action_result.succeeded?
57
61
  time = (Time.now.to_i - started_at)
58
- print_result("Service deployment finished! (#{time}s)", result: result)
62
+ print_result("Service deployment finished! (#{time}s)", result: {
63
+ services: action_result.finished_tasks,
64
+ deployment: action_result.all_results
65
+ })
59
66
  else
60
67
  exit 1
61
68
  end
@@ -178,8 +185,12 @@ class KuberKit::CLI < Thor
178
185
  KuberKit.set_ui_mode(options[:ui].to_sym)
179
186
  end
180
187
 
188
+ if options[:user]
189
+ KuberKit.set_user(options[:user])
190
+ end
191
+
181
192
  # We should load config before loading any bean, to make sure that bean won't be built with default config
182
- root_path = options[:path] || File.join(Dir.pwd, KuberKit::Container['configs'].kuber_kit_dirname)
193
+ root_path = KuberKit::Container['tools.workdir_detector'].call(options)
183
194
  config_file_path = File.join(root_path, APP_CONFIG_FILENAME)
184
195
  if File.exists?(config_file_path)
185
196
  require config_file_path
@@ -189,21 +200,4 @@ class KuberKit::CLI < Thor
189
200
  def print_result(message, data = {})
190
201
  KuberKit::Container['ui'].print_result(message, data)
191
202
  end
192
-
193
- def cleanup_processes
194
- # Stop all threads
195
- Thread.list.each do |t|
196
- t.abort_on_exception = false
197
- t.report_on_exception = false
198
- Thread.kill(t) if t != Thread.current
199
- end
200
-
201
- # Find all system calls
202
- child_pids_raw = `ps auxww | grep '[K]IT=#{Process.pid}' | awk '{print $2}'`
203
- child_pids = child_pids_raw.to_s.split("\n").reject(&:empty?)
204
- child_pids.each do |pid|
205
- puts "Killing child process: #{pid}"
206
- Process.kill("SIGHUP", pid.to_i)
207
- end
208
- end
209
203
  end
@@ -121,6 +121,10 @@ class KuberKit::Container
121
121
  KuberKit::Core::ContextHelper::ContextHelperFactory.new
122
122
  end
123
123
 
124
+ register "tools.build_dir_cleaner" do
125
+ KuberKit::Tools::BuildDirCleaner.new
126
+ end
127
+
124
128
  register "tools.file_presence_checker" do
125
129
  KuberKit::Tools::FilePresenceChecker.new
126
130
  end
@@ -137,6 +141,10 @@ class KuberKit::Container
137
141
  KuberKit::Tools::ProcessCleaner.new
138
142
  end
139
143
 
144
+ register "tools.workdir_detector" do
145
+ KuberKit::Tools::WorkdirDetector.new
146
+ end
147
+
140
148
  register "shell.bash_commands" do
141
149
  KuberKit::Shell::Commands::BashCommands.new
142
150
  end
@@ -269,6 +277,10 @@ class KuberKit::Container
269
277
  KuberKit::ServiceDeployer::Deployer.new
270
278
  end
271
279
 
280
+ register "service_deployer.deployment_options_selector" do
281
+ KuberKit::ServiceDeployer::DeploymentOptionsSelector.new
282
+ end
283
+
272
284
  register "service_deployer.service_list_resolver" do
273
285
  KuberKit::ServiceDeployer::ServiceListResolver.new
274
286
  end
@@ -2,12 +2,15 @@ class KuberKit::ImageCompiler::ActionHandler
2
2
  include KuberKit::Import[
3
3
  "image_compiler.compiler",
4
4
  "core.image_store",
5
+ "tools.build_dir_cleaner",
5
6
  "configs",
6
7
  ]
7
8
 
8
9
  Contract KuberKit::Shell::AbstractShell, Symbol, String => Any
9
10
  def call(shell, image_name, build_id)
10
11
  image = image_store.get_image(image_name)
12
+
13
+ build_dir_cleaner.call(parent_dir: configs.image_compile_dir)
11
14
 
12
15
  compile_dir = generate_compile_dir(build_id: build_id)
13
16
 
@@ -0,0 +1,49 @@
1
+ class KuberKit::ServiceDeployer::DeploymentOptionsSelector
2
+ include KuberKit::Import[
3
+ "core.service_store",
4
+ "ui"
5
+ ]
6
+
7
+ OPTION_SPECIFIC_SERVICE = "deploy specific service".freeze
8
+ OPTION_ALL_SERVICES = "deploy all services"
9
+
10
+ def call()
11
+ tags = [OPTION_SPECIFIC_SERVICE, OPTION_ALL_SERVICES]
12
+ tags += service_store
13
+ .all_definitions
14
+ .values
15
+ .map(&:to_service_attrs)
16
+ .map(&:tags)
17
+ .flatten
18
+ .uniq
19
+ .sort
20
+ .map(&:to_s)
21
+
22
+ selected_tag = ui.prompt("Please select which tag to deploy", tags)
23
+
24
+ if selected_tag == OPTION_SPECIFIC_SERVICE
25
+ show_service_selection
26
+ elsif selected_tag == OPTION_ALL_SERVICES
27
+ [["*"], []]
28
+ else
29
+ [[], [selected_tag]]
30
+ end
31
+ end
32
+
33
+ def show_service_selection()
34
+ services = service_store
35
+ .all_definitions
36
+ .values
37
+ .map(&:service_name)
38
+ .uniq
39
+ .sort
40
+ .map(&:to_s)
41
+
42
+ if services.empty?
43
+ return [[], []]
44
+ end
45
+
46
+ selected_service = ui.prompt("Please select which service to deploy", services)
47
+ [[selected_service], []]
48
+ end
49
+ end
@@ -20,7 +20,8 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
20
20
  :networks,
21
21
  :expose,
22
22
  :publish,
23
- :env_file_names
23
+ :env_file_names,
24
+ :env_vars
24
25
  ]
25
26
 
26
27
  Contract KuberKit::Shell::AbstractShell, KuberKit::Core::Service => Any
@@ -44,6 +45,7 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
44
45
 
45
46
  env_file_names = strategy_options.fetch(:env_file_names, [])
46
47
  env_files = prepare_env_files(shell, env_file_names)
48
+ env_vars = strategy_options.fetch(:env_vars, {})
47
49
 
48
50
  image_name = strategy_options.fetch(:image_name, nil)
49
51
  if image_name.nil?
@@ -84,6 +86,9 @@ class KuberKit::ServiceDeployer::Strategies::Docker < KuberKit::ServiceDeployer:
84
86
  Array(env_files).each do |env_file|
85
87
  custom_args << "--env-file #{env_file}"
86
88
  end
89
+ env_vars.each do |key, value|
90
+ custom_args << "--env #{key}=#{value}"
91
+ end
87
92
 
88
93
  docker_commands.run(
89
94
  shell, image.remote_registry_url,
@@ -100,6 +100,18 @@ class KuberKit::Shell::LocalShell < KuberKit::Shell::AbstractShell
100
100
  end
101
101
  end
102
102
 
103
+ def list_dirs(path)
104
+ command = %Q{find -L #{path} -type f}
105
+ command += " -name '#{name}'" if name
106
+ exec!(command).split(/[\r\n]+/)
107
+ rescue => e
108
+ if e.message.include?("No such file or directory")
109
+ raise DirNotFoundError.new("Dir not found: #{path}")
110
+ else
111
+ raise e
112
+ end
113
+ end
114
+
103
115
  def wrap_command_with_pid(command)
104
116
  "KIT=#{Process.pid} #{command}"
105
117
  end
@@ -0,0 +1,26 @@
1
+ class KuberKit::Tools::BuildDirCleaner
2
+ include KuberKit::Import[
3
+ "shell.bash_commands",
4
+ "shell.local_shell",
5
+ ]
6
+
7
+ KEEP_DIRS_COUNT = 10
8
+
9
+ def call(parent_dir:)
10
+ dirs_to_delete = get_ancient_builds_dirs(parent_dir: parent_dir)
11
+
12
+ dirs_to_delete.each do |dir|
13
+ bash_commands.rm_rf(local_shell, dir)
14
+ end
15
+ end
16
+
17
+ private
18
+ def get_ancient_builds_dirs(parent_dir:)
19
+ all_dirs = Dir.glob("#{parent_dir}/*")
20
+ skip_dirs = all_dirs
21
+ .sort_by{ |f| File.ctime(f) }
22
+ .reverse[0...KEEP_DIRS_COUNT]
23
+
24
+ all_dirs - skip_dirs
25
+ end
26
+ end
@@ -10,16 +10,17 @@ class KuberKit::Tools::LoggerFactory
10
10
  Logger::FATAL => String::Colors::PURPLE,
11
11
  }
12
12
 
13
+ MAX_LOGS_TO_KEEP = 3
14
+ MAX_LOG_FILE_SIZE = 512000
15
+
13
16
  include KuberKit::Import[
14
17
  "configs",
15
18
  ]
16
19
 
17
- def create(stdout = nil, level = nil)
18
- if !stdout
19
- prepare_log_file(configs.log_file_path)
20
- end
20
+ def create(level: nil)
21
+ prepare_log_file(configs.log_file_path)
21
22
 
22
- logger = Logger.new(stdout || configs.log_file_path)
23
+ logger = Logger.new(configs.log_file_path, MAX_LOGS_TO_KEEP, MAX_LOG_FILE_SIZE)
23
24
 
24
25
  logger.level = level || Logger::DEBUG
25
26
 
@@ -0,0 +1,33 @@
1
+ class KuberKit::Tools::WorkdirDetector
2
+ include KuberKit::Import[
3
+ "configs",
4
+ "tools.file_presence_checker"
5
+ ]
6
+
7
+ def call(options, current_dir: nil)
8
+ current_dir ||= Dir.pwd
9
+ default_dir = File.join(current_dir, configs.kuber_kit_dirname)
10
+ workdir_path = options[:path] || ENV['KUBER_KIT_PATH'] || default_dir
11
+
12
+ unless file_presence_checker.dir_exists?(workdir_path)
13
+ workdir_in_ancestors = find_workdir_in_ancestors(current_dir)
14
+ workdir_path = workdir_in_ancestors if workdir_in_ancestors
15
+ end
16
+
17
+ workdir_path
18
+ end
19
+
20
+ private
21
+ def find_workdir_in_ancestors(dir)
22
+ if dir == "/"
23
+ return nil
24
+ end
25
+
26
+ workdir_path = File.join(dir, configs.kuber_kit_dirname)
27
+ if file_presence_checker.dir_exists?(workdir_path)
28
+ return workdir_path
29
+ end
30
+
31
+ find_workdir_in_ancestors(File.dirname(dir))
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module KuberKit
2
- VERSION = "0.5.6"
2
+ VERSION = "0.6.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kuber_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iskander Khaziev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-11 00:00:00.000000000 Z
11
+ date: 2021-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: contracts-lite
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: dry-auto_inject
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 0.7.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 0.7.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: thor
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: dry-container
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.7.2
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.7.2
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: bundler
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -184,6 +198,8 @@ files:
184
198
  - example/images/app_sources/Dockerfile
185
199
  - example/images/app_sources/build_context/source.rb
186
200
  - example/images/app_sources/image.rb
201
+ - example/images/failing_app/Dockerfile
202
+ - example/images/failing_app/image.rb
187
203
  - example/images/ruby/Dockerfile
188
204
  - example/images/ruby/image.rb
189
205
  - example/images/ruby_app/Dockerfile
@@ -200,9 +216,11 @@ files:
200
216
  - example/services/compose_app.rb
201
217
  - example/services/docker_app.rb
202
218
  - example/services/env_file.rb
219
+ - example/services/failing_app.rb
203
220
  - example/services/ruby_app.rb
204
221
  - kuber_kit.gemspec
205
222
  - lib/kuber_kit.rb
223
+ - lib/kuber_kit/actions/action_result.rb
206
224
  - lib/kuber_kit/actions/configuration_loader.rb
207
225
  - lib/kuber_kit/actions/env_file_reader.rb
208
226
  - lib/kuber_kit/actions/image_compiler.rb
@@ -288,6 +306,7 @@ files:
288
306
  - lib/kuber_kit/preprocessing/text_preprocessor.rb
289
307
  - lib/kuber_kit/service_deployer/action_handler.rb
290
308
  - lib/kuber_kit/service_deployer/deployer.rb
309
+ - lib/kuber_kit/service_deployer/deployment_options_selector.rb
291
310
  - lib/kuber_kit/service_deployer/service_dependency_resolver.rb
292
311
  - lib/kuber_kit/service_deployer/service_list_resolver.rb
293
312
  - lib/kuber_kit/service_deployer/strategies/abstract.rb
@@ -313,9 +332,11 @@ files:
313
332
  - lib/kuber_kit/template_reader/reader.rb
314
333
  - lib/kuber_kit/template_reader/strategies/abstract.rb
315
334
  - lib/kuber_kit/template_reader/strategies/artifact_file.rb
335
+ - lib/kuber_kit/tools/build_dir_cleaner.rb
316
336
  - lib/kuber_kit/tools/file_presence_checker.rb
317
337
  - lib/kuber_kit/tools/logger_factory.rb
318
338
  - lib/kuber_kit/tools/process_cleaner.rb
339
+ - lib/kuber_kit/tools/workdir_detector.rb
319
340
  - lib/kuber_kit/ui.rb
320
341
  - lib/kuber_kit/ui/api.rb
321
342
  - lib/kuber_kit/ui/debug.rb