kubernetes-deploy 0.29.0 → 1.0.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/pipeline.nightly.yml +7 -0
  3. data/.rubocop.yml +0 -12
  4. data/.shopify-build/{kubernetes-deploy.yml → krane.yml} +8 -2
  5. data/1.0-Upgrade.md +109 -0
  6. data/CHANGELOG.md +60 -0
  7. data/CONTRIBUTING.md +2 -2
  8. data/Gemfile +1 -0
  9. data/README.md +86 -2
  10. data/dev.yml +3 -1
  11. data/dev/flamegraph-from-tests +1 -1
  12. data/exe/kubernetes-deploy +12 -9
  13. data/exe/kubernetes-render +9 -7
  14. data/exe/kubernetes-restart +3 -3
  15. data/exe/kubernetes-run +1 -1
  16. data/kubernetes-deploy.gemspec +5 -5
  17. data/lib/krane.rb +5 -3
  18. data/lib/{kubernetes-deploy → krane}/bindings_parser.rb +1 -1
  19. data/lib/krane/cli/deploy_command.rb +25 -13
  20. data/lib/krane/cli/global_deploy_command.rb +55 -0
  21. data/lib/krane/cli/krane.rb +12 -3
  22. data/lib/krane/cli/render_command.rb +19 -9
  23. data/lib/krane/cli/restart_command.rb +4 -4
  24. data/lib/krane/cli/run_command.rb +4 -4
  25. data/lib/krane/cli/version_command.rb +1 -1
  26. data/lib/krane/cluster_resource_discovery.rb +113 -0
  27. data/lib/{kubernetes-deploy → krane}/common.rb +8 -9
  28. data/lib/krane/concerns/template_reporting.rb +29 -0
  29. data/lib/{kubernetes-deploy → krane}/concurrency.rb +1 -1
  30. data/lib/{kubernetes-deploy → krane}/container_logs.rb +3 -2
  31. data/lib/{kubernetes-deploy → krane}/deferred_summary_logging.rb +2 -2
  32. data/lib/{kubernetes-deploy → krane}/delayed_exceptions.rb +0 -0
  33. data/lib/krane/deploy_task.rb +16 -0
  34. data/lib/krane/deploy_task_config_validator.rb +29 -0
  35. data/lib/krane/deprecated_deploy_task.rb +404 -0
  36. data/lib/{kubernetes-deploy → krane}/duration_parser.rb +1 -3
  37. data/lib/{kubernetes-deploy → krane}/ejson_secret_provisioner.rb +10 -13
  38. data/lib/krane/errors.rb +28 -0
  39. data/lib/{kubernetes-deploy → krane}/formatted_logger.rb +2 -2
  40. data/lib/krane/global_deploy_task.rb +210 -0
  41. data/lib/krane/global_deploy_task_config_validator.rb +12 -0
  42. data/lib/{kubernetes-deploy → krane}/kubeclient_builder.rb +13 -5
  43. data/lib/{kubernetes-deploy → krane}/kubectl.rb +14 -16
  44. data/lib/{kubernetes-deploy → krane}/kubernetes_resource.rb +110 -27
  45. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/cloudsql.rb +1 -1
  46. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/config_map.rb +1 -1
  47. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/cron_job.rb +1 -1
  48. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/custom_resource.rb +2 -2
  49. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/custom_resource_definition.rb +1 -5
  50. data/lib/krane/kubernetes_resource/daemon_set.rb +90 -0
  51. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/deployment.rb +2 -2
  52. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/horizontal_pod_autoscaler.rb +1 -1
  53. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/ingress.rb +1 -1
  54. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/job.rb +1 -1
  55. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/network_policy.rb +1 -1
  56. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/persistent_volume_claim.rb +1 -1
  57. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/pod.rb +6 -2
  58. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/pod_disruption_budget.rb +2 -2
  59. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/pod_set_base.rb +3 -3
  60. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/pod_template.rb +1 -1
  61. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/replica_set.rb +2 -2
  62. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/resource_quota.rb +1 -1
  63. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/role.rb +1 -1
  64. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/role_binding.rb +1 -1
  65. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/secret.rb +1 -1
  66. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/service.rb +2 -2
  67. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/service_account.rb +1 -1
  68. data/lib/{kubernetes-deploy → krane}/kubernetes_resource/stateful_set.rb +2 -2
  69. data/lib/{kubernetes-deploy → krane}/label_selector.rb +1 -1
  70. data/lib/{kubernetes-deploy → krane}/oj.rb +0 -0
  71. data/lib/{kubernetes-deploy → krane}/options_helper.rb +2 -2
  72. data/lib/{kubernetes-deploy → krane}/remote_logs.rb +2 -2
  73. data/lib/krane/render_task.rb +149 -0
  74. data/lib/{kubernetes-deploy → krane}/renderer.rb +1 -1
  75. data/lib/{kubernetes-deploy → krane}/resource_cache.rb +10 -9
  76. data/lib/krane/resource_deployer.rb +265 -0
  77. data/lib/{kubernetes-deploy → krane}/resource_watcher.rb +24 -25
  78. data/lib/krane/restart_task.rb +228 -0
  79. data/lib/{kubernetes-deploy → krane}/rollout_conditions.rb +1 -1
  80. data/lib/krane/runner_task.rb +212 -0
  81. data/lib/{kubernetes-deploy → krane}/runner_task_config_validator.rb +1 -1
  82. data/lib/{kubernetes-deploy → krane}/statsd.rb +13 -27
  83. data/lib/krane/task_config.rb +22 -0
  84. data/lib/{kubernetes-deploy → krane}/task_config_validator.rb +1 -1
  85. data/lib/{kubernetes-deploy → krane}/template_sets.rb +5 -5
  86. data/lib/krane/version.rb +4 -0
  87. data/lib/kubernetes-deploy/deploy_task.rb +6 -608
  88. data/lib/kubernetes-deploy/errors.rb +1 -26
  89. data/lib/kubernetes-deploy/render_task.rb +5 -122
  90. data/lib/kubernetes-deploy/rescue_krane_exceptions.rb +18 -0
  91. data/lib/kubernetes-deploy/restart_task.rb +6 -198
  92. data/lib/kubernetes-deploy/runner_task.rb +6 -184
  93. metadata +96 -70
  94. data/lib/kubernetes-deploy/cluster_resource_discovery.rb +0 -34
  95. data/lib/kubernetes-deploy/kubernetes_resource/daemon_set.rb +0 -54
  96. data/lib/kubernetes-deploy/task_config.rb +0 -16
  97. data/lib/kubernetes-deploy/version.rb +0 -4
