Skip to content

Commit

Permalink
Add a common module and fix up tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dturn committed Oct 22, 2019
1 parent 196db20 commit fb31d05
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 96 deletions.
24 changes: 24 additions & 0 deletions lib/krane/concerns/template_reporting.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module Krane
module TemplateReporting
def record_invalid_template(err:, filename:, content: nil)
debug_msg = ColorizedString.new("Invalid template: #{filename}\n").red
debug_msg += "> Error message:\n#{KubernetesDeploy::FormattedLogger.indent_four(err)}"
if content
debug_msg += if content =~ /kind:\s*Secret/
"\n> Template content: Suppressed because it may contain a Secret"
else
"\n> Template content:\n#{KubernetesDeploy::FormattedLogger.indent_four(content)}"
end
end
logger.summary.add_paragraph(debug_msg)
end

def record_warnings(warning:, filename:)
warn_msg = "Template warning: #{filename}\n"
warn_msg += "> Warning message:\n#{KubernetesDeploy::FormattedLogger.indent_four(warning)}"
logger.summary.add_paragraph(ColorizedString.new(warn_msg).yellow)
end
end
end
71 changes: 25 additions & 46 deletions lib/krane/global_deploy_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
require 'kubernetes-deploy/cluster_resource_discovery'
require 'kubernetes-deploy/template_sets'
require 'kubernetes-deploy/resource_deployer'

require 'kubernetes-deploy/kubernetes_resource'
%w(
custom_resource
Expand All @@ -19,11 +18,13 @@
end

require 'krane/global_deploy_task_config_validator'
require 'krane/concerns/template_reporting'

module Krane
# Ship global resources to a context
class GlobalDeployTask
extend KubernetesDeploy::StatsD::MeasureMethods
include Krane::TemplateReporting
delegate :context, :logger, to: :@task_config

# Initializes the deploy task
Expand Down Expand Up @@ -80,16 +81,36 @@ def run!(verify_result: true, prune: true)
check_initial_status(resources)

logger.phase_heading("Deploying all resources")
deploy!(resources, verify_result, prune, start)
deploy!(resources, verify_result, prune)
StatsD.event("Deployment succeeded",
"Successfully deployed all resources to #{context}",
alert_type: "success", tags: statsd_tags << "status:success")
StatsD.distribution('all_resources.duration', KubernetesDeploy::StatsD.duration(start), tags: statsd_tags << "status:success")
logger.print_summary(:success)
rescue KubernetesDeploy::DeploymentTimeoutError
logger.print_summary(:timed_out)
StatsD.event("Deployment timed out",
"One or more resources failed to deploy to #{context} in time",
alert_type: "error", tags: statsd_tags << "status:timeout")
StatsD.distribution('all_resources.duration', KubernetesDeploy::StatsD.duration(start), tags: statsd_tags << "status:timeout")
raise
rescue KubernetesDeploy::FatalDeploymentError => error
logger.summary.add_action(error.message) if error.message != error.class.to_s
logger.print_summary(:failure)
StatsD.event("Deployment failed",
"One or more resources failed to deploy to #{context}",
alert_type: "error", tags: statsd_tags << "status:failed")
StatsD.distribution('all_resources.duration', KubernetesDeploy::StatsD.duration(start), tags: statsd_tags << "status:failed")
raise
end

private

def deploy!(resources, verify_result, prune, start)
def deploy!(resources, verify_result, prune)
prune_whitelist = []
deployer = KubernetesDeploy::ResourceDeployer.new(task_config: @task_config,
prune_whitelist: prune_whitelist, max_watch_seconds: @max_watch_seconds,
selector: @selector, global_mode: true)
selector: @selector, statsd_tags: statsd_tags)
if verify_result
deployer.deploy_all_resources(resources, prune: prune, verify: true)
failed_resources = resources.reject(&:deploy_succeeded?)
Expand All @@ -107,28 +128,6 @@ def deploy!(resources, verify_result, prune, start)
MSG
logger.summary.add_paragraph(ColorizedString.new(warning).yellow)
end

