tobsch-krane 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.buildkite/pipeline.nightly.yml +43 -0
- data/.github/probots.yml +2 -0
- data/.gitignore +20 -0
- data/.rubocop.yml +17 -0
- data/.shopify-build/VERSION +1 -0
- data/.shopify-build/kubernetes-deploy.yml +53 -0
- data/1.0-Upgrade.md +185 -0
- data/CHANGELOG.md +431 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/CONTRIBUTING.md +164 -0
- data/Gemfile +16 -0
- data/ISSUE_TEMPLATE.md +25 -0
- data/LICENSE.txt +21 -0
- data/README.md +655 -0
- data/Rakefile +36 -0
- data/bin/ci +21 -0
- data/bin/setup +16 -0
- data/bin/test +47 -0
- data/dev.yml +28 -0
- data/dev/flamegraph-from-tests +35 -0
- data/exe/krane +5 -0
- data/krane.gemspec +44 -0
- data/lib/krane.rb +7 -0
- data/lib/krane/bindings_parser.rb +88 -0
- data/lib/krane/cli/deploy_command.rb +75 -0
- data/lib/krane/cli/global_deploy_command.rb +54 -0
- data/lib/krane/cli/krane.rb +91 -0
- data/lib/krane/cli/render_command.rb +41 -0
- data/lib/krane/cli/restart_command.rb +34 -0
- data/lib/krane/cli/run_command.rb +54 -0
- data/lib/krane/cli/version_command.rb +13 -0
- data/lib/krane/cluster_resource_discovery.rb +113 -0
- data/lib/krane/common.rb +23 -0
- data/lib/krane/concerns/template_reporting.rb +29 -0
- data/lib/krane/concurrency.rb +18 -0
- data/lib/krane/container_logs.rb +106 -0
- data/lib/krane/deferred_summary_logging.rb +95 -0
- data/lib/krane/delayed_exceptions.rb +14 -0
- data/lib/krane/deploy_task.rb +363 -0
- data/lib/krane/deploy_task_config_validator.rb +29 -0
- data/lib/krane/duration_parser.rb +27 -0
- data/lib/krane/ejson_secret_provisioner.rb +154 -0
- data/lib/krane/errors.rb +28 -0
- data/lib/krane/formatted_logger.rb +57 -0
- data/lib/krane/global_deploy_task.rb +210 -0
- data/lib/krane/global_deploy_task_config_validator.rb +12 -0
- data/lib/krane/kubeclient_builder.rb +156 -0
- data/lib/krane/kubectl.rb +120 -0
- data/lib/krane/kubernetes_resource.rb +621 -0
- data/lib/krane/kubernetes_resource/cloudsql.rb +43 -0
- data/lib/krane/kubernetes_resource/config_map.rb +22 -0
- data/lib/krane/kubernetes_resource/cron_job.rb +18 -0
- data/lib/krane/kubernetes_resource/custom_resource.rb +87 -0
- data/lib/krane/kubernetes_resource/custom_resource_definition.rb +98 -0
- data/lib/krane/kubernetes_resource/daemon_set.rb +90 -0
- data/lib/krane/kubernetes_resource/deployment.rb +213 -0
- data/lib/krane/kubernetes_resource/horizontal_pod_autoscaler.rb +65 -0
- data/lib/krane/kubernetes_resource/ingress.rb +18 -0
- data/lib/krane/kubernetes_resource/job.rb +60 -0
- data/lib/krane/kubernetes_resource/network_policy.rb +22 -0
- data/lib/krane/kubernetes_resource/persistent_volume_claim.rb +80 -0
- data/lib/krane/kubernetes_resource/pod.rb +269 -0
- data/lib/krane/kubernetes_resource/pod_disruption_budget.rb +23 -0
- data/lib/krane/kubernetes_resource/pod_set_base.rb +71 -0
- data/lib/krane/kubernetes_resource/pod_template.rb +20 -0
- data/lib/krane/kubernetes_resource/replica_set.rb +92 -0
- data/lib/krane/kubernetes_resource/resource_quota.rb +22 -0
- data/lib/krane/kubernetes_resource/role.rb +22 -0
- data/lib/krane/kubernetes_resource/role_binding.rb +22 -0
- data/lib/krane/kubernetes_resource/secret.rb +24 -0
- data/lib/krane/kubernetes_resource/service.rb +104 -0
- data/lib/krane/kubernetes_resource/service_account.rb +22 -0
- data/lib/krane/kubernetes_resource/stateful_set.rb +70 -0
- data/lib/krane/label_selector.rb +42 -0
- data/lib/krane/oj.rb +4 -0
- data/lib/krane/options_helper.rb +39 -0
- data/lib/krane/remote_logs.rb +60 -0
- data/lib/krane/render_task.rb +118 -0
- data/lib/krane/renderer.rb +118 -0
- data/lib/krane/resource_cache.rb +68 -0
- data/lib/krane/resource_deployer.rb +265 -0
- data/lib/krane/resource_watcher.rb +171 -0
- data/lib/krane/restart_task.rb +228 -0
- data/lib/krane/rollout_conditions.rb +103 -0
- data/lib/krane/runner_task.rb +212 -0
- data/lib/krane/runner_task_config_validator.rb +18 -0
- data/lib/krane/statsd.rb +65 -0
- data/lib/krane/task_config.rb +22 -0
- data/lib/krane/task_config_validator.rb +96 -0
- data/lib/krane/template_sets.rb +173 -0
- data/lib/krane/version.rb +4 -0
- data/pull_request_template.md +8 -0
- data/screenshots/deploy-demo.gif +0 -0
- data/screenshots/migrate-logs.png +0 -0
- data/screenshots/missing-secret-fail.png +0 -0
- data/screenshots/success.png +0 -0
- data/screenshots/test-output.png +0 -0
- metadata +375 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Krane
|
4
|
+
class LabelSelector
|
5
|
+
def self.parse(string)
|
6
|
+
selector = {}
|
7
|
+
|
8
|
+
string.split(',').each do |kvp|
|
9
|
+
key, value = kvp.split('=', 2)
|
10
|
+
|
11
|
+
if key.blank?
|
12
|
+
raise ArgumentError, "key is blank"
|
13
|
+
end
|
14
|
+
|
15
|
+
if key.end_with?("!")
|
16
|
+
raise ArgumentError, "!= selectors are not supported"
|
17
|
+
end
|
18
|
+
|
19
|
+
if value&.start_with?("=")
|
20
|
+
raise ArgumentError, "== selectors are not supported"
|
21
|
+
end
|
22
|
+
|
23
|
+
selector[key] = value
|
24
|
+
end
|
25
|
+
|
26
|
+
new(selector)
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(hash)
|
30
|
+
@selector = hash
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_h
|
34
|
+
@selector
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
return "" if @selector.nil?
|
39
|
+
@selector.map { |k, v| "#{k}=#{v}" }.join(",")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/krane/oj.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Krane
|
4
|
+
module OptionsHelper
|
5
|
+
class OptionsError < StandardError; end
|
6
|
+
|
7
|
+
STDIN_TEMP_FILE = "from_stdin.yml"
|
8
|
+
class << self
|
9
|
+
def with_processed_template_paths(template_paths, render_erb: false)
|
10
|
+
validated_paths = []
|
11
|
+
template_paths.uniq!
|
12
|
+
template_paths.each do |template_path|
|
13
|
+
next if template_path == '-'
|
14
|
+
validated_paths << template_path
|
15
|
+
end
|
16
|
+
|
17
|
+
if template_paths.include?("-")
|
18
|
+
Dir.mktmpdir("krane") do |dir|
|
19
|
+
template_dir_from_stdin(temp_dir: dir, render_erb: render_erb)
|
20
|
+
validated_paths << dir
|
21
|
+
yield validated_paths
|
22
|
+
end
|
23
|
+
else
|
24
|
+
yield validated_paths
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def template_dir_from_stdin(temp_dir:, render_erb:)
|
31
|
+
tempfile = STDIN_TEMP_FILE
|
32
|
+
tempfile += ".erb" if render_erb
|
33
|
+
File.open(File.join(temp_dir, tempfile), 'w+') { |f| f.print($stdin.read) }
|
34
|
+
rescue IOError, Errno::ENOENT => e
|
35
|
+
raise OptionsError, e.message
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'krane/container_logs'
|
3
|
+
|
4
|
+
module Krane
|
5
|
+
class RemoteLogs
|
6
|
+
attr_reader :container_logs
|
7
|
+
|
8
|
+
def initialize(logger:, parent_id:, container_names:, namespace:, context:)
|
9
|
+
@logger = logger
|
10
|
+
@parent_id = parent_id
|
11
|
+
@container_logs = container_names.map do |n|
|
12
|
+
ContainerLogs.new(
|
13
|
+
logger: logger,
|
14
|
+
container_name: n,
|
15
|
+
parent_id: parent_id,
|
16
|
+
namespace: namespace,
|
17
|
+
context: context
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def empty?
|
23
|
+
@container_logs.all?(&:empty?)
|
24
|
+
end
|
25
|
+
|
26
|
+
def sync
|
27
|
+
@container_logs.each(&:sync)
|
28
|
+
end
|
29
|
+
|
30
|
+
def print_latest
|
31
|
+
@container_logs.each do |cl|
|
32
|
+
unless cl.printing_started?
|
33
|
+
@logger.info("Streaming logs from #{@parent_id} container '#{cl.container_name}':")
|
34
|
+
end
|
35
|
+
cl.print_latest(prefix: @container_logs.length > 1)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def print_all(prevent_duplicate: true)
|
40
|
+
return if @already_displayed && prevent_duplicate
|
41
|
+
|
42
|
+
if @container_logs.all?(&:empty?)
|
43
|
+
@logger.warn("No logs found for #{@parent_id}")
|
44
|
+
return
|
45
|
+
end
|
46
|
+
|
47
|
+
@container_logs.each do |cl|
|
48
|
+
if cl.empty?
|
49
|
+
@logger.warn("No logs found for #{@parent_id} container '#{cl.container_name}'")
|
50
|
+
else
|
51
|
+
@logger.info("Logs from #{@parent_id} container '#{cl.container_name}':")
|
52
|
+
cl.print_all
|
53
|
+
@logger.blank_line
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
@already_displayed = true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,118 @@
|
|
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 filenames [Array<String>] An array of filenames and/or directories containing templates (*required*)
|
16
|
+
# @param bindings [Hash] Bindings parsed by Krane::BindingsParser
|
17
|
+
def initialize(logger: nil, current_sha:, filenames: [], bindings:)
|
18
|
+
@logger = logger || Krane::FormattedLogger.build
|
19
|
+
@filenames = filenames.map { |path| File.expand_path(path) }
|
20
|
+
@bindings = bindings
|
21
|
+
@current_sha = current_sha
|
22
|
+
end
|
23
|
+
|
24
|
+
# Runs the task, returning a boolean representing success or failure
|
25
|
+
#
|
26
|
+
# @return [Boolean]
|
27
|
+
def run(*args)
|
28
|
+
run!(*args)
|
29
|
+
true
|
30
|
+
rescue Krane::FatalDeploymentError
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
# Runs the task, raising exceptions in case of issues
|
35
|
+
#
|
36
|
+
# @param stream [IO] Place to stream the output to
|
37
|
+
#
|
38
|
+
# @return [nil]
|
39
|
+
def run!(stream:)
|
40
|
+
@logger.reset
|
41
|
+
@logger.phase_heading("Initializing render task")
|
42
|
+
|
43
|
+
ts = TemplateSets.from_dirs_and_files(paths: @filenames, logger: @logger)
|
44
|
+
|
45
|
+
validate_configuration(ts)
|
46
|
+
count = render_templates(stream, ts)
|
47
|
+
|
48
|
+
@logger.summary.add_action("Successfully rendered #{count} template(s)")
|
49
|
+
@logger.print_summary(:success)
|
50
|
+
rescue Krane::FatalDeploymentError
|
51
|
+
@logger.print_summary(:failure)
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def render_templates(stream, template_sets)
|
58
|
+
@logger.phase_heading("Rendering template(s)")
|
59
|
+
count = 0
|
60
|
+
template_sets.with_resource_definitions_and_filename(current_sha: @current_sha,
|
61
|
+
bindings: @bindings, raw: true) do |rendered_content, filename|
|
62
|
+
write_to_stream(rendered_content, filename, stream)
|
63
|
+
count += 1
|
64
|
+
end
|
65
|
+
|
66
|
+
count
|
67
|
+
rescue Krane::InvalidTemplateError => exception
|
68
|
+
log_invalid_template(exception)
|
69
|
+
raise
|
70
|
+
end
|
71
|
+
|
72
|
+
def write_to_stream(rendered_content, filename, stream)
|
73
|
+
file_basename = File.basename(filename)
|
74
|
+
@logger.info("Rendering #{file_basename}...")
|
75
|
+
implicit = []
|
76
|
+
YAML.parse_stream(rendered_content, "<rendered> #{filename}") { |d| implicit << d.implicit }
|
77
|
+
if rendered_content.present?
|
78
|
+
stream.puts "---\n" if implicit.first
|
79
|
+
stream.puts rendered_content
|
80
|
+
@logger.info("Rendered #{file_basename}")
|
81
|
+
else
|
82
|
+
@logger.warn("Rendered #{file_basename} successfully, but the result was blank")
|
83
|
+
end
|
84
|
+
rescue Psych::SyntaxError => exception
|
85
|
+
raise InvalidTemplateError.new("Template is not valid YAML. #{exception.message}", filename: filename)
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate_configuration(template_sets)
|
89
|
+
@logger.info("Validating configuration")
|
90
|
+
errors = []
|
91
|
+
if @filenames.blank?
|
92
|
+
errors << "filenames must be set"
|
93
|
+
end
|
94
|
+
|
95
|
+
if !@current_sha.nil? && @current_sha.empty?
|
96
|
+
errors << "current-sha is optional but can not be blank"
|
97
|
+
end
|
98
|
+
errors += template_sets.validate
|
99
|
+
|
100
|
+
unless errors.empty?
|
101
|
+
@logger.summary.add_action("Configuration invalid")
|
102
|
+
@logger.summary.add_paragraph(errors.map { |err| "- #{err}" }.join("\n"))
|
103
|
+
raise Krane::TaskConfigurationError, "Configuration invalid: #{errors.join(', ')}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def log_invalid_template(exception)
|
108
|
+
@logger.error("Failed to render #{exception.filename}")
|
109
|
+
|
110
|
+
debug_msg = ColorizedString.new("Invalid template: #{exception.filename}\n").red
|
111
|
+
debug_msg += "> Error message:\n#{FormattedLogger.indent_four(exception.to_s)}"
|
112
|
+
if exception.content
|
113
|
+
debug_msg += "\n> Template content:\n#{FormattedLogger.indent_four(exception.content)}"
|
114
|
+
end
|
115
|
+
@logger.summary.add_paragraph(debug_msg)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require 'securerandom'
|
5
|
+
require 'yaml'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
module Krane
|
9
|
+
class Renderer
|
10
|
+
class InvalidPartialError < InvalidTemplateError
|
11
|
+
attr_accessor :parents, :content, :filename
|
12
|
+
def initialize(msg, parents: [], content: nil, filename:)
|
13
|
+
@parents = parents
|
14
|
+
super(msg, content: content, filename: filename)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
class PartialNotFound < InvalidTemplateError; end
|
18
|
+
|
19
|
+
def initialize(current_sha:, template_dir:, logger:, bindings: {})
|
20
|
+
@current_sha = current_sha
|
21
|
+
@template_dir = template_dir
|
22
|
+
@partials_dirs =
|
23
|
+
%w(partials ../partials).map { |d| File.expand_path(File.join(@template_dir, d)) }
|
24
|
+
@logger = logger
|
25
|
+
@bindings = bindings
|
26
|
+
# Max length of podname is only 63chars so try to save some room by truncating sha to 8 chars
|
27
|
+
@id = if ENV["TASK_ID"]
|
28
|
+
ENV["TASK_ID"]
|
29
|
+
elsif current_sha
|
30
|
+
current_sha[0...8] + "-#{SecureRandom.hex(4)}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def render_template(filename, raw_template)
|
35
|
+
return raw_template unless File.extname(filename) == ".erb"
|
36
|
+
|
37
|
+
erb_binding = TemplateContext.new(self).template_binding
|
38
|
+
bind_template_variables(erb_binding, template_variables)
|
39
|
+
|
40
|
+
ERB.new(raw_template, nil, '-').result(erb_binding)
|
41
|
+
rescue InvalidPartialError => err
|
42
|
+
err.parents = err.parents.dup.unshift(filename)
|
43
|
+
err.filename = "#{err.filename} (partial included from: #{err.parents.join(' -> ')})"
|
44
|
+
raise err
|
45
|
+
rescue StandardError => err
|
46
|
+
raise InvalidTemplateError.new(err.message, filename: filename, content: raw_template)
|
47
|
+
end
|
48
|
+
|
49
|
+
def render_partial(partial, locals)
|
50
|
+
variables = template_variables.merge(locals)
|
51
|
+
erb_binding = TemplateContext.new(self).template_binding
|
52
|
+
bind_template_variables(erb_binding, variables)
|
53
|
+
erb_binding.local_variable_set("locals", locals)
|
54
|
+
|
55
|
+
partial_path = find_partial(partial)
|
56
|
+
template = File.read(partial_path)
|
57
|
+
expanded_template = ERB.new(template, nil, '-').result(erb_binding)
|
58
|
+
|
59
|
+
docs = Psych.parse_stream(expanded_template, partial_path)
|
60
|
+
# If the partial contains multiple documents or has an explicit document header,
|
61
|
+
# we know it cannot validly be indented in the parent, so return it immediately.
|
62
|
+
return expanded_template unless docs.children.one? && docs.children.first.implicit
|
63
|
+
# Make sure indentation isn't a problem by producing a single line of parseable YAML.
|
64
|
+
# Note that JSON is a subset of YAML.
|
65
|
+
JSON.generate(docs.children.first.to_ruby)
|
66
|
+
rescue PartialNotFound => err
|
67
|
+
# get the filename from the first parent, not the missing partial itself
|
68
|
+
raise err if err.filename == partial
|
69
|
+
raise InvalidPartialError.new(err.message, filename: partial, content: expanded_template || template)
|
70
|
+
rescue InvalidPartialError => err
|
71
|
+
err.parents = err.parents.dup.unshift(File.basename(partial_path))
|
72
|
+
raise err
|
73
|
+
rescue StandardError => err
|
74
|
+
raise InvalidPartialError.new(err.message, filename: partial_path, content: expanded_template || template)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def template_variables
|
80
|
+
{
|
81
|
+
'current_sha' => @current_sha,
|
82
|
+
'deployment_id' => @id,
|
83
|
+
}.merge(@bindings)
|
84
|
+
end
|
85
|
+
|
86
|
+
def bind_template_variables(erb_binding, variables)
|
87
|
+
variables.each do |var_name, value|
|
88
|
+
erb_binding.local_variable_set(var_name, value)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def find_partial(name)
|
93
|
+
partial_names = [name + '.yaml.erb', name + '.yml.erb']
|
94
|
+
@partials_dirs.each do |dir|
|
95
|
+
partial_names.each do |partial_name|
|
96
|
+
partial_path = File.join(dir, partial_name)
|
97
|
+
return partial_path if File.exist?(partial_path)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
raise PartialNotFound.new("Could not find partial '#{name}' in any of #{@partials_dirs.join(':')}",
|
101
|
+
filename: name)
|
102
|
+
end
|
103
|
+
|
104
|
+
class TemplateContext
|
105
|
+
def initialize(renderer)
|
106
|
+
@_renderer = renderer
|
107
|
+
end
|
108
|
+
|
109
|
+
def template_binding
|
110
|
+
binding
|
111
|
+
end
|
112
|
+
|
113
|
+
def partial(partial, locals = {})
|
114
|
+
@_renderer.render_partial(partial, locals)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'concurrent/hash'
|
4
|
+
|
5
|
+
module Krane
|
6
|
+
class ResourceCache
|
7
|
+
delegate :namespace, :context, :logger, to: :@task_config
|
8
|
+
|
9
|
+
def initialize(task_config)
|
10
|
+
@task_config = task_config
|
11
|
+
|
12
|
+
@kind_fetcher_locks = Concurrent::Hash.new { |hash, key| hash[key] = Mutex.new }
|
13
|
+
@data = Concurrent::Hash.new
|
14
|
+
@kubectl = Kubectl.new(task_config: @task_config, log_failure_by_default: false)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_instance(kind, resource_name, raise_if_not_found: false)
|
18
|
+
instance = use_or_populate_cache(kind).fetch(resource_name, {})
|
19
|
+
if instance.blank? && raise_if_not_found
|
20
|
+
raise Krane::Kubectl::ResourceNotFoundError, "Resource does not exist (used cache for kind #{kind})"
|
21
|
+
end
|
22
|
+
instance
|
23
|
+
rescue KubectlError
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_all(kind, selector = nil)
|
28
|
+
instances = use_or_populate_cache(kind).values
|
29
|
+
return instances unless selector
|
30
|
+
|
31
|
+
instances.select do |r|
|
32
|
+
labels = r.dig("metadata", "labels") || {}
|
33
|
+
labels >= selector
|
34
|
+
end
|
35
|
+
rescue KubectlError
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def statsd_tags
|
42
|
+
{ namespace: namespace, context: context }
|
43
|
+
end
|
44
|
+
|
45
|
+
def use_or_populate_cache(kind)
|
46
|
+
@kind_fetcher_locks[kind].synchronize do
|
47
|
+
return @data[kind] if @data.key?(kind)
|
48
|
+
@data[kind] = fetch_by_kind(kind)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def fetch_by_kind(kind)
|
53
|
+
resource_class = KubernetesResource.class_for_kind(kind)
|
54
|
+
global_kind = @task_config.global_kinds.map(&:downcase).include?(kind.downcase)
|
55
|
+
output_is_sensitive = resource_class.nil? ? false : resource_class::SENSITIVE_TEMPLATE_CONTENT
|
56
|
+
raw_json, _, st = @kubectl.run("get", kind, "--chunk-size=0", attempts: 5, output: "json",
|
57
|
+
output_is_sensitive: output_is_sensitive, use_namespace: !global_kind)
|
58
|
+
raise KubectlError unless st.success?
|
59
|
+
|
60
|
+
instances = {}
|
61
|
+
JSON.parse(raw_json)["items"].each do |resource|
|
62
|
+
resource_name = resource.dig("metadata", "name")
|
63
|
+
instances[resource_name] = resource
|
64
|
+
end
|
65
|
+
instances
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|