class Krane::Pod
Constants
- FAILED_PHASE_NAME
- TIMEOUT
- TRANSIENT_FAILURE_REASONS
Attributes
stream_logs[RW]
Public Class Methods
new(namespace:, context:, definition:, logger:, statsd_tags: nil, parent: nil, deploy_started_at: nil, stream_logs: false)
click to toggle source
Calls superclass method
Krane::KubernetesResource::new
# File lib/krane/kubernetes_resource/pod.rb, line 14 def initialize(namespace:, context:, definition:, logger:, statsd_tags: nil, parent: nil, deploy_started_at: nil, stream_logs: false) @parent = parent @deploy_started_at = deploy_started_at @containers = definition.fetch("spec", {}).fetch("containers", []).map { |c| Container.new(c) } unless @containers.present? logger.summary.add_paragraph("Rendered template content:\n#{definition.to_yaml}") raise FatalDeploymentError, "Template is missing required field spec.containers" end @containers += definition["spec"].fetch("initContainers", []).map { |c| Container.new(c, init_container: true) } @stream_logs = stream_logs super(namespace: namespace, context: context, definition: definition, logger: logger, statsd_tags: statsd_tags) end
Public Instance Methods
after_sync()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 42 def after_sync if @stream_logs logs.print_latest elsif unmanaged? && deploy_succeeded? logs.print_all end end
deploy_failed?()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 63 def deploy_failed? failure_message.present? end
deploy_succeeded?()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 55 def deploy_succeeded? if unmanaged? phase == "Succeeded" else phase == "Running" && ready? end end
failure_message()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 79 def failure_message doomed_containers = @containers.select(&:doomed?) if doomed_containers.present? container_problems = if unmanaged? "The following containers encountered errors:\n" else "The following containers are in a state that is unlikely to be recoverable:\n" end doomed_containers.each do |c| red_name = ColorizedString.new(c.name).red container_problems += "> #{red_name}: #{c.doom_reason}\n" end end "#{phase_failure_message} #{container_problems}".strip.presence end
fetch_debug_logs()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 95 def fetch_debug_logs logs.sync logs end
node_name()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 104 def node_name @instance_data.dig('spec', 'nodeName') end
print_debug_logs?()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 100 def print_debug_logs? exists? && !@stream_logs # don't print them a second time end
status()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 50 def status return phase if reason.blank? "#{phase} (Reason: #{reason})" end
sync(_cache)
click to toggle source
Calls superclass method
Krane::KubernetesResource#sync
# File lib/krane/kubernetes_resource/pod.rb, line 30 def sync(_cache) super raise_predates_deploy_error if exists? && unmanaged? && !deploy_started? if exists? logs.sync if unmanaged? update_container_statuses(@instance_data["status"]) else # reset @containers.each(&:reset_status) end end
timeout_message()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 67 def timeout_message if readiness_probe_failure? probe_failure_msgs = @containers.map(&:readiness_fail_reason).compact header = "The following containers have not passed their readiness probes on at least one pod:\n" header + probe_failure_msgs.join("\n") elsif failed_schedule_reason.present? "Pod could not be scheduled because #{failed_schedule_reason}" else STANDARD_TIMEOUT_MESSAGE end end
Private Instance Methods
failed_phase?()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 120 def failed_phase? phase == FAILED_PHASE_NAME end
failed_schedule_reason()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 110 def failed_schedule_reason if phase == "Pending" conditions = @instance_data.dig('status', 'conditions') || [] unschedulable = conditions.find do |condition| condition["type"] == "PodScheduled" && condition["status"] == "False" end unschedulable&.dig('message') end end
logs()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 143 def logs @logs ||= Krane::RemoteLogs.new( logger: @logger, parent_id: id, container_names: @containers.map(&:name), namespace: @namespace, context: @context ) end
phase()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 153 def phase @instance_data.dig("status", "phase") || "Unknown" end
phase_failure_message()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 129 def phase_failure_message if failed_phase? && !transient_failure_reason? return "Pod status: #{status}." end return unless unmanaged? if terminating? "Pod status: Terminating." elsif disappeared? "Pod status: Disappeared." end end
raise_predates_deploy_error()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 189 def raise_predates_deploy_error example_color = :green msg = <<-STRING.strip_heredoc Unmanaged pods like #{id} must have unique names on every deploy in order to work as intended. The recommended way to achieve this is to include "<%= deployment_id %>" in the pod's name, like this: #{ColorizedString.new('kind: Pod').colorize(example_color)} #{ColorizedString.new('metadata:').colorize(example_color)} #{ColorizedString.new("name: #{@name}-<%= deployment_id %>").colorize(example_color)} STRING @logger.summary.add_paragraph(msg) raise FatalDeploymentError, "#{id} existed before the deploy started" end
readiness_probe_failure?()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 161 def readiness_probe_failure? return false if ready? || unmanaged? return false if phase != "Running" @containers.any?(&:readiness_fail_reason) end
ready?()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 167 def ready? return false unless (status_data = @instance_data["status"]) ready_condition = status_data.fetch("conditions", []).find { |condition| condition["type"] == "Ready" } ready_condition.present? && (ready_condition["status"] == "True") end
reason()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 157 def reason @instance_data.dig('status', 'reason') end
transient_failure_reason?()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 124 def transient_failure_reason? return false if unmanaged? TRANSIENT_FAILURE_REASONS.include?(reason) end
unmanaged?()
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 185 def unmanaged? @parent.blank? end
update_container_statuses(status_data)
click to toggle source
# File lib/krane/kubernetes_resource/pod.rb, line 173 def update_container_statuses(status_data) @containers.each do |c| key = c.init_container? ? "initContainerStatuses" : "containerStatuses" if status_data.key?(key) data = status_data[key].find { |st| st["name"] == c.name } c.update_status(data) else c.reset_status end end end