@@ -2,15 +2,15 @@
2
2
  require 'json'
3
3
  require 'shellwords'
4
4
 
5
- require 'kubernetes-deploy/remote_logs'
6
- require 'kubernetes-deploy/duration_parser'
7
- require 'kubernetes-deploy/label_selector'
8
- require 'kubernetes-deploy/rollout_conditions'
5
+ require 'krane/remote_logs'
6
+ require 'krane/duration_parser'
7
+ require 'krane/label_selector'
8
+ require 'krane/rollout_conditions'
9
9
 
10
- module KubernetesDeploy
10
+ module Krane
11
11
  class KubernetesResource
12
12
  attr_reader :name, :namespace, :context
13
- attr_writer :type, :deploy_started_at
13
+ attr_writer :type, :deploy_started_at, :global
14
14
 
15
15
  GLOBAL = false
16
16
  TIMEOUT = 5.minutes
@@ -40,7 +40,7 @@ module KubernetesDeploy
40
40
  SERVER_DRY_RUNNABLE = false
41
41
 
42
42
  class << self
43
- def build(namespace:, context:, definition:, logger:, statsd_tags:, crd: nil)
43
+ def build(namespace: nil, context:, definition:, logger:, statsd_tags:, crd: nil, global_names: [])
44
44
  validate_definition_essentials(definition)
45
45
  opts = { namespace: namespace, context: context, definition: definition, logger: logger,
46
46
  statsd_tags: statsd_tags }
@@ -50,15 +50,17 @@ module KubernetesDeploy
50
50
  if crd
51
51
  CustomResource.new(crd: crd, **opts)
52
52
  else
53
+ type = definition["kind"]
53
54
  inst = new(**opts)
54
- inst.type = definition["kind"]
55
+ inst.type = type
56
+ inst.global = global_names.map(&:downcase).include?(type.downcase)
55
57
  inst
56
58
  end
57
59
  end
58
60
 
59
61
  def class_for_kind(kind)
60
- if KubernetesDeploy.const_defined?(kind)
61
- KubernetesDeploy.const_get(kind)
62
+ if Krane.const_defined?(kind)
63
+ Krane.const_get(kind)
62
64
  end
63
65
  rescue NameError
64
66
  nil
@@ -85,8 +87,9 @@ module KubernetesDeploy
85
87
  raise InvalidTemplateError.new("Template is missing required field 'kind'", content: debug_content)
