kubert 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +43 -20
- data/lib/kubert.rb +6 -73
- data/lib/kubert/cli.rb +13 -6
- data/lib/kubert/configuration.rb +81 -0
- data/lib/kubert/deployment.rb +20 -8
- data/lib/kubert/env_cli.rb +41 -0
- data/lib/kubert/environment.rb +122 -0
- data/lib/kubert/file_access.rb +75 -0
- data/lib/kubert/version.rb +1 -1
- metadata +6 -4
- data/.rspec +0 -2
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b10631ed96955a9a447aeaf376dbd7e4ca077908
|
4
|
+
data.tar.gz: 4fbf424aa122d476bb4043bc37ceb1066cffddf4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38e72a5c366ff85f1e6b0b5e3964b537984b6d6503e579edc2d0e48fcf7e152302d550a588168944cb656688bba328b4a48e344b7b39f52dd1939576f33c49f0
|
7
|
+
data.tar.gz: c6c36898f08d865f6f9fb441c01ec0400fd934d2b3f54b027ca4a2fd62d1a88f83b11bde2024860f8f3ce34da6de1f343ff8823e8c57d6fcc0fe611a51121c44
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# Kubert - Your helpful kubernetes ruby terminal friend!
|
2
2
|
|
3
|
-
## The gem relies on a second gem, [ky](https://github.com/stellaservice/ky)
|
3
|
+
## The gem relies on a second gem, [ky](https://github.com/stellaservice/ky), though the two may also be used independently, other than a shared config file.
|
4
4
|
|
5
|
-
|
5
|
+
Install gem via `gem install kubert` as usual. This will also install the ky gem, which handles configuration and manages environments and DRYing yaml for deployments. (If anyone wanted to provide similar interoperability with [helm](http://helm.sh) that would be awesome, we might prefer using that as the more standard solution but we use ky for now for various interoperabiltiy related reasons.)
|
6
6
|
|
7
7
|
Kubert assumes your kubernetes config file lives in `~/.kube/config` and reads that to talk to the cluster.
|
8
8
|
|
@@ -11,21 +11,31 @@ Compile and Rollback actions are only available if using ky for generating your
|
|
11
11
|
ky manages the scope of a deployment as a group of related, seperate kubernetes deployments. Typing `ky example` at the console will import example ky configuration, including kubert configuration. You may ignore/delete most of this if not using ky itself, and focus primarily on the kubert section of the yml for a few pieces of kubert configuration... the important ones are these:
|
12
12
|
|
13
13
|
```
|
14
|
+
environments: [dev, stg, prd]
|
15
|
+
secret_path: "deploy/my-project.secret.yml"
|
16
|
+
config_path: "deploy/my-project.configmap.yml"
|
14
17
|
project_name: "my-project"
|
15
18
|
kubert:
|
16
19
|
contexts:
|
17
|
-
staging: staging.example.com
|
20
|
+
staging: staging.example.com # as many values here as you have distinct clusters in kubeconfig
|
18
21
|
prod: production.example.com
|
19
|
-
excluded_deployments: [sanitize,
|
22
|
+
excluded_deployments: [sanitize,migration] # optional/possibly uncommon use case, see below
|
20
23
|
default_environment: stg
|
21
|
-
default_namespace: default
|
22
|
-
task_pod: console
|
23
|
-
console_command: rails c
|
24
|
-
command_prefix: bundle exec
|
25
|
-
kube_config_path: ~/.kube/config
|
24
|
+
default_namespace: default # defaults to same as default_environment, specify if different
|
25
|
+
task_pod: console # deployment id (from Procfile) for tasks/console, selected at random if blank
|
26
|
+
console_command: rails c # optional, but no console command unless present
|
27
|
+
command_prefix: bundle exec # optional
|
28
|
+
kube_config_path: ~/.kube/config # No need to specify unless you store file elsewhere
|
29
|
+
s3_secret_path: s3://my-bucket/environments/ # If defined, must manually install aws-sdk gem and have credentials for bucket as defaults (for now)
|
30
|
+
s3_config_path: s3://my-bucket/environments # Ditto, with or w/o trailing slash, less likely as could be checked in but supporting for symmetry
|
26
31
|
```
|
27
32
|
|
28
|
-
|
33
|
+
project_name is used by ky and assumes a metadata namespace for your app deployments in the format of `{{project_name}}-{{deployment_name}}`, so as long as your deployments obey this pattern it should be usable for you without ky.
|
34
|
+
|
35
|
+
environments defines valid environments with overrideable configuration located in the same directory as ky config with names like `stg.yml`
|
36
|
+
|
37
|
+
secret_path and config_path will likely NOT be defined in your global ky configuration as above but in environment specific files... ky assumes one such file per environment listed in the environments config, and merges any keys defined in those files (under a configuration key) as overrides of the global ky config, but perhaps in this example dev and stg share configmap and secret so only prd needs to override these
|
38
|
+
|
29
39
|
contexts is used to create convenience functions for switching between different clusters defined in the same kubeconfig file, i.e. `kubert staging` with above config will switch/ensure your config is using staging.example.com
|
30
40
|
|
31
41
|
excluded_deployments says not to deploy the following deployments defined in your Procfile during a normal deployment, and not to rollback during a rollback.
|
@@ -38,17 +48,30 @@ console_command and console_prefix are for opening a REPL and for prefixing all
|
|
38
48
|
|
39
49
|
kube_config_path is probably not needed unless your kubernetes config is located elsewhere
|
40
50
|
|
51
|
+
s3_secret_path and s3_config_path tell kubert not to use the locally configured ky build path, but to read and write either/both values to a an s3 bucket
|
52
|
+
The value provided must begin with s3:// and provide bucket name and path to a folder in bucket containing one folder per environment, i.e. for
|
53
|
+
example above s3://my-bucket/environments/stg/my-project.secret.yml and s3://my-bucket/environments/stg/my-project.configmap.yml
|
54
|
+
|
55
|
+
Kubert will also download from these locations when deploying to kubernetes, and then delete when done to avoid confusion/leaking data, if specified.
|
56
|
+
|
41
57
|
###Example usage
|
42
58
|
```
|
43
|
-
$ kubert console
|
44
|
-
$ kubert execute rake db:migrate
|
45
|
-
$ kubert list web
|
46
|
-
$ kubert sandbox
|
47
|
-
$ kubert context
|
48
|
-
$ kubert deploy -e prd
|
49
|
-
$ kubert rollback -e prd
|
50
|
-
$ kubert deploy
|
51
|
-
$ kubert logs web
|
59
|
+
$ kubert console # open a console on a task_pod
|
60
|
+
$ kubert execute rake db:migrate # run a migration
|
61
|
+
$ kubert list web # list all running web pods
|
62
|
+
$ kubert sandbox # only if rails c/rails console is console_command above, opens console wrapped in DB transaction
|
63
|
+
$ kubert context # print current kubectl context/cluster
|
64
|
+
$ kubert deploy -e prd # perform a production deployment
|
65
|
+
$ kubert rollback -e prd # rollback a production deployment
|
66
|
+
$ kubert deploy # perform a deployment to the default environment
|
67
|
+
$ kubert logs web # tail the logs from all web pods and interleave together
|
68
|
+
$ kubert env all # print all secret/configmap values, with secrets sanitized showing last 4 characters
|
69
|
+
$ kubert env all --cleartext-secrets # print all secret/configmap values, with secrets fully visible
|
70
|
+
$ kubert env get secret-or-config-key # print one env value defined in configmap or secrets for default environment
|
71
|
+
$ kubert env set key value # update one env key/value defined in configmap or secrets for default environment
|
72
|
+
$ kubert env set key value -s # create new env key/value defined in secrets for default environment
|
73
|
+
$ kubert env set key value -c # create new env key/value defined in configmap for default environment
|
74
|
+
$ kubert env unset key # remove an env key/value defined in configmap or secrets for default environment
|
52
75
|
```
|
53
76
|
|
54
|
-
A valid url may also be used in place of a file path for input.
|
77
|
+
A valid url may also be used in place of a file path for input.
|
data/lib/kubert.rb
CHANGED
@@ -4,63 +4,14 @@ require 'open3'
|
|
4
4
|
require 'fiber'
|
5
5
|
require_relative "kubert/pods"
|
6
6
|
require_relative "kubert/deployment"
|
7
|
+
require_relative "kubert/environment"
|
8
|
+
require_relative "kubert/configuration"
|
9
|
+
require_relative "kubert/file_access"
|
10
|
+
require_relative "kubert/env_cli"
|
7
11
|
|
8
12
|
module Kubert
|
9
|
-
extend
|
10
|
-
|
11
|
-
def kube_config
|
12
|
-
@kube_config ||= Kubeclient::Config.read(File.expand_path(kube_config_path))
|
13
|
-
end
|
14
|
-
|
15
|
-
def kube_config_path
|
16
|
-
configuration[:kube_config_path] || DEFAULT_KUBE_CONFIG_PATH
|
17
|
-
end
|
18
|
-
|
19
|
-
def contexts
|
20
|
-
configuration[:contexts] || []
|
21
|
-
end
|
22
|
-
|
23
|
-
def task_pod
|
24
|
-
configuration[:task_pod] || random_pod_type
|
25
|
-
end
|
26
|
-
|
27
|
-
def default_environment
|
28
|
-
configuration[:default_environment]
|
29
|
-
end
|
30
|
-
|
31
|
-
def default_namespace
|
32
|
-
configuration[:default_namespace] || configuration[:default_environment]
|
33
|
-
end
|
34
|
-
|
35
|
-
def context
|
36
|
-
kube_config.contexts.select {|c| kube_config.context.api_endpoint.match(c) }
|
37
|
-
end
|
38
|
-
|
39
|
-
def console_command
|
40
|
-
Array(configuration[:console_command] && configuration[:console_command].split(" "))
|
41
|
-
end
|
42
|
-
|
43
|
-
def command_prefix
|
44
|
-
configuration[:command_prefix]
|
45
|
-
end
|
46
|
-
|
47
|
-
def excluded_deployments
|
48
|
-
configuration[:excluded_deployments] || []
|
49
|
-
end
|
50
|
-
|
51
|
-
def ky_configuration
|
52
|
-
@ky_configuration ||= KY::Configuration.new
|
53
|
-
end
|
54
|
-
|
55
|
-
def ky_active?
|
56
|
-
ky_configuration[:image] && ky_configuration[:deployment] && ky_configuration[:procfile_path]
|
57
|
-
end
|
58
|
-
|
59
|
-
def configuration
|
60
|
-
@config ||= (ky_configuration[:kubert] || {}).merge(project_name: ky_configuration[:project_name])
|
61
|
-
end
|
62
|
-
|
63
|
-
def client
|
13
|
+
extend Configuration
|
14
|
+
def self.client
|
64
15
|
@client ||= begin
|
65
16
|
Kubeclient::Client.new(
|
66
17
|
kube_config.context.api_endpoint,
|
@@ -72,22 +23,4 @@ module Kubert
|
|
72
23
|
)
|
73
24
|
end
|
74
25
|
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
def random_pod_type
|
79
|
-
Kubert.client.get_pods(namespace: current_namespace)
|
80
|
-
.sample
|
81
|
-
.metadata
|
82
|
-
.name
|
83
|
-
.split("-")
|
84
|
-
.first
|
85
|
-
end
|
86
|
-
|
87
|
-
def current_namespace
|
88
|
-
ky_configuration[:namespace] ||
|
89
|
-
default_namespace ||
|
90
|
-
(raise "MUST DEFINE A NAMESPACE FOR POD OPERATIONS, ky namespace, default_namespace or default_environment")
|
91
|
-
end
|
92
|
-
|
93
26
|
end
|
data/lib/kubert/cli.rb
CHANGED
@@ -38,8 +38,8 @@ module Kubert
|
|
38
38
|
Pods.execute(command)
|
39
39
|
end
|
40
40
|
|
41
|
-
desc "logs pod_type (status, default Running)", "Interleave and tail logs from all running pods of the specified type"
|
42
|
-
def logs(pod_type, status= :running)
|
41
|
+
desc "logs (pod_type, default 'web') (status, default 'Running')", "Interleave and tail logs from all running pods of the specified type"
|
42
|
+
def logs(pod_type='web', status= :running)
|
43
43
|
Pods.logs(pod_type, status)
|
44
44
|
end
|
45
45
|
|
@@ -49,20 +49,27 @@ module Kubert
|
|
49
49
|
method_option :namespace, type: :string, aliases: "-n"
|
50
50
|
method_option :environment, type: :string, aliases: "-e"
|
51
51
|
method_option :image_tag, type: :string, aliases: "-t"
|
52
|
-
method_option :configmap_path, type: :string, aliases: "-
|
53
|
-
method_option :secrets_path, type: :string, aliases: "-
|
52
|
+
method_option :configmap_path, type: :string, aliases: "-k"
|
53
|
+
method_option :secrets_path, type: :string, aliases: "-p"
|
54
54
|
method_option :output_dir, type: :string, aliases: "-o"
|
55
|
+
method_option :skip_confirmation, type: :boolean, aliases: "-s"
|
55
56
|
def deploy
|
56
57
|
Deployment.perform(options)
|
57
58
|
end
|
58
59
|
|
60
|
+
desc "env", "Sub commands to manage secrets and configmap values"
|
61
|
+
def env(*args)
|
62
|
+
Kubert::EnvCli.start(args)
|
63
|
+
end
|
64
|
+
|
59
65
|
desc "rollback", "Rollback a deployment, reverse of a kubert deploy command with same flags"
|
60
66
|
method_option :namespace, type: :string, aliases: "-n"
|
61
67
|
method_option :environment, type: :string, aliases: "-e"
|
62
68
|
method_option :image_tag, type: :string, aliases: "-t"
|
63
|
-
method_option :configmap_path, type: :string, aliases: "-
|
64
|
-
method_option :secrets_path, type: :string, aliases: "-
|
69
|
+
method_option :configmap_path, type: :string, aliases: "-k"
|
70
|
+
method_option :secrets_path, type: :string, aliases: "-p"
|
65
71
|
method_option :output_dir, type: :string, aliases: "-o"
|
72
|
+
method_option :skip_confirmation, type: :boolean, aliases: "-s"
|
66
73
|
def rollback
|
67
74
|
Deployment.rollback(options)
|
68
75
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Kubert
|
2
|
+
module Configuration
|
3
|
+
DEFAULT_KUBE_CONFIG_PATH = '~/.kube/config'
|
4
|
+
def kube_config
|
5
|
+
@kube_config ||= Kubeclient::Config.read(File.expand_path(kube_config_path))
|
6
|
+
end
|
7
|
+
|
8
|
+
# Config methods which correspond to config or default value/value_method
|
9
|
+
{
|
10
|
+
default_environment: nil,
|
11
|
+
command_prefix: nil,
|
12
|
+
s3_secret_path: nil,
|
13
|
+
s3_config_path: nil,
|
14
|
+
kube_config_path: DEFAULT_KUBE_CONFIG_PATH,
|
15
|
+
contexts: [],
|
16
|
+
excluded_deployments: [],
|
17
|
+
task_pod: :random_pod_type,
|
18
|
+
default_namespace: :default_environment
|
19
|
+
}.each do |config, default_value|
|
20
|
+
define_method(config) do
|
21
|
+
return configuration[config] if configuration[config]
|
22
|
+
default_value.is_a?(Symbol) ? public_send(default_value) : default_value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def context
|
27
|
+
kube_config.contexts.select {|c| kube_config.context.api_endpoint.match(c) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def console_command
|
31
|
+
Array(configuration[:console_command] && configuration[:console_command].split(" "))
|
32
|
+
end
|
33
|
+
|
34
|
+
def ky_configuration(options={})
|
35
|
+
@ky_configuration ||= KY::Configuration.new({environment: Kubert.default_environment, namespace: Kubert.default_namespace}.merge(options))
|
36
|
+
end
|
37
|
+
|
38
|
+
def ky_active?
|
39
|
+
ky_configuration[:image] && ky_configuration[:deployment] && ky_configuration[:procfile_path]
|
40
|
+
end
|
41
|
+
|
42
|
+
def configuration
|
43
|
+
@configuration ||= begin
|
44
|
+
temp_ky_configuration = KY::Configuration.new
|
45
|
+
(temp_ky_configuration[:kubert] || {}).merge(project_name: temp_ky_configuration[:project_name])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def config_file_name
|
50
|
+
"#{configuration[:project_name]}#{KY::Manipulation::CONFIG_SUFFIX}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def secret_file_name
|
54
|
+
"#{configuration[:project_name]}#{KY::Manipulation::SECRET_SUFFIX}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def current_namespace
|
58
|
+
ky_configuration[:namespace] ||
|
59
|
+
default_namespace ||
|
60
|
+
(raise "MUST DEFINE A NAMESPACE FOR POD OPERATIONS, ky namespace, default_namespace or default_environment")
|
61
|
+
end
|
62
|
+
|
63
|
+
def current_environment
|
64
|
+
ky_configuration[:environment] ||
|
65
|
+
default_environment ||
|
66
|
+
(raise "MUST DEFINE AN ENVIRONMENT FOR SECRETS, ky environment, environment flag in command or default_environment")
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def random_pod_type
|
72
|
+
Kubert.client.get_pods(namespace: current_namespace)
|
73
|
+
.sample
|
74
|
+
.metadata
|
75
|
+
.name
|
76
|
+
.split("-")
|
77
|
+
.first
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
data/lib/kubert/deployment.rb
CHANGED
@@ -8,11 +8,11 @@ module Kubert
|
|
8
8
|
new(options).rollback
|
9
9
|
end
|
10
10
|
|
11
|
-
attr_reader :project_name, :
|
11
|
+
attr_reader :project_name, :options, :operation_statuses
|
12
12
|
def initialize(options, project_name= Kubert.configuration[:project_name])
|
13
13
|
@project_name = project_name
|
14
|
-
@deployments = []
|
15
14
|
@options = options
|
15
|
+
Kubert.ky_configuration(options) # memoize options for FileAccess usage
|
16
16
|
end
|
17
17
|
|
18
18
|
def rollback
|
@@ -26,15 +26,25 @@ module Kubert
|
|
26
26
|
|
27
27
|
def perform
|
28
28
|
confirm :deploy do
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
handle_env_deploy(:config) do
|
30
|
+
handle_env_deploy(:secret) do
|
31
|
+
compilation.deploy_generation.to_h.each do |deployment_file, _template_hash|
|
32
|
+
perform_with_status { `kubectl apply -f #{File.expand_path(deployment_file)} --record` unless excluded?(deployment_file) }
|
33
|
+
end
|
34
|
+
report_status(:deploy)
|
35
|
+
end
|
33
36
|
end
|
34
|
-
report_status(:deploy)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
40
|
+
def handle_env_deploy(env)
|
41
|
+
data = FileAccess.new(:config)
|
42
|
+
data.write_local unless data.local?
|
43
|
+
perform_with_status { `kubectl apply -f #{File.expand_path(output_dir)}/#{Kubert.public_send("#{env}_file_name")} --record` }
|
44
|
+
yield
|
45
|
+
data.clean_local unless data.local?
|
46
|
+
end
|
47
|
+
|
38
48
|
def compilation
|
39
49
|
@compilation ||= KY::API.compile(options[:configmap_path], options[:secrets_path], options[:output_dir], options_with_defaults)
|
40
50
|
end
|
@@ -42,11 +52,13 @@ module Kubert
|
|
42
52
|
private
|
43
53
|
|
44
54
|
def confirm(action)
|
45
|
-
unless
|
55
|
+
unless options[:skip_confirmation]
|
46
56
|
puts "Press any key to confirm, ctl-c to abort: #{action.to_s.upcase} on #{Kubert.context}"
|
47
57
|
$stdin.gets
|
48
58
|
end
|
49
59
|
yield
|
60
|
+
rescue Interrupt
|
61
|
+
puts "Aborting #{action}"
|
50
62
|
end
|
51
63
|
|
52
64
|
def report_status(action)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'thor'
|
2
|
+
module Kubert
|
3
|
+
class EnvCli < Thor
|
4
|
+
desc "env all", "Get all keys and values from configmap and secrets"
|
5
|
+
method_option :environment, type: :string, aliases: "-e"
|
6
|
+
method_option :configmap_path, type: :string, aliases: "-k"
|
7
|
+
method_option :secrets_path, type: :string, aliases: "-p"
|
8
|
+
method_option :cleartext_secrets, type: :string, aliases: "-c"
|
9
|
+
def all
|
10
|
+
Environment.get(nil, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "env get", "Get named env value from configmap or secrets"
|
14
|
+
method_option :environment, type: :string, aliases: "-e"
|
15
|
+
method_option :configmap_path, type: :string, aliases: "-k"
|
16
|
+
method_option :secrets_path, type: :string, aliases: "-p"
|
17
|
+
def get(key)
|
18
|
+
Environment.get(key, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "env unset", "Clear named env value from configmap or secrets, error if not present"
|
22
|
+
method_option :environment, type: :string, aliases: "-e"
|
23
|
+
method_option :configmap_path, type: :string, aliases: "-k"
|
24
|
+
method_option :secrets_path, type: :string, aliases: "-p"
|
25
|
+
method_option :cleartext_secrets, type: :string, aliases: "-c"
|
26
|
+
def unset(key)
|
27
|
+
Environment.unset(key, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
method_option :environment, type: :string, aliases: "-e"
|
31
|
+
method_option :configmap_path, type: :string, aliases: "-k"
|
32
|
+
method_option :secrets_path, type: :string, aliases: "-p"
|
33
|
+
method_option :new_secret, type: :string, aliases: "-s"
|
34
|
+
method_option :new_config, type: :string, aliases: "-c"
|
35
|
+
desc "env set", "change existing env value in configmap or secrets, or new one with flag option"
|
36
|
+
def set(key, value)
|
37
|
+
Environment.set(key, value, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Kubert
|
2
|
+
class Environment
|
3
|
+
PEEK_LENGTH = 4
|
4
|
+
def self.get(key, options)
|
5
|
+
new(key, nil, options).get
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.set(key, value, options)
|
9
|
+
new(key, value, options).set
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.unset(key, options)
|
13
|
+
new(key, nil, options).set
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(key, value, raw_options)
|
17
|
+
@key = key
|
18
|
+
@value = value
|
19
|
+
@options = raw_options.with_indifferent_access
|
20
|
+
abort("ERROR: Cannot specify env set as both new_secret and new_config") if options[:new_config] && options[:new_secret]
|
21
|
+
Kubert.ky_configuration(options) # memoizes and avoids passing to FileAccess
|
22
|
+
@config_data = FileAccess.new(:config, yaml_key)
|
23
|
+
@secret_data = FileAccess.new(:secret, yaml_key)
|
24
|
+
return if print_all?
|
25
|
+
@create_mode = (options[:new_config] || options[:new_secret])&.to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
def set
|
29
|
+
if create_mode
|
30
|
+
abort("ERROR: #{key} exists but #{create_mode} flag set! Call without flag to update existing value") unless total_found == 0
|
31
|
+
create
|
32
|
+
else
|
33
|
+
report_unchanged if existing_value == value
|
34
|
+
update
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def get
|
39
|
+
return get_all if print_all?
|
40
|
+
case total_found
|
41
|
+
when 0
|
42
|
+
puts "#{yaml_key} not found in configmap or secrets"
|
43
|
+
when 1
|
44
|
+
puts existing_value
|
45
|
+
else
|
46
|
+
puts "ERROR! multiple entries found for key: config - #{config_data.found}, secret - #{secret_data.found}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
attr_reader :key, :value, :options, :create_mode, :config_data, :secret_data
|
52
|
+
|
53
|
+
def print_all?
|
54
|
+
key.nil? && value.nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_all
|
58
|
+
puts "CONFIGMAP:"
|
59
|
+
output_hash(config_data.data[:data])
|
60
|
+
puts "SECRETS:"
|
61
|
+
output_hash(options[:cleartext_secrets] ? secret_data.data[:data] : obscured_secrets)
|
62
|
+
end
|
63
|
+
|
64
|
+
def output_hash(hsh)
|
65
|
+
hsh.each {|k, v| puts "#{k}: #{v}" }
|
66
|
+
end
|
67
|
+
|
68
|
+
def create
|
69
|
+
case create_mode
|
70
|
+
when :new_secret
|
71
|
+
secret_data.set(value).write
|
72
|
+
when :new_config
|
73
|
+
config_data.set(value).write
|
74
|
+
else
|
75
|
+
abort("ERROR: unknown create env type error")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def update
|
80
|
+
if secret_data.found.any?
|
81
|
+
secret_data.set(value).write
|
82
|
+
elsif config_data.found.any?
|
83
|
+
config_data.set(value).write
|
84
|
+
else
|
85
|
+
abort("ERROR: your key is new, must specify secret or configmap with flag")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def obscured_secrets
|
90
|
+
values = secret_data.data[:data].values
|
91
|
+
secret_data.data[:data].keys.zip(
|
92
|
+
values.map do |secret|
|
93
|
+
obscure_length = [(secret.size - PEEK_LENGTH), 0].max
|
94
|
+
sneak_peek = secret.slice(obscure_length, secret.size)
|
95
|
+
"#{'*' * obscure_length}#{sneak_peek}"
|
96
|
+
end
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
def insert_ordered_hash(hsh)
|
101
|
+
hsh[:data][yaml_key] = value
|
102
|
+
hsh[:data] = hsh[:data].sort.to_h
|
103
|
+
end
|
104
|
+
|
105
|
+
def existing_value
|
106
|
+
config_data.found.merge(secret_data.found).values.first
|
107
|
+
end
|
108
|
+
|
109
|
+
def total_found
|
110
|
+
secret_data.found.size + config_data.found.size
|
111
|
+
end
|
112
|
+
|
113
|
+
def report_unchanged
|
114
|
+
puts "WARN: #{key} value unchanged, already set to #{value}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def yaml_key
|
118
|
+
key&.downcase&.dasherize
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Kubert
|
2
|
+
class FileAccess
|
3
|
+
attr_reader :data
|
4
|
+
def initialize(type, key = nil)
|
5
|
+
@type = type
|
6
|
+
@key = key
|
7
|
+
@s3_path = Kubert.public_send("s3_#{type}_path")
|
8
|
+
@file_name = Kubert.public_send("#{type}_file_name")
|
9
|
+
@data = read
|
10
|
+
end
|
11
|
+
|
12
|
+
def found
|
13
|
+
data[:data].select {|k, _v| k == key }
|
14
|
+
end
|
15
|
+
|
16
|
+
def read
|
17
|
+
YAML.load(file_read).with_indifferent_access
|
18
|
+
end
|
19
|
+
|
20
|
+
def set(value)
|
21
|
+
if value.nil?
|
22
|
+
data[:data].delete(key)
|
23
|
+
else
|
24
|
+
data[:data][key] = value
|
25
|
+
end
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def get
|
30
|
+
data[:data][key]
|
31
|
+
end
|
32
|
+
|
33
|
+
def local?
|
34
|
+
!s3_path
|
35
|
+
end
|
36
|
+
|
37
|
+
def write
|
38
|
+
return write_local if local?
|
39
|
+
s3_object.put(body: data.to_plain_yaml, content_encoding: 'application/octet-stream', content_type: "text/vnd.yaml", metadata: {author: `whoami`})
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_local
|
43
|
+
File.write(local_path, data.to_plain_yaml)
|
44
|
+
end
|
45
|
+
|
46
|
+
def clean_local
|
47
|
+
File.delete(local_path)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
attr_reader :s3_path, :file_name, :type, :key
|
53
|
+
|
54
|
+
def file_read
|
55
|
+
return s3_object.get.body.read unless local?
|
56
|
+
File.read(local_path)
|
57
|
+
end
|
58
|
+
|
59
|
+
def local_path
|
60
|
+
Kubert.ky_configuration["#{type}_path"] # options set & memoized elsewhere if needed
|
61
|
+
end
|
62
|
+
|
63
|
+
def s3_object
|
64
|
+
@s3_object ||= begin
|
65
|
+
require 'aws-sdk'
|
66
|
+
s3 = Aws::S3::Resource.new
|
67
|
+
match_data = s3_path.match(/\As3:\/\/(?<bucket>[^\/]+)\/(?<folder_path>\S+[^\/])\/?\z/)
|
68
|
+
bucket = s3.bucket(match_data[:bucket])
|
69
|
+
bucket.objects(prefix: "#{match_data[:folder_path]}/#{Kubert.current_namespace}/#{file_name}").first
|
70
|
+
rescue LoadError
|
71
|
+
puts "ERROR: s3_#{type}_path defined, but aws-sdk gem not available... it is not a hard dependency of kubert, but kubert requires it for s3 read/write if s3_#{type}_path defined"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/kubert/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubert
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Glusman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -119,8 +119,6 @@ extensions: []
|
|
119
119
|
extra_rdoc_files: []
|
120
120
|
files:
|
121
121
|
- ".gitignore"
|
122
|
-
- ".rspec"
|
123
|
-
- ".travis.yml"
|
124
122
|
- Gemfile
|
125
123
|
- LICENSE.txt
|
126
124
|
- README.md
|
@@ -131,7 +129,11 @@ files:
|
|
131
129
|
- kubert.gemspec
|
132
130
|
- lib/kubert.rb
|
133
131
|
- lib/kubert/cli.rb
|
132
|
+
- lib/kubert/configuration.rb
|
134
133
|
- lib/kubert/deployment.rb
|
134
|
+
- lib/kubert/env_cli.rb
|
135
|
+
- lib/kubert/environment.rb
|
136
|
+
- lib/kubert/file_access.rb
|
135
137
|
- lib/kubert/pods.rb
|
136
138
|
- lib/kubert/version.rb
|
137
139
|
homepage:
|
data/.rspec
DELETED