kubernetes-deploy 0.30.0 → 0.31.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +15 -0
- data/CONTRIBUTING.md +2 -2
- data/README.md +1 -1
- data/dev.yml +1 -1
- data/dev/flamegraph-from-tests +1 -1
- data/exe/kubernetes-deploy +11 -9
- data/exe/kubernetes-render +9 -7
- data/exe/kubernetes-restart +3 -3
- data/exe/kubernetes-run +1 -1
- data/kubernetes-deploy.gemspec +3 -3
- data/lib/krane.rb +5 -3
- data/lib/{kubernetes-deploy → krane}/bindings_parser.rb +1 -1
- data/lib/krane/cli/deploy_command.rb +14 -11
- data/lib/krane/cli/global_deploy_command.rb +47 -0
- data/lib/krane/cli/krane.rb +12 -3
- data/lib/krane/cli/render_command.rb +11 -9
- data/lib/krane/cli/restart_command.rb +4 -4
- data/lib/krane/cli/run_command.rb +3 -3
- data/lib/krane/cli/version_command.rb +1 -1
- data/lib/krane/cluster_resource_discovery.rb +102 -0
- data/lib/{kubernetes-deploy → krane}/common.rb +8 -9
- data/lib/krane/concerns/template_reporting.rb +29 -0
- data/lib/{kubernetes-deploy → krane}/concurrency.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/container_logs.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/deferred_summary_logging.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/delayed_exceptions.rb +0 -0
- data/lib/krane/deploy_task.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/deploy_task_config_validator.rb +1 -1
- data/lib/krane/deprecated_deploy_task.rb +404 -0
- data/lib/{kubernetes-deploy → krane}/duration_parser.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/ejson_secret_provisioner.rb +3 -3
- data/lib/krane/errors.rb +28 -0
- data/lib/{kubernetes-deploy → krane}/formatted_logger.rb +2 -2
- data/lib/krane/global_deploy_task.rb +210 -0
- data/lib/krane/global_deploy_task_config_validator.rb +12 -0
- data/lib/{kubernetes-deploy → krane}/kubeclient_builder.rb +11 -3
- data/lib/{kubernetes-deploy → krane}/kubectl.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource.rb +54 -22
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/cloudsql.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/config_map.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/cron_job.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/custom_resource.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/custom_resource_definition.rb +1 -5
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/daemon_set.rb +7 -4
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/deployment.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/horizontal_pod_autoscaler.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/ingress.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/job.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/network_policy.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/persistent_volume_claim.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/pod.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/pod_disruption_budget.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/pod_set_base.rb +3 -3
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/pod_template.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/replica_set.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/resource_quota.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/role.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/role_binding.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/secret.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/service.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/service_account.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/kubernetes_resource/stateful_set.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/label_selector.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/oj.rb +0 -0
- data/lib/{kubernetes-deploy → krane}/options_helper.rb +2 -2
- data/lib/{kubernetes-deploy → krane}/remote_logs.rb +2 -2
- data/lib/krane/render_task.rb +149 -0
- data/lib/{kubernetes-deploy → krane}/renderer.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/resource_cache.rb +4 -3
- data/lib/krane/resource_deployer.rb +265 -0
- data/lib/{kubernetes-deploy → krane}/resource_watcher.rb +6 -6
- data/lib/krane/restart_task.rb +224 -0
- data/lib/{kubernetes-deploy → krane}/rollout_conditions.rb +1 -1
- data/lib/krane/runner_task.rb +212 -0
- data/lib/{kubernetes-deploy → krane}/runner_task_config_validator.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/statsd.rb +13 -27
- data/lib/krane/task_config.rb +19 -0
- data/lib/{kubernetes-deploy → krane}/task_config_validator.rb +1 -1
- data/lib/{kubernetes-deploy → krane}/template_sets.rb +5 -5
- data/lib/krane/version.rb +4 -0
- data/lib/kubernetes-deploy/deploy_task.rb +6 -603
- data/lib/kubernetes-deploy/errors.rb +1 -26
- data/lib/kubernetes-deploy/render_task.rb +5 -139
- data/lib/kubernetes-deploy/rescue_krane_exceptions.rb +18 -0
- data/lib/kubernetes-deploy/restart_task.rb +6 -215
- data/lib/kubernetes-deploy/runner_task.rb +6 -203
- metadata +75 -58
- data/lib/kubernetes-deploy/cluster_resource_discovery.rb +0 -57
- data/lib/kubernetes-deploy/task_config.rb +0 -16
- data/lib/kubernetes-deploy/version.rb +0 -4
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'jsonpath'
|
3
3
|
|
4
|
-
module
|
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
|
-
"
|
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
|
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"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require '
|
3
|
-
module
|
2
|
+
require 'krane/kubernetes_resource/pod_set_base'
|
3
|
+
module Krane
|
4
4
|
class DaemonSet < PodSetBase
|
5
5
|
TIMEOUT = 5.minutes
|
6
6
|
attr_reader :pods
|
@@ -58,8 +58,11 @@ module KubernetesDeploy
|
|
58
58
|
return true if rollout_data["desiredNumberScheduled"].to_i == rollout_data["numberReady"].to_i # all pods ready
|
59
59
|
relevant_node_names = @nodes.map(&:name)
|
60
60
|
considered_pods = @pods.select { |p| relevant_node_names.include?(p.node_name) }
|
61
|
-
@logger.debug("
|
62
|
-
|
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
|
63
66
|
end
|
64
67
|
|
65
68
|
def find_nodes(cache)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require '
|
2
|
+
require 'krane/kubernetes_resource/replica_set'
|
3
3
|
|
4
|
-
module
|
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
|
2
|
+
module Krane
|
3
3
|
class Pod < KubernetesResource
|
4
4
|
TIMEOUT = 10.minutes
|
5
5
|
|
@@ -141,7 +141,7 @@ module KubernetesDeploy
|
|
141
141
|
end
|
142
142
|
|
143
143
|
def logs
|
144
|
-
@logs ||=
|
144
|
+
@logs ||= Krane::RemoteLogs.new(
|
145
145
|
logger: @logger,
|
146
146
|
parent_id: id,
|
147
147
|
container_names: @containers.map(&:name),
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module
|
2
|
+
module Krane
|
3
3
|
class PodDisruptionBudget < KubernetesResource
|
4
4
|
TIMEOUT = 10.seconds
|
5
5
|
|
@@ -13,7 +13,7 @@ module KubernetesDeploy
|
|
13
13
|
|
14
14
|
def deploy_method
|
15
15
|
# Required until https://github.com/kubernetes/kubernetes/issues/45398 changes
|
16
|
-
:replace_force
|
16
|
+
uses_generate_name? ? :create : :replace_force
|
17
17
|
end
|
18
18
|
|
19
19
|
def timeout_message
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require '
|
2
|
+
require 'krane/kubernetes_resource/pod'
|
3
3
|
|
4
|
-
module
|
4
|
+
module Krane
|
5
5
|
class PodSetBase < KubernetesResource
|
6
6
|
def failure_message
|
7
7
|
pods.map(&:failure_message).compact.uniq.join("\n")
|
@@ -19,7 +19,7 @@ module KubernetesDeploy
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def fetch_debug_logs
|
22
|
-
logs =
|
22
|
+
logs = Krane::RemoteLogs.new(
|
23
23
|
logger: @logger,
|
24
24
|
parent_id: id,
|
25
25
|
container_names: container_names,
|
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Krane
|
4
4
|
module OptionsHelper
|
5
5
|
class OptionsError < StandardError; end
|
6
6
|
|
@@ -19,7 +19,7 @@ module KubernetesDeploy
|
|
19
19
|
end
|
20
20
|
|
21
21
|
if template_paths.include?("-")
|
22
|
-
Dir.mktmpdir("
|
22
|
+
Dir.mktmpdir("krane") do |dir|
|
23
23
|
template_dir_from_stdin(temp_dir: dir)
|
24
24
|
validated_paths << dir
|
25
25
|
yield validated_paths
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
require 'krane/common'
|
5
|
+
require 'krane/renderer'
|
6
|
+
require 'krane/template_sets'
|
7
|
+
|
8
|
+
module Krane
|
9
|
+
# Render templates
|
10
|
+
class RenderTask
|
11
|
+
# Initializes the render task
|
12
|
+
#
|
13
|
+
# @param logger [Object] Logger object (defaults to an instance of Krane::FormattedLogger)
|
14
|
+
# @param current_sha [String] The SHA of the commit
|
15
|
+
# @param template_dir [String] Path to a directory with templates to render (deprecated)
|
16
|
+
# @param template_paths [Array<String>] An array of template paths to render
|
17
|
+
# @param bindings [Hash] Bindings parsed by Krane::BindingsParser
|
18
|
+
def initialize(logger: nil, current_sha:, template_dir: nil, template_paths: [], bindings:)
|
19
|
+
@logger = logger || Krane::FormattedLogger.build
|
20
|
+
@template_dir = template_dir
|
21
|
+
@template_paths = template_paths.map { |path| File.expand_path(path) }
|
22
|
+
@bindings = bindings
|
23
|
+
@current_sha = current_sha
|
24
|
+
end
|
25
|
+
|
26
|
+
# Runs the task, returning a boolean representing success or failure
|
27
|
+
#
|
28
|
+
# @return [Boolean]
|
29
|
+
def run(*args)
|
30
|
+
run!(*args)
|
31
|
+
true
|
32
|
+
rescue Krane::FatalDeploymentError
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
# Runs the task, raising exceptions in case of issues
|
37
|
+
#
|
38
|
+
# @param stream [IO] Place to stream the output to
|
39
|
+
# @param only_filenames [Array<String>] List of filenames to render
|
40
|
+
#
|
41
|
+
# @return [nil]
|
42
|
+
def run!(stream, only_filenames = [])
|
43
|
+
@logger.reset
|
44
|
+
@logger.phase_heading("Initializing render task")
|
45
|
+
|
46
|
+
ts = TemplateSets.from_dirs_and_files(paths: template_sets_paths(only_filenames), logger: @logger)
|
47
|
+
|
48
|
+
validate_configuration(ts, only_filenames)
|
49
|
+
count = render_templates(stream, ts)
|
50
|
+
|
51
|
+
@logger.summary.add_action("Successfully rendered #{count} template(s)")
|
52
|
+
@logger.print_summary(:success)
|
53
|
+
rescue Krane::FatalDeploymentError
|
54
|
+
@logger.print_summary(:failure)
|
55
|
+
raise
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def template_sets_paths(only_filenames)
|
61
|
+
if @template_paths.present?
|
62
|
+
# Validation will catch @template_paths & @template_dir being present
|
63
|
+
@template_paths
|
64
|
+
elsif only_filenames.blank?
|
65
|
+
[File.expand_path(@template_dir || '')]
|
66
|
+
else
|
67
|
+
absolute_template_dir = File.expand_path(@template_dir || '')
|
68
|
+
only_filenames.map do |name|
|
69
|
+
File.join(absolute_template_dir, name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def render_templates(stream, template_sets)
|
75
|
+
@logger.phase_heading("Rendering template(s)")
|
76
|
+
count = 0
|
77
|
+
template_sets.with_resource_definitions_and_filename(render_erb: true,
|
78
|
+
current_sha: @current_sha, bindings: @bindings, raw: true) do |rendered_content, filename|
|
79
|
+
write_to_stream(rendered_content, filename, stream)
|
80
|
+
count += 1
|
81
|
+
end
|
82
|
+
|
83
|
+
count
|
84
|
+
rescue Krane::InvalidTemplateError => exception
|
85
|
+
log_invalid_template(exception)
|
86
|
+
raise
|
87
|
+
end
|
88
|
+
|
89
|
+
def write_to_stream(rendered_content, filename, stream)
|
90
|
+
file_basename = File.basename(filename)
|
91
|
+
@logger.info("Rendering #{file_basename}...")
|
92
|
+
implicit = []
|
93
|
+
YAML.parse_stream(rendered_content, "<rendered> #{filename}") { |d| implicit << d.implicit }
|
94
|
+
if rendered_content.present?
|
95
|
+
stream.puts "---\n" if implicit.first
|
96
|
+
stream.puts rendered_content
|
97
|
+
@logger.info("Rendered #{file_basename}")
|
98
|
+
else
|
99
|
+
@logger.warn("Rendered #{file_basename} successfully, but the result was blank")
|
100
|
+
end
|
101
|
+
rescue Psych::SyntaxError => exception
|
102
|
+
raise InvalidTemplateError.new("Template is not valid YAML. #{exception.message}", filename: filename)
|
103
|
+
end
|
104
|
+
|
105
|
+
def validate_configuration(template_sets, filenames)
|
106
|
+
@logger.info("Validating configuration")
|
107
|
+
errors = []
|
108
|
+
if @template_dir.present? && @template_paths.present?
|
109
|
+
errors << "template_dir and template_paths can not be combined"
|
110
|
+
elsif @template_dir.blank? && @template_paths.blank?
|
111
|
+
errors << "template_dir or template_paths must be set"
|
112
|
+
end
|
113
|
+
|
114
|
+
if filenames.present?
|
115
|
+
if @template_dir.nil?
|
116
|
+
errors << "template_dir must be set to use filenames"
|
117
|
+
else
|
118
|
+
absolute_template_dir = File.expand_path(@template_dir)
|
119
|
+
filenames.each do |filename|
|
120
|
+
absolute_file = File.expand_path(File.join(@template_dir, filename))
|
121
|
+
unless absolute_file.start_with?(absolute_template_dir)
|
122
|
+
errors << "Filename \"#{absolute_file}\" is outside the template directory," \
|
123
|
+
" which was resolved as #{absolute_template_dir}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
errors += template_sets.validate
|
130
|
+
|
131
|
+
unless errors.empty?
|
132
|
+
@logger.summary.add_action("Configuration invalid")
|
133
|
+
@logger.summary.add_paragraph(errors.map { |err| "- #{err}" }.join("\n"))
|
134
|
+
raise Krane::TaskConfigurationError, "Configuration invalid: #{errors.join(', ')}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def log_invalid_template(exception)
|
139
|
+
@logger.error("Failed to render #{exception.filename}")
|
140
|
+
|
141
|
+
debug_msg = ColorizedString.new("Invalid template: #{exception.filename}\n").red
|
142
|
+
debug_msg += "> Error message:\n#{FormattedLogger.indent_four(exception.to_s)}"
|
143
|
+
if exception.content
|
144
|
+
debug_msg += "\n> Template content:\n#{FormattedLogger.indent_four(exception.content)}"
|
145
|
+
end
|
146
|
+
@logger.summary.add_paragraph(debug_msg)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|