Skip to content

Commit

Permalink
Pull in upstream changes
Browse files Browse the repository at this point in the history
  • Loading branch information
c-gerke committed Dec 5, 2024
1 parent ed0b0f4 commit b82c2fd
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 4 deletions.
12 changes: 12 additions & 0 deletions lib/krane/deploy_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,19 @@ def predeploy_sequence
).map { |r| [r, default_group] }

after_crs = %w(
Deployment
Service
Ingress
Pod
Job
CronJob
DaemonSet
HorizontalPodAutoscaler
PodDisruptionBudget
PodSetBase
PodTemplate
ReplicaSet
StatefulSet
).map { |r| [r, default_group] }

crs = cluster_resource_discoverer.crds.select(&:predeployed?).map { |cr| [cr.kind, { group: cr.group }] }
Expand Down
17 changes: 17 additions & 0 deletions lib/krane/kubernetes_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,23 @@ def use_generated_name(instance_data)
@file = create_definition_tempfile
end

PREDEPLOYED_RESOURCE_TYPES = [
"ResourceQuota",
"NetworkPolicy",
"ConfigMap",
"PersistentVolumeClaim",
"ServiceAccount",
"Role",
"RoleBinding",
"Secret",
"Pod"
]

def predeployed?
predeployed = krane_annotation_value("predeployed")
PREDEPLOYED_RESOURCE_TYPES.include?(type) || predeployed == "true"
end

class Event
EVENT_SEPARATOR = "ENDEVENT--BEGINEVENT"
FIELD_SEPARATOR = "ENDFIELD--BEGINFIELD"
Expand Down
5 changes: 5 additions & 0 deletions lib/krane/kubernetes_resource/custom_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ def type
kind
end

def predeployed?
predeployed = krane_annotation_value("predeployed")
predeployed.nil? || predeployed == "true"
end

def validate_definition(*, **)
super

Expand Down
3 changes: 2 additions & 1 deletion lib/krane/resource_deployer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ def predeploy_priority_resources(resource_list, predeploy_sequence)
predeploy_sequence.each do |resource_type, attributes|
matching_resources = resource_list.select do |r|
r.type == resource_type &&
(!attributes[:group] || r.group == attributes[:group])
(!attributes[:group] || r.group == attributes[:group]) &&
r.predeployed?
end
StatsD.client.gauge('priority_resources.count', matching_resources.size, tags: statsd_tags)

Expand Down
4 changes: 4 additions & 0 deletions test/helpers/mock_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ def group
"core"
end

def predeployed?
false
end

def pretty_timeout_type
end

Expand Down
160 changes: 158 additions & 2 deletions test/integration-serial/serial_deploy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,7 @@ def test_cr_success_with_service

assert_deploy_success(deploy_fixtures("crd", subset: %w(web.yml)))

refute_logs_match(/Predeploying priority resources/)
assert_logs_match_all([/Phase 3: Deploying all resources/])
assert_logs_match_all([/Phase 4: Deploying all resources/])
ensure
build_kubectl.run("delete", "-f", filepath, use_namespace: false, log_failure: false)
end
Expand Down Expand Up @@ -526,6 +525,163 @@ def test_resource_discovery_stops_deploys_when_fetch_crds_kubectl_errs
], in_order: true)
end

def test_deployment_with_predeploy_annotation_is_predeployed
# Deploy the fixtures with a modified deployment that has the predeploy annotation
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "web.yml.erb"], render_erb: true) do |fixtures|
deployment = fixtures["web.yml.erb"]["Deployment"].first
deployment["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true"
}
end

assert_deploy_success(result)

# Verify the deployment was predeployed before other resources by checking log order
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: Deployment/web},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, Deployment\/web, Ingress\/web, Service\/web/,
], in_order: true)
end

def test_service_with_predeploy_annotation_is_predeployed
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "web.yml.erb"], render_erb: true) do |fixtures|
service = fixtures["web.yml.erb"]["Service"].first
service["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true",
"krane.shopify.io/skip-endpoint-validation" => "true"
}
end

assert_deploy_success(result)
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: Service/web},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, Deployment\/web, Ingress\/web, Service\/web/,
], in_order: true)
end

def test_ingress_with_predeploy_annotation_is_predeployed
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "web.yml.erb"], render_erb: true) do |fixtures|
ingress = fixtures["web.yml.erb"]["Ingress"].first
ingress["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true"
}
end

assert_deploy_success(result)
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: Ingress/web},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, Deployment\/web, Ingress\/web, Service\/web/,
], in_order: true)
end