StatsD.event("Deployment succeeded",
"Successfully deployed all resources to #{context}",
alert_type: "success", tags: statsd_tags << "status:success")
StatsD.distribution('all_resources.duration', KubernetesDeploy::StatsD.duration(start), tags: statsd_tags << "status:success")
logger.print_summary(:success)

rescue KubernetesDeploy::DeploymentTimeoutError
logger.print_summary(:timed_out)
StatsD.event("Deployment timed out",
"One or more resources failed to deploy to #{context} in time",
alert_type: "error", tags: statsd_tags << "status:timeout")
StatsD.distribution('all_resources.duration', KubernetesDeploy::StatsD.duration(start), tags: statsd_tags << "status:timeout")
raise
rescue KubernetesDeploy::FatalDeploymentError => error
logger.summary.add_action(error.message) if error.message != error.class.to_s
logger.print_summary(:failure)
StatsD.event("Deployment failed",
"One or more resources failed to deploy to #{context}",
alert_type: "error", tags: statsd_tags << "status:failed")
StatsD.distribution('all_resources.duration', KubernetesDeploy::StatsD.duration(start), tags: statsd_tags << "status:failed")
raise
end

def validate_configuration
Expand Down Expand Up @@ -208,7 +207,6 @@ def statsd_tags
%W(context:#{@context})
end

### Could be common
def kubectl
@kubectl ||= KubernetesDeploy::Kubectl.new(task_config: @task_config, log_failure_by_default: true)
end
Expand All @@ -221,25 +219,6 @@ def global_resource_kinds
cluster_resource_discoverer.global_resource_kinds
end

def record_invalid_template(err:, filename:, content: nil)
debug_msg = ColorizedString.new("Invalid template: #{filename}\n").red
debug_msg += "> Error message:\n#{KubernetesDeploy::FormattedLogger.indent_four(err)}"
if content
debug_msg += if content =~ /kind:\s*Secret/
"\n> Template content: Suppressed because it may contain a Secret"
else
"\n> Template content:\n#{KubernetesDeploy::FormattedLogger.indent_four(content)}"
end
end
logger.summary.add_paragraph(debug_msg)
end

def record_warnings(warning:, filename:)
warn_msg = "Template warning: #{filename}\n"
warn_msg += "> Warning message:\n#{KubernetesDeploy::FormattedLogger.indent_four(warning)}"
logger.summary.add_paragraph(ColorizedString.new(warn_msg).yellow)
end

def check_initial_status(resources)
@task_config.global_kinds = global_resource_kinds.map(&:downcase)
cache = KubernetesDeploy::ResourceCache.new(@task_config)
Expand Down
69 changes: 27 additions & 42 deletions lib/kubernetes-deploy/deploy_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,14 @@
require 'kubernetes-deploy/deploy_task_config_validator'
require 'kubernetes-deploy/resource_deployer'

require 'krane/concerns/template_reporting'

module KubernetesDeploy
# Ship resources to a namespace
class DeployTask
extend KubernetesDeploy::StatsD::MeasureMethods
include Krane::TemplateReporting
delegate :logger, to: :@task_config

PROTECTED_NAMESPACES = %w(
default
Expand Down Expand Up @@ -184,18 +188,38 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true)
raise FatalDeploymentError, "Refusing to deploy to protected namespace '#{@namespace}' with pruning enabled"
end

deploy!(resource, verify_result, prune)
deploy!(resources, verify_result, prune)
StatsD.event("Deployment of #{@namespace} succeeded",
"Successfully deployed all #{@namespace} resources to #{@context}",
alert_type: "success", tags: statsd_tags << "status:success")
StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:success")
@logger.print_summary(:success)
rescue DeploymentTimeoutError
@logger.print_summary(:timed_out)
StatsD.event("Deployment of #{@namespace} timed out",
"One or more #{@namespace} resources failed to deploy to #{@context} in time",
alert_type: "error", tags: statsd_tags << "status:timeout")
StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:timeout")
raise
rescue FatalDeploymentError => error
@logger.summary.add_action(error.message) if error.message != error.class.to_s
@logger.print_summary(:failure)
StatsD.event("Deployment of #{@namespace} failed",
"One or more #{@namespace} resources failed to deploy to #{@context}",
alert_type: "error", tags: statsd_tags << "status:failed")
StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:failed")
raise
end

private

def resource_deployer
@resource_deployer ||= KubernetesDeploy::ResourceDeployer.new(task_config: @task_config,
prune_whitelist: prune_whitelist, max_watch_seconds: @max_watch_seconds,
selector: @selector)
selector: @selector, statsd_tags: statsd_tags)
end