86
88
  end
87
89
 
88
- if definition.dig('metadata', 'name').blank?
89
- raise InvalidTemplateError.new("Template is missing required field 'metadata.name'", content: debug_content)
90
+ if definition.dig('metadata', 'name').blank? && definition.dig('metadata', 'generateName').blank?
91
+ raise InvalidTemplateError.new("Template must specify one of 'metadata.name' or 'metadata.generateName'",
92
+ content: debug_content)
90
93
  end
91
94
  end
92
95
  end
@@ -110,7 +113,7 @@ module KubernetesDeploy
110
113
 
111
114
  def initialize(namespace:, context:, definition:, logger:, statsd_tags: [])
112
115
  # subclasses must also set these if they define their own initializer
113
- @name = definition.dig("metadata", "name").to_s
116
+ @name = (definition.dig("metadata", "name") || definition.dig("metadata", "generateName")).to_s
114
117
  @optional_statsd_tags = statsd_tags
115
118
  @namespace = namespace
116
119
  @context = context
@@ -168,7 +171,7 @@ module KubernetesDeploy
168
171
 
169
172
  def sync(cache)
170
173
  @instance_data = cache.get_instance(kubectl_resource_type, name, raise_if_not_found: true)
171
- rescue KubernetesDeploy::Kubectl::ResourceNotFoundError
174
+ rescue Krane::Kubectl::ResourceNotFoundError
172
175
  @disappeared = true if deploy_started?
173
176
  @instance_data = {}
174
177
  end
@@ -233,9 +236,13 @@ module KubernetesDeploy
233
236
  !deploy_succeeded? && !deploy_failed? && (Time.now.utc - @deploy_started_at > timeout)
234
237
  end
235
238
 
236
- # Expected values: :apply, :replace, :replace_force
239
+ # Expected values: :apply, :create, :replace, :replace_force
237
240
  def deploy_method
238
- :apply
241
+ if @definition.dig("metadata", "name").blank? && uses_generate_name?
242
+ :create
243
+ else
244
+ :apply
245
+ end
239
246
  end
240
247
 
241
248
  def sync_debug_info(kubectl)
@@ -315,7 +322,7 @@ module KubernetesDeploy
315
322
  def fetch_events(kubectl)
316
323
  return {} unless exists?
317
324
  out, _err, st = kubectl.run("get", "events", "--output=go-template=#{Event.go_template_for(type, name)}",
318
- log_failure: false)
325
+ log_failure: false, use_namespace: !global?)
319
326
  return {} unless st.success?
320
327
 
321
328
  event_collector = Hash.new { |hash, key| hash[key] = [] }
@@ -338,7 +345,7 @@ module KubernetesDeploy
338
345
 
339
346
  def report_status_to_statsd(watch_time)
340
347
  unless @statsd_report_done
341
- StatsD.distribution('resource.duration', watch_time, tags: statsd_tags)
348
+ StatsD.client.distribution('resource.duration', watch_time, tags: statsd_tags)
342
349
  @statsd_report_done = true
343
350
  end
344
351
  end
@@ -348,13 +355,29 @@ module KubernetesDeploy
348
355
  end
349
356
 
350
357
  def server_dry_runnable_resource?
351
- self.class::SERVER_DRY_RUNNABLE
358
+ # generateName and server-side dry run are incompatible because the former only works with `create`
359
+ # and the latter only works with `apply`
360
+ self.class::SERVER_DRY_RUNNABLE && !uses_generate_name?
361
+ end
362
+
363
+ def uses_generate_name?
364
+ @definition.dig('metadata', 'generateName').present?
352
365
  end
353
366
 
354
367
  def server_dry_run_validated?
355
368
  @server_dry_run_validated
356
369
  end
357
370
 
371
+ # If a resource uses generateName, we don't know the full name of the resource until it's deployed to the cluster.
372
+ # In this case, we need to update our local definition with the realized name in order to accurately track the
373
+ # resource during deploy
374
+ def use_generated_name(instance_data)
375
+ @name = instance_data.dig('metadata', 'name')
376
+ @definition['metadata']['name'] = @name
377
+ @definition['metadata'].delete('generateName')
378
+ @file = create_definition_tempfile
379
+ end
380
+
358
381
  class Event
359
382
  EVENT_SEPARATOR = "ENDEVENT--BEGINEVENT"
360
383
  FIELD_SEPARATOR = "ENDFIELD--BEGINFIELD"
