kubernetes-deploy 0.14.0 → 0.14.1

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: 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