tobsch-krane 1.0.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 +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
|