kubernetes-deploy 0.14.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b83794f813d2a4f1b2b3aba98a9181fc2c041f85
4
- data.tar.gz: 1d0dc0a38cdd5a44adb1e914751cea41dd8dbce1
3
+ metadata.gz: 2b7eaf966de6685ee13686190feda92f7d5e249c
4
+ data.tar.gz: 7bc442ae69145779cd8965caababf22545a5d954
5
5
  SHA512:
6
- metadata.gz: 82153cb31bd8108540cdbe92fe25d25e6c4d09e3f9781c00f74f664ca2ea1a5fa65311bd940565ea5b7fefa9ec4bcae36f533855cc6f068b4970c3ecf9e06478
7
- data.tar.gz: 30fbefaae8d80f503ec2e31664a4ee29097ee80a92f9d398d6ce4e1e76d0f350855fd85048ae6ae7d1fb8932abf6be48b754d4e569626ae0a52e3fb716f54e6b
6
+ metadata.gz: 983f99b3be92381d2838bc7b7cd4d9efd4220e9b13cd68d795d1d5523cd550d15effea7da8dc273d6dec8825e23372a63ff82a05e577ebcbdac0a3c2b9c2095b
7
+ data.tar.gz: 28eb00deaa911348e3d27be549bcd0c788e8efc00977edd1c3986521b9e82367b06a8d80a258a371ec9dcd9d4b9dc7100d6e4856f0f98596fd2ab2b43dfd005b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ### 0.14.1
2
+ *Bug Fixes*
3
+ - Make deployments whose pods crash because of CreateContainerConfigError fail fast in 1.8+ too (they would previously time out).
4
+ - Fix crashes when deploying ExternalName services or services without selectors ([#211](https://github.com/Shopify/kubernetes-deploy/pull/211))
5
+ - Predeploy ServiceAccount resources ([#221](https://github.com/Shopify/kubernetes-deploy/pull/221))
6
+
7
+ *Enhancements*
8
+ - Make it possible to pass bindings (via the --bindings flag) for which the value contains commas or is a JSON encoded hash ([#219](https://github.com/Shopify/kubernetes-deploy/pull/219))
9
+ - Support KUBECONFIG referencing multiple files ([#222](https://github.com/Shopify/kubernetes-deploy/pull/222))
10
+
1
11
  ### 0.14.0
2
12
  *Bug Fixes*
3
13
  - Fix incorrect timeouts occasionally observed on deployments using progressDeadlineSeconds in Kubernetes <1.7.7
data/README.md CHANGED
@@ -91,7 +91,7 @@ This repo also includes related tools for [running tasks](#kubernetes-run) and [
91
91
  *Environment variables:*
92
92
 
93
93
  - `$REVISION` **(required)**: the SHA of the commit you are deploying. Will be exposed to your ERB templates as `current_sha`.
94
- - `$KUBECONFIG` **(required)**: points to a valid kubeconfig file that includes the context you want to deploy to
94
+ - `$KUBECONFIG` **(required)**: points to one or multiple valid kubeconfig files that include the context you want to deploy to. File names are separated by colon for Linux and Mac, and semi-colon for Windows.
95
95
  - `$ENVIRONMENT`: used to set the deploy directory to `config/deploy/$ENVIRONMENT`. You can use the `--template-dir=DIR` option instead if you prefer (**one or the other is required**).
96
96
  - `$GOOGLE_APPLICATION_CREDENTIALS`: points to the credentials for an authenticated service account (required if your kubeconfig `user`'s auth provider is GCP)
97
97
 
@@ -12,13 +12,9 @@ bindings = {}
12
12
  verbose_log_prefix = false
13
13
 
14
14
  ARGV.options do |opts|
15
- opts.on("--bindings=BINDINGS", Array, "Expose additional variables to ERB templates (format: k1=v1,k2=v2)") do |binds|
16
- bindings = binds.each_with_object({}) do |bind, acc|
17
- k, v = bind.split('=')
18
- raise "key for value #{v} is blank!" if k.blank?
19
- raise "value for key #{k} is blank!" if v.blank?
20
- acc[k] = v
21
- end
15
+ opts.on("--bindings=BINDINGS", "Expose additional variables to ERB templates " \
16
+ "(format: k1=v1,k2=v2 or JSON)") do |binds|
17
+ bindings = KubernetesDeploy::BindingsParser.parse(binds)
22
18
  end
23
19
 
24
20
  opts.on("--skip-wait", "Skip verification of non-priority-resource success (not recommended)") { skip_wait = true }
@@ -16,6 +16,7 @@ require 'kubernetes-deploy/formatted_logger'
16
16
  require 'kubernetes-deploy/deploy_task'
17
17
  require 'kubernetes-deploy/statsd'
18
18
  require 'kubernetes-deploy/concurrency'
19
+ require 'kubernetes-deploy/bindings_parser'
19
20
 
20
21
  module KubernetesDeploy
21
22
  KubernetesDeploy::StatsD.build
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ require 'json'
3
+ require 'csv'
4
+
5
+ module KubernetesDeploy
6
+ module BindingsParser
7
+ extend self
8
+
9
+ def parse(string)
10
+ bindings = parse_json(string) || parse_csv(string)
11
+
12
+ unless bindings
13
+ raise ArgumentError, "Failed to parse bindings."
14
+ end
15
+
16
+ bindings
17
+ end
18
+
19
+ private
20
+
21
+ def parse_json(string)
22
+ bindings = JSON.parse(string)
23
+
24
+ unless bindings.is_a?(Hash)
25
+ raise ArgumentError, "Expected JSON data to be a hash."
26
+ end
27
+
28
+ bindings
29
+ rescue JSON::ParserError
30
+ nil
31
+ end
32
+
33
+ def parse_csv(string)
34
+ lines = CSV.parse(string)
35
+ bindings = {}
36
+
37
+ lines.each do |line|
38
+ line.each do |binding|
39
+ key, value = binding.split('=', 2)
40
+
41
+ if key.blank?
42
+ raise ArgumentError, "key is blank"
43
+ end
44
+
45
+ bindings[key] = value
46
+ end
47
+ end
48
+
49
+ bindings
50
+ rescue CSV::MalformedCSVError
51
+ nil
52
+ end
53
+ end
54
+ end
@@ -48,6 +48,7 @@ module KubernetesDeploy
48
48
  Bugsnag
49
49
  ConfigMap
50
50
  PersistentVolumeClaim
51
+ ServiceAccount
51
52
  Pod
52
53
  )
53
54
  PROTECTED_NAMESPACES = %w(
@@ -277,8 +278,14 @@ module KubernetesDeploy
277
278
  errors = []
278
279
  if ENV["KUBECONFIG"].blank?
279
280
  errors << "$KUBECONFIG not set"
280
- elsif !File.file?(ENV["KUBECONFIG"])
281
- errors << "Kube config not found at #{ENV['KUBECONFIG']}"
281
+ elsif config_files.empty?
282
+ errors << "Kube config file name(s) not set in $KUBECONFIG"
283
+ else
284
+ config_files.each do |f|
285
+ unless File.file?(f)
286
+ errors << "Kube config not found at #{f}"
287
+ end
288
+ end
282
289
  end
283
290
 
284
291
  if @current_sha.blank?
@@ -6,7 +6,8 @@ module KubernetesDeploy
6
6
  module KubeclientBuilder
7
7
  class ContextMissingError < FatalDeploymentError
8
8
  def initialize(context_name)
9
- super("`#{context_name}` context must be configured in your KUBECONFIG (#{ENV['KUBECONFIG']}).")
9
+ super("`#{context_name}` context must be configured in your " \
10
+ "KUBECONFIG file(s) (#{ENV['KUBECONFIG']}).")
10
11
  end
11
12
  end
12
13
 
@@ -44,10 +45,12 @@ module KubernetesDeploy
44
45
  end
45
46
 
46
47
  def _build_kubeclient(api_version:, context:, endpoint_path: nil)
47
- config = GoogleFriendlyConfig.read(ENV.fetch("KUBECONFIG"))
48
- unless config.contexts.include?(context)
49
- raise ContextMissingError, context
50
- end
48
+ # Find a context defined in kube conf files that matches the input context by name
49
+ friendly_configs = config_files.map { |f| GoogleFriendlyConfig.read(f) }
50
+ config = friendly_configs.find { |c| c.contexts.include?(context) }
51
+
52
+ raise ContextMissingError, context unless config
53
+
51
54
  kube_context = config.context(context)
52
55
 
53
56
  client = Kubeclient::Client.new(
@@ -59,5 +62,10 @@ module KubernetesDeploy
59
62
  client.discover
60
63
  client
61
64
  end
65
+
66
+ def config_files
67
+ # Split the list by colon for Linux and Mac, and semicolon for Windows.
68
+ ENV.fetch("KUBECONFIG").split(/[:;]/).map!(&:strip).reject(&:empty?)
69
+ end
62
70
  end
63
71
  end
@@ -202,9 +202,11 @@ module KubernetesDeploy
202
202
  "Failed to pull image #{@image}. "\
203
203
  "Did you wait for it to be built and pushed to the registry before deploying?"
204
204
  elsif limbo_message == "Generate Container Config Failed"
205
- # reason/message are backwards
206
- # Flip this after https://github.com/kubernetes/kubernetes/commit/df41787b1a3f51b73fb6db8a2203f0a7c7c92931
205
+ # reason/message are backwards in <1.8.0 (next condition used by 1.8.0+)
206
+ # Fixed by https://github.com/kubernetes/kubernetes/commit/df41787b1a3f51b73fb6db8a2203f0a7c7c92931
207
207
  "Failed to generate container configuration: #{limbo_reason}"
208
+ elsif limbo_reason == "CreateContainerConfigError"
209
+ "Failed to generate container configuration: #{limbo_message}"
208
210
  end
209
211
  end
210
212
 
@@ -11,7 +11,9 @@ module KubernetesDeploy
11
11
  end
12
12
 
13
13
  def status
14
- if @num_pods_selected.blank?
14
+ if !requires_endpoints?
15
+ "Doesn't require any endpoint"
16
+ elsif @num_pods_selected.blank?
15
17
  "Failed to count related pods"
16
18
  elsif selects_some_pods?
17
19
  "Selects at least 1 pod"
@@ -21,6 +23,7 @@ module KubernetesDeploy
21
23
  end
22
24
 
23
25
  def deploy_succeeded?
26
+ return exists? unless requires_endpoints?
24
27
  # We can't use endpoints if we want the service to be able to fail fast when the pods are down
25
28
  exposes_zero_replica_deployment? || selects_some_pods?
26
29
  end
@@ -44,22 +47,34 @@ module KubernetesDeploy
44
47
  @related_deployment_replicas == 0
45
48
  end
46
49
 
50
+ def requires_endpoints?
51
+ # service of type External don't have endpoints
52
+ return false if external_name_svc?
53
+
54
+ # problem counting replicas - by default, assume endpoints are required
55
+ return true if @related_deployment_replicas.blank?
56
+
57
+ @related_deployment_replicas > 0
58
+ end
59
+
47
60
  def selects_some_pods?
48
61
  return false unless @num_pods_selected
49
62
  @num_pods_selected > 0
50
63
  end
51
64
 
52
65
  def selector
53
- @selector ||= @definition["spec"]["selector"].map { |k, v| "#{k}=#{v}" }.join(",")
66
+ @selector ||= @definition["spec"].fetch("selector", []).map { |k, v| "#{k}=#{v}" }.join(",")
54
67
  end
55
68
 
56
69
  def fetch_related_pod_count
70
+ return 0 unless selector.present?
57
71
  raw_json, _err, st = kubectl.run("get", "pods", "--selector=#{selector}", "--output=json")
58
72
  return unless st.success?
59
73
  JSON.parse(raw_json)["items"].length
60
74
  end
61
75
 
62
76
  def fetch_related_replica_count
77
+ return 0 unless selector.present?
63
78
  raw_json, _err, st = kubectl.run("get", "deployments", "--selector=#{selector}", "--output=json")
64
79
  return unless st.success?
65
80
 
@@ -67,5 +82,9 @@ module KubernetesDeploy
67
82
  return unless deployments.length == 1
68
83
  deployments.first["spec"]["replicas"].to_i
69
84
  end
85
+
86
+ def external_name_svc?
87
+ @definition["spec"]["type"] == "ExternalName"
88
+ end
70
89
  end
71
90
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module KubernetesDeploy
3
- VERSION = "0.14.0"
3
+ VERSION = "0.14.1"
4
4
  end
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.14.0
4
+ version: 0.14.1
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: 2017-11-30 00:00:00.000000000 Z
12
+ date: 2017-12-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -223,6 +223,7 @@ files:
223
223
  - exe/kubernetes-run
224
224
  - kubernetes-deploy.gemspec
225
225
  - lib/kubernetes-deploy.rb
226
+ - lib/kubernetes-deploy/bindings_parser.rb
226
227
  - lib/kubernetes-deploy/concurrency.rb
227
228
  - lib/kubernetes-deploy/deferred_summary_logging.rb
228
229
  - lib/kubernetes-deploy/deploy_task.rb