def deploy!(resources, verify_result, prune, start)
def deploy!(resources, verify_result, prune)
if verify_result
resource_deployer.deploy_all_resources(resources, prune: prune, verify: true)
failed_resources = resources.reject(&:deploy_succeeded?)
Expand All @@ -213,26 +237,6 @@ def deploy!(resources, verify_result, prune, start)
MSG
@logger.summary.add_paragraph(ColorizedString.new(warning).yellow)
end
StatsD.event("Deployment of #{@namespace} succeeded",
"Successfully deployed all #{@namespace} resources to #{@context}",
alert_type: "success", tags: statsd_tags << "status:success")
StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:success")
@logger.print_summary(:success)
rescue DeploymentTimeoutError
@logger.print_summary(:timed_out)
StatsD.event("Deployment of #{@namespace} timed out",
"One or more #{@namespace} resources failed to deploy to #{@context} in time",
alert_type: "error", tags: statsd_tags << "status:timeout")
StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:timeout")
raise
rescue FatalDeploymentError => error
@logger.summary.add_action(error.message) if error.message != error.class.to_s
@logger.print_summary(:failure)
StatsD.event("Deployment of #{@namespace} failed",
"One or more #{@namespace} resources failed to deploy to #{@context}",
alert_type: "error", tags: statsd_tags << "status:failed")
StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:failed")
raise
end

def global_resource_names
Expand Down Expand Up @@ -342,25 +346,6 @@ def discover_resources
end
measure_method(:discover_resources)

def record_invalid_template(err:, filename:, content: nil)
debug_msg = ColorizedString.new("Invalid template: #{filename}\n").red
debug_msg += "> Error message:\n#{FormattedLogger.indent_four(err)}"
if content
debug_msg += if content =~ /kind:\s*Secret/
"\n> Template content: Suppressed because it may contain a Secret"
else
"\n> Template content:\n#{FormattedLogger.indent_four(content)}"
end
end
@logger.summary.add_paragraph(debug_msg)
end

def record_warnings(warning:, filename:)
warn_msg = "Template warning: #{filename}\n"
warn_msg += "> Warning message:\n#{FormattedLogger.indent_four(warning)}"
@logger.summary.add_paragraph(ColorizedString.new(warn_msg).yellow)
end

def validate_configuration(allow_protected_ns:, prune:)
task_config_validator = DeployTaskConfigValidator.new(@protected_namespaces, allow_protected_ns, prune,
@task_config, kubectl, kubeclient_builder)
Expand Down
11 changes: 8 additions & 3 deletions lib/kubernetes-deploy/resource_deployer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ class ResourceDeployer

delegate :logger, to: :@task_config

def initialize(task_config:, prune_whitelist:, max_watch_seconds:, current_sha: nil, selector:, global_mode: false)
def initialize(task_config:, prune_whitelist:, max_watch_seconds:, current_sha: nil, selector:, statsd_tags:)
@task_config = task_config
@prune_whitelist = prune_whitelist
@max_watch_seconds = max_watch_seconds
@current_sha = current_sha
@selector = selector
@global_mode = global_mode
@statsd_tags = statsd_tags
end

