kubernetes-deploy 0.3.4 → 0.4.0
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 +4 -4
- data/Gemfile +1 -1
- data/README.md +8 -1
- data/exe/kubernetes-deploy +6 -0
- data/exe/kubernetes-restart +23 -0
- data/kubernetes-deploy.gemspec +2 -0
- data/lib/kubernetes-deploy.rb +1 -0
- data/lib/kubernetes-deploy/kubeclient_builder.rb +47 -0
- data/lib/kubernetes-deploy/resource_watcher.rb +37 -0
- data/lib/kubernetes-deploy/restart_task.rb +130 -0
- data/lib/kubernetes-deploy/runner.rb +30 -36
- data/lib/kubernetes-deploy/ui_helpers.rb +19 -0
- data/lib/kubernetes-deploy/version.rb +1 -1
- metadata +36 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5719744341ee174982a0aeec721aca1fac39154
|
4
|
+
data.tar.gz: 4d705c38c73e5de46b428b2475ad3f2dcc19bd48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f97774306df820422fd5fa2cb91408e0f89e50f9e2257b003d1026a80df060db3a7e844b9a806a44b2552c8b4d88d960396f38ac99b87663478b4e6c4f3972ba
|
7
|
+
data.tar.gz: 85602d28ddb571043f4ab89239b90b6777197ca90c2a37565a78630042507dc98d493e36f0c24fc7b944485892b8a25d0565655a32f38163fb94c223fe858fd4
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -29,9 +29,16 @@ Requirements:
|
|
29
29
|
- kubectl 1.5.1+ binary must be available in your path
|
30
30
|
- `ENV['KUBECONFIG']` must point to a valid kubeconfig file that includes the context you want to deploy to
|
31
31
|
- The target namespace must already exist in the target context
|
32
|
-
- `ENV['GOOGLE_APPLICATION_CREDENTIALS']` must point to the credentials for an authenticated service account if your user's auth provider is
|
32
|
+
- `ENV['GOOGLE_APPLICATION_CREDENTIALS']` must point to the credentials for an authenticated service account if your user's auth provider is GCP
|
33
33
|
- `ENV['ENVIRONMENT']` must be set to use the default template path (`config/deploy/$ENVIRONMENT`) in the absence of the `--template-dir=DIR` option
|
34
34
|
|
35
|
+
The tool also provides a task for restarting all of the pods in one or more deployments.
|
36
|
+
It triggers the restart by touching the `RESTARTED_AT` environment variable in the deployment's podSpec.
|
37
|
+
The rollout strategy defined for each deployment will be respected by the restart.
|
38
|
+
|
39
|
+
The following command will restart all pods in the `web` and `jobs` deployments:
|
40
|
+
|
41
|
+
`kubernetes-restart <kube namespace> <kube context> --deployments=web,jobs`
|
35
42
|
|
36
43
|
## Development
|
37
44
|
|
data/exe/kubernetes-deploy
CHANGED
@@ -7,8 +7,12 @@ require 'optparse'
|
|
7
7
|
|
8
8
|
skip_wait = false
|
9
9
|
template_dir = nil
|
10
|
+
allow_protected_ns = false
|
11
|
+
prune = true
|
10
12
|
ARGV.options do |opts|
|
11
13
|
opts.on("--skip-wait") { skip_wait = true }
|
14
|
+
opts.on("--allow-protected-ns") { allow_protected_ns = true }
|
15
|
+
opts.on("--no-prune") { prune = false }
|
12
16
|
opts.on("--template-dir=DIR") { |v| template_dir = v }
|
13
17
|
opts.parse!
|
14
18
|
end
|
@@ -35,6 +39,8 @@ KubernetesDeploy::Runner.with_friendly_errors do
|
|
35
39
|
current_sha: revision,
|
36
40
|
template_dir: template_dir,
|
37
41
|
wait_for_completion: !skip_wait,
|
42
|
+
allow_protected_ns: allow_protected_ns,
|
43
|
+
prune: prune,
|
38
44
|
)
|
39
45
|
runner.run
|
40
46
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
require 'kubernetes-deploy'
|
7
|
+
require 'kubernetes-deploy/restart_task'
|
8
|
+
|
9
|
+
raw_deployments = nil
|
10
|
+
ARGV.options do |opts|
|
11
|
+
opts.on("--deployments=LIST") { |v| raw_deployments = v }
|
12
|
+
opts.parse!
|
13
|
+
end
|
14
|
+
|
15
|
+
if raw_deployments.nil?
|
16
|
+
puts "Failed: specify at least one deployment to restart with --deployments flag"
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
KubernetesDeploy::Runner.with_friendly_errors do
|
21
|
+
restart = KubernetesDeploy::RestartTask.new(namespace: ARGV[0], context: ARGV[1])
|
22
|
+
restart.perform(raw_deployments.split(","))
|
23
|
+
end
|
data/kubernetes-deploy.gemspec
CHANGED
@@ -21,8 +21,10 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
spec.add_dependency "activesupport", ">= 4.2"
|
24
|
+
spec.add_dependency "kubeclient", "~> 2.3"
|
24
25
|
|
25
26
|
spec.add_development_dependency "bundler", "~> 1.13"
|
26
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
28
|
spec.add_development_dependency "minitest", "~> 5.0"
|
29
|
+
spec.add_development_dependency "minitest-stub-const", "~> 0.6"
|
28
30
|
end
|
data/lib/kubernetes-deploy.rb
CHANGED
@@ -3,6 +3,7 @@ require 'active_support/core_ext/object/blank'
|
|
3
3
|
require 'active_support/core_ext/hash/slice'
|
4
4
|
require 'active_support/core_ext/numeric/time'
|
5
5
|
require 'active_support/core_ext/string/inflections'
|
6
|
+
require 'active_support/core_ext/string/strip'
|
6
7
|
|
7
8
|
require 'logger'
|
8
9
|
require 'kubernetes-deploy/runner'
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'kubeclient'
|
3
|
+
|
4
|
+
module KubernetesDeploy
|
5
|
+
module KubeclientBuilder
|
6
|
+
class ContextMissingError < FatalDeploymentError
|
7
|
+
def initialize(context_name)
|
8
|
+
super("`#{context_name}` context must be configured in your KUBECONFIG (#{ENV['KUBECONFIG']}). " \
|
9
|
+
"Please see the README.")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def build_v1_kubeclient(context)
|
16
|
+
_build_kubeclient(
|
17
|
+
api_version: "v1",
|
18
|
+
context: context
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_v1beta1_kubeclient(context)
|
23
|
+
_build_kubeclient(
|
24
|
+
api_version: "v1beta1",
|
25
|
+
context: context,
|
26
|
+
endpoint_path: "/apis/extensions/"
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def _build_kubeclient(api_version:, context:, endpoint_path: nil)
|
31
|
+
config = Kubeclient::Config.read(ENV.fetch("KUBECONFIG"))
|
32
|
+
unless config.contexts.include?(context)
|
33
|
+
raise ContextMissingError, context
|
34
|
+
end
|
35
|
+
kube_context = config.context(context)
|
36
|
+
|
37
|
+
client = Kubeclient::Client.new(
|
38
|
+
"#{kube_context.api_endpoint}#{endpoint_path}",
|
39
|
+
api_version,
|
40
|
+
ssl_options: kube_context.ssl_options,
|
41
|
+
auth_options: kube_context.auth_options
|
42
|
+
)
|
43
|
+
client.discover
|
44
|
+
client
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module KubernetesDeploy
|
3
|
+
class ResourceWatcher
|
4
|
+
def initialize(resources)
|
5
|
+
unless resources.is_a?(Enumerable)
|
6
|
+
raise ArgumentError, <<-MSG.strip
|
7
|
+
ResourceWatcher expects Enumerable collection, got `#{resources.class}` instead
|
8
|
+
MSG
|
9
|
+
end
|
10
|
+
@resources = resources
|
11
|
+
end
|
12
|
+
|
13
|
+
def run(delay_sync: 3.seconds, logger: KubernetesDeploy.logger)
|
14
|
+
delay_sync_until = Time.now.utc
|
15
|
+
started_at = delay_sync_until
|
16
|
+
human_resources = @resources.map(&:id).join(", ")
|
17
|
+
max_wait_time = @resources.map(&:timeout).max
|
18
|
+
logger.info("Waiting for #{human_resources} with #{max_wait_time}s timeout")
|
19
|
+
|
20
|
+
while @resources.present?
|
21
|
+
if Time.now.utc < delay_sync_until
|
22
|
+
sleep(delay_sync_until - Time.now.utc)
|
23
|
+
end
|
24
|
+
delay_sync_until = Time.now.utc + delay_sync # don't pummel the API if the sync is fast
|
25
|
+
@resources.each(&:sync)
|
26
|
+
newly_finished_resources, @resources = @resources.partition(&:deploy_finished?)
|
27
|
+
newly_finished_resources.each do |resource|
|
28
|
+
next unless resource.deploy_failed? || resource.deploy_timed_out?
|
29
|
+
logger.error("#{resource.id} failed to deploy with status '#{resource.status}'.")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
watch_time = Time.now.utc - started_at
|
34
|
+
logger.info("Spent #{watch_time.round(2)}s waiting for #{human_resources}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'kubernetes-deploy/kubeclient_builder'
|
3
|
+
require 'kubernetes-deploy/ui_helpers'
|
4
|
+
require 'kubernetes-deploy/resource_watcher'
|
5
|
+
|
6
|
+
module KubernetesDeploy
|
7
|
+
class RestartTask
|
8
|
+
include UIHelpers
|
9
|
+
include KubernetesDeploy::KubeclientBuilder
|
10
|
+
|
11
|
+
class DeploymentNotFoundError < FatalDeploymentError
|
12
|
+
def initialize(name, namespace)
|
13
|
+
super("Deployment `#{name}` not found in namespace `#{namespace}`. Aborting the task.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class NamespaceNotFoundError < FatalDeploymentError
|
18
|
+
def initialize(name, context)
|
19
|
+
super("Namespace `#{name}` not found in context `#{context}`. Aborting the task.")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class RestartError < FatalDeploymentError
|
24
|
+
def initialize(deployment_name, response)
|
25
|
+
super("Failed to restart #{deployment_name}. " \
|
26
|
+
"API returned non-200 response code (#{response.code})\n" \
|
27
|
+
"Response:\n#{response.body}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
HTTP_OK_RANGE = 200..299
|
32
|
+
|
33
|
+
def initialize(context:, namespace:, logger: KubernetesDeploy.logger)
|
34
|
+
@context = context
|
35
|
+
@namespace = namespace
|
36
|
+
@logger = logger
|
37
|
+
@kubeclient = build_v1_kubeclient(context)
|
38
|
+
@v1beta1_kubeclient = build_v1beta1_kubeclient(context)
|
39
|
+
end
|
40
|
+
|
41
|
+
def perform(deployments_names)
|
42
|
+
verify_namespace
|
43
|
+
|
44
|
+
if deployments_names.empty?
|
45
|
+
raise ArgumentError, "#perform takes at least one deployment to restart"
|
46
|
+
end
|
47
|
+
|
48
|
+
phase_heading("Triggering restart by touching ENV[RESTARTED_AT]")
|
49
|
+
deployments = fetch_deployments(deployments_names.uniq)
|
50
|
+
patch_kubeclient_deployments(deployments)
|
51
|
+
|
52
|
+
phase_heading("Waiting for rollout")
|
53
|
+
wait_for_rollout(deployments)
|
54
|
+
|
55
|
+
names = deployments.map { |d| "`#{d.metadata.name}`" }
|
56
|
+
@logger.info "Restart of #{names.join(', ')} deployments succeeded"
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def wait_for_rollout(kubeclient_resources)
|
62
|
+
resources = kubeclient_resources.map { |d| Deployment.new(d.metadata.name, @namespace, @context, nil) }
|
63
|
+
watcher = ResourceWatcher.new(resources)
|
64
|
+
watcher.run
|
65
|
+
end
|
66
|
+
|
67
|
+
def verify_namespace
|
68
|
+
@kubeclient.get_namespace(@namespace)
|
69
|
+
rescue KubeException => error
|
70
|
+
if error.error_code == 404
|
71
|
+
raise NamespaceNotFoundError.new(@namespace, @context)
|
72
|
+
else
|
73
|
+
raise
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def patch_deployment_with_restart(record)
|
78
|
+
@v1beta1_kubeclient.patch_deployment(
|
79
|
+
record.metadata.name,
|
80
|
+
build_patch_payload(record),
|
81
|
+
@namespace
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def patch_kubeclient_deployments(deployments)
|
86
|
+
deployments.each do |record|
|
87
|
+
response = patch_deployment_with_restart(record)
|
88
|
+
if HTTP_OK_RANGE.cover?(response.code)
|
89
|
+
@logger.info "Triggered `#{record.metadata.name}` restart"
|
90
|
+
else
|
91
|
+
raise RestartError.new(record.metadata.name, response)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def fetch_deployments(list)
|
97
|
+
list.map do |name|
|
98
|
+
record = nil
|
99
|
+
begin
|
100
|
+
record = @v1beta1_kubeclient.get_deployment(name, @namespace)
|
101
|
+
rescue KubeException => error
|
102
|
+
if error.error_code == 404
|
103
|
+
raise DeploymentNotFoundError.new(name, @namespace)
|
104
|
+
else
|
105
|
+
raise
|
106
|
+
end
|
107
|
+
end
|
108
|
+
record
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_patch_payload(deployment)
|
113
|
+
containers = deployment.spec.template.spec.containers
|
114
|
+
{
|
115
|
+
spec: {
|
116
|
+
template: {
|
117
|
+
spec: {
|
118
|
+
containers: containers.map do |container|
|
119
|
+
{
|
120
|
+
name: container.name,
|
121
|
+
env: [{ name: "RESTARTED_AT", value: Time.now.to_i.to_s }]
|
122
|
+
}
|
123
|
+
end
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -19,9 +19,13 @@ require 'kubernetes-deploy/kubernetes_resource'
|
|
19
19
|
).each do |subresource|
|
20
20
|
require "kubernetes-deploy/kubernetes_resource/#{subresource}"
|
21
21
|
end
|
22
|
+
require 'kubernetes-deploy/resource_watcher'
|
23
|
+
require "kubernetes-deploy/ui_helpers"
|
22
24
|
|
23
25
|
module KubernetesDeploy
|
24
26
|
class Runner
|
27
|
+
include UIHelpers
|
28
|
+
|
25
29
|
PREDEPLOY_SEQUENCE = %w(
|
26
30
|
Cloudsql
|
27
31
|
Redis
|
@@ -64,7 +68,8 @@ MSG
|
|
64
68
|
exit 1
|
65
69
|
end
|
66
70
|
|
67
|
-
def initialize(namespace:, current_sha:, context:,
|
71
|
+
def initialize(namespace:, current_sha:, context:, template_dir:,
|
72
|
+
wait_for_completion:, allow_protected_ns: false, prune: true)
|
68
73
|
@namespace = namespace
|
69
74
|
@context = context
|
70
75
|
@current_sha = current_sha
|
@@ -72,14 +77,19 @@ MSG
|
|
72
77
|
# Max length of podname is only 63chars so try to save some room by truncating sha to 8 chars
|
73
78
|
@id = current_sha[0...8] + "-#{SecureRandom.hex(4)}" if current_sha
|
74
79
|
@wait_for_completion = wait_for_completion
|
80
|
+
@allow_protected_ns = allow_protected_ns
|
81
|
+
@prune = prune
|
75
82
|
end
|
76
83
|
|
77
84
|
def wait_for_completion?
|
78
85
|
@wait_for_completion
|
79
86
|
end
|
80
87
|
|
88
|
+
def allow_protected_ns?
|
89
|
+
@allow_protected_ns
|
90
|
+
end
|
91
|
+
|
81
92
|
def run
|
82
|
-
@current_phase = 0
|
83
93
|
phase_heading("Validating configuration")
|
84
94
|
validate_configuration
|
85
95
|
|
@@ -97,7 +107,10 @@ MSG
|
|
97
107
|
predeploy_priority_resources(resources)
|
98
108
|
|
99
109
|
phase_heading("Deploying all resources")
|
100
|
-
|
110
|
+
if PROTECTED_NAMESPACES.include?(@namespace) && @prune
|
111
|
+
raise FatalDeploymentError, "Refusing to deploy to protected namespace '#{@namespace}' with pruning enabled"
|
112
|
+
end
|
113
|
+
deploy_resources(resources, prune: @prune)
|
101
114
|
|
102
115
|
return unless wait_for_completion?
|
103
116
|
wait_for_completion(resources)
|
@@ -192,26 +205,8 @@ MSG
|
|
192
205
|
end
|
193
206
|
|
194
207
|
def wait_for_completion(watched_resources)
|
195
|
-
|
196
|
-
|
197
|
-
human_resources = watched_resources.map(&:id).join(", ")
|
198
|
-
max_wait_time = watched_resources.map(&:timeout).max
|
199
|
-
KubernetesDeploy.logger.info("Waiting for #{human_resources} with #{max_wait_time}s timeout")
|
200
|
-
while watched_resources.present?
|
201
|
-
if Time.now.utc < delay_sync_until
|
202
|
-
sleep(delay_sync_until - Time.now.utc)
|
203
|
-
end
|
204
|
-
delay_sync_until = Time.now.utc + 3 # don't pummel the API if the sync is fast
|
205
|
-
watched_resources.each(&:sync)
|
206
|
-
newly_finished_resources, watched_resources = watched_resources.partition(&:deploy_finished?)
|
207
|
-
newly_finished_resources.each do |resource|
|
208
|
-
next unless resource.deploy_failed? || resource.deploy_timed_out?
|
209
|
-
KubernetesDeploy.logger.error("#{resource.id} failed to deploy with status '#{resource.status}'.")
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
watch_time = Time.now.utc - started_at
|
214
|
-
KubernetesDeploy.logger.info("Spent #{watch_time.round(2)}s waiting for #{human_resources}")
|
208
|
+
watcher = ResourceWatcher.new(watched_resources)
|
209
|
+
watcher.run
|
215
210
|
end
|
216
211
|
|
217
212
|
def render_template(filename, raw_template)
|
@@ -244,7 +239,18 @@ MSG
|
|
244
239
|
if @namespace.blank?
|
245
240
|
errors << "Namespace must be specified"
|
246
241
|
elsif PROTECTED_NAMESPACES.include?(@namespace)
|
247
|
-
|
242
|
+
if allow_protected_ns? && @prune
|
243
|
+
errors << "Refusing to deploy to protected namespace '#{@namespace}' with pruning enabled"
|
244
|
+
elsif allow_protected_ns?
|
245
|
+
warning = <<-WARNING.strip_heredoc
|
246
|
+
You're deploying to protected namespace #{@namespace}, which cannot be pruned.
|
247
|
+
Existing resources can only be removed manually with kubectl. Removing templates from the set deployed will have no effect.
|
248
|
+
***Please do not deploy to #{@namespace} unless you really know what you are doing.***
|
249
|
+
WARNING
|
250
|
+
KubernetesDeploy.logger.warn(warning)
|
251
|
+
else
|
252
|
+
errors << "Refusing to deploy to protected namespace '#{@namespace}'"
|
253
|
+
end
|
248
254
|
end
|
249
255
|
|
250
256
|
if @context.blank?
|
@@ -335,17 +341,5 @@ MSG
|
|
335
341
|
end
|
336
342
|
[out.chomp, err.chomp, st]
|
337
343
|
end
|
338
|
-
|
339
|
-
def phase_heading(phase_name)
|
340
|
-
@current_phase += 1
|
341
|
-
heading = "Phase #{@current_phase}: #{phase_name}"
|
342
|
-
padding = (100.0 - heading.length) / 2
|
343
|
-
KubernetesDeploy.logger.info("")
|
344
|
-
KubernetesDeploy.logger.info("#{'-' * padding.floor}#{heading}#{'-' * padding.ceil}")
|
345
|
-
end
|
346
|
-
|
347
|
-
def log_green(msg)
|
348
|
-
KubernetesDeploy.logger.info("\033[0;32m#{msg}\x1b[0m")
|
349
|
-
end
|
350
344
|
end
|
351
345
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module KubernetesDeploy
|
3
|
+
module UIHelpers
|
4
|
+
private
|
5
|
+
|
6
|
+
def phase_heading(phase_name)
|
7
|
+
@current_phase ||= 0
|
8
|
+
@current_phase += 1
|
9
|
+
heading = "Phase #{@current_phase}: #{phase_name}"
|
10
|
+
padding = (100.0 - heading.length) / 2
|
11
|
+
KubernetesDeploy.logger.info("")
|
12
|
+
KubernetesDeploy.logger.info("#{'-' * padding.floor}#{heading}#{'-' * padding.ceil}")
|
13
|
+
end
|
14
|
+
|
15
|
+
def log_green(msg)
|
16
|
+
KubernetesDeploy.logger.info("\033[0;32m#{msg}\x1b[0m")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
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.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kir Shatrov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-03-
|
13
|
+
date: 2017-03-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -26,6 +26,20 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '4.2'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: kubeclient
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '2.3'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2.3'
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: bundler
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,11 +82,26 @@ dependencies:
|
|
68
82
|
- - "~>"
|
69
83
|
- !ruby/object:Gem::Version
|
70
84
|
version: '5.0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: minitest-stub-const
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - "~>"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0.6'
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - "~>"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0.6'
|
71
99
|
description: Kubernetes deploy scripts
|
72
100
|
email:
|
73
101
|
- ops-accounts+shipit@shopify.com
|
74
102
|
executables:
|
75
103
|
- kubernetes-deploy
|
104
|
+
- kubernetes-restart
|
76
105
|
extensions: []
|
77
106
|
extra_rdoc_files: []
|
78
107
|
files:
|
@@ -85,8 +114,10 @@ files:
|
|
85
114
|
- bin/ci
|
86
115
|
- bin/setup
|
87
116
|
- exe/kubernetes-deploy
|
117
|
+
- exe/kubernetes-restart
|
88
118
|
- kubernetes-deploy.gemspec
|
89
119
|
- lib/kubernetes-deploy.rb
|
120
|
+
- lib/kubernetes-deploy/kubeclient_builder.rb
|
90
121
|
- lib/kubernetes-deploy/kubernetes_resource.rb
|
91
122
|
- lib/kubernetes-deploy/kubernetes_resource/cloudsql.rb
|
92
123
|
- lib/kubernetes-deploy/kubernetes_resource/config_map.rb
|
@@ -96,7 +127,10 @@ files:
|
|
96
127
|
- lib/kubernetes-deploy/kubernetes_resource/pod.rb
|
97
128
|
- lib/kubernetes-deploy/kubernetes_resource/redis.rb
|
98
129
|
- lib/kubernetes-deploy/kubernetes_resource/service.rb
|
130
|
+
- lib/kubernetes-deploy/resource_watcher.rb
|
131
|
+
- lib/kubernetes-deploy/restart_task.rb
|
99
132
|
- lib/kubernetes-deploy/runner.rb
|
133
|
+
- lib/kubernetes-deploy/ui_helpers.rb
|
100
134
|
- lib/kubernetes-deploy/version.rb
|
101
135
|
homepage: https://github.com/Shopify/kubernetes-deploy
|
102
136
|
licenses:
|