Skip to content

Commit

Permalink
Add Deploy and GlobalDeploy TaskConfigValidators
Browse files Browse the repository at this point in the history
  • Loading branch information
dturn committed Oct 10, 2019
1 parent 3f90cde commit 8545bcc
Show file tree
Hide file tree
Showing 13 changed files with 43 additions and 32 deletions.
9 changes: 5 additions & 4 deletions lib/krane/global_deploy_task.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# frozen_string_literal: true
require 'kubernetes-deploy/deploy_task'
require 'kubernetes-deploy/global_deploy_task_config_validator'

module Krane
class GlobalDeployTask < KubernetesDeploy::DeployTask
def initialize(**args)
super(args.merge(allow_globals: true))
end

private

def namespace_definition
nil
def run!(**args)
super(args.merge(task_config_validator: GlobalDeployTaskConfigValidator))
end

private

def validate_globals(resources)
return unless (namespaced = resources.reject(&:global?).presence)
namespaced_names = namespaced.map do |resource|
Expand Down
21 changes: 8 additions & 13 deletions lib/kubernetes-deploy/deploy_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def initialize(namespace: nil, context:, current_sha:, logger: nil, kubectl_inst

@logger = logger || KubernetesDeploy::FormattedLogger.build(namespace, context)
@template_sets = TemplateSets.from_dirs_and_files(paths: template_paths, logger: @logger)
@task_config = KubernetesDeploy::DeployTaskConfig.new(context, namespace, @logger, allow_globals)
@task_config = KubernetesDeploy::TaskConfig.new(context, namespace, @logger, allow_globals && namespace.empty?)
@bindings = bindings
@namespace = namespace
@namespace_tags = []
Expand Down Expand Up @@ -162,12 +162,13 @@ def run(*args)
# @param prune [Boolean] Enable deletion of resources that do not appear in the template dir
#
# @return [nil]
def run!(verify_result: true, allow_protected_ns: false, prune: true)
def run!(verify_result: true, allow_protected_ns: false, prune: true, task_config_validator: DeployTaskConfigValidator)
start = Time.now.utc
@logger.reset

@logger.phase_heading("Initializing deploy")
validate_configuration(allow_protected_ns: allow_protected_ns, prune: prune)
validate_configuration(allow_protected_ns: allow_protected_ns, prune: prune, task_config_validator: DeployTaskConfigValidator)

resources = discover_resources
validate_resources(resources)

Expand Down Expand Up @@ -376,8 +377,8 @@ def record_warnings(warning:, filename:)
@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,
def validate_configuration(allow_protected_ns:, prune:, task_config_validator:)
task_config_validator = task_config_validator.new(@protected_namespaces, allow_protected_ns, prune,
@task_config, kubectl, kubeclient_builder)
errors = []
errors += task_config_validator.errors
Expand Down Expand Up @@ -476,7 +477,7 @@ def apply_all(resources, prune)

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

if st.success?
log_pruning(out) if prune
Expand Down Expand Up @@ -557,13 +558,7 @@ def find_bad_files_from_kubectl_output(line)
end

def namespace_definition
@namespace_definition ||= begin
definition, _err, st = kubectl.run("get", "namespace", @namespace, use_namespace: false,
log_failure: true, raise_if_not_found: true, attempts: 3, output: 'json')
st.success? ? JSON.parse(definition, symbolize_names: true) : nil
end
rescue Kubectl::ResourceNotFoundError
nil
@task_config.namespace_definition
end

# make sure to never prune the ejson-keys secret
Expand Down
4 changes: 1 addition & 3 deletions lib/kubernetes-deploy/deploy_task_config_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
module KubernetesDeploy
class DeployTaskConfigValidator < TaskConfigValidator
def initialize(protected_namespaces, allow_protected_ns, prune, *arguments)
task_config = arguments.first
skip = task_config.allow_globals ? [:validate_namespace_exists] : []
super(*arguments, skip: skip)
super(*arguments)
@protected_namespaces = protected_namespaces
@allow_protected_ns = allow_protected_ns
@prune = prune
Expand Down
11 changes: 11 additions & 0 deletions lib/kubernetes-deploy/global_deploy_task_config_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true
module KubernetesDeploy
class GlobalDeployTaskConfigValidator < TaskConfigValidator
def initialize(protected_namespaces, allow_protected_ns, prune, *arguments)
super(*arguments, skip: [:validate_namespace_exists])
@protected_namespaces = protected_namespaces
@allow_protected_ns = allow_protected_ns
@prune = prune
end
end
end
4 changes: 2 additions & 2 deletions lib/kubernetes-deploy/resource_cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

module KubernetesDeploy
class ResourceCache
delegate :namespace, :context, :logger, :allow_globals, to: :@task_config
delegate :namespace, :context, :logger, :global_mode, to: :@task_config

def initialize(task_config)
@task_config = task_config
Expand Down Expand Up @@ -53,7 +53,7 @@ def fetch_by_kind(kind)
resource_class = KubernetesResource.class_for_kind(kind)
output_is_sensitive = resource_class.nil? ? false : resource_class::SENSITIVE_TEMPLATE_CONTENT
raw_json, _, st = @kubectl.run("get", kind, "--chunk-size=0", attempts: 5, output: "json",
output_is_sensitive: output_is_sensitive, use_namespace: !allow_globals)
output_is_sensitive: output_is_sensitive, use_namespace: !global_mode)
raise KubectlError unless st.success?

