kubernetes-deploy 0.19.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.buildkite/pipeline.nightly.yml +8 -7
- data/CHANGELOG.md +20 -0
- data/dev.yml +1 -1
- data/kubernetes-deploy.gemspec +1 -1
- data/lib/kubernetes-deploy/deploy_task.rb +70 -41
- data/lib/kubernetes-deploy/errors.rb +9 -0
- data/lib/kubernetes-deploy/kubernetes_resource.rb +8 -4
- data/lib/kubernetes-deploy/kubernetes_resource/deployment.rb +15 -4
- data/lib/kubernetes-deploy/kubernetes_resource/pod.rb +4 -2
- data/lib/kubernetes-deploy/kubernetes_resource/replica_set.rb +4 -2
- data/lib/kubernetes-deploy/renderer.rb +17 -19
- data/lib/kubernetes-deploy/resource_watcher.rb +2 -2
- data/lib/kubernetes-deploy/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a581b73a9b59ce7dbc35a528acf269ba9ee12523
|
4
|
+
data.tar.gz: 4d3b6268317bf30b3011d1eb3e9f8bcc9c731c4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15197ca3f8d90b28927dc8a5ab365bb7f455434c49af708db82b2f8f5dd7430420a8e4819edbc1d4579cd2291df0a002f11924be3a865631a11e5a1fa3f3b344
|
7
|
+
data.tar.gz: bae4f408b4bfad19e61754991f24bf34d48dca2929f1d33dbd592b2fcc009b7135adc3dc92201c1e8d7633d80520a798e03aedec45778d59d81aa0a872ab7426
|
@@ -1,10 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
# Disableed until minikube can run 1.10
|
2
|
+
# - name: 'Run Test Suite (:kubernetes: 1.10-latest)'
|
3
|
+
# command: bin/ci
|
4
|
+
# agents:
|
5
|
+
# queue: minikube-ci
|
6
|
+
# env:
|
7
|
+
# LOGGING_LEVEL: 4
|
8
|
+
# KUBERNETES_VERSION: v1.10-latest
|
8
9
|
- name: 'Run Test Suite (:kubernetes: 1.9-latest)'
|
9
10
|
command: bin/ci
|
10
11
|
agents:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
### Master
|
2
|
+
|
3
|
+
*Features*
|
4
|
+
|
5
|
+
*Bug Fixes*
|
6
|
+
|
7
|
+
*Enhancements*
|
8
|
+
|
9
|
+
### 0.20.0
|
10
|
+
|
11
|
+
*Features*
|
12
|
+
- Automatically add all Kubernetes namespace labels to StatsD tags ([#278](https://github.com/Shopify/kubernetes-deploy/pull/278))
|
13
|
+
|
14
|
+
*Bug Fixes*
|
15
|
+
- Prevent calling sleep with a negative value ([#273](https://github.com/Shopify/kubernetes-deploy/pull/273))
|
16
|
+
- Prevent no-op redeploys of bad code from hanging forever ([#262](https://github.com/Shopify/kubernetes-deploy/pull/262))
|
17
|
+
|
18
|
+
*Enhancements*
|
19
|
+
- Improve output for rendering errors ([#253](https://github.com/Shopify/kubernetes-deploy/pull/253))
|
20
|
+
|
1
21
|
### 0.19.0
|
2
22
|
*Features*
|
3
23
|
- Added `--max-watch-seconds=seconds` to kubernetes-restart and kubernetes-deploy. When set
|
data/dev.yml
CHANGED
@@ -8,7 +8,7 @@ up:
|
|
8
8
|
- custom:
|
9
9
|
name: Minikube Cluster
|
10
10
|
met?: test $(minikube status | grep Running | wc -l) -eq 2 && $(minikube status | grep -q 'Correctly Configured')
|
11
|
-
meet: minikube start --
|
11
|
+
meet: minikube start --kubernetes-version=v1.9.4 --vm-driver=hyperkit
|
12
12
|
down: minikube stop
|
13
13
|
commands:
|
14
14
|
reset-minikube: minikube delete && rm -rf ~/.minikube
|
data/kubernetes-deploy.gemspec
CHANGED
@@ -36,5 +36,5 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_development_dependency "minitest", "~> 5.0"
|
37
37
|
spec.add_development_dependency "minitest-stub-const", "~> 0.6"
|
38
38
|
spec.add_development_dependency "webmock", "~> 3.0"
|
39
|
-
spec.add_development_dependency "mocha", "~> 1.
|
39
|
+
spec.add_development_dependency "mocha", "~> 1.5"
|
40
40
|
end
|
@@ -92,6 +92,7 @@ module KubernetesDeploy
|
|
92
92
|
def initialize(namespace:, context:, current_sha:, template_dir:, logger:, kubectl_instance: nil, bindings: {},
|
93
93
|
max_watch_seconds: nil)
|
94
94
|
@namespace = namespace
|
95
|
+
@namespace_tags = []
|
95
96
|
@context = context
|
96
97
|
@current_sha = current_sha
|
97
98
|
@template_dir = File.expand_path(template_dir)
|
@@ -122,6 +123,7 @@ module KubernetesDeploy
|
|
122
123
|
validate_configuration(allow_protected_ns: allow_protected_ns, prune: prune)
|
123
124
|
confirm_context_exists
|
124
125
|
confirm_namespace_exists
|
126
|
+
@namespace_tags |= tags_from_namespace_labels
|
125
127
|
resources = discover_resources
|
126
128
|
validate_definitions(resources)
|
127
129
|
|
@@ -187,15 +189,6 @@ module KubernetesDeploy
|
|
187
189
|
|
188
190
|
private
|
189
191
|
|
190
|
-
# Inspect the file referenced in the kubectl stderr
|
191
|
-
# to make it easier for developer to understand what's going on
|
192
|
-
def find_bad_files_from_kubectl_output(stderr)
|
193
|
-
# stderr often contains one or more lines like the following, from which we can extract the file path(s):
|
194
|
-
# Error from server (TypeOfError): error when creating "/path/to/service-gqq5oh.yml": Service "web" is invalid:
|
195
|
-
matches = stderr.scan(%r{"(/\S+\.ya?ml\S*)"})
|
196
|
-
matches&.flatten
|
197
|
-
end
|
198
|
-
|
199
192
|
def deploy_has_priority_resources?(resources)
|
200
193
|
resources.any? { |r| PREDEPLOY_SEQUENCE.include?(r.type) }
|
201
194
|
end
|
@@ -225,7 +218,8 @@ module KubernetesDeploy
|
|
225
218
|
return unless failed_resources.present?
|
226
219
|
|
227
220
|
failed_resources.each do |r|
|
228
|
-
|
221
|
+
content = File.read(r.file_path) if File.file?(r.file_path)
|
222
|
+
record_invalid_template(err: r.validation_error_msg, filename: File.basename(r.file_path), content: content)
|
229
223
|
end
|
230
224
|
raise FatalDeploymentError, "Template validation failed"
|
231
225
|
end
|
@@ -238,7 +232,8 @@ module KubernetesDeploy
|
|
238
232
|
next unless filename.end_with?(".yml.erb", ".yml", ".yaml", ".yaml.erb")
|
239
233
|
|
240
234
|
split_templates(filename) do |r_def|
|
241
|
-
r = KubernetesResource.build(namespace: @namespace, context: @context, logger: @logger,
|
235
|
+
r = KubernetesResource.build(namespace: @namespace, context: @context, logger: @logger,
|
236
|
+
definition: r_def, statsd_tags: @namespace_tags)
|
242
237
|
resources << r
|
243
238
|
@logger.info " - #{r.id}"
|
244
239
|
end
|
@@ -250,34 +245,25 @@ module KubernetesDeploy
|
|
250
245
|
file_content = File.read(File.join(@template_dir, filename))
|
251
246
|
rendered_content = @renderer.render_template(filename, file_content)
|
252
247
|
YAML.load_stream(rendered_content) do |doc|
|
253
|
-
|
248
|
+
next if doc.blank?
|
249
|
+
unless doc.is_a?(Hash)
|
250
|
+
raise InvalidTemplateError.new("Template is not a valid Kubernetes manifest",
|
251
|
+
filename: filename, content: doc)
|
252
|
+
end
|
253
|
+
yield doc
|
254
254
|
end
|
255
|
+
rescue InvalidTemplateError => e
|
256
|
+
record_invalid_template(err: e.message, filename: e.filename, content: e.content)
|
257
|
+
raise FatalDeploymentError, "Failed to render and parse template"
|
255
258
|
rescue Psych::SyntaxError => e
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
Template content:
|
260
|
-
---
|
261
|
-
INFO
|
262
|
-
debug_msg += rendered_content
|
263
|
-
@logger.summary.add_paragraph(debug_msg)
|
264
|
-
raise FatalDeploymentError, "Template '#{filename}' cannot be parsed"
|
259
|
+
record_invalid_template(err: e.message, filename: filename, content: rendered_content)
|
260
|
+
raise FatalDeploymentError, "Failed to render and parse template"
|
265
261
|
end
|
266
262
|
|
267
|
-
def record_invalid_template(err
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
contents << File.read(file_path)
|
272
|
-
template_names << File.basename(file_path) unless original_filenames
|
273
|
-
end.join("\n")
|
274
|
-
template_list = template_names.compact.join(", ").presence || "See error message"
|
275
|
-
|
276
|
-
debug_msg = ColorizedString.new("Invalid #{'template'.pluralize(template_names.length)}: #{template_list}\n").red
|
277
|
-
debug_msg += "> Error from kubectl:\n#{indent_four(err)}"
|
278
|
-
if file_content.present?
|
279
|
-
debug_msg += "\n> Rendered template content:\n#{indent_four(file_content)}"
|
280
|
-
end
|
263
|
+
def record_invalid_template(err:, filename:, content:)
|
264
|
+
debug_msg = ColorizedString.new("Invalid template: #{filename}\n").red
|
265
|
+
debug_msg += "> Error message:\n#{indent_four(err)}"
|
266
|
+
debug_msg += "\n> Template content:\n#{indent_four(content)}"
|
281
267
|
@logger.summary.add_paragraph(debug_msg)
|
282
268
|
end
|
283
269
|
|
@@ -406,11 +392,7 @@ module KubernetesDeploy
|
|
406
392
|
if st.success?
|
407
393
|
log_pruning(out) if prune
|
408
394
|
else
|
409
|
-
|
410
|
-
warn_msg = "WARNING: Any resources not mentioned in the error below were likely created/updated. " \
|
411
|
-
"You may wish to roll back this deploy."
|
412
|
-
@logger.summary.add_paragraph(ColorizedString.new(warn_msg).yellow)
|
413
|
-
record_invalid_template(err, file_paths: file_paths)
|
395
|
+
record_apply_failure(err)
|
414
396
|
raise FatalDeploymentError, "Command failed: #{Shellwords.join(command)}"
|
415
397
|
end
|
416
398
|
end
|
@@ -424,6 +406,41 @@ module KubernetesDeploy
|
|
424
406
|
@logger.summary.add_action("pruned #{pruned.length} #{'resource'.pluralize(pruned.length)}")
|
425
407
|
end
|
426
408
|
|
409
|
+
def record_apply_failure(err)
|
410
|
+
warn_msg = "WARNING: Any resources not mentioned in the error(s) below were likely created/updated. " \
|
411
|
+
"You may wish to roll back this deploy."
|
412
|
+
@logger.summary.add_paragraph(ColorizedString.new(warn_msg).yellow)
|
413
|
+
|
414
|
+
unidentified_errors = []
|
415
|
+
err.each_line do |line|
|
416
|
+
bad_files = find_bad_files_from_kubectl_output(line)
|
417
|
+
if bad_files.present?
|
418
|
+
bad_files.each { |f| record_invalid_template(err: f[:err], filename: f[:filename], content: f[:content]) }
|
419
|
+
else
|
420
|
+
unidentified_errors << line
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
if unidentified_errors.present?
|
425
|
+
msg = "#{ColorizedString.new('Unidentified error(s):').red}\n#{indent_four(unidentified_errors.join)}"
|
426
|
+
@logger.summary.add_paragraph(msg)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
# Inspect the file referenced in the kubectl stderr
|
431
|
+
# to make it easier for developer to understand what's going on
|
432
|
+
def find_bad_files_from_kubectl_output(line)
|
433
|
+
# stderr often contains one or more lines like the following, from which we can extract the file path(s):
|
434
|
+
# Error from server (TypeOfError): error when creating "/path/to/service-gqq5oh.yml": Service "web" is invalid:
|
435
|
+
|
436
|
+
line.scan(%r{"(/\S+\.ya?ml\S*)"}).each_with_object([]) do |matches, bad_files|
|
437
|
+
matches.each do |path|
|
438
|
+
content = File.read(path) if File.file?(path)
|
439
|
+
bad_files << { filename: File.basename(path), err: line, content: content }
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
427
444
|
def confirm_context_exists
|
428
445
|
out, err, st = kubectl.run("config", "get-contexts", "-o", "name",
|
429
446
|
use_namespace: false, use_context: false, log_failure: false)
|
@@ -462,12 +479,24 @@ module KubernetesDeploy
|
|
462
479
|
@logger.info("Namespace #{@namespace} found")
|
463
480
|
end
|
464
481
|
|
482
|
+
def tags_from_namespace_labels
|
483
|
+
namespace_info = nil
|
484
|
+
with_retries(2) do
|
485
|
+
namespace_info, _, st = kubectl.run("get", "namespace", @namespace, "-o", "json", use_namespace: false,
|
486
|
+
log_failure: true)
|
487
|
+
st.success?
|
488
|
+
end
|
489
|
+
return [] if namespace_info.blank?
|
490
|
+
namespace_labels = JSON.parse(namespace_info, symbolize_names: true).fetch(:metadata, {}).fetch(:labels, {})
|
491
|
+
namespace_labels.map { |key, value| "#{key}:#{value}" }
|
492
|
+
end
|
493
|
+
|
465
494
|
def kubectl
|
466
495
|
@kubectl ||= Kubectl.new(namespace: @namespace, context: @context, logger: @logger, log_failure_by_default: true)
|
467
496
|
end
|
468
497
|
|
469
498
|
def statsd_tags
|
470
|
-
%W(namespace:#{@namespace} sha:#{@current_sha} context:#{@context})
|
499
|
+
%W(namespace:#{@namespace} sha:#{@current_sha} context:#{@context}) | @namespace_tags
|
471
500
|
end
|
472
501
|
|
473
502
|
def with_retries(limit)
|
@@ -3,6 +3,15 @@ module KubernetesDeploy
|
|
3
3
|
class FatalDeploymentError < StandardError; end
|
4
4
|
class KubectlError < StandardError; end
|
5
5
|
|
6
|
+
class InvalidTemplateError < FatalDeploymentError
|
7
|
+
attr_reader :filename, :content
|
8
|
+
def initialize(err, filename:, content: nil)
|
9
|
+
@filename = filename
|
10
|
+
@content = content
|
11
|
+
super(err)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
6
15
|
class NamespaceNotFoundError < FatalDeploymentError
|
7
16
|
def initialize(name, context)
|
8
17
|
super("Namespace `#{name}` not found in context `#{context}`")
|
@@ -28,8 +28,9 @@ module KubernetesDeploy
|
|
28
28
|
TIMEOUT_OVERRIDE_ANNOTATION = "kubernetes-deploy.shopify.io/timeout-override"
|
29
29
|
|
30
30
|
class << self
|
31
|
-
def build(namespace:, context:, definition:, logger:)
|
32
|
-
opts = { namespace: namespace, context: context, definition: definition, logger: logger
|
31
|
+
def build(namespace:, context:, definition:, logger:, statsd_tags:)
|
32
|
+
opts = { namespace: namespace, context: context, definition: definition, logger: logger,
|
33
|
+
statsd_tags: statsd_tags }
|
33
34
|
if KubernetesDeploy.const_defined?(definition["kind"])
|
34
35
|
klass = KubernetesDeploy.const_get(definition["kind"])
|
35
36
|
klass.new(**opts)
|
@@ -65,7 +66,7 @@ module KubernetesDeploy
|
|
65
66
|
"timeout: #{timeout}s"
|
66
67
|
end
|
67
68
|
|
68
|
-
def initialize(namespace:, context:, definition:, logger:)
|
69
|
+
def initialize(namespace:, context:, definition:, logger:, statsd_tags: [])
|
69
70
|
# subclasses must also set these if they define their own initializer
|
70
71
|
@name = definition.dig("metadata", "name")
|
71
72
|
unless @name.present?
|
@@ -73,6 +74,7 @@ module KubernetesDeploy
|
|
73
74
|
raise FatalDeploymentError, "Template is missing required field metadata.name"
|
74
75
|
end
|
75
76
|
|
77
|
+
@optional_statsd_tags = statsd_tags
|
76
78
|
@namespace = namespace
|
77
79
|
@context = context
|
78
80
|
@logger = logger
|
@@ -356,7 +358,9 @@ module KubernetesDeploy
|
|
356
358
|
else
|
357
359
|
"unknown"
|
358
360
|
end
|
359
|
-
%W(context:#{context} namespace:#{namespace} resource:#{id}
|
361
|
+
tags = %W(context:#{context} namespace:#{namespace} resource:#{id}
|
362
|
+
type:#{type} sha:#{ENV['REVISION']} status:#{status})
|
363
|
+
tags | @optional_statsd_tags
|
360
364
|
end
|
361
365
|
end
|
362
366
|
end
|
@@ -96,6 +96,16 @@ module KubernetesDeploy
|
|
96
96
|
|
97
97
|
private
|
98
98
|
|
99
|
+
def current_generation
|
100
|
+
return -2 unless exists? # different default than observed
|
101
|
+
@instance_data.dig('metadata', 'generation')
|
102
|
+
end
|
103
|
+
|
104
|
+
def observed_generation
|
105
|
+
return -1 unless exists? # different default than current
|
106
|
+
@instance_data.dig('status', 'observedGeneration')
|
107
|
+
end
|
108
|
+
|
99
109
|
def desired_replicas
|
100
110
|
return -1 unless exists?
|
101
111
|
@instance_data["spec"]["replicas"].to_i
|
@@ -133,12 +143,13 @@ module KubernetesDeploy
|
|
133
143
|
# Deployments were being updated prematurely with incorrect progress information
|
134
144
|
# https://github.com/kubernetes/kubernetes/issues/49637
|
135
145
|
return false unless Time.now.utc - @deploy_started_at >= progress_deadline.to_i
|
136
|
-
else
|
137
|
-
return false unless deploy_started?
|
138
146
|
end
|
139
147
|
|
140
|
-
|
141
|
-
|
148
|
+
# This assumes that when the controller bumps the observed generation, it also updates/clears all the status
|
149
|
+
# conditions. Specifically, it assumes the progress condition is immediately set to True if a rollout is starting.
|
150
|
+
deploy_started? &&
|
151
|
+
current_generation == observed_generation &&
|
152
|
+
progress_condition["status"] == 'False'
|
142
153
|
end
|
143
154
|
|
144
155
|
def find_latest_rs(mediator)
|
@@ -5,7 +5,8 @@ module KubernetesDeploy
|
|
5
5
|
|
6
6
|
FAILED_PHASE_NAME = "Failed"
|
7
7
|
|
8
|
-
def initialize(namespace:, context:, definition:, logger:,
|
8
|
+
def initialize(namespace:, context:, definition:, logger:,
|
9
|
+
statsd_tags: nil, parent: nil, deploy_started_at: nil)
|
9
10
|
@parent = parent
|
10
11
|
@deploy_started_at = deploy_started_at
|
11
12
|
@containers = definition.fetch("spec", {}).fetch("containers", []).map { |c| Container.new(c) }
|
@@ -14,7 +15,8 @@ module KubernetesDeploy
|
|
14
15
|
raise FatalDeploymentError, "Template is missing required field spec.containers"
|
15
16
|
end
|
16
17
|
@containers += definition["spec"].fetch("initContainers", []).map { |c| Container.new(c, init_container: true) }
|
17
|
-
super(namespace: namespace, context: context, definition: definition,
|
18
|
+
super(namespace: namespace, context: context, definition: definition,
|
19
|
+
logger: logger, statsd_tags: statsd_tags)
|
18
20
|
end
|
19
21
|
|
20
22
|
def sync(mediator)
|
@@ -5,11 +5,13 @@ module KubernetesDeploy
|
|
5
5
|
TIMEOUT = 5.minutes
|
6
6
|
attr_reader :pods
|
7
7
|
|
8
|
-
def initialize(namespace:, context:, definition:, logger:,
|
8
|
+
def initialize(namespace:, context:, definition:, logger:, statsd_tags: nil,
|
9
|
+
parent: nil, deploy_started_at: nil)
|
9
10
|
@parent = parent
|
10
11
|
@deploy_started_at = deploy_started_at
|
11
12
|
@pods = []
|
12
|
-
super(namespace: namespace, context: context, definition: definition,
|
13
|
+
super(namespace: namespace, context: context, definition: definition,
|
14
|
+
logger: logger, statsd_tags: statsd_tags)
|
13
15
|
end
|
14
16
|
|
15
17
|
SYNC_DEPENDENCIES = %w(Pod)
|
@@ -7,14 +7,14 @@ require 'json'
|
|
7
7
|
|
8
8
|
module KubernetesDeploy
|
9
9
|
class Renderer
|
10
|
-
class InvalidPartialError <
|
11
|
-
|
12
|
-
def initialize(msg, parents
|
10
|
+
class InvalidPartialError < InvalidTemplateError
|
11
|
+
attr_accessor :parents, :content, :filename
|
12
|
+
def initialize(msg, parents: [], content: nil, filename:)
|
13
13
|
@parents = parents
|
14
|
-
super(msg)
|
14
|
+
super(msg, content: content, filename: filename)
|
15
15
|
end
|
16
16
|
end
|
17
|
-
class PartialNotFound <
|
17
|
+
class PartialNotFound < InvalidTemplateError; end
|
18
18
|
|
19
19
|
def initialize(current_sha:, template_dir:, logger:, bindings: {})
|
20
20
|
@current_sha = current_sha
|
@@ -35,11 +35,11 @@ module KubernetesDeploy
|
|
35
35
|
|
36
36
|
ERB.new(raw_template, nil, '-').result(erb_binding)
|
37
37
|
rescue InvalidPartialError => err
|
38
|
-
|
39
|
-
|
38
|
+
err.parents = err.parents.dup.unshift(filename)
|
39
|
+
err.filename = "#{err.filename} (partial included from: #{err.parents.join(' -> ')})"
|
40
|
+
raise err
|
40
41
|
rescue StandardError => err
|
41
|
-
|
42
|
-
raise FatalDeploymentError, "Template '#{filename}' cannot be rendered"
|
42
|
+
raise InvalidTemplateError.new(err.message, filename: filename, content: raw_template)
|
43
43
|
end
|
44
44
|
|
45
45
|
def render_partial(partial, locals)
|
@@ -60,12 +60,14 @@ module KubernetesDeploy
|
|
60
60
|
# Note that JSON is a subset of YAML.
|
61
61
|
JSON.generate(docs.children.first.to_ruby)
|
62
62
|
rescue PartialNotFound => err
|
63
|
-
|
63
|
+
# get the filename from the first parent, not the missing partial itself
|
64
|
+
raise err if err.filename == partial
|
65
|
+
raise InvalidPartialError.new(err.message, filename: partial, content: expanded_template || template)
|
64
66
|
rescue InvalidPartialError => err
|
65
|
-
|
67
|
+
err.parents = err.parents.dup.unshift(File.basename(partial_path))
|
68
|
+
raise err
|
66
69
|
rescue StandardError => err
|
67
|
-
|
68
|
-
raise InvalidPartialError, "Template '#{partial_path}' cannot be rendered"
|
70
|
+
raise InvalidPartialError.new(err.message, filename: partial_path, content: expanded_template || template)
|
69
71
|
end
|
70
72
|
|
71
73
|
private
|
@@ -91,12 +93,8 @@ module KubernetesDeploy
|
|
91
93
|
return partial_path if File.exist?(partial_path)
|
92
94
|
end
|
93
95
|
end
|
94
|
-
raise PartialNotFound
|
95
|
-
|
96
|
-
|
97
|
-
def report_template_invalid(message, content)
|
98
|
-
@logger.summary.add_paragraph("Error from renderer:\n #{message.tr("\n", ' ')}")
|
99
|
-
@logger.summary.add_paragraph("Rendered template content:\n#{content}")
|
96
|
+
raise PartialNotFound.new("Could not find partial '#{name}' in any of #{@partials_dirs.join(':')}",
|
97
|
+
filename: name)
|
100
98
|
end
|
101
99
|
|
102
100
|
class TemplateContext
|
@@ -24,8 +24,8 @@ module KubernetesDeploy
|
|
24
24
|
if @timeout && (Time.now.utc - monitoring_started > @timeout)
|
25
25
|
report_and_give_up(remainder)
|
26
26
|
end
|
27
|
-
if Time.now.utc
|
28
|
-
sleep(
|
27
|
+
if (sleep_duration = delay_sync_until - Time.now.utc) > 0
|
28
|
+
sleep(sleep_duration)
|
29
29
|
end
|
30
30
|
delay_sync_until = Time.now.utc + delay_sync # don't pummel the API if the sync is fast
|
31
31
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubernetes-deploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.20.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Katrina Verey
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-04-
|
12
|
+
date: 2018-04-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -185,14 +185,14 @@ dependencies:
|
|
185
185
|
requirements:
|
186
186
|
- - "~>"
|
187
187
|
- !ruby/object:Gem::Version
|
188
|
-
version: '1.
|
188
|
+
version: '1.5'
|
189
189
|
type: :development
|
190
190
|
prerelease: false
|
191
191
|
version_requirements: !ruby/object:Gem::Requirement
|
192
192
|
requirements:
|
193
193
|
- - "~>"
|
194
194
|
- !ruby/object:Gem::Version
|
195
|
-
version: '1.
|
195
|
+
version: '1.5'
|
196
196
|
description: Kubernetes deploy scripts
|
197
197
|
email:
|
198
198
|
- ops-accounts+shipit@shopify.com
|