class Krane::RestartTask
Restart the pods in one or more deployments
Constants
- ANNOTATION
- HTTP_OK_RANGE
Attributes
task_config[R]
Public Class Methods
new(context:, namespace:, logger: nil, global_timeout: nil, kubeconfig: nil)
click to toggle source
Initializes the restart task
@param context [String] Kubernetes context / cluster (required) @param namespace [String] Kubernetes namespace (required) @param logger [Object] Logger object (defaults to an instance of Krane::FormattedLogger
) @param global_timeout [Integer] Timeout in seconds
# File lib/krane/restart_task.rb, line 35 def initialize(context:, namespace:, logger: nil, global_timeout: nil, kubeconfig: nil) @logger = logger || Krane::FormattedLogger.build(namespace, context) @task_config = Krane::TaskConfig.new(context, namespace, @logger, kubeconfig) @context = context @namespace = namespace @global_timeout = global_timeout end
Public Instance Methods
run(**args)
click to toggle source
Runs the task, returning a boolean representing success or failure
@return [Boolean]
# File lib/krane/restart_task.rb, line 46 def run(**args) perform!(**args) true rescue FatalDeploymentError false end
Also aliased as: perform
run!(deployments: nil, selector: nil, verify_result: true)
click to toggle source
Runs the task, raising exceptions in case of issues
@param deployments [Array<String>] Array of workload names to restart @param selector [Hash] Selector(s) parsed by Krane::LabelSelector
@param verify_result [Boolean] Wait for completion and verify success
@return [nil]
# File lib/krane/restart_task.rb, line 61 def run!(deployments: nil, selector: nil, verify_result: true) start = Time.now.utc @logger.reset @logger.phase_heading("Initializing restart") verify_config! deployments = identify_target_deployments(deployments, selector: selector) @logger.phase_heading("Triggering restart by touching ENV[RESTARTED_AT]") patch_kubeclient_deployments(deployments) if verify_result @logger.phase_heading("Waiting for rollout") resources = build_watchables(deployments, start) verify_restart(resources) else warning = "Result verification is disabled for this task" @logger.summary.add_paragraph(ColorizedString.new(warning).yellow) end StatsD.client.distribution('restart.duration', StatsD.duration(start), tags: tags('success', deployments)) @logger.print_summary(:success) rescue DeploymentTimeoutError StatsD.client.distribution('restart.duration', StatsD.duration(start), tags: tags('timeout', deployments)) @logger.print_summary(:timed_out) raise rescue FatalDeploymentError => error StatsD.client.distribution('restart.duration', StatsD.duration(start), tags: tags('failure', deployments)) @logger.summary.add_action(error.message) if error.message != error.class.to_s @logger.print_summary(:failure) raise end
Also aliased as: perform!
Private Instance Methods
apps_v1_kubeclient()
click to toggle source
# File lib/krane/restart_task.rb, line 212 def apps_v1_kubeclient @apps_v1_kubeclient ||= kubeclient_builder.build_apps_v1_kubeclient(@context) end
build_patch_payload(deployment)
click to toggle source
# File lib/krane/restart_task.rb, line 174 def build_patch_payload(deployment) containers = deployment.spec.template.spec.containers { spec: { template: { spec: { containers: containers.map do |container| { name: container.name, env: [{ name: "RESTARTED_AT", value: Time.now.to_i.to_s }], } end, }, }, }, } end
build_watchables(kubeclient_resources, started)
click to toggle source
# File lib/krane/restart_task.rb, line 134 def build_watchables(kubeclient_resources, started) kubeclient_resources.map do |d| definition = d.to_h.deep_stringify_keys r = Deployment.new(namespace: @namespace, context: @context, definition: definition, logger: @logger) r.deploy_started_at = started # we don't care what happened to the resource before the restart cmd ran r end end
fetch_deployments(list)
click to toggle source
# File lib/krane/restart_task.rb, line 162 def fetch_deployments(list) list.map do |name| record = nil begin record = apps_v1_kubeclient.get_deployment(name, @namespace) rescue Kubeclient::ResourceNotFoundError raise FatalRestartError, "Deployment `#{name}` not found in namespace `#{@namespace}`" end record end end
identify_target_deployments(deployment_names, selector: nil)
click to toggle source
# File lib/krane/restart_task.rb, line 100 def identify_target_deployments(deployment_names, selector: nil) if deployment_names.nil? deployments = if selector.nil? @logger.info("Configured to restart all deployments with the `#{ANNOTATION}` annotation") apps_v1_kubeclient.get_deployments(namespace: @namespace) else selector_string = selector.to_s @logger.info( "Configured to restart all deployments with the `#{ANNOTATION}` annotation and #{selector_string} selector" ) apps_v1_kubeclient.get_deployments(namespace: @namespace, label_selector: selector_string) end deployments.select! { |d| d.metadata.annotations[ANNOTATION] } if deployments.none? raise FatalRestartError, "no deployments with the `#{ANNOTATION}` annotation found in namespace #{@namespace}" end elsif deployment_names.empty? raise FatalRestartError, "Configured to restart deployments by name, but list of names was blank" elsif !selector.nil? raise FatalRestartError, "Can't specify deployment names and selector at the same time" else deployment_names = deployment_names.uniq list = deployment_names.join(', ') @logger.info("Configured to restart deployments by name: #{list}") deployments = fetch_deployments(deployment_names) if deployments.none? raise FatalRestartError, "no deployments with names #{list} found in namespace #{@namespace}" end end deployments end
kubeclient()
click to toggle source
# File lib/krane/restart_task.rb, line 216 def kubeclient @kubeclient ||= kubeclient_builder.build_v1_kubeclient(@context) end
kubectl()
click to toggle source
# File lib/krane/restart_task.rb, line 220 def kubectl @kubectl ||= Kubectl.new(task_config: @task_config, log_failure_by_default: true) end
patch_deployment_with_restart(record)
click to toggle source
# File lib/krane/restart_task.rb, line 143 def patch_deployment_with_restart(record) apps_v1_kubeclient.patch_deployment( record.metadata.name, build_patch_payload(record), @namespace ) end
patch_kubeclient_deployments(deployments)
click to toggle source
# File lib/krane/restart_task.rb, line 151 def patch_kubeclient_deployments(deployments) deployments.each do |record| begin patch_deployment_with_restart(record) @logger.info("Triggered `#{record.metadata.name}` restart") rescue Kubeclient::HttpError => e raise RestartAPIError.new(record.metadata.name, e.message) end end end
v1beta1_kubeclient()
click to toggle source
# File lib/krane/restart_task.rb, line 224 def v1beta1_kubeclient @v1beta1_kubeclient ||= kubeclient_builder.build_v1beta1_kubeclient(@context) end
verify_config!()
click to toggle source
# File lib/krane/restart_task.rb, line 203 def verify_config! task_config_validator = TaskConfigValidator.new(@task_config, kubectl, kubeclient_builder) unless task_config_validator.valid? @logger.summary.add_action("Configuration invalid") @logger.summary.add_paragraph(task_config_validator.errors.map { |err| "- #{err}" }.join("\n")) raise Krane::TaskConfigurationError end end
verify_restart(resources)
click to toggle source
# File lib/krane/restart_task.rb, line 192 def verify_restart(resources) ResourceWatcher.new(resources: resources, operation_name: "restart", timeout: @global_timeout, task_config: @task_config).run failed_resources = resources.reject(&:deploy_succeeded?) success = failed_resources.empty? if !success && failed_resources.all?(&:deploy_timed_out?) raise DeploymentTimeoutError end raise FatalDeploymentError unless success end