helm_upgrade_logs 0.3.3 → 0.3.6

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.
@@ -1,86 +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
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
- logfile_pid = Process.spawn(
50
- add_ns("kubectl logs #{pod} -f --all-containers --prefix --ignore-errors=true --timestamps=true"),
51
- out: "#{UPGRADE_LOG_FOLDER}/#{pod.gsub("/", "_")}.log"
52
- )
53
- @pod_pids["#{pod}_stdout"] = std_out_pid
54
- @pod_pids["#{pod}_fileout"] = logfile_pid
55
- end
56
- end
57
- sleep 1
58
- end
59
- puts "[INFO] Cleaning up loggers after helm upgrade"
60
- helm_status = $CHILD_STATUS.exitstatus
61
- Process.kill("KILL", event_pid)
62
- Process.kill("KILL", service_pid)
63
- puts @pod_pids if ENV["helm_upgrade_logs_debug"] == "true"
64
- @pod_pids.each do |_pod, pid|
65
- puts "Terminating #{_pod} #{pid}" if ENV["helm_upgrade_logs_debug"] == "true"
66
- Process.kill("KILL", pid)
67
- end
68
-
69
- if ENV["helm_upgrade_logs_error_msg"]
70
- pod_logs_files = Dir.glob("#{UPGRADE_LOG_FOLDER}/*.log")
71
- puts "Reading logs from #{pod_logs_files.count} pod logs" if ENV["helm_upgrade_logs_debug"] == "true"
72
- pod_logs_files.each do |log_file|
73
- lines = File.readlines log_file
74
- lines.each_with_index do |line, index|
75
- next unless line.include?(ENV["helm_upgrade_logs_error_msg"])
76
-
77
- msg = "Helm install error: #{line} from #{log_file} (Line #{index + 1})"
78
- if ENV["helm_upgrade_logs_ado_error"] == "true"
79
- puts "##vso[task.logissue type=error] #{msg}"
80
- else
81
- puts "[ERROR] #{msg}"
82
- end
83
- end
84
- end
85
- end
86
- 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.3"
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.3
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-29 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.