kubernetes-deploy 0.7.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eed75bcad069720e6c7c9d44555af98924edca18
4
- data.tar.gz: 0f83407244b6b0f63ebceb7dffe92dccefa44f3b
3
+ metadata.gz: 255ea8b3ecd484e3867da8b34b4a61a927d99c1f
4
+ data.tar.gz: 79c4034b3460995f65fbeb54216688a5b1f448b6
5
5
  SHA512:
6
- metadata.gz: a13bc984fae5dd38639ab6ad8c0a4c3d69b6dd776f117ede5b47f05fa80199e59c8da0d6be6b35ca43455e8d1a9e4dd839932ca3f7db12983c247d940e4e9220
7
- data.tar.gz: 2412db53a8791bad8debfdf5bae2cfde075e49bbb725995fd972ce49b6936469db5281bb95befba25885e06cd45819002eb27af16237934d554494fac54ba4d2
6
+ metadata.gz: 8c9b9c54dea86318add19d23123e00ec5f3195488ec0ecbf954cdfe126dd1ca780d2c7cea6687342f2df8410ef7c5a53fd8b3ebb0649b6e8488fb1f2be42f0ef
7
+ data.tar.gz: a2cc7698a3b9f9b66bf8a54b7c5ac2483946760cdb52612c8b73fbc3c57ad8f716e8cedb4e1a732ecda59a82f37815de4ba41eb212a1e75399bd461b06061ebc
data/.rubocop.yml CHANGED
@@ -3,3 +3,6 @@ inherit_from:
3
3
 
4
4
  AllCops:
5
5
  TargetRubyVersion: 2.1
6
+
7
+ Layout/IndentHeredoc:
8
+ EnforcedStyle: active_support
data/README.md CHANGED
@@ -123,7 +123,13 @@ To run the tests:
123
123
  * Make sure you have a context named "minikube" in your kubeconfig. Minikube adds this context for you when you run `minikube start`; please do not rename it. You can check for it using `kubectl config get-contexts`.
124
124
  * Run `bundle exec rake test`
125
125
 