def test_job_with_predeploy_annotation_is_predeployed
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "job.yml"]) do |fixtures|
job = fixtures["job.yml"]["Job"].first
job["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true"
}
end

assert_deploy_success(result)
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: Job/hello-job},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, Job\/hello-job/,
], in_order: true)
end

def test_daemonset_with_predeploy_annotation_is_predeployed
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "daemon_set.yml"]) do |fixtures|
daemon_set = fixtures["daemon_set.yml"]["DaemonSet"].first
daemon_set["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true"
}
end

assert_deploy_success(result)
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: DaemonSet/ds-app},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, DaemonSet\/ds-app/,
], in_order: true)
end

def test_pod_disruption_budget_with_predeploy_annotation_is_predeployed
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "disruption-budgets.yml"]) do |fixtures|
pdb = fixtures["disruption-budgets.yml"]["PodDisruptionBudget"].first
pdb["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true"
}
end

assert_deploy_success(result)
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: PodDisruptionBudget/test},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, PodDisruptionBudget\/test/,
], in_order: true)
end

def test_pod_template_with_predeploy_annotation_is_predeployed
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "template-runner.yml"]) do |fixtures|
template = fixtures["template-runner.yml"]["PodTemplate"].first
template["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true"
}
end

assert_deploy_success(result)
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: PodTemplate/hello-cloud-template-runner},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, PodTemplate\/hello-cloud-template-runner/,
], in_order: true)
end

def test_replica_set_with_predeploy_annotation_is_predeployed
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "bare_replica_set.yml"]) do |fixtures|
rs = fixtures["bare_replica_set.yml"]["ReplicaSet"].first
rs["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true"
}
end

assert_deploy_success(result)
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: ReplicaSet/bare-replica-set},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, ReplicaSet\/bare-replica-set/,
], in_order: true)
end

def test_stateful_set_with_predeploy_annotation_is_predeployed
result = deploy_fixtures("hello-cloud", subset: ["configmap-data.yml", "stateful_set.yml"]) do |fixtures|
stateful_set = fixtures["stateful_set.yml"]["StatefulSet"].first
stateful_set["metadata"]["annotations"] = {
"krane.shopify.io/predeployed" => "true"
}
end

assert_deploy_success(result)
assert_logs_match_all([
"Phase 3: Predeploying priority resources",
%r{Successfully deployed in \d+.\ds: StatefulSet/stateful-busybox},
"Phase 4: Deploying all resources",
/Successfully deployed in \d+.\ds: ConfigMap\/hello-cloud-configmap-data, Service\/stateful-busybox, StatefulSet\/stateful-busybox/,
], in_order: true)
end

private

def rollout_conditions_annotation_key
Expand Down
22 changes: 21 additions & 1 deletion test/unit/krane/resource_deployer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ def test_deploy_verify_false_no_failure_error
def test_predeploy_priority_resources_respects_pre_deploy_list
kind = "MockResource"
resource = build_mock_resource
priority_list = { kind => { group: "not-#{resource.group}" } }
resource_deployer(kubectl_times: 0).predeploy_priority_resources([resource], priority_list)
end

def test_predeploy_priority_resources_respects_pre_deploy_list_and_predeployed_true_annotation
kind = "MockResource"
resource = build_mock_resource
resource.expects(:predeployed?).returns(true)
watcher = mock("ResourceWatcher")
watcher.expects(:run).returns(true)
# ResourceDeployer only creates a ResourceWatcher if one or more resources
Expand All @@ -76,6 +84,18 @@ def test_predeploy_priority_resources_respects_pre_deploy_list
resource_deployer.predeploy_priority_resources([resource], priority_list)
end

def test_predeploy_priority_resources_respects_pre_deploy_list_and_predeployed_false_annotation
kind = "MockResource"
resource = build_mock_resource
resource.expects(:predeployed?).returns(false)
# ResourceDeployer only creates a ResourceWatcher if one or more resources
# are deployed. See test_predeploy_priority_resources_respects_empty_pre_deploy_list
# for counter example
Krane::ResourceWatcher.expects(:new).never
priority_list = { kind => { group: "core" } }
resource_deployer(kubectl_times: 0).predeploy_priority_resources([resource], priority_list)
end

def test_predeploy_priority_resources_respects_empty_pre_deploy_list
resource = build_mock_resource
priority_list = []
Expand All @@ -98,4 +118,4 @@ def resource_deployer(kubectl_times: 1, prune_allowlist: [])
def build_mock_resource(final_status: "success", hits_to_complete: 0, name: "web-pod")
MockResource.new(name, hits_to_complete, final_status)
end
end
end

0 comments on commit b82c2fd

Please sign in to comment.