tobsch-krane 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.buildkite/pipeline.nightly.yml +43 -0
- data/.github/probots.yml +2 -0
- data/.gitignore +20 -0
- data/.rubocop.yml +17 -0
- data/.shopify-build/VERSION +1 -0
- data/.shopify-build/kubernetes-deploy.yml +53 -0
- data/1.0-Upgrade.md +185 -0
- data/CHANGELOG.md +431 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/CONTRIBUTING.md +164 -0
- data/Gemfile +16 -0
- data/ISSUE_TEMPLATE.md +25 -0
- data/LICENSE.txt +21 -0
- data/README.md +655 -0
- data/Rakefile +36 -0
- data/bin/ci +21 -0
- data/bin/setup +16 -0
- data/bin/test +47 -0
- data/dev.yml +28 -0
- data/dev/flamegraph-from-tests +35 -0
- data/exe/krane +5 -0
- data/krane.gemspec +44 -0
- data/lib/krane.rb +7 -0
- data/lib/krane/bindings_parser.rb +88 -0
- data/lib/krane/cli/deploy_command.rb +75 -0
- data/lib/krane/cli/global_deploy_command.rb +54 -0
- data/lib/krane/cli/krane.rb +91 -0
- data/lib/krane/cli/render_command.rb +41 -0
- data/lib/krane/cli/restart_command.rb +34 -0
- data/lib/krane/cli/run_command.rb +54 -0
- data/lib/krane/cli/version_command.rb +13 -0
- data/lib/krane/cluster_resource_discovery.rb +113 -0
- data/lib/krane/common.rb +23 -0
- data/lib/krane/concerns/template_reporting.rb +29 -0
- data/lib/krane/concurrency.rb +18 -0
- data/lib/krane/container_logs.rb +106 -0
- data/lib/krane/deferred_summary_logging.rb +95 -0
- data/lib/krane/delayed_exceptions.rb +14 -0
- data/lib/krane/deploy_task.rb +363 -0
- data/lib/krane/deploy_task_config_validator.rb +29 -0
- data/lib/krane/duration_parser.rb +27 -0
- data/lib/krane/ejson_secret_provisioner.rb +154 -0
- data/lib/krane/errors.rb +28 -0
- data/lib/krane/formatted_logger.rb +57 -0
- data/lib/krane/global_deploy_task.rb +210 -0
- data/lib/krane/global_deploy_task_config_validator.rb +12 -0
- data/lib/krane/kubeclient_builder.rb +156 -0
- data/lib/krane/kubectl.rb +120 -0
- data/lib/krane/kubernetes_resource.rb +621 -0
- data/lib/krane/kubernetes_resource/cloudsql.rb +43 -0
- data/lib/krane/kubernetes_resource/config_map.rb +22 -0
- data/lib/krane/kubernetes_resource/cron_job.rb +18 -0
- data/lib/krane/kubernetes_resource/custom_resource.rb +87 -0
- data/lib/krane/kubernetes_resource/custom_resource_definition.rb +98 -0
- data/lib/krane/kubernetes_resource/daemon_set.rb +90 -0
- data/lib/krane/kubernetes_resource/deployment.rb +213 -0
- data/lib/krane/kubernetes_resource/horizontal_pod_autoscaler.rb +65 -0
- data/lib/krane/kubernetes_resource/ingress.rb +18 -0
- data/lib/krane/kubernetes_resource/job.rb +60 -0
- data/lib/krane/kubernetes_resource/network_policy.rb +22 -0
- data/lib/krane/kubernetes_resource/persistent_volume_claim.rb +80 -0
- data/lib/krane/kubernetes_resource/pod.rb +269 -0
- data/lib/krane/kubernetes_resource/pod_disruption_budget.rb +23 -0
- data/lib/krane/kubernetes_resource/pod_set_base.rb +71 -0
- data/lib/krane/kubernetes_resource/pod_template.rb +20 -0
- data/lib/krane/kubernetes_resource/replica_set.rb +92 -0
- data/lib/krane/kubernetes_resource/resource_quota.rb +22 -0
- data/lib/krane/kubernetes_resource/role.rb +22 -0
- data/lib/krane/kubernetes_resource/role_binding.rb +22 -0
- data/lib/krane/kubernetes_resource/secret.rb +24 -0
- data/lib/krane/kubernetes_resource/service.rb +104 -0
- data/lib/krane/kubernetes_resource/service_account.rb +22 -0
- data/lib/krane/kubernetes_resource/stateful_set.rb +70 -0
- data/lib/krane/label_selector.rb +42 -0
- data/lib/krane/oj.rb +4 -0
- data/lib/krane/options_helper.rb +39 -0
- data/lib/krane/remote_logs.rb +60 -0
- data/lib/krane/render_task.rb +118 -0
- data/lib/krane/renderer.rb +118 -0
- data/lib/krane/resource_cache.rb +68 -0
- data/lib/krane/resource_deployer.rb +265 -0
- data/lib/krane/resource_watcher.rb +171 -0
- data/lib/krane/restart_task.rb +228 -0
- data/lib/krane/rollout_conditions.rb +103 -0
- data/lib/krane/runner_task.rb +212 -0
- data/lib/krane/runner_task_config_validator.rb +18 -0
- data/lib/krane/statsd.rb +65 -0
- data/lib/krane/task_config.rb +22 -0
- data/lib/krane/task_config_validator.rb +96 -0
- data/lib/krane/template_sets.rb +173 -0
- data/lib/krane/version.rb +4 -0
- data/pull_request_template.md +8 -0
- data/screenshots/deploy-demo.gif +0 -0
- data/screenshots/migrate-logs.png +0 -0
- data/screenshots/missing-secret-fail.png +0 -0
- data/screenshots/success.png +0 -0
- data/screenshots/test-output.png +0 -0
- metadata +375 -0
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require "rake/testtask"
|
4
|
+
|
5
|
+
desc("Run integration tests that can be run in parallel")
|
6
|
+
Rake::TestTask.new(:integration_test) do |t|
|
7
|
+
t.libs << "test"
|
8
|
+
t.libs << "lib"
|
9
|
+
t.test_files = FileList['test/integration/**/*_test.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
desc("Run integration tests that CANNOT be run in parallel")
|
13
|
+
Rake::TestTask.new(:serial_integration_test) do |t|
|
14
|
+
t.libs << "test"
|
15
|
+
t.libs << "lib"
|
16
|
+
t.test_files = FileList['test/integration-serial/**/*_test.rb']
|
17
|
+
end
|
18
|
+
|
19
|
+
desc("Run unit tests")
|
20
|
+
Rake::TestTask.new(:unit_test) do |t|
|
21
|
+
t.libs << "test"
|
22
|
+
t.libs << "lib"
|
23
|
+
t.test_files = FileList['test/unit/**/*_test.rb']
|
24
|
+
end
|
25
|
+
|
26
|
+
desc("Run cli tests")
|
27
|
+
Rake::TestTask.new(:cli_test) do |t|
|
28
|
+
t.libs << "test"
|
29
|
+
t.libs << "lib"
|
30
|
+
t.test_files = FileList['test/exe/**/*_test.rb']
|
31
|
+
end
|
32
|
+
|
33
|
+
desc("Run all tests")
|
34
|
+
task(test: %w(unit_test serial_integration_test integration_test cli_test))
|
35
|
+
|
36
|
+
task(default: :test)
|
data/bin/ci
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -euo pipefail
|
3
|
+
|
4
|
+
if [[ -n "${DEBUG:+set}" ]]; then
|
5
|
+
set -x
|
6
|
+
fi
|
7
|
+
|
8
|
+
docker run --rm \
|
9
|
+
--net=host \
|
10
|
+
-v "$HOME/.kube":"/root/.kube" \
|
11
|
+
-v "$HOME/.minikube":"$HOME/.minikube" \
|
12
|
+
-v "$PWD":/usr/src/app \
|
13
|
+
-v "/usr/bin/kubectl":"/usr/bin/kubectl" \
|
14
|
+
-e CI=1 \
|
15
|
+
-e CODECOV_TOKEN=$CODECOV_TOKEN \
|
16
|
+
-e COVERAGE=1 \
|
17
|
+
-e VERBOSE=1 \
|
18
|
+
-e PARALLELISM=$PARALLELISM \
|
19
|
+
-w /usr/src/app \
|
20
|
+
ruby:2.4 \
|
21
|
+
bin/test
|
data/bin/setup
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
set -euo pipefail
|
3
|
+
IFS=$'\n\t'
|
4
|
+
|
5
|
+
bundle install
|
6
|
+
|
7
|
+
if [ ! -x "$(which minikube)" ]; then
|
8
|
+
echo -e "\n\033[0;33mIf you're going to run the tests, please follow the minikube setup instructions for your operating system:\nhttps://kubernetes.io/docs/getting-started-guides/minikube/#installation\033[0m"
|
9
|
+
fi
|
10
|
+
|
11
|
+
if [ ! -x "$(which kubectl)" ]; then
|
12
|
+
echo -e "\n\033[0;33mPlease install kubectl version 1.11.0 or higher:\nhttps://kubernetes.io/docs/user-guide/prereqs/\033[0m"
|
13
|
+
else
|
14
|
+
KUBECTL_VERSION=$(kubectl version --short --client | grep -oe "v[[:digit:]\.]\+")
|
15
|
+
echo -e "\n\033[0;32mKubectl version $KUBECTL_VERSION is already installed. This gem requires version v1.11.0 or greater.\033[0m"
|
16
|
+
fi
|
data/bin/test
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -uo pipefail
|
3
|
+
|
4
|
+
err=0
|
5
|
+
trap 'err=1' ERR
|
6
|
+
trap 'exit 1' SIGINT
|
7
|
+
|
8
|
+
function print_header() {
|
9
|
+
if [[ ${CI:="0"} == "1" ]]; then
|
10
|
+
printf "+++ :kubernetes: %s\n" "${1}"
|
11
|
+
else
|
12
|
+
printf "\n\n\033[0;35m⎈ %s\033[0m\n" "${1}"
|
13
|
+
fi
|
14
|
+
}
|
15
|
+
|
16
|
+
if [[ ${PARALLELISM:=0} -lt 1 ]]; then
|
17
|
+
if [[ $(uname) == "Darwin" ]]; then
|
18
|
+
num_cpus=$(sysctl -n hw.ncpu)
|
19
|
+
else
|
20
|
+
num_cpus=$(nproc --all)
|
21
|
+
fi
|
22
|
+
|
23
|
+
if [[ $num_cpus -le 2 ]]; then
|
24
|
+
PARALLELISM=1
|
25
|
+
else
|
26
|
+
(( PARALLELISM=num_cpus/2 ))
|
27
|
+
fi
|
28
|
+
fi
|
29
|
+
|
30
|
+
if [[ ${CI:="0"} == "1" ]]; then
|
31
|
+
echo "--- :ruby: Bundle Install"
|
32
|
+
bundle install --jobs 4
|
33
|
+
fi
|
34
|
+
|
35
|
+
print_header "Run CLI Tests"
|
36
|
+
bundle exec rake cli_test
|
37
|
+
|
38
|
+
print_header "Run Unit Tests"
|
39
|
+
bundle exec rake unit_test
|
40
|
+
|
41
|
+
print_header "Run Non-Parallel Integration Tests"
|
42
|
+
bundle exec rake serial_integration_test
|
43
|
+
|
44
|
+
print_header "Run Parallel Integration Tests (N=$PARALLELISM)"
|
45
|
+
PARALLELIZE_ME=1 N=$PARALLELISM bundle exec rake integration_test
|
46
|
+
|
47
|
+
test $err -eq 0
|
data/dev.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
---
|
2
|
+
name: krane
|
3
|
+
up:
|
4
|
+
- ruby: 2.4.6 # Matches gemspec
|
5
|
+
- bundler
|
6
|
+
- homebrew:
|
7
|
+
- Caskroom/cask/minikube
|
8
|
+
- custom:
|
9
|
+
name: Install the minikube fork of driver-hyperkit
|
10
|
+
met?: command -v docker-machine-driver-hyperkit
|
11
|
+
meet: curl -LO https://storage.googleapis.com/minikube/releases/latest/docker-machine-driver-hyperkit && sudo install -o root -g wheel -m 4755 docker-machine-driver-hyperkit /usr/local/bin/ && rm ./docker-machine-driver-hyperkit
|
12
|
+
- custom:
|
13
|
+
name: Minikube Cluster
|
14
|
+
met?: test $(minikube status | grep Running | wc -l) -ge 2 && $(minikube status | grep -q 'Configured')
|
15
|
+
meet: minikube start --kubernetes-version=v1.11.10 --vm-driver=hyperkit
|
16
|
+
down: minikube stop
|
17
|
+
commands:
|
18
|
+
reset-minikube: minikube delete && rm -rf ~/.minikube
|
19
|
+
test:
|
20
|
+
run: bin/test
|
21
|
+
tophat:
|
22
|
+
run: PRINT_LOGS=1 bundle exec ruby -I test test/integration/krane_deploy_test.rb -n/${1}/
|
23
|
+
desc: Tophat a change by running a test scenario with logging output enabled.
|
24
|
+
syntax:
|
25
|
+
optional:
|
26
|
+
argument: TEST_REGEX
|
27
|
+
doc:
|
28
|
+
run: bundle exec yard doc
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
SVG_FILENAME="dev/flamegraph.svg"
|
3
|
+
PROFILE_FILENAME="dev/profile"
|
4
|
+
FLAMEGRAPH_PL="dev/flamegraph.pl"
|
5
|
+
|
6
|
+
if [[ -z $1 ]]; then
|
7
|
+
echo "Usage: `basename "$0"` TEST_NAME_OR_REGEX"
|
8
|
+
exit 1
|
9
|
+
fi
|
10
|
+
|
11
|
+
if ! [[ -s $FLAMEGRAPH_PL ]]; then
|
12
|
+
echo "Downloading flamegraph.pl"
|
13
|
+
curl -Lo $FLAMEGRAPH_PL https://raw.githubusercontent.com/brendangregg/FlameGraph/master/flamegraph.pl
|
14
|
+
fi
|
15
|
+
|
16
|
+
if [[ -f $SVG_FILENAME ]]; then
|
17
|
+
rm $SVG_FILENAME
|
18
|
+
fi
|
19
|
+
|
20
|
+
if [[ -f $PROFILE_FILENAME ]]; then
|
21
|
+
rm $PROFILE_FILENAME
|
22
|
+
fi
|
23
|
+
|
24
|
+
echo "Running test(s) with profiling"
|
25
|
+
PROFILE=1 bundle exec ruby -I test test/integration/krane_deploy_test.rb -n /$1/ > /dev/null
|
26
|
+
|
27
|
+
echo "Processing profile"
|
28
|
+
cat $PROFILE_FILENAME | perl -w $FLAMEGRAPH_PL --countname=ms --width=1500 --title=$1 > $SVG_FILENAME
|
29
|
+
|
30
|
+
if [[ -f $SVG_FILENAME ]]; then
|
31
|
+
echo "Done. Opening ${SVG_FILENAME}"
|
32
|
+
open $SVG_FILENAME
|
33
|
+
else
|
34
|
+
echo "Done, but ${SVG_FILENAME} does not exist. Something went wrong."
|
35
|
+
fi
|
data/exe/krane
ADDED
data/krane.gemspec
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'krane/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "tobsch-krane"
|
9
|
+
spec.version = Krane::VERSION
|
10
|
+
spec.authors = ["Katrina Verey", "Daniel Turner", "Kir Shatrov"]
|
11
|
+
spec.email = ["ops-accounts+shipit@shopify.com"]
|
12
|
+
|
13
|
+
spec.summary = 'A command line tool that helps you ship changes to a Kubernetes' \
|
14
|
+
' namespace and understand the result'
|
15
|
+
spec.description = spec.summary
|
16
|
+
spec.homepage = "https://github.com/Shopify/krane"
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = %x(git ls-files -z).split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(test|spec|features)/})
|
21
|
+
end
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = %w(lib)
|
25
|
+
|
26
|
+
spec.required_ruby_version = '>= 2.4.0'
|
27
|
+
spec.add_dependency("activesupport", ">= 5.0")
|
28
|
+
spec.add_dependency("kubeclient", "~> 4.3")
|
29
|
+
spec.add_dependency("googleauth", "~> 0.8.0")
|
30
|
+
spec.add_dependency("ejson", "~> 1.0")
|
31
|
+
spec.add_dependency("colorize", "~> 0.8")
|
32
|
+
spec.add_dependency("statsd-instrument", ['>= 2.8', "< 3.1"])
|
33
|
+
spec.add_dependency("oj", "~> 3.0")
|
34
|
+
spec.add_dependency("concurrent-ruby", "~> 1.1")
|
35
|
+
spec.add_dependency("jsonpath", "~> 0.9.6")
|
36
|
+
spec.add_dependency("thor", "~> 0.20.3")
|
37
|
+
|
38
|
+
spec.add_development_dependency("bundler")
|
39
|
+
spec.add_development_dependency("rake", "~> 10.0")
|
40
|
+
spec.add_development_dependency("minitest", "~> 5.0")
|
41
|
+
spec.add_development_dependency("minitest-stub-const", "~> 0.6")
|
42
|
+
spec.add_development_dependency("webmock", "~> 3.0")
|
43
|
+
spec.add_development_dependency("mocha", "~> 1.5")
|
44
|
+
end
|
data/lib/krane.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'json'
|
3
|
+
require 'yaml'
|
4
|
+
require 'csv'
|
5
|
+
|
6
|
+
module Krane
|
7
|
+
class BindingsParser
|
8
|
+
def self.parse(string)
|
9
|
+
new(string).parse
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(initial_string = nil)
|
13
|
+
@raw_bindings = Array(initial_string)
|
14
|
+
end
|
15
|
+
|
16
|
+
def add(string)
|
17
|
+
@raw_bindings << string
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse
|
21
|
+
result = {}
|
22
|
+
@raw_bindings.each do |string|
|
23
|
+
bindings = parse_file(string) || parse_json(string) || parse_csv(string)
|
24
|
+
unless bindings
|
25
|
+
raise ArgumentError, "Failed to parse bindings."
|
26
|
+
end
|
27
|
+
result.deep_merge!(bindings)
|
28
|
+
end
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def parse_file(string)
|
35
|
+
return unless string =~ /\A@/
|
36
|
+
|
37
|
+
begin
|
38
|
+
file_path = string.gsub(/\A@/, '')
|
39
|
+
|
40
|
+
case File.extname(file_path)
|
41
|
+
when '.json'
|
42
|
+
bindings = parse_json(File.read(file_path))
|
43
|
+
when '.yaml', '.yml'
|
44
|
+
bindings = YAML.safe_load(File.read(file_path), [], [], true, file_path)
|
45
|
+
else
|
46
|
+
raise ArgumentError, "Supplied file does not appear to be JSON or YAML"
|
47
|
+
end
|
48
|
+
|
49
|
+
bindings
|
50
|
+
rescue Errno::ENOENT
|
51
|
+
raise ArgumentError, "Supplied file does not exist: #{string}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_json(string)
|
56
|
+
bindings = JSON.parse(string)
|
57
|
+
|
58
|
+
unless bindings.is_a?(Hash)
|
59
|
+
raise ArgumentError, "Expected JSON data to be a hash."
|
60
|
+
end
|
61
|
+
|
62
|
+
bindings
|
63
|
+
rescue JSON::ParserError
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_csv(string)
|
68
|
+
lines = CSV.parse(string)
|
69
|
+
bindings = {}
|
70
|
+
|
71
|
+
lines.each do |line|
|
72
|
+
line.each do |binding|
|
73
|
+
key, value = binding.split('=', 2)
|
74
|
+
|
75
|
+
if key.blank?
|
76
|
+
raise ArgumentError, "key is blank"
|
77
|
+
end
|
78
|
+
|
79
|
+
bindings[key] = value
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
bindings
|
84
|
+
rescue CSV::MalformedCSVError
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Krane
|
4
|
+
module CLI
|
5
|
+
class DeployCommand
|
6
|
+
DEFAULT_DEPLOY_TIMEOUT = '300s'
|
7
|
+
PROTECTED_NAMESPACES = %w(
|
8
|
+
default
|
9
|
+
kube-system
|
10
|
+
kube-public
|
11
|
+
)
|
12
|
+
OPTIONS = {
|
13
|
+
"filenames" => { type: :array, banner: 'config/deploy/production config/deploy/my-extra-resource.yml',
|
14
|
+
aliases: :f, required: false, default: [],
|
15
|
+
desc: "Directories and files that contains the configuration to apply" },
|
16
|
+
"stdin" => { type: :boolean, default: false,
|
17
|
+
desc: "Read resources from stdin" },
|
18
|
+
"global-timeout" => { type: :string, banner: "duration", default: DEFAULT_DEPLOY_TIMEOUT,
|
19
|
+
desc: "Max duration to monitor workloads correctly deployed" },
|
20
|
+
"protected-namespaces" => { type: :array, banner: "namespace1 namespace2 namespaceN",
|
21
|
+
desc: "Enable deploys to a list of selected namespaces; set to an empty string "\
|
22
|
+
"to disable",
|
23
|
+
default: PROTECTED_NAMESPACES },
|
24
|
+
"prune" => { type: :boolean, desc: "Enable deletion of resources that do not appear in the template dir",
|
25
|
+
default: true },
|
26
|
+
"selector" => { type: :string, banner: "'label=value'",
|
27
|
+
desc: "Select workloads by selector(s)" },
|
28
|
+
"verbose-log-prefix" => { type: :boolean, desc: "Add [context][namespace] to the log prefix",
|
29
|
+
default: true },
|
30
|
+
"verify-result" => { type: :boolean, default: true,
|
31
|
+
desc: "Verify workloads correctly deployed" },
|
32
|
+
}
|
33
|
+
|
34
|
+
def self.from_options(namespace, context, options)
|
35
|
+
require 'krane/deploy_task'
|
36
|
+
require 'krane/options_helper'
|
37
|
+
require 'krane/label_selector'
|
38
|
+
|
39
|
+
selector = ::Krane::LabelSelector.parse(options[:selector]) if options[:selector]
|
40
|
+
|
41
|
+
logger = ::Krane::FormattedLogger.build(namespace, context,
|
42
|
+
verbose_prefix: options['verbose-log-prefix'])
|
43
|
+
|
44
|
+
protected_namespaces = options['protected-namespaces']
|
45
|
+
if options['protected-namespaces'].size == 1 && %w('' "").include?(options['protected-namespaces'][0])
|
46
|
+
protected_namespaces = []
|
47
|
+
end
|
48
|
+
|
49
|
+
# never mutate options directly
|
50
|
+
filenames = options[:filenames].dup
|
51
|
+
filenames << "-" if options[:stdin]
|
52
|
+
if filenames.empty?
|
53
|
+
raise Thor::RequiredArgumentMissingError, 'At least one of --filenames or --stdin must be set'
|
54
|
+
end
|
55
|
+
|
56
|
+
::Krane::OptionsHelper.with_processed_template_paths(filenames) do |paths|
|
57
|
+
deploy = ::Krane::DeployTask.new(
|
58
|
+
namespace: namespace,
|
59
|
+
context: context,
|
60
|
+
filenames: paths,
|
61
|
+
logger: logger,
|
62
|
+
global_timeout: ::Krane::DurationParser.new(options["global-timeout"]).parse!.to_i,
|
63
|
+
selector: selector,
|
64
|
+
protected_namespaces: protected_namespaces,
|
65
|
+
)
|
66
|
+
|
67
|
+
deploy.run!(
|
68
|
+
verify_result: options["verify-result"],
|
69
|
+
prune: options[:prune]
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Krane
|
4
|
+
module CLI
|
5
|
+
class GlobalDeployCommand
|
6
|
+
DEFAULT_DEPLOY_TIMEOUT = '300s'
|
7
|
+
OPTIONS = {
|
8
|
+
"filenames" => { type: :array, banner: 'config/deploy/production config/deploy/my-extra-resource.yml',
|
9
|
+
aliases: :f, required: false, default: [],
|
10
|
+
desc: "Directories and files that contains the configuration to apply" },
|
11
|
+
"stdin" => { type: :boolean, default: false, desc: "Read resources from stdin" },
|
12
|
+
"global-timeout" => { type: :string, banner: "duration", default: DEFAULT_DEPLOY_TIMEOUT,
|
13
|
+
desc: "Max duration to monitor workloads correctly deployed" },
|
14
|
+
"verify-result" => { type: :boolean, default: true,
|
15
|
+
desc: "Verify workloads correctly deployed" },
|
16
|
+
"selector" => { type: :string, banner: "'label=value'", required: true,
|
17
|
+
desc: "Select workloads owned by selector(s)" },
|
18
|
+
"prune" => { type: :boolean, desc: "Enable deletion of resources that match"\
|
19
|
+
" the provided selector and do not appear in the provided templates",
|
20
|
+
default: true },
|
21
|
+
}
|
22
|
+
|
23
|
+
def self.from_options(context, options)
|
24
|
+
require 'krane/global_deploy_task'
|
25
|
+
require 'krane/options_helper'
|
26
|
+
require 'krane/label_selector'
|
27
|
+
require 'krane/duration_parser'
|
28
|
+
|
29
|
+
selector = ::Krane::LabelSelector.parse(options[:selector])
|
30
|
+
|
31
|
+
# never mutate options directly
|
32
|
+
filenames = options[:filenames].dup
|
33
|
+
filenames << "-" if options[:stdin]
|
34
|
+
if filenames.empty?
|
35
|
+
raise Thor::RequiredArgumentMissingError, 'At least one of --filenames or --stdin must be set'
|
36
|
+
end
|
37
|
+
|
38
|
+
::Krane::OptionsHelper.with_processed_template_paths(filenames) do |paths|
|
39
|
+
deploy = ::Krane::GlobalDeployTask.new(
|
40
|
+
context: context,
|
41
|
+
filenames: paths,
|
42
|
+
global_timeout: ::Krane::DurationParser.new(options["global-timeout"]).parse!.to_i,
|
43
|
+
selector: selector,
|
44
|
+
)
|
45
|
+
|
46
|
+
deploy.run!(
|
47
|
+
verify_result: options["verify-result"],
|
48
|
+
prune: options[:prune],
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|