Skip to content

Commit 983fac1

Browse files
Capture admission hook changes of created resources
1 parent 6236b52 commit 983fac1

2 files changed

Lines changed: 37 additions & 11 deletions

File tree

lib/krane/kubernetes_resource/custom_resource.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class CustomResource < KubernetesResource
88
(.metadata.generation != .status.observedGeneration).
99
MSG
1010

11+
attr_reader :crd
12+
1113
def initialize(namespace:, context:, definition:, logger:, statsd_tags: [], crd:)
1214
super(namespace: namespace, context: context, definition: definition,
1315
logger: logger, statsd_tags: statsd_tags)

lib/krane/resource_deployer.rb

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,21 +96,27 @@ def deploy_resources(resources, prune: false, verify:, record_summary: true)
9696
applyables, individuals = resources.partition { |r| r.deploy_method == :apply }
9797
# Prunable resources should also applied so that they can be pruned
9898
pruneable_types = @prune_allowlist.map { |t| t.split("/").last }
99-
applyables += individuals.select { |r| pruneable_types.include?(r.type) && !r.deploy_method_override }
10099

100+
# Admission hooks can mutate resources, so we need to track those changes, otherwise the subsquent pruning
101+
# may fail if we present a document that no longer matches the resource in the cluster.
102+
updated_individuals = []
101103
individuals.each do |individual_resource|
102104
individual_resource.deploy_started_at = Time.now.utc
103105
case individual_resource.deploy_method
104106
when :create
105-
err, status = create_resource(individual_resource)
107+
updated_resource, err, status = create_resource(individual_resource)
108+
updated_individuals << updated_resource if status.success?
106109
when :replace
107-
err, status = replace_or_create_resource(individual_resource)
110+
updated_resource, err, status = replace_or_create_resource(individual_resource)
111+
updated_individuals << updated_resource if status.success?
108112
when :replace_force
109-
err, status = replace_or_create_resource(individual_resource, force: true)
113+
updated_resource, err, status = replace_or_create_resource(individual_resource, force: true)
114+
updated_individuals << updated_resource if status.success?
110115
else
111116
# Fail Fast! This is a programmer mistake.
112117
raise ArgumentError, "Unexpected deploy method! (#{individual_resource.deploy_method.inspect})"
113118
end
119+
applyables += possibly_mutated_resources.select { |r| pruneable_types.include?(r.type) && !r.deploy_method_override }
114120

115121
next if status.success?
116122

@@ -229,27 +235,45 @@ def replace_or_create_resource(resource, force: false)
229235
["replace", "-f", resource.file_path]
230236
end
231237

232-
_, err, status = kubectl.run(*args, log_failure: false, output_is_sensitive: resource.sensitive_template_content?,
233-
raise_if_not_found: true, use_namespace: !resource.global?)
234-
235-
[err, status]
238+
updated_resource_definition, err, status = kubectl.run(*args, log_failure: false, output_is_sensitive: resource.sensitive_template_content?,
239+
raise_if_not_found: true, output: 'json', use_namespace: !resource.global?)
240+
241+
updated_resources = KubernetesResource.build(
242+
namespace: @task_config.namespace,
243+
context: @task_config.context,
244+
definition: updated_resource_definition,
245+
logger:,
246+
statsd_tags:,
247+
crd: resource.is_a?(CustomResource) ? resource.crd : nil,
248+
global_names: []
249+
)
250+
[updated_resource, err, status]
236251
rescue Krane::Kubectl::ResourceNotFoundError
237252
# it doesn't exist so we can't replace it, we try to create it
238253
create_resource(resource)
239254
end
240255

241256
def create_resource(resource)
242-
out, err, status = kubectl.run("create", "-f", resource.file_path, log_failure: false,
257+
updated_resource_definition, err, status = kubectl.run("create", "-f", resource.file_path, log_failure: false,
243258
output: 'json', output_is_sensitive: resource.sensitive_template_content?,
244259
use_namespace: !resource.global?)
245260

246261
# For resources that rely on a generateName attribute, we get the `name` from the result of the call to `create`
247262
# We must explicitly set this name value so that the `apply` step for pruning can run successfully
248263
if status.success? && resource.uses_generate_name?
249-
resource.use_generated_name(MultiJson.load(out))
264+
resource.use_generated_name(MultiJson.load(updated_resource_definition))
250265
end
251266

252-
[err, status]
267+
updated_resources = KubernetesResource.build(
268+
namespace: @task_config.namespace,
269+
context: @task_config.context,
270+
definition: updated_resource_definition,
271+
logger:,
272+
statsd_tags:,
273+
crd: resource.is_a?(CustomResource) ? resource.crd : nil,
274+
global_names: []
275+
)
276+
[updated_resource, err, status]
253277
end
254278

255279
# Inspect the file referenced in the kubectl stderr

0 commit comments

Comments
 (0)