def deploy_all_resources(resources, prune: false, verify:, record_summary: true)
Expand Down Expand Up @@ -124,8 +124,9 @@ def apply_all(resources, prune)
end

output_is_sensitive = resources.any?(&:sensitive_template_content?)
global_mode = resources.all?(&:global?)
out, err, st = kubectl.run(*command, log_failure: false, output_is_sensitive: output_is_sensitive,
use_namespace: !@global_mode)
use_namespace: !global_mode)

if st.success?
log_pruning(out) if prune
Expand Down Expand Up @@ -221,5 +222,9 @@ def record_invalid_template(err:, filename:, content: nil)
def kubectl
@kubectl ||= Kubectl.new(task_config: @task_config, log_failure_by_default: true)
end

def statsd_tags
@statsd_tags
end
end
end
75 changes: 75 additions & 0 deletions test/exe/global_deploy_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# frozen_string_literal: true
require 'test_helper'
require 'krane/cli/krane'
require 'krane/global_deploy_task'

class GlobalDeployTest < KubernetesDeploy::TestCase
def test_global_deploy_with_default_options
set_krane_global_deploy_expectations!
krane_global_deploy!
end

def test_deploy_parses_global_timeout
set_krane_global_deploy_expectations!(new_args: { max_watch_seconds: 10 })
krane_global_deploy!(flags: '--global-timeout 10s')
set_krane_global_deploy_expectations!(new_args: { max_watch_seconds: 60**2 })
krane_global_deploy!(flags: '--global-timeout 1h')
end

def test_deploy_passes_verify_result
set_krane_global_deploy_expectations!(run_args: { verify_result: true })
krane_global_deploy!(flags: '--verify-result true')
set_krane_global_deploy_expectations!(run_args: { verify_result: false })
krane_global_deploy!(flags: '--verify-result false')
end

def test_deploy_passes_filename
set_krane_global_deploy_expectations!(new_args: { template_paths: ['/my/file/path'] })
krane_global_deploy!(flags: '-f /my/file/path')
set_krane_global_deploy_expectations!(new_args: { template_paths: ['/my/other/file/path'] })
krane_global_deploy!(flags: '--filenames /my/other/file/path')
end

def test_deploy_parses_selector
selector = 'name:web'
set_krane_global_deploy_expectations!(new_args: { selector: selector })
krane_global_deploy!(flags: "--selector #{selector}")
end

private

def set_krane_global_deploy_expectations!(new_args: {}, run_args: {})
options = default_options(new_args, run_args)
selector_args = options[:new_args][:selector]
selector = mock('LabelSelector')
KubernetesDeploy::LabelSelector.expects(:parse).with(selector_args).returns(selector)
response = mock('GlobalDeployTask')
response.expects(:run!).with(options[:run_args]).returns(true)
Krane::GlobalDeployTask.expects(:new).with(options[:new_args].merge(selector: selector)).returns(response)
end

def krane_global_deploy!(flags: '')
flags += ' -f /tmp' unless flags.include?('-f')
flags += ' --selector name:web' unless flags.include?('--selector')
krane = Krane::CLI::Krane.new(
[task_config.context],
flags.split
)
krane.invoke("global_deploy")
end

def default_options(new_args = {}, run_args = {})
{
new_args: {
context: task_config.context,
template_paths: ['/tmp'],
max_watch_seconds: 300,
selector: 'name:web',
}.merge(new_args),
run_args: {
verify_result: true,
prune: false,
}.merge(run_args),
}
end
end
2 changes: 1 addition & 1 deletion test/helpers/resource_cache_test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def stub_kind_get(kind, items: [], times: 1)
kind,
"--chunk-size=0",
resp: { items: items },
kwargs: { attempts: 5, output_is_sensitive: false },
kwargs: { attempts: 5, output_is_sensitive: false, use_namespace: true },
times: times,
)
end
Expand Down
Loading

0 comments on commit fb31d05

Please sign in to comment.