instances = {}
Expand Down
6 changes: 4 additions & 2 deletions lib/kubernetes-deploy/task_config.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# frozen_string_literal: true
module KubernetesDeploy
class TaskConfig
attr_reader :context, :namespace
attr_reader :context, :namespace, :global_mode
attr_accessor :namespace_definition

def initialize(context, namespace, logger = nil)
def initialize(context, namespace, logger = nil, global_mode = false)
@context = context
@namespace = namespace
@logger = logger
@global_mode = global_mode
end

def logger
Expand Down
8 changes: 5 additions & 3 deletions lib/kubernetes-deploy/task_config_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ def validate_namespace_exists
return @errors << "Namespace can not be blank"
end

_, err, st = @kubectl.run("get", "namespace", "-o", "name", namespace,
use_namespace: false, log_failure: false)
definition, err, st = @kubectl.run("get", "namespace", namespace,
use_namespace: false, log_failure: false, attempts: 3, output: 'json')

unless st.success?
if st.success?
@task_config.namespace_definition = JSON.parse(definition, symbolize_names: true)
else
@errors << if err.match("Error from server [(]NotFound[)]: namespace")
"Could not find Namespace: #{namespace} in Context: #{context}"
else
Expand Down
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
2 changes: 1 addition & 1 deletion test/unit/kubernetes-deploy/deploy_task_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def test_that_it_has_a_version_number
end

def test_initializer_without_valid_file
KubernetesDeploy::Kubectl.any_instance.expects(:run).at_least_once.returns(["", "", SystemExit.new(0)])
KubernetesDeploy::Kubectl.any_instance.expects(:run).at_least_once.returns(["{}", "", SystemExit.new(0)])
KubernetesDeploy::Kubectl.any_instance.expects(:server_version).at_least_once.returns(
Gem::Version.new(KubernetesDeploy::MIN_KUBE_VERSION)
)
Expand Down
2 changes: 2 additions & 0 deletions test/unit/kubernetes-deploy/ejson_secret_provisioner_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def stub_dry_run_validation_request
output_is_sensitive: true,
retry_whitelist: [:client_timeout],
attempts: 3,
use_namespace: true
})
end

Expand All @@ -120,6 +121,7 @@ def stub_server_dry_run_validation_request
output_is_sensitive: true,
retry_whitelist: [:client_timeout],
attempts: 3,
use_namespace: true,
})
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class HorizontalPodAutoscalerTest < KubernetesDeploy::TestCase
# We can't get integration coverage for HPA right now because the metrics server just isn't reliable enough on our CI
def test_hpa_is_whitelisted_for_pruning
KubernetesDeploy::Kubectl.any_instance.expects("run")
.with("get", "CustomResourceDefinition", output: "json", attempts: 5)
.with("get", "CustomResourceDefinition", output: "json", attempts: 5, use_namespace: false)
.returns(['{ "items": [] }', "", SystemExit.new(0)])
task = KubernetesDeploy::DeployTask.new(namespace: 'test', context: KubeclientHelper::TEST_CONTEXT,
current_sha: 'foo', template_paths: [''], logger: logger)
Expand Down
2 changes: 1 addition & 1 deletion test/unit/kubernetes-deploy/kubernetes_resource_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ def test_disappeared_is_true_if_resource_has_been_deployed_and_404s

def test_disappeared_is_false_if_resource_has_been_deployed_and_we_get_a_server_error
dummy = DummyResource.new
cache = KubernetesDeploy::ResourceCache.new(task_config: task_config(namespace: 'test', context: 'minikube'))
cache = KubernetesDeploy::ResourceCache.new(task_config(namespace: 'test', context: 'minikube'))
KubernetesDeploy::Kubectl.any_instance.expects(:run).returns(["", "NotFound", stub(success?: false)]).twice

dummy.sync(cache)
Expand Down
2 changes: 1 addition & 1 deletion test/unit/resource_cache_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_get_all_populates_cache_and_returns_array_of_instance_hashes
end

def test_if_kubectl_error_then_empty_result_returned_but_not_cached
stub_kubectl_response('get', 'FakeConfigMap', '--chunk-size=0', kwargs: { attempts: 5, output_is_sensitive: false },
stub_kubectl_response('get', 'FakeConfigMap', '--chunk-size=0', kwargs: { use_namespace: true, attempts: 5, output_is_sensitive: false },
success: false, resp: { "items" => [] }, err: 'no', times: 4)

# All of these calls should attempt the request again (see the 'times' arg above)
Expand Down

0 comments on commit 8545bcc

Please sign in to comment.