126
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
126
+ To install this gem onto your local machine, run `bundle exec rake install`.
127
+
128
+ To release a new version:
129
+
130
+ * Update the version number in `version.rb`
131
+ * Tag the version with `git tag vx.y.z && git push --tags`
132
+ * A Shopify employee can use the [Shipit Stack](https://shipit.shopify.io/shopify/kubernetes-deploy/rubygems) to build the `.gem` file and upload to [rubygems.org](https://rubygems.org/gems/kubernetes-deploy).
127
133
 
128
134
  ## CI
129
135
 
data/Rakefile CHANGED
@@ -7,4 +7,4 @@ Rake::TestTask.new(:test) do |t|
7
7
  t.test_files = FileList['test/**/*_test.rb']
8
8
  end
9
9
 
10
- task :default => :test
10
+ task default: :test
@@ -15,7 +15,7 @@ verbose_log_prefix = false
15
15
  ARGV.options do |opts|
16
16
  opts.on("--bindings=BINDINGS", Array, "k1=v1,k2=v2") do |binds|
17
17
  bindings = binds.each_with_object({}) do |bind, acc|
18
- k,v = bind.split('=')
18
+ k, v = bind.split('=')
19
19
  raise "key for value #{v} is blank!" if k.blank?
20
20
  raise "value for key #{k} is blank!" if v.blank?
21
21
  acc[k] = v
data/exe/kubernetes-run CHANGED
@@ -11,7 +11,7 @@ env_vars = []
11
11
 
12
12
  ARGV.options do |opts|
13
13
  opts.on("--template=TEMPLATE") { |n| template = n }
14
- opts.on("--env-vars=ENV_VARS") { |vars| env_vars = n.split(",")}
14
+ opts.on("--env-vars=ENV_VARS") { |vars| env_vars = vars.split(",") }
15
15
  opts.on("--entrypoint=ENTRYPOINT") { |c| entrypoint = [c] }
16
16
  opts.parse!
17
17
  end
@@ -6,10 +6,10 @@ require 'kubernetes-deploy/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "kubernetes-deploy"
8
8
  spec.version = KubernetesDeploy::VERSION
9
- spec.authors = ["Kir Shatrov", "Jean Boussier", "Katrina Verey"]
9
+ spec.authors = ["Katrina Verey", "Kir Shatrov"]
10
10
  spec.email = ["ops-accounts+shipit@shopify.com"]
11
11
 
12
- spec.summary = %q{Kubernetes deploy scripts}
12
+ spec.summary = 'Kubernetes deploy scripts'
13
13
  spec.description = spec.summary
14
14
  spec.homepage = "https://github.com/Shopify/kubernetes-deploy"
15
15
  spec.license = "MIT"
@@ -1,4 +1,6 @@
1
+ # rubocop:disable Style/FileName
1
2
  # frozen_string_literal: true
3
+
2
4
  require 'active_support/core_ext/object/blank'
3
5
  require 'active_support/core_ext/hash/slice'
4
6
  require 'active_support/core_ext/numeric/time'
@@ -23,12 +23,12 @@ module KubernetesDeploy
23
23
  heading("Phase #{@current_phase}: #{phase_name}")
24
24
  end
25
25
 
26
- def heading(text, secondary_msg = '', secondary_msg_color = :light_blue)
26
+ def heading(text, secondary_msg = '', secondary_msg_color = :cyan)
27
27
  padding = (100.0 - (text.length + secondary_msg.length)) / 2
28
28
  blank_line
29
- part1 = ColorizedString.new("#{'-' * padding.floor}#{text}").light_blue
29
+ part1 = ColorizedString.new("#{'-' * padding.floor}#{text}").cyan
30
30
  part2 = ColorizedString.new(secondary_msg).colorize(secondary_msg_color)
31
- part3 = ColorizedString.new('-' * padding.ceil).light_blue
31
+ part3 = ColorizedString.new('-' * padding.ceil).cyan
32
32
  info(part1 + part2 + part3)
33
33
  end
34
34
 
@@ -10,6 +10,7 @@ module KubernetesDeploy
10
10
  attr_writer :type, :deploy_started
11
11
 
12
12
  TIMEOUT = 5.minutes
13
+ LOG_LINE_COUNT = 250
13
14
 
14
15
  DEBUG_RESOURCE_NOT_FOUND_MESSAGE = "None found. Please check your usual logging service (e.g. Splunk)."
15
16
  UNUSUAL_FAILURE_MESSAGE = <<-MSG.strip_heredoc
@@ -138,7 +139,7 @@ module KubernetesDeploy
138
139
  if container_logs.blank? || container_logs.values.all?(&:blank?)
139
140
  helpful_info << " - Logs: #{DEBUG_RESOURCE_NOT_FOUND_MESSAGE}"
140
141
  else
141
- helpful_info << " - Logs:"
142
+ helpful_info << " - Logs (last #{LOG_LINE_COUNT} lines shown):"
142
143
  container_logs.each do |identifier, logs|
143
144
  logs.split("\n").each do |line|
144
145
  helpful_info << " [#{identifier}]\t#{line}"
@@ -75,12 +75,14 @@ module KubernetesDeploy
75
75
  return {} unless exists? && @containers.present?
76
76
 
77
77
  @containers.each_with_object({}) do |container_name, container_logs|
78
- out, _err, _st = kubectl.run(
78
+ cmd = [
79
79
  "logs",
80
80
  @name,
81
81
  "--container=#{container_name}",
82
- "--since-time=#{@deploy_started.to_datetime.rfc3339}"
83
- )
82
+ "--since-time=#{@deploy_started.to_datetime.rfc3339}",
83
+ ]
84
+ cmd << "--tail=#{LOG_LINE_COUNT}" unless unmanaged?
85
+ out, _err, _st = kubectl.run(*cmd)
84
86
  container_logs["#{id}/#{container_name}"] = out
85
87
  end
86
88
  end
@@ -1,25 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
  module KubernetesDeploy
3
3
  class ResourceWatcher
4
- def initialize(resources, logger:)
4
+ def initialize(resources, logger:, deploy_started_at: Time.now.utc)
5
5
  unless resources.is_a?(Enumerable)
6
- raise ArgumentError, <<-MSG.strip
7
- ResourceWatcher expects Enumerable collection, got `#{resources.class}` instead
8
- MSG
6
+ raise ArgumentError, <<-MSG.strip_heredoc
7
+ ResourceWatcher expects Enumerable collection, got `#{resources.class}` instead
8
+ MSG
9
9
  end
10
10
  @resources = resources
11
11
  @logger = logger
12
+ @deploy_started_at = deploy_started_at
12
13
  end
13
14
 
14
15
  def run(delay_sync: 3.seconds)
15
16
  delay_sync_until = Time.now.utc
16
- started_at = delay_sync_until
17
17
 
18
18
  while @resources.present?
19
19
  if Time.now.utc < delay_sync_until
20
20
  sleep(delay_sync_until - Time.now.utc)
21
21
  end
22
- watch_time = (Time.now.utc - started_at).round(1)
22
+ watch_time = (Time.now.utc - @deploy_started_at).round(1)
23
23
  delay_sync_until = Time.now.utc + delay_sync # don't pummel the API if the sync is fast
24
24
  @resources.each(&:sync)
25
25
  newly_finished_resources, @resources = @resources.partition(&:deploy_finished?)
@@ -111,21 +111,20 @@ module KubernetesDeploy
111
111
  raise FatalDeploymentError, "Refusing to deploy to protected namespace '#{@namespace}' with pruning enabled"
112
112
  end
113
113
 
114
- deploy_resources(resources, prune: prune)
115
-
116
- unless verify_result
114
+ if verify_result
115
+ deploy_resources(resources, prune: prune, verify: true)
116
+ record_statuses(resources)
117
+ success = resources.all?(&:deploy_succeeded?)
118
+ else
119
+ deploy_resources(resources, prune: prune, verify: false)
117
120
  @logger.summary.add_action("deployed #{resources.length} #{'resource'.pluralize(resources.length)}")
118
121
  warning = <<-MSG.strip_heredoc
119
122
  Deploy result verification is disabled for this deploy.
120
123
  This means the desired changes were communicated to Kubernetes, but the deploy did not make sure they actually succeeded.
121
124
  MSG
122
125
  @logger.summary.add_paragraph(ColorizedString.new(warning).yellow)
123
- return success = true
126
+ success = true
124
127
  end
125
-
126
- wait_for_completion(resources)
127
- record_statuses(resources)
128
- success = resources.all?(&:deploy_succeeded?)
129
128
  rescue FatalDeploymentError => error
130
129
  @logger.summary.add_action(error.message)
131
130
  success = false
@@ -200,8 +199,7 @@ module KubernetesDeploy
200
199
  PREDEPLOY_SEQUENCE.each do |resource_type|
201
200
  matching_resources = resource_list.select { |r| r.type == resource_type }
202
201
  next if matching_resources.empty?
203
- deploy_resources(matching_resources)
204
- wait_for_completion(matching_resources)
202
+ deploy_resources(matching_resources, verify: true)
205
203
 
206
204
  failed_resources = matching_resources.reject(&:deploy_succeeded?)
207
205
  fail_count = failed_resources.length
@@ -297,8 +295,8 @@ module KubernetesDeploy
297
295
  @logger.summary.add_paragraph(debug_msg)
298
296
  end
299
297
 
300
- def wait_for_completion(watched_resources)
301
- watcher = ResourceWatcher.new(watched_resources, logger: @logger)
298
+ def wait_for_completion(watched_resources, started_at)
299
+ watcher = ResourceWatcher.new(watched_resources, logger: @logger, deploy_started_at: started_at)
302
300
  watcher.run
303
301
  end
304
302
 
@@ -359,37 +357,46 @@ module KubernetesDeploy
359
357
  @logger.info("All required parameters and files are present")
360
358
  end
361
359
 
362
- def deploy_resources(resources, prune: false)
363
- @logger.info("Deploying resources:")
360
+ def deploy_resources(resources, prune: false, verify:)
361
+ return if resources.empty?
362
+ deploy_started_at = Time.now.utc
363
+
364
+ if resources.length > 1
365
+ @logger.info("Deploying resources:")
366
+ else
367
+ resource = resources.first
368
+ @logger.info("Deploying #{resource.id} (timeout: #{resource.timeout}s)")
369
+ end
364
370
 
365
371
  # Apply can be done in one large batch, the rest have to be done individually
366
372
  applyables, individuals = resources.partition { |r| r.deploy_method == :apply }
367
373
 
368
374
  individuals.each do |r|
369
- @logger.info("- #{r.id}")
375
+ @logger.info("- #{r.id} (timeout: #{r.timeout}s)") if resources.length > 1
370
376
  r.deploy_started = Time.now.utc
371
377
  case r.deploy_method
372
378
  when :replace
373
- _, _, st = kubectl.run("replace", "-f", r.file.path, log_failure: false)
379
+ _, _, replace_st = kubectl.run("replace", "-f", r.file.path, log_failure: false)
374
380
  when :replace_force
375
- _, _, st = kubectl.run("replace", "--force", "-f", r.file.path, log_failure: false)
381
+ _, _, replace_st = kubectl.run("replace", "--force", "-f", r.file.path, log_failure: false)
376
382
  else
377
383
  # Fail Fast! This is a programmer mistake.
378
384
  raise ArgumentError, "Unexpected deploy method! (#{r.deploy_method.inspect})"
379
385
  end
380
386
 
381
- next if st.success?
387
+ next if replace_st.success?
382
388
  # it doesn't exist so we can't replace it
383
- _, err, st = kubectl.run("create", "-f", r.file.path, log_failure: false)
384
- unless st.success?
385
- raise FatalDeploymentError, <<-MSG.strip_heredoc
386
- Failed to replace or create resource: #{r.id}
387
- #{err}
388
- MSG
389
- end
389
+ _, err, create_st = kubectl.run("create", "-f", r.file.path, log_failure: false)
390
+
391
+ next if create_st.success?
392
+ raise FatalDeploymentError, <<-MSG.strip_heredoc
393
+ Failed to replace or create resource: #{r.id}
394
+ #{err}
395
+ MSG
390
396
  end
391
397
 
392
398
  apply_all(applyables, prune)
399
+ wait_for_completion(resources, deploy_started_at) if verify
393
400
  end
394
401
 
395
402
  def apply_all(resources, prune)
@@ -397,7 +404,7 @@ module KubernetesDeploy
397
404
 
398
405
  command = ["apply"]
399
406
  resources.each do |r|
400
- @logger.info("- #{r.id} (timeout: #{r.timeout}s)")
407
+ @logger.info("- #{r.id} (timeout: #{r.timeout}s)") if resources.length > 1
401
408
  command.push("-f", r.file.path)
402
409
  r.deploy_started = Time.now.utc
403
410
  end
@@ -68,11 +68,8 @@ module KubernetesDeploy
68
68
  begin
69
69
  @kubeclient.get_namespace(@namespace) if @namespace.present?
70
70
  rescue KubeException => e
71
- errors << if e.error_code == 404
72
- "Namespace was not found"
73
- else
74
- "Could not connect to kubernetes cluster"
75
- end
71
+ msg = e.error_code == 404 ? "Namespace was not found" : "Could not connect to kubernetes cluster"
72
+ errors << msg
76
73
  end
77
74
 
78
75
  raise FatalTaskRunError, "Configuration invalid: #{errors.join(', ')}" unless errors.empty?
@@ -1,3 +1,3 @@
1
1
  module KubernetesDeploy
2
- VERSION = "0.7.3"
2
+ VERSION = "0.7.4"
3
3
  end
metadata CHANGED
@@ -1,16 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kubernetes-deploy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
- - Kir Shatrov
8
- - Jean Boussier
9
7
  - Katrina Verey
8
+ - Kir Shatrov
10
9
  autorequire:
11
10
  bindir: exe
12
11
  cert_chain: []
13
- date: 2017-06-02 00:00:00.000000000 Z
12
+ date: 2017-06-05 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: activesupport