kubernetes-deploy 0.20.4 → 0.20.5

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: f0b4318bc1b5546351e5aaaa8a2e5a40675349c6
4
- data.tar.gz: 3f4df1e8c2010d668118fae08a15de4ab21b67b3
3
+ metadata.gz: b01e4098e730e6ee300284d185adb140cf3cdc80
4
+ data.tar.gz: 6416b255318a78d3a1b6383263bbecd7b3603a4b
5
5
  SHA512:
6
- metadata.gz: db3e58f8c6ae85a41a436f24068a03d7312df2080a62ab05abb818f5723b07e7875be5d3a7af95f56edf67d5f4be5cff5536a2506465152f205f49c32b5686e5
7
- data.tar.gz: 3093b949fa36286f03548c3e91ebbc0378d27dafd922b7677dd7b902b9288fee2e8e2120306b3eaccd70f74337ddf2713842457445410b4fd77ee6030191aa97
6
+ metadata.gz: aeeb95108945428fe39de942b7285843cd8a3960344089386bfbf1cfc1a551a50c1531d3e7d2082187f67640e6978ad1ab00f8ed7176b14d92bb56410ba78380
7
+ data.tar.gz: d0c1753242a3131586627252707ef9674ff94d2ac0e8e9f39f6a147dbc05449b5414ce6f26c1e8ede9bb4bd58d5919bf94ed6629f97ff2abc9db5c74e4b70e82
@@ -1,11 +1,11 @@
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
1
+ steps:
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
9
9
  - name: 'Run Test Suite (:kubernetes: 1.9-latest)'
10
10
  command: bin/ci
11
11
  agents:
@@ -1,3 +1,11 @@
1
+ steps:
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
1
9
  - name: 'Run Test Suite (:kubernetes: 1.9-latest)'
2
10
  command: bin/ci
3
11
  agents:
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  ### Master
2
2
 