@@ -365,7 +388,12 @@ module KubernetesDeploy
365
388
  .lastTimestamp
366
389
  .reason
367
390
  .message
391
+ .eventTime
392
+ .deprecatedCount
393
+ .deprecatedLastTimestamp
394
+ .series
368
395
  )
396
+ FIELD_EMPTY_VALUE = '<no value>'
369
397
 
370
398
  def self.go_template_for(kind, name)
371
399
  and_conditions = [
@@ -386,17 +414,61 @@ module KubernetesDeploy
386
414
  def self.extract_all_from_go_template_blob(blob)
387
415
  blob.split(EVENT_SEPARATOR).map do |event_blob|
388
416
  pieces = event_blob.split(FIELD_SEPARATOR, FIELDS.length)
417
+ count = extract_event_count(pieces)
418
+ timestamp = extract_event_timestamp(pieces)
419
+
389
420
  new(
390
421
  subject_kind: pieces[FIELDS.index(".involvedObject.kind")],
391
422
  subject_name: pieces[FIELDS.index(".involvedObject.name")],
392
- count: pieces[FIELDS.index(".count")],
393
- last_timestamp: pieces[FIELDS.index(".lastTimestamp")],
423
+ count: count,
424
+ last_timestamp: timestamp,
394
425
  reason: pieces[FIELDS.index(".reason")],
395
426
  message: pieces[FIELDS.index(".message")]
396
427
  )
397
428
  end
398
429
  end
399
430
 
431
+ def self.extract_event_count(pieces)
432
+ series = pieces[FIELDS.index(".series")]
433
+ count = pieces[FIELDS.index(".count")]
434
+ deprecated_count = pieces[FIELDS.index(".deprecatedCount")]
435
+
436
+ # Find the right event count according to Kubernetes API and kubectl version
437
+ if count.present? && count != FIELD_EMPTY_VALUE
438
+ count # This is the default field, so let's try to use it first
439
+ elsif series.present? && series != FIELD_EMPTY_VALUE
440
+ # kubectl 1.16 uses Events/v1, which has the .series/.count field
441
+ count_regex = /count:(?<value>\S+?(?=\s))/
442
+ count_regex.match(series)['value']
443
+ elsif deprecated_count.present? && deprecated_count != FIELD_EMPTY_VALUE
444
+ # kubectl < 1.16 uses events.k8s.io/v1beta1, which has .deprecatedCount
445
+ deprecated_count
446
+ else
447
+ "1" # Fallback to 1 when all count fields are null
448
+ end
449
+ end
450
+
451
+ def self.extract_event_timestamp(pieces)
452
+ series = pieces[FIELDS.index(".series")]
453
+ last_timestamp = pieces[FIELDS.index(".lastTimestamp")]
454
+ deprecated_timestamp = pieces[FIELDS.index(".deprecatedLastTimestamp")]
455
+
456
+ # Find the right event timestamp according to Kubernetes API and kubectl version
457
+ if last_timestamp.present? && last_timestamp != FIELD_EMPTY_VALUE
458
+ last_timestamp # kubernetes 1.16 also exposes .last_timestamp field, so let's support it
459
+ elsif series.present? && series != FIELD_EMPTY_VALUE
460
+ # kubectl 1.16 uses Events/v1, which has the .series/.lastObservedTime field
461
+ timestamp_regex = /lastObservedTime:(?<value>\S+?(?=\]))/
462
+ timestamp_regex.match(series)['value']
463
+ elsif deprecated_timestamp.present? && deprecated_timestamp != FIELD_EMPTY_VALUE
464
+ # kubectl < 1.16 uses events.k8s.io/v1beta1, which has .deprecatedLastTimestamp
465
+ deprecated_timestamp
466
+ else
467
+ pieces[FIELDS.index(".eventTime")] # Fallback to eventTime when other timestamp fields are null
468
+ end
469
+ end
470
+ private_class_method :extract_event_timestamp, :extract_event_count
471
+
400
472
  def initialize(subject_kind:, last_timestamp:, reason:, message:, count:, subject_name:)
401
473
  @subject_kind = subject_kind
402
474
  @subject_name = subject_name
@@ -416,7 +488,7 @@ module KubernetesDeploy
416
488
  end
417
489
 
418
490
  def global?
419
- self.class::GLOBAL
491
+ @global || self.class::GLOBAL
420
492
  end
421
493
 
422
494
  private
@@ -478,13 +550,13 @@ module KubernetesDeploy
478
550
  def validate_spec_with_kubectl(kubectl)
