helm_upgrade_logs 0.3.5 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,96 +1,97 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "open3"
5
- require "fileutils"
6
- $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "..", "lib")
7
- require "helm_upgrade_logs"
8
- UPGRADE_LOG_FOLDER = "helm_upgrade_logs"
9
-
10
- @release_name = ARGV.find { |arg| !arg.start_with?("-") }
11
- @namespace = namespace_from_args(ARGV)
12
-
13
- @helm_pid = Process.spawn "helm upgrade #{ARGV.join(" ")}"
14
-
15
- pods_before_upgrade = read_pods
16
- puts "[INFO] Pods before upgrade #{pods_before_upgrade}" if pods_before_upgrade.size.positive?
17
-
18
- event_pid = Process.spawn(add_ns("kubectl get events --watch-only=true"))
19
- service_pid = Process.spawn(add_ns("kubectl get services --watch-only=true"))
20
-
21
- wait_for_pod_to_log
22
-
23
- @pods = []
24
- @pod_pids = {}
25
-
26
- begin
27
- Process.waitpid(@helm_pid, Process::WNOHANG)
28
- rescue Errno::ECHILD
29
- Process.kill("KILL", event_pid)
30
- Process.kill("KILL", service_pid)
31
- raise HelmUpgradeLogs::Error, "Failed to find logs before helm finished"
32
- end
33
-
34
- FileUtils.mkdir_p(UPGRADE_LOG_FOLDER) if ENV["helm_upgrade_logs_error_msg"]
35
-
36
- while Process.waitpid(@helm_pid, Process::WNOHANG).nil?
37
- pods = read_pods - pods_before_upgrade
38
- if pods != @pods
39
- @pods = pods
40
- puts "[INFO] Pods: #{pods.join(",")}"
41
- # Could change this each to Parallel.each
42
- @pods.each do |pod|
43
- next unless @pod_pids[pod].nil?
44
-
45
- wait_for_specific_pod_to_log pod
46
- std_out_pid = Process.spawn(
47
- add_ns("kubectl logs #{pod} -f --all-containers --prefix --ignore-errors=true --timestamps=true")
48
- )
49
- @pod_pids[pod] = std_out_pid
50
- next unless ENV["helm_upgrade_logs_error_msg"]
51
-
52
- logfile_pid = Process.spawn(
53
- add_ns("kubectl logs #{pod} -f --all-containers --prefix --ignore-errors=true --timestamps=true"),
54
- out: "#{UPGRADE_LOG_FOLDER}/#{pod.gsub("/", "_")}.log"
55
- )
56
- @pod_pids["#{pod}_fileout"] = logfile_pid
57
- end
58
- end
59
- sleep 1
60
- end
61
- puts "[INFO] Cleaning up loggers after helm upgrade"
62
- helm_status = $CHILD_STATUS.exitstatus
63
- Process.kill("KILL", event_pid)
64
- Process.wait event_pid
65
- Process.kill("KILL", service_pid)
66
- Process.wait service_pid
67
-
68
- if ENV["helm_upgrade_logs_debug"] == "true"
69
- puts "[INFO] Log processes"
70
- puts @pod_pids
71
- end
72
- @pod_pids.each do |_pod, pid|
73
- puts "Terminating #{_pod} #{pid}" if ENV["helm_upgrade_logs_debug"] == "true"
74
- Process.kill("KILL", pid)
75
- Process.wait pid
76
- end
77
- puts `ps` if ENV["helm_upgrade_logs_debug"] == "true"
78
-
79
- if ENV["helm_upgrade_logs_error_msg"]
80
- pod_logs_files = Dir.glob("#{UPGRADE_LOG_FOLDER}/*.log")
81
- puts "Reading logs from #{pod_logs_files.count} pod logs" if ENV["helm_upgrade_logs_debug"] == "true"
82
- pod_logs_files.each do |log_file|
83
- lines = File.readlines log_file
84
- lines.each_with_index do |line, index|
85
- next unless line.include?(ENV["helm_upgrade_logs_error_msg"])
86
-
87
- msg = "Helm install error: #{line} from #{log_file} (Line #{index + 1})"
88
- if ENV["helm_upgrade_logs_ado_error"] == "true"
89
- puts "##vso[task.logissue type=error] #{msg}"
90
- else
91
- puts "[ERROR] #{msg}"
92
- end
93
- end
94
- end
95
- end
96
- exit helm_status
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "open3"
5
+ require "fileutils"
6
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "..", "lib")
7
+ require "helm_upgrade_logs"
8
+ UPGRADE_LOG_FOLDER = "helm_upgrade_logs"
9
+
10
+ @release_name = ARGV.find { |arg| !arg.start_with?("-") }
11
+ @namespace = namespace_from_args(ARGV)
12
+
13
+ @helm_pid = Process.spawn "helm upgrade #{ARGV.join(" ")}"
14
+
15
+ pods_before_upgrade = read_pods
16
+ puts "[INFO] Pods before upgrade #{pods_before_upgrade}" if pods_before_upgrade.size.positive?
17
+
18
+ event_pid = Process.spawn(add_ns("kubectl get events --watch-only=true"))
19
+ service_pid = Process.spawn(add_ns("kubectl get services --watch-only=true"))
20
+
21
+ wait_for_pod_to_log
22
+
23
+ @pods = []
24
+ @pod_pids = {}
25
+
26
+ begin
27
+ Process.waitpid(@helm_pid, Process::WNOHANG)
28
+ rescue Errno::ECHILD
29
+ Process.kill("KILL", event_pid)
30
+ Process.kill("KILL", service_pid)
31
+ raise HelmUpgradeLogs::Error, "Failed to find logs before helm finished"
32
+ end
33
+
34
+ FileUtils.mkdir_p(UPGRADE_LOG_FOLDER) if ENV["helm_upgrade_logs_error_msg"]
35
+
36
+ while Process.waitpid(@helm_pid, Process::WNOHANG).nil?
37
+ pods = read_pods - pods_before_upgrade
38
+ if pods != @pods
39
+ @pods = pods
40
+ puts "[INFO] Pods: #{pods.join(",")}"
41
+ # Could change this each to Parallel.each
42
+ @pods.each do |pod|
43
+ next unless @pod_pids[pod].nil?
44
+
45
+ wait_for_specific_pod_to_log pod
46
+ std_out_pid = Process.spawn(
47
+ add_ns("kubectl logs #{pod} -f --all-containers --prefix --ignore-errors=true --timestamps=true")
48
+ )
49
+ @pod_pids[pod] = std_out_pid
50
+ next unless ENV["helm_upgrade_logs_error_msg"]
51
+
52
+ logfile_pid = Process.spawn(
53
+ add_ns("kubectl logs #{pod} -f --all-containers --prefix --ignore-errors=true --timestamps=true"),
54
+ out: "#{UPGRADE_LOG_FOLDER}/#{pod.gsub("/", "_")}.log"
55
+ )
56
+ @pod_pids["#{pod}_fileout"] = logfile_pid
57
+ end
58
+ end
59
+ sleep 1
60
+ end
61
+ puts "[INFO] Cleaning up loggers after helm upgrade"
62
+ helm_status = $CHILD_STATUS.exitstatus
63
+ Process.kill("KILL", event_pid)
64
+ Process.wait event_pid
65
+ Process.kill("KILL", service_pid)
66
+ Process.wait service_pid
67
+
68
+ if ENV["helm_upgrade_logs_debug"] == "true"
69
+ puts "[INFO] Log processes"
70
+ puts @pod_pids
71
+ end
72
+ @pod_pids.each do |_pod, pid|
73
+ puts "Terminating #{_pod} #{pid}" if ENV["helm_upgrade_logs_debug"] == "true"
74
+ Process.kill("KILL", pid)
75
+ Process.wait pid
76
+ end
77
+ puts `ps` if ENV["helm_upgrade_logs_debug"] == "true"
78
+
79
+ if ENV["helm_upgrade_logs_error_msg"]
80
+ pod_logs_files = Dir.glob("#{UPGRADE_LOG_FOLDER}/*.log")
81
+ puts "Reading logs from #{pod_logs_files.count} pod logs" if ENV["helm_upgrade_logs_debug"] == "true"
82
+ error_messages = ENV["helm_upgrade_logs_error_msg"].split(",")
83
+ pod_logs_files.each do |log_file|
84
+ lines = File.readlines log_file
85
+ lines.each_with_index do |line, index|
86
+ next unless error_messages.any? { |error| line.include? error }
87
+
88
+ msg = "Helm install error: #{line} from #{log_file} (Line #{index + 1})"
89
+ if ENV["helm_upgrade_logs_ado_error"] == "true"
90
+ puts "##vso[task.logissue type=error] #{msg}"
91
+ else
92
+ puts "[ERROR] #{msg}"
93
+ end
94
+ end
95
+ end
96
+ end
97
+ exit helm_status
@@ -1,35 +1,35 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/helm_upgrade_logs/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "helm_upgrade_logs"
7
- spec.version = HelmUpgradeLogs::VERSION
8
- spec.authors = ["Samuel Garratt"]
9
- spec.email = ["samuel.garratt@sentify.co"]
10
-
11
- spec.summary = "Basic wrapper around helm and kubectl to allow easy debugging of a helm release."
12
- spec.description = "Basic wrapper around helm and kubectl to allow easy debugging of a helm release. All arguments after a usual helm upgrade are used as normal"
13
- spec.homepage = "https://gitlab.com/samuel-garratt/helm_upgrade_logs"
14
- spec.license = "MIT"
15
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
-
17
- spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = "https://gitlab.com/samuel-garratt/helm_upgrade_logs"
19
- spec.metadata["changelog_uri"] = "https://gitlab.com/samuel-garratt/helm_upgrade_logs/CHANGELOG.md"
20
-
21
- # Specify which files should be added to the gem when it is released.
22
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:spec)/}) }
25
- end
26
- spec.bindir = "exe"
27
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
- spec.require_paths = ["lib"]
29
-
30
- # Uncomment to register a new dependency of your gem
31
- # spec.add_dependency "example-gem", "~> 1.0"
32
-
33
- # For more information and examples about making a new gem, checkout our
34
- # guide at: https://bundler.io/guides/creating_gem.html
35
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/helm_upgrade_logs/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "helm_upgrade_logs"
7
+ spec.version = HelmUpgradeLogs::VERSION
8
+ spec.authors = ["Samuel Garratt"]
9
+ spec.email = ["samuel.garratt@sentify.co"]
10
+
11
+ spec.summary = "Basic wrapper around helm and kubectl to allow easy debugging of a helm release."
12
+ spec.description = "Basic wrapper around helm and kubectl to allow easy debugging of a helm release. All arguments after a usual helm upgrade are used as normal"
13
+ spec.homepage = "https://gitlab.com/samuel-garratt/helm_upgrade_logs"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://gitlab.com/samuel-garratt/helm_upgrade_logs"
19
+ spec.metadata["changelog_uri"] = "https://gitlab.com/samuel-garratt/helm_upgrade_logs/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:spec)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ # Uncomment to register a new dependency of your gem
31
+ # spec.add_dependency "example-gem", "~> 1.0"
32
+
33
+ # For more information and examples about making a new gem, checkout our
34
+ # guide at: https://bundler.io/guides/creating_gem.html
35
+ end
@@ -1,6 +1,6 @@
1
- # frozen_string_literal: true
2
-
3
- module HelmUpgradeLogs
4
- # @return [String] Version of helm upgrade logs
5
- VERSION = "0.3.5"
6
- end
1
+ # frozen_string_literal: true
2
+
3
+ module HelmUpgradeLogs
4
+ # @return [String] Version of helm upgrade logs
5
+ VERSION = "0.3.6"
6
+ end
@@ -1,81 +1,81 @@
1
- # frozen_string_literal: true
2
-
3
- require "open3"
4
- require 'English'
5
- require_relative "helm_upgrade_logs/version"
6
-
7
- ENV["helm_upgrade_logs_log_start"] ||= "90"
8
- ENV["helm_upgrade_logs_pod_start"] ||= "35"
9
-
10
- # Approach not ideal as it will for all containers to be ready and want to stream logs before that
11
- def wait_for_container_ready
12
- wait_pid = Process.spawn 'kubectl wait --for=condition=ContainersReady pod --selector "app.kubernetes.io/managed-by=Helm" --timeout=30s'
13
- Process.wait wait_pid
14
- end
15
-
16
- # Wait for very first pods with logs to be present
17
- # Not ideal due to https://github.com/kubernetes/kubernetes/issues/28746
18
- def wait_for_pod_to_log
19
- ENV["helm_upgrade_logs_log_start"].to_i.times do |i|
20
- break unless Process.waitpid(@helm_pid, Process::WNOHANG).nil?
21
-
22
- sleep 1
23
- stdout, stderr, = Open3.capture3(add_ns("kubectl logs -lapp.kubernetes.io/instance=#{@release_name}"))
24
- if stderr.empty? && !stdout.strip.empty?
25
- puts "[INFO] Pods with logs found"
26
- break
27
- elsif (i % 3).zero?
28
- puts "[INFO] Waiting for pod logs: #{stderr}"
29
- end
30
- end
31
- end
32
-
33
- # Wait for logs from a specific pod
34
- def wait_for_specific_pod_to_log(pod_name)
35
- ENV["helm_upgrade_logs_pod_start"].to_i.times do |i|
36
- sleep 1
37
- stdout, stderr, = Open3.capture3(add_ns("kubectl logs #{pod_name}"))
38
- if stderr.empty? && !stdout.strip.empty?
39
- puts "[INFO] Pod #{pod_name} with logs found"
40
- break
41
- elsif i.even?
42
- puts "[INFO] Waiting for pod #{pod_name} logs: #{stderr}"
43
- end
44
- end
45
- end
46
-
47
- # Get pods
48
- def read_pods
49
- stdout, stderr, = Open3.capture3(add_ns("kubectl get pods -lapp.kubernetes.io/instance=#{@release_name} -o name"))
50
- if stderr.empty?
51
- stdout.lines.collect(&:strip)
52
- else
53
- []
54
- end
55
- end
56
-
57
- # @param [Array] args
58
- def namespace_from_args(args)
59
- match_index = args.find_index { |arg| %w[-n --namespace].include?(arg) }
60
- return nil unless match_index
61
-
62
- args[match_index + 1]
63
- end
64
-
65
- # Add namespace to kube query
66
- def add_ns(kube_query)
67
- kube_query += " -n #{@namespace}" if @namespace
68
- kube_query
69
- end
70
-
71
- # Add namespace to kube query
72
- def add_ns_file(kube_query, pod)
73
- kube_query += " -n #{@namespace}" if @namespace
74
- kube_query += "> #{pod}.log"
75
- kube_query
76
- end
77
-
78
- module HelmUpgradeLogs
79
- class Error < StandardError; end
80
- # Your code goes here...
81
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require 'English'
5
+ require_relative "helm_upgrade_logs/version"
6
+
7
+ ENV["helm_upgrade_logs_log_start"] ||= "90"
8
+ ENV["helm_upgrade_logs_pod_start"] ||= "35"
9
+
10
+ # Approach not ideal as it will for all containers to be ready and want to stream logs before that
11
+ def wait_for_container_ready
12
+ wait_pid = Process.spawn 'kubectl wait --for=condition=ContainersReady pod --selector "app.kubernetes.io/managed-by=Helm" --timeout=30s'
13
+ Process.wait wait_pid
14
+ end
15
+
16
+ # Wait for very first pods with logs to be present
17
+ # Not ideal due to https://github.com/kubernetes/kubernetes/issues/28746
18
+ def wait_for_pod_to_log
19
+ ENV["helm_upgrade_logs_log_start"].to_i.times do |i|
20
+ break unless Process.waitpid(@helm_pid, Process::WNOHANG).nil?
21
+
22
+ sleep 1
23
+ stdout, stderr, = Open3.capture3(add_ns("kubectl logs -lapp.kubernetes.io/instance=#{@release_name}"))
24
+ if stderr.empty? && !stdout.strip.empty?
25
+ puts "[INFO] Pods with logs found"
26
+ break
27
+ elsif (i % 3).zero?
28
+ puts "[INFO] Waiting for pod logs: #{stderr}"
29
+ end
30
+ end
31
+ end
32
+
33
+ # Wait for logs from a specific pod
34
+ def wait_for_specific_pod_to_log(pod_name)
35
+ ENV["helm_upgrade_logs_pod_start"].to_i.times do |i|
36
+ sleep 1
37
+ stdout, stderr, = Open3.capture3(add_ns("kubectl logs #{pod_name}"))
38
+ if stderr.empty? && !stdout.strip.empty?
39
+ puts "[INFO] Pod #{pod_name} with logs found"
40
+ break
41
+ elsif i.even?
42
+ puts "[INFO] Waiting for pod #{pod_name} logs: #{stderr}"
43
+ end
44
+ end
45
+ end
46
+
47
+ # Get pods
48
+ def read_pods
49
+ stdout, stderr, = Open3.capture3(add_ns("kubectl get pods -lapp.kubernetes.io/instance=#{@release_name} -o name"))
50
+ if stderr.empty?
51
+ stdout.lines.collect(&:strip)
52
+ else
53
+ []
54
+ end
55
+ end
56
+
57
+ # @param [Array] args
58
+ def namespace_from_args(args)
59
+ match_index = args.find_index { |arg| %w[-n --namespace].include?(arg) }
60
+ return nil unless match_index
61
+
62
+ args[match_index + 1]
63
+ end
64
+
65
+ # Add namespace to kube query
66
+ def add_ns(kube_query)
67
+ kube_query += " -n #{@namespace}" if @namespace
68
+ kube_query
69
+ end
70
+
71
+ # Add namespace to kube query
72
+ def add_ns_file(kube_query, pod)
73
+ kube_query += " -n #{@namespace}" if @namespace
74
+ kube_query += "> #{pod}.log"
75
+ kube_query
76
+ end
77
+
78
+ module HelmUpgradeLogs
79
+ class Error < StandardError; end
80
+ # Your code goes here...
81
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: helm_upgrade_logs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Garratt
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-30 00:00:00.000000000 Z
11
+ date: 2022-08-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Basic wrapper around helm and kubectl to allow easy debugging of a helm
14
14
  release. All arguments after a usual helm upgrade are used as normal
@@ -66,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
68
  requirements: []
69
- rubygems_version: 3.2.3
69
+ rubygems_version: 3.2.32
70
70
  signing_key:
71
71
  specification_version: 4
72
72
  summary: Basic wrapper around helm and kubectl to allow easy debugging of a helm release.