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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 11a4977bc3bcc125b5c7d631fde64ad7d4bcd857
4
- data.tar.gz: 257585ae70feb31f2896193dab4ac09041100a95
3
+ metadata.gz: b10631ed96955a9a447aeaf376dbd7e4ca077908
4
+ data.tar.gz: 4fbf424aa122d476bb4043bc37ceb1066cffddf4
5
5
  SHA512:
6
- metadata.gz: 0401b4d08e0b7cfb568368a8779c810e20fe466163a394a485afed04327b5855eed089769e997ae5573facce97531ac9bd4dec474b69f6d5c083a9d8e376a9db
7
- data.tar.gz: 7f9705992329e778645ea4b0df82db81389b321bf7d3b81a018c81b786b44ea398ae904f84431fbab8f6e7bbfbe19d518013237462f3daab88e40fa6289e42cc
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) which may be used independently
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
- # Install gem via `gem install kubert` as usual. This will also install the ky gem, which handles configuration.
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 # as many values here as you have distinct clusters in kubeconfig
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, migration] # optional/possibly uncommon use case, see below
22
+ excluded_deployments: [sanitize,migration] # optional/possibly uncommon use case, see below
20
23
  default_environment: stg
21
- default_namespace: default # defaults to same as default_environment, specify if different
22
- task_pod: console
23
- console_command: rails c # optional, but no console command unless present
24
- command_prefix: bundle exec # optional
25
- kube_config_path: ~/.kube/config # No need to specify unless you store file elsewhere
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
- The 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.
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 # open a console on a task_pod
44
- $ kubert execute rake db:migrate # run a migration
45
- $ kubert list web # list all running web pods
46
- $ kubert sandbox # only if rails c/rails console is console_command above, opens console wrapped in DB transaction
47
- $ kubert context # print current kubectl context/cluster
48
- $ kubert deploy -e prd # perform a production deployment
49
- $ kubert rollback -e prd # rollback a production deployment
50
- $ kubert deploy # perform a deployment to the default environment
51
- $ kubert logs web # tail the logs from all web pods and interleave together
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 self
10
- DEFAULT_KUBE_CONFIG_PATH = '~/.kube/config'
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: "-c"
53
- method_option :secrets_path, type: :string, aliases: "-s"
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: "-c"
64
- method_option :secrets_path, type: :string, aliases: "-s"
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
@@ -8,11 +8,11 @@ module Kubert
8
8
  new(options).rollback
9
9
  end
10
10
 
11
- attr_reader :project_name, :deployments, :options, :operation_statuses
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
- perform_with_status { `kubectl apply -f #{output_dir}/#{Kubert.configuration[:project_name]}#{KY::Manipulation::CONFIG_SUFFIX}` }
30
- perform_with_status {`kubectl apply -f #{output_dir}/#{Kubert.configuration[:project_name]}#{KY::Manipulation::SECRET_SUFFIX}` }
31
- compilation.deploy_generation.to_h.each do |deployment_file, _template_hash|
32
- perform_with_status { `kubectl apply -f #{deployment_file}` unless excluded?(deployment_file) }
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 ENV['SKIP_CONFIRMATION']
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
@@ -1,3 +1,3 @@
1
1
  module Kubert
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
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.1.2
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-03-29 00:00:00.000000000 Z
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
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.3.1
5
- before_install: gem install bundler -v 1.13.6