479
551
  err = ""
480
552
  if kubectl.server_dry_run_enabled? && server_dry_runnable_resource?
481
- _, err, st = validate_with_dry_run_option(kubectl, "--server-dry-run")
553
+ _, err, st = validate_with_server_side_dry_run(kubectl)
482
554
  @server_dry_run_validated = st.success?
483
555
  return true if st.success?
484
556
  end
485
557
 
486
558
  if err.empty? || err.match(SERVER_DRY_RUN_DISABLED_ERROR)
487
- _, err, st = validate_with_dry_run_option(kubectl, "--dry-run")
559
+ _, err, st = validate_with_local_dry_run(kubectl)
488
560
  end
489
561
 
490
562
  return true if st.success?
@@ -495,10 +567,21 @@ module KubernetesDeploy
495
567
  end
496
568
  end
497
569
 
498
- def validate_with_dry_run_option(kubectl, dry_run_option)
499
- command = ["apply", "-f", file_path, dry_run_option, "--output=name"]
570
+ # Server side dry run is only supported on apply
571
+ def validate_with_server_side_dry_run(kubectl)
572
+ command = ["apply", "-f", file_path, "--server-dry-run", "--output=name"]
573
+ kubectl.run(*command, log_failure: false, output_is_sensitive: sensitive_template_content?,
574
+ retry_whitelist: [:client_timeout], attempts: 3)
575
+ end
576
+
577
+ # Local dry run is supported on only create and apply
578
+ # If the deploy method is create, validating with apply will fail
579
+ # If the resource template uses generateName, validating with apply will fail
580
+ def validate_with_local_dry_run(kubectl)
581
+ verb = deploy_method == :apply ? "apply" : "create"
582
+ command = [verb, "-f", file_path, "--dry-run", "--output=name"]
500
583
  kubectl.run(*command, log_failure: false, output_is_sensitive: sensitive_template_content?,
501
- retry_whitelist: [:client_timeout], attempts: 3)
584
+ retry_whitelist: [:client_timeout], attempts: 3, use_namespace: !global?)
502
585
  end
503
586
 
504
587
  def labels
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- module KubernetesDeploy
2
+ module Krane
3
3
  class Cloudsql < KubernetesResource
4
4
  TIMEOUT = 10.minutes
5
5
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- module KubernetesDeploy
2
+ module Krane
3
3
  class ConfigMap < KubernetesResource
4
4
  TIMEOUT = 30.seconds
5
5
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- module KubernetesDeploy
2
+ module Krane
3
3
  class CronJob < KubernetesResource
4
4
  TIMEOUT = 30.seconds
5
5
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require 'jsonpath'
3
3
 
4
- module KubernetesDeploy
4
+ module Krane
5
5
  class CustomResource < KubernetesResource
6
6
  TIMEOUT_MESSAGE_DIFFERENT_GENERATIONS = <<~MSG
7
7
  This resource's status could not be used to determine rollout success because it is not up-to-date
@@ -68,7 +68,7 @@ module KubernetesDeploy
68
68
  @crd.validate_rollout_conditions
69
69
  rescue RolloutConditionsError => e
70
70
  @validation_errors << "The CRD that specifies this resource is using invalid rollout conditions. " \
71
- "Kubernetes-deploy will not be able to continue until those rollout conditions are fixed.\n" \
71
+ "Krane will not be able to continue until those rollout conditions are fixed.\n" \
72
72
  "Rollout conditions can be found on the CRD that defines this resource (#{@crd.name}), " \
73
73
  "under the annotation #{CustomResourceDefinition::ROLLOUT_CONDITIONS_ANNOTATION}.\n" \
74
74
  "Validation failed with: #{e}"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- module KubernetesDeploy
2
+ module Krane
3
3
  class CustomResourceDefinition < KubernetesResource
4
4
  TIMEOUT = 2.minutes
5
5
  ROLLOUT_CONDITIONS_ANNOTATION_SUFFIX = "instance-rollout-conditions"
@@ -46,10 +46,6 @@ module KubernetesDeploy
46
46
  @definition.dig("spec", "names", "kind")
47
47
  end
48
48
 
49
- def name
50
- @definition.dig("metadata", "name")
51
- end
52
-
53
49
  def prunable?
54
50
  prunable = krane_annotation_value("prunable")
