Skip to content

Commit

Permalink
Add daemon set resource
Browse files Browse the repository at this point in the history
  • Loading branch information
karanthukral committed Jul 25, 2017
1 parent 8bf95c0 commit 8301ed3
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 4 deletions.
95 changes: 95 additions & 0 deletions lib/kubernetes-deploy/kubernetes_resource/daemon_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# frozen_string_literal: true
module KubernetesDeploy
class DaemonSet < KubernetesResource
TIMEOUT = 5.minutes

def sync
raw_json, _err, st = kubectl.run("get", type, @name, "--output=json")
@found = st.success?

if @found
daemonset_data = JSON.parse(raw_json)
@current_generation = daemonset_data["metadata"]["generation"]
@observed_generation = daemonset_data["status"]["observedGeneration"]
@rollout_data = daemonset_data["status"]
.slice("currentNumberScheduled", "desiredNumberScheduled", "numberReady", "numberAvailable")
@status = @rollout_data.map { |state_replicas, num| "#{num} #{state_replicas}" }.join(", ")
@pods = find_pods(daemonset_data)
else # reset
@rollout_data = { "currentNumberScheduled" => 0 }
@current_generation = 1 # to make sure the current and observed generations are different
@observed_generation = 0
@status = nil
@pods = []
end
end

def deploy_succeeded?
@rollout_data["desiredNumberScheduled"].to_i == @rollout_data["currentNumberScheduled"].to_i &&
@rollout_data["desiredNumberScheduled"].to_i == @rollout_data["numberAvailable"].to_i &&
@current_generation == @observed_generation
end

def deploy_failed?
@pods.present? && @pods.any?(&:deploy_failed?)
end

def failure_message
@pods.map(&:failure_message).compact.uniq.join("\n")
end

def timeout_message
@pods.map(&:timeout_message).compact.uniq.join("\n")
end

def deploy_timed_out?
super || @pods.present? && @pods.any?(&:deploy_timed_out?)
end

def exists?
@found
end

def fetch_events
own_events = super
return own_events unless @pods.present?
most_useful_pod = @pods.find(&:deploy_failed?) || @pods.find(&:deploy_timed_out?) || @pods.first
own_events.merge(most_useful_pod.fetch_events)
end

def fetch_logs
most_useful_pod = @pods.find(&:deploy_failed?) || @pods.find(&:deploy_timed_out?) || @pods.first
most_useful_pod.fetch_logs
end

private

def find_pods(ds_data)
label_string = ds_data["spec"]["selector"]["matchLabels"].map { |k, v| "#{k}=#{v}" }.join(",")
raw_json, _err, st = kubectl.run("get", "pods", "-a", "--output=json", "--selector=#{label_string}")
return [] unless st.success?

all_pods = JSON.parse(raw_json)["items"]
current_generation = ds_data["metadata"]["generation"]

latest_pods = all_pods.find_all do |pods|
pods["metadata"]["ownerReferences"].any? { |ref| ref["uid"] == ds_data["metadata"]["uid"] } &&
pods["metadata"]["labels"]["pod-template-generation"].to_i == current_generation.to_i
end
return unless latest_pods.present?

latest_pods.each_with_object([]) do |pod_data, relevant_pods|
pod = Pod.new(
namespace: namespace,
context: context,
definition: pod_data,
logger: @logger,
parent: "#{@name.capitalize} daemon set",
deploy_started: @deploy_started
)
pod.sync(pod_data)
relevant_pods << pod
end
end
end
end
1 change: 1 addition & 0 deletions lib/kubernetes-deploy/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
pod_disruption_budget
replica_set
service_account
daemon_set
).each do |subresource|
require "kubernetes-deploy/kubernetes_resource/#{subresource}"
end
Expand Down
16 changes: 16 additions & 0 deletions test/fixtures/hello-cloud/daemon_set.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: nginx
spec:
template:
metadata:
labels:
app: hello-cloud
name: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
7 changes: 7 additions & 0 deletions test/helpers/fixture_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ def assert_service_account_present(name)
assert desired.present?, "Service account #{name} does not exist"
end

def assert_daemon_set_present(name)
labels = "name=#{name},app=#{app_name}"
daemon_sets = v1beta1_kubeclient.get_daemon_sets(namespace: namespace, label_selector: labels)
desired = daemon_sets.find { |ds| ds.metadata.name == name }
assert desired.present?, "Daemon set #{name} does not exist"
end

def assert_annotated(obj, annotation)
annotations = obj.metadata.annotations.to_h.stringify_keys
assert annotations.key?(annotation), "Expected secret to have annotation #{annotation}, but it did not"
Expand Down
5 changes: 5 additions & 0 deletions test/helpers/fixture_sets/hello_cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def assert_all_up
assert_poddisruptionbudget
assert_bare_replicaset_up
assert_all_service_accounts_up
assert_daemon_set_up
end

def assert_unmanaged_pod_statuses(status, count = 1)
Expand Down Expand Up @@ -84,5 +85,9 @@ def assert_bare_replicaset_up
def assert_all_service_accounts_up
assert_service_account_present("build-robot")
end

def assert_daemon_set_up
assert_daemon_set_present("nginx")
end
end
end
30 changes: 26 additions & 4 deletions test/integration/kubernetes_deploy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ def test_full_hello_cloud_set_deploy_succeeds
"Deploying ConfigMap/hello-cloud-configmap-data (timeout: 30s)",
"Hello from Docker!", # unmanaged pod logs
"Result: SUCCESS",
"Successfully deployed 13 resources"
"Successfully deployed 14 resources"
], in_order: true)

assert_logs_match_all([
%r{ReplicaSet/bare-replica-set\s+1 replica, 1 availableReplica, 1 readyReplica},
%r{Deployment/web\s+1 replica, 1 updatedReplica, 1 availableReplica},
%r{Service/web\s+Selects at least 1 pod}
%r{Service/web\s+Selects at least 1 pod},
%r{DaemonSet/nginx\s+1 currentNumberScheduled, 1 desiredNumberScheduled, 1 numberReady, 1 numberAvailable}
])
end

Expand Down Expand Up @@ -49,9 +50,10 @@ def test_pruning_works
'pod "unmanaged-pod-',
'service "web"',
'deployment "web"',
'ingress "web"'
'ingress "web"',
'daemonset "nginx"'
] # not necessarily listed in this order
expected_msgs = [/Pruned 5 resources and successfully deployed 3 resources/]
expected_msgs = [/Pruned 6 resources and successfully deployed 3 resources/]
expected_pruned.map do |resource|
expected_msgs << /The following resources were pruned:.*#{resource}/
end
Expand Down Expand Up @@ -632,6 +634,26 @@ def test_output_when_unmanaged_pod_preexists
assert_logs_match("Unmanaged pods like Pod/oops-it-is-static must have unique names on every deploy")
end

def test_bad_container_on_daemon_sets_fails
success = deploy_fixtures("hello-cloud", subset: ["daemon_set.yml"]) do |fixtures|
daemon_set = fixtures['daemon_set.yml']['DaemonSet'].first
container = daemon_set['spec']['template']['spec']['containers'].first
container["image"] = "busybox"
container["command"] = ["ls", "/not-a-dir"]
end

refute success
assert_logs_match_all([
"DaemonSet/nginx: FAILED",
"nginx: Crashing repeatedly (exit 1). See logs for more information.",
"Final status: 1 currentNumberScheduled, 1 desiredNumberScheduled, 0 numberReady",
"Events (common success events excluded):",
"BackOff: Back-off restarting failed container",
"Logs from container 'nginx' (last 250 lines shown):",
"ls: /not-a-dir: No such file or directory"
], in_order: true)
end

private

def count_by_revisions(pods)
Expand Down

0 comments on commit 8301ed3

Please sign in to comment.