3
+ *Enhancements*
4
+ - Add Job resource class ([#295](https://github.com/Shopify/kubernetes-deploy/pull/296))
5
+ - Add CustomResourceDefinition resource class ([#306](https://github.com/Shopify/kubernetes-deploy/pull/306))
6
+ - Officially support Kubernetes 1.10 ([#308](https://github.com/Shopify/kubernetes-deploy/pull/308))
7
+ - SyncMediator will only batch fetch resources when there is a sufficiently large enough set of resources
8
+ being tracked ([#316](https://github.com/Shopify/kubernetes-deploy/pull/316))
9
+ - Allow CRs to be pruned based on `kubernetes-deploy.shopify.io/prunable` annotation on the custom resource definitions ([312](https://github.com/Shopify/kubernetes-deploy/pull/312))
10
+ - Add HorizontalPodAutoscaler resource class ([#305](https://github.com/Shopify/kubernetes-deploy/pull/305))
11
+
3
12
  ### 0.20.4
13
+ *Enhancements*
4
14
  - Don't consider pod preempting a failure ([#317](https://github.com/shopify/kubernetes-deploy/pull/317))
5
15
 
6
16
  ### 0.20.3
@@ -8,7 +18,6 @@
8
18
  - Evictions are recoverable so prevent them from triggering fast failure detection ([#293](https://github.com/Shopify/kubernetes-deploy/pull/293)).
9
19
  - Use YAML.safe_load over YAML.load_file ([#295](https://github.com/Shopify/kubernetes-deploy/pull/295)).
10
20
 
11
-
12
21
  *Bug Fixes*
13
22
  - Default rollout strategy is compatible required-rollout annotation ([#289](https://github.com/Shopify/kubernetes-deploy/pull/289)).
14
23
 
@@ -16,7 +25,6 @@
16
25
  *Enhancements*
17
26
  - Emit data dog events when deploys succeed, time out or fail ([#292](https://github.com/Shopify/kubernetes-deploy/pull/292)).
18
27
  ### 0.20.1
19
- *Features*
20
28
 
21
29
  *Bug Fixes*
22
30
  - Display a nice error instead of crashing when a YAML document is missing 'Kind'
data/README.md CHANGED
@@ -241,6 +241,10 @@ before the deployment is considered successful.
241
241
  that use the `RollingUpdate` strategy.
242
242
  - Percent (e.g. 90%): The deploy is successful when the number of new pods that are ready is equal to
243
243
  `spec.replicas` * Percent.
244
+ - `kubernetes-deploy.shopify.io/prunable`: Allows a Custom Resource to be pruned during deployment.
245
+ - _Compatibility_: Custom Resource Definition
246
+ - `true`: The custom resource will be pruned if the resource is not in the deploy directory.
247
+ - All other values: The custom resource will not be pruned.
244
248
 
245
249
  ### Running tasks at the beginning of a deploy
246
250
 
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 --kubernetes-version=v1.9.4 --vm-driver=hyperkit
11
+ meet: minikube start --kubernetes-version=v1.10.0 --vm-driver=hyperkit
12
12
  down: minikube stop
13
13
  commands:
14
14
  reset-minikube: minikube delete && rm -rf ~/.minikube
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.required_ruby_version = '>= 2.3.0'
26
26
  spec.add_dependency "activesupport", ">= 5.0"
27
27
  spec.add_dependency "kubeclient", "~> 3.0"
28
- spec.add_dependency "googleauth", ">= 0.5"
28
+ spec.add_dependency "googleauth", "= 0.6.2" # https://github.com/google/google-auth-library-ruby/issues/153
29
29
  spec.add_dependency "ejson", "1.0.1"
30
30
  spec.add_dependency "colorize", "~> 0.8"
31
31
  spec.add_dependency "statsd-instrument", "~> 2.2"
@@ -27,6 +27,9 @@ require 'kubernetes-deploy/kubernetes_resource'
27
27
  bucket
28
28
  stateful_set
29
29
  cron_job
30
+ job
31
+ custom_resource_definition
32
+ horizontal_pod_autoscaler
30
33
  ).each do |subresource|
31
34
  require "kubernetes-deploy/kubernetes_resource/#{subresource}"
32
35
  end
@@ -35,6 +38,7 @@ require 'kubernetes-deploy/kubectl'
35
38
  require 'kubernetes-deploy/kubeclient_builder'
36
39
  require 'kubernetes-deploy/ejson_secret_provisioner'
37
40
  require 'kubernetes-deploy/renderer'
41
+ require 'kubernetes-deploy/resource_discovery'
38
42
 
39
43
  module KubernetesDeploy
40
44
  class DeployTask
@@ -50,6 +54,7 @@ module KubernetesDeploy
50
54
  ServiceAccount
51
55
  Pod
52
56
  )
57
+
53
58
  PROTECTED_NAMESPACES = %w(
54
59
  default
55
60
  kube-system
@@ -63,6 +68,7 @@ module KubernetesDeploy
63
68
  # core/v1/ReplicationController -- superseded by deployments/replicasets
64
69
  # extensions/v1beta1/ReplicaSet -- managed by deployments
65
70
  # core/v1/Secret -- should not committed / managed by shipit
71
+
66
72
  def prune_whitelist
67
73
  wl = %w(
68
74
  core/v1/ConfigMap
@@ -80,7 +86,7 @@ module KubernetesDeploy
80
86
  if server_version >= Gem::Version.new('1.8.0')
81
87
  wl << "batch/v1beta1/CronJob"
82
88
  end
83
- wl
89
+ wl + cluster_resource_discoverer.crds(@sync_mediator).select(&:prunable?).map(&:group_version_kind)
84
90
  end
85
91
 
86
92
  def server_version
@@ -198,6 +204,10 @@ module KubernetesDeploy
198
204
 
199
205
  private
200
206
 
207
+ def cluster_resource_discoverer
208
+ ResourceDiscovery.new(namespace: @namespace, context: @context, logger: @logger, namespace_tags: @namespace_tags)
209
+ end
210
+
201
211
  def deploy_has_priority_resources?(resources)
202
212
  resources.any? { |r| PREDEPLOY_SEQUENCE.include?(r.type) }
203
213
  end
@@ -247,6 +257,10 @@ module KubernetesDeploy
247
257
  @logger.info " - #{r.id}"
248
258
  end
249
259
  end
260
+ if (global = resources.select(&:global?).presence)
261
+ @logger.warn("Detected non-namespaced #{'resource'.pluralize(global.count)} which will never be pruned:")
262
+ global.each { |r| @logger.warn(" - #{r.id}") }
263
+ end
250
264
  resources
251
265
  end
252
266
 
@@ -36,6 +36,14 @@ module KubernetesDeploy
36
36
  )
37
37
  end
38
38
 
39
+ def build_batch_v1_kubeclient(context)
40
+ _build_kubeclient(
41
+ api_version: "v1",
42
+ context: context,
43
+ endpoint_path: "/apis/batch/"
44
+ )
45
+ end
46
+
39
47
  def build_policy_v1beta1_kubeclient(context)
40
48
  _build_kubeclient(
41
49
  api_version: "v1beta1",
@@ -52,6 +60,22 @@ module KubernetesDeploy
52
60
  )
53
61
  end
54
62
 
63
+ def build_apiextensions_v1beta1_kubeclient(context)
64
+ _build_kubeclient(
65
+ api_version: "v1beta1",
66
+ context: context,
67
+ endpoint_path: "/apis/apiextensions.k8s.io"
68
+ )
69
+ end
70
+
71
+ def build_autoscaling_v1_kubeclient(context)
72
+ _build_kubeclient(
73
+ api_version: "v2beta1",
74
+ context: context,
75
+ endpoint_path: "/apis/autoscaling"
76
+ )
77
+ end
78
+
55
79
  def _build_kubeclient(api_version:, context:, endpoint_path: nil)
56
80
  # Find a context defined in kube conf files that matches the input context by name
57
81
  friendly_configs = config_files.map { |f| GoogleFriendlyConfig.read(f) }
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ module KubernetesDeploy
3
+ class CustomResourceDefinition < KubernetesResource
4
+ TIMEOUT = 2.minutes
5
+ GLOBAL = true
6
+
7
+ def deploy_succeeded?
8
+ names_accepted_status == "True"
9
+ end
10
+
11
+ def deploy_failed?
12
+ names_accepted_status == "False"
13
+ end
14
+
15
+ def timeout_message
16
+ "The names this CRD is attempting to register were neither accepted nor rejected in time"
17
+ end
18
+
19
+ def status
20
+ if !exists?
21
+ super
22
+ elsif deploy_succeeded?
23
+ "Names accepted"
24
+ else
25
+ "#{names_accepted_condition['reason']} (#{names_accepted_condition['message']})"
26
+ end
27
+ end
28
+
29
+ def group_version_kind
30
+ group = @definition.dig("spec", "group")
31
+ version = @definition.dig("spec", "version")
32
+ "#{group}/#{version}/#{kind}"
33
+ end
34
+
35
+ def kind
36
+ @definition.dig("spec", "names", "kind")
37
+ end
38
+
39
+ def prunable?
40
+ prunable = @definition.dig("metadata", "annotations", "kubernetes-deploy.shopify.io/prunable")
41
+ prunable == "true"
42
+ end
43
+
44
+ private
45
+
46
+ def names_accepted_condition
47
+ conditions = @instance_data.dig("status", "conditions") || []
48
+ conditions.detect { |c| c["type"] == "NamesAccepted" } || {}
49
+ end
50
+
51
+ def names_accepted_status
52
+ names_accepted_condition["status"]
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+ module KubernetesDeploy
3
+ class HorizontalPodAutoscaler < KubernetesResource
4
+ TIMEOUT = 3.minutes
5
+ RECOVERABLE_CONDITIONS = %w(ScalingDisabled FailedGet)
6
+
7
+ def deploy_succeeded?
8
+ scaling_active_condition["status"] == "True"
9
+ end
10
+
11
+ def deploy_failed?
12
+ return false unless exists?
13
+ recoverable = RECOVERABLE_CONDITIONS.any? { |c| scaling_active_condition.fetch("reason", "").start_with?(c) }
14
+ scaling_active_condition["status"] == "False" && !recoverable
15
+ end
16
+
17
+ def kubectl_resource_type
18
+ 'hpa.v2beta1.autoscaling'
19
+ end
20
+
21
+ def status
22
+ if !exists?
23
+ super
24
+ elsif deploy_succeeded?
25
+ "Configured"
26
+ elsif scaling_active_condition.present? || able_to_scale_condition.present?
27
+ condition = scaling_active_condition.presence || able_to_scale_condition
28
+ condition['reason']
29
+ else
30
+ "Unknown"
31
+ end
32
+ end
33
+
34
+ def failure_message
35
+ condition = scaling_active_condition.presence || able_to_scale_condition.presence || {}
36
+ condition['message']
37
+ end
38
+
39
+ def timeout_message
40
+ failure_message.presence || super
41
+ end
42
+
43
+ private
44
+
45
+ def conditions
46
+ @instance_data.dig("status", "conditions") || []
47
+ end
48
+
49
+ def able_to_scale_condition
50
+ conditions.detect { |c| c["type"] == "AbleToScale" } || {}
51
+ end
52
+
53
+ def scaling_active_condition
54
+ conditions.detect { |c| c["type"] == "ScalingActive" } || {}
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ module KubernetesDeploy
3
+ class Job < KubernetesResource
4
+ TIMEOUT = 10.minutes
5
+
6
+ def deploy_succeeded?
7
+ # Don't block deploys for long running jobs,
8
+ # Instead report success when there is at least 1 active
9
+ return false unless deploy_started?
10
+ done? || running?
11
+ end
12
+
13
+ def deploy_failed?
14
+ return false unless deploy_started?
15
+ return false unless @instance_data.dig("spec", "backoffLimit").present?
16
+ (@instance_data.dig("status", "failed") || 0) >= @instance_data.dig("spec", "backoffLimit")
17
+ end
18
+
19
+ def status
20
+ if !exists?
21
+ super
22
+ elsif done?
23
+ "Succeeded"
24
+ elsif running?
25
+ "Started"
26
+ elsif deploy_failed?
27
+ "Failed"
28
+ else
29
+ "Unknown"
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def done?
36
+ (@instance_data.dig("status", "succeeded") || 0) == @instance_data.dig("spec", "completions")
37
+ end
38
+
39
+ def running?
40
+ now = Time.now.utc
41
+ start_time = @instance_data.dig("status", "startTime")
42
+ # Wait 5 seconds to ensure job doesn't immediately fail.
43
+ return false if !start_time.present? || now - Time.parse(start_time) < 5.second
44
+ (@instance_data.dig("status", "active") || 0) >= 1
45
+ end
46
+ end
47
+ end
@@ -8,6 +8,7 @@ module KubernetesDeploy
8
8
  attr_reader :name, :namespace, :context
9
9
  attr_writer :type, :deploy_started_at
10
10
 
11
+ GLOBAL = false
11
12
  TIMEOUT = 5.minutes
12
13
  LOG_LINE_COUNT = 250
13
14
 
@@ -114,7 +115,7 @@ module KubernetesDeploy
114
115
  end
115
116
 
116
117
  def sync(mediator)
117
- @instance_data = mediator.get_instance(type, name)
118
+ @instance_data = mediator.get_instance(kubectl_resource_type, name)
118
119
  end
119
120
 
120
121
  def deploy_failed?
@@ -146,6 +147,10 @@ module KubernetesDeploy
146
147
  @type || self.class.kind
147
148
  end
148
149
 
150
+ def kubectl_resource_type
151
+ type
152
+ end
153
+
149
154
  def deploy_timed_out?
150
155
  return false unless deploy_started?
151
156
  !deploy_succeeded? && !deploy_failed? && (Time.now.utc - @deploy_started_at > timeout)
@@ -315,6 +320,10 @@ module KubernetesDeploy
315
320
  end
316
321
  end
317
322
 
323
+ def global?
324
+ self.class::GLOBAL
325
+ end
326
+
318
327
  private
319
328
 
320
329
  def validate_timeout_annotation
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KubernetesDeploy
4
+ class ResourceDiscovery
5
+ def initialize(namespace:, context:, logger:, namespace_tags:)
6
+ @namespace = namespace
7
+ @context = context
8
+ @logger = logger
9
+ @namespace_tags = namespace_tags
10
+ end
11
+
12
+ def crds(sync_mediator)
13
+ sync_mediator.get_all(CustomResourceDefinition.kind).map do |r_def|
14
+ CustomResourceDefinition.new(namespace: @namespace, context: @context, logger: @logger,
15
+ definition: r_def, statsd_tags: @namespace_tags)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -15,7 +15,7 @@ module KubernetesDeploy
15
15
  if ENV['STATSD_DEV'].present?
16
16
  ::StatsD.backend = ::StatsD::Instrument::Backends::LoggerBackend.new(Logger.new($stderr))
17
17
  elsif ENV['STATSD_ADDR'].present?
18
- statsd_impl = ENV['STATSD_IMPLEMENTATION'].empty? ? "datadog" : ENV['STATSD_IMPLEMENTATION']
18
+ statsd_impl = ENV['STATSD_IMPLEMENTATION'].present? ? ENV['STATSD_IMPLEMENTATION'] : "datadog"
19
19
  ::StatsD.backend = ::StatsD::Instrument::Backends::UDPBackend.new(ENV['STATSD_ADDR'], statsd_impl)
20
20
  else
21
21
  ::StatsD.backend = ::StatsD::Instrument::Backends::NullBackend.new
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module KubernetesDeploy
3
3
  class SyncMediator
4
+ LARGE_BATCH_THRESHOLD = Concurrency::MAX_THREADS * 3
5
+
4
6
  def initialize(namespace:, context:, logger:)
5
7
  @namespace = namespace
6
8
  @context = context
@@ -29,11 +31,14 @@ module KubernetesDeploy
29
31
 
30
32
  def sync(resources)
31
33
  clear_cache
32
- dependencies = resources.map(&:class).uniq.flat_map do |c|
33
- c::SYNC_DEPENDENCIES if c.const_defined?('SYNC_DEPENDENCIES')
34
+
35
+ if resources.count > LARGE_BATCH_THRESHOLD
36
+ dependencies = resources.map(&:class).uniq.flat_map do |c|
37
+ c::SYNC_DEPENDENCIES if c.const_defined?('SYNC_DEPENDENCIES')
38
+ end
39
+ kinds = (resources.map(&:kubectl_resource_type) + dependencies).compact.uniq
40
+ kinds.each { |kind| fetch_by_kind(kind) }
34
41
  end
35
- kinds = (resources.map(&:type) + dependencies).compact.uniq
36
- kinds.each { |kind| fetch_by_kind(kind) }
37
42
 
38
43
  KubernetesDeploy::Concurrency.split_across_threads(resources) do |r|
39
44
  r.sync(dup)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module KubernetesDeploy
3
- VERSION = "0.20.4"
3
+ VERSION = "0.20.5"
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.20.4
4
+ version: 0.20.5
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-07-18 00:00:00.000000000 Z
12
+ date: 2018-08-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -43,16 +43,16 @@ dependencies:
43
43
  name: googleauth
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - ">="
46
+ - - '='
47
47
  - !ruby/object:Gem::Version
48
- version: '0.5'
48
+ version: 0.6.2
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - ">="
53
+ - - '='
54
54
  - !ruby/object:Gem::Version
55
- version: '0.5'
55
+ version: 0.6.2
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: ejson
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -227,10 +227,13 @@ files:
227
227
  - lib/kubernetes-deploy/kubernetes_resource/cloudsql.rb
228
228
  - lib/kubernetes-deploy/kubernetes_resource/config_map.rb
229
229
  - lib/kubernetes-deploy/kubernetes_resource/cron_job.rb
230
+ - lib/kubernetes-deploy/kubernetes_resource/custom_resource_definition.rb
230
231
  - lib/kubernetes-deploy/kubernetes_resource/daemon_set.rb
231
232
  - lib/kubernetes-deploy/kubernetes_resource/deployment.rb
232
233
  - lib/kubernetes-deploy/kubernetes_resource/elasticsearch.rb
234
+ - lib/kubernetes-deploy/kubernetes_resource/horizontal_pod_autoscaler.rb
233
235
  - lib/kubernetes-deploy/kubernetes_resource/ingress.rb
236
+ - lib/kubernetes-deploy/kubernetes_resource/job.rb
234
237
  - lib/kubernetes-deploy/kubernetes_resource/memcached.rb
235
238
  - lib/kubernetes-deploy/kubernetes_resource/persistent_volume_claim.rb
236
239
  - lib/kubernetes-deploy/kubernetes_resource/pod.rb
@@ -246,6 +249,7 @@ files:
246
249
  - lib/kubernetes-deploy/kubernetes_resource/statefulservice.rb
247
250
  - lib/kubernetes-deploy/kubernetes_resource/topic.rb
248
251
  - lib/kubernetes-deploy/renderer.rb
252
+ - lib/kubernetes-deploy/resource_discovery.rb
249
253
  - lib/kubernetes-deploy/resource_watcher.rb
250
254
  - lib/kubernetes-deploy/restart_task.rb
251
255
  - lib/kubernetes-deploy/runner_task.rb