55
51
  prunable == "true"
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+ require "krane/kubernetes_resource/pod_set_base"
3
+ module Krane
4
+ class DaemonSet < PodSetBase
5
+ TIMEOUT = 5.minutes
6
+ attr_reader :pods
7
+
8
+ def sync(cache)
9
+ super
10
+ @pods = exists? ? find_pods(cache) : []
11
+ @nodes = find_nodes(cache) if @nodes.blank?
12
+ end
13
+
14
+ def status
15
+ return super unless exists?
16
+ rollout_data.map { |state_replicas, num| "#{num} #{state_replicas}" }.join(", ")
17
+ end
18
+
19
+ def deploy_succeeded?
20
+ return false unless exists?
21
+ current_generation == observed_generation &&
22
+ rollout_data["desiredNumberScheduled"].to_i == rollout_data["updatedNumberScheduled"].to_i &&
23
+ relevant_pods_ready?
24
+ end
25
+
26
+ def deploy_failed?
27
+ pods.present? && pods.any?(&:deploy_failed?) &&
28
+ observed_generation == current_generation
29
+ end
30
+
31
+ def fetch_debug_logs
32
+ most_useful_pod = pods.find(&:deploy_failed?) || pods.find(&:deploy_timed_out?) || pods.first
33
+ most_useful_pod.fetch_debug_logs
34
+ end
35
+
36
+ def print_debug_logs?
37
+ pods.present? # the kubectl command times out if no pods exist
38
+ end
39
+
40
+ private
41
+
42
+ class Node
43
+ attr_reader :name
44
+
45
+ class << self
46
+ def kind
47
+ name.demodulize
48
+ end
49
+ end
50
+
51
+ def initialize(definition:)
52
+ @name = definition.dig("metadata", "name").to_s
53
+ @definition = definition
54
+ end
55
+ end
56
+
57
+ def relevant_pods_ready?
58
+ return true if rollout_data["desiredNumberScheduled"].to_i == rollout_data["numberReady"].to_i # all pods ready
59
+ relevant_node_names = @nodes.map(&:name)
60
+ considered_pods = @pods.select { |p| relevant_node_names.include?(p.node_name) }
61
+ @logger.debug("DaemonSet is reporting #{rollout_data['numberReady']} pods ready." \
62
+ " Considered #{considered_pods.size} pods out of #{@pods.size} for #{@nodes.size} nodes.")
63
+ considered_pods.present? &&
64
+ considered_pods.all?(&:deploy_succeeded?) &&
65
+ rollout_data["numberReady"].to_i >= considered_pods.length
66
+ end
67
+
68
+ def find_nodes(cache)
69
+ all_nodes = cache.get_all(Node.kind)
70
+ all_nodes.map { |node_data| Node.new(definition: node_data) }
71
+ end
72
+
73
+ def rollout_data
74
+ return { "currentNumberScheduled" => 0 } unless exists?
75
+ @instance_data["status"]
76
+ .slice("updatedNumberScheduled", "desiredNumberScheduled", "numberReady")
77
+ end
78
+
79
+ def parent_of_pod?(pod_data)
80
+ return false unless pod_data.dig("metadata", "ownerReferences")
81
+
82
+ template_generation = @instance_data.dig("spec", "templateGeneration") ||
83
+ @instance_data.dig("metadata", "annotations", "deprecated.daemonset.template.generation")
84
+ return false unless template_generation.present?
85
+
86
+ pod_data["metadata"]["ownerReferences"].any? { |ref| ref["uid"] == @instance_data["metadata"]["uid"] } &&
87
+ pod_data["metadata"]["labels"]["pod-template-generation"].to_i == template_generation.to_i
88
+ end
89
+ end
90
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
- require 'kubernetes-deploy/kubernetes_resource/replica_set'
2
+ require 'krane/kubernetes_resource/replica_set'
3
3
 
4
- module KubernetesDeploy
4
+ module Krane
5
5
  class Deployment < KubernetesResource
6
6
  TIMEOUT = 7.minutes
7
7
  REQUIRED_ROLLOUT_ANNOTATION_SUFFIX = "required-rollout"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- module KubernetesDeploy
2
+ module Krane
3
3
  class HorizontalPodAutoscaler < KubernetesResource
4
4
  TIMEOUT = 3.minutes
5
5
  RECOVERABLE_CONDITION_PREFIX = "FailedGet"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- module KubernetesDeploy
2
+ module Krane
3
3
  class Ingress < KubernetesResource
4
4
  TIMEOUT = 30.seconds
5
5
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- module KubernetesDeploy
2
+ module Krane
3
3
  class Job < KubernetesResource
4
4
  TIMEOUT = 10.minutes
5
5