kubernetes-deploy 0.6.2 → 0.6.3

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: 55540c9fa5a002f87eba1c06883e0b237d194803
4
- data.tar.gz: 5d2e45261bb51d18d34f5337eb7006892885b99e
3
+ metadata.gz: 315b39149d1da2c636e590c936d537c2cf99efd1
4
+ data.tar.gz: 2a6a00d4408877852e7e50ac11648a5598fcdf57
5
5
  SHA512:
6
- metadata.gz: 0fb77ac54ebf8f56eb7c116a29ef373da76d694c4977a5c704f78cafacf9c97c2cad25e5137e9991eaf689661323ab889b205da8db96a87c02c0ce94d641f023
7
- data.tar.gz: 2e00d11e27cd3965e30592552adcf77ea7b599cb120a376d2c32b226b7bd07f4c0a1040da24534304b9910ed8c95cf4ad447937a3773d01cc11d5e1b5eac3e2a
6
+ metadata.gz: c0847ad6ae5468233e7223a1947a06e3f19552bf6e32d6aba0c2aa2470d5118c4e4a7f3d0957326efe9dcebaf4086e81c513bde9ad220761b76407379a22b795
7
+ data.tar.gz: 72d92f343209f183cbae64f4dc59413d17bd7883a8182e4a8f8352cb9629d89b7f6b114bb1356a278a4dd9d198040def3ec680735bbe8be39a4b36c921c71e55
data/.rubocop.yml CHANGED
@@ -2,4 +2,4 @@ inherit_from:
2
2
  - http://shopify.github.io/ruby-style-guide/rubocop.yml
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.3
5
+ TargetRubyVersion: 2.1
@@ -3,6 +3,7 @@ require 'json'
3
3
  require 'base64'
4
4
  require 'open3'
5
5
  require 'kubernetes-deploy/logger'
6
+ require 'kubernetes-deploy/kubectl'
6
7
 
7
8
  module KubernetesDeploy
8
9
  class EjsonSecretError < FatalDeploymentError
@@ -17,10 +18,13 @@ module KubernetesDeploy
17
18
  EJSON_SECRETS_FILE = "secrets.ejson"
18
19
  EJSON_KEYS_SECRET = "ejson-keys"
19
20
 
20
- def initialize(namespace:, template_dir:, client:)
21
+ def initialize(namespace:, context:, template_dir:)
21
22
  @namespace = namespace
23
+ @context = context
22
24
  @ejson_file = "#{template_dir}/#{EJSON_SECRETS_FILE}"
23
- @kubeclient = client
25
+
26
+ raise FatalDeploymentError, "Cannot create secrets without a namespace" if @namespace.blank?
27
+ raise FatalDeploymentError, "Cannot create secrets without a context" if @context.blank?
24
28
  end
25
29
 
26
30
  def secret_changes_required?
@@ -52,25 +56,27 @@ module KubernetesDeploy
52
56
 
53
57
  def prune_managed_secrets
54
58
  ejson_secret_names = encrypted_ejson.fetch(MANAGED_SECRET_EJSON_KEY, {}).keys
55
- live_secrets = @kubeclient.get_secrets(namespace: @namespace)
59
+ live_secrets = run_kubectl_json("get", "secrets")
56
60
 
57
61
  live_secrets.each do |secret|
58
- secret_name = secret.metadata.name
62
+ secret_name = secret["metadata"]["name"]
59
63
  next unless secret_managed?(secret)
60
64
  next if ejson_secret_names.include?(secret_name)
61
65
 
62
66
  KubernetesDeploy.logger.info("Pruning secret #{secret_name}")
63
- @kubeclient.delete_secret(secret_name, @namespace)
67
+ out, err, st = run_kubectl("delete", "secret", secret_name)
68
+ KubernetesDeploy.logger.debug(out)
69
+ raise EjsonSecretError, err unless st.success?
64
70
  end
65
71
  end
66
72
 
67
73
  def managed_secrets_exist?
68
- all_secrets = @kubeclient.get_secrets(namespace: @namespace)
74
+ all_secrets = run_kubectl_json("get", "secrets")
69
75
  all_secrets.any? { |secret| secret_managed?(secret) }
70
76
  end
71
77
 
72
78
  def secret_managed?(secret)
73
- secret.metadata.annotations.to_h.stringify_keys.key?(MANAGEMENT_ANNOTATION)
79
+ secret["metadata"].fetch("annotations", {}).key?(MANAGEMENT_ANNOTATION)
74
80
  end
75
81
 
76
82
  def encrypted_ejson
@@ -96,31 +102,47 @@ module KubernetesDeploy
96
102
  end
97
103
 
98
104
  def create_or_update_secret(secret_name, secret_type, data)
99
- metadata = {
100
- name: secret_name,
101
- labels: { "name" => secret_name },
102
- namespace: @namespace,
103
- annotations: { MANAGEMENT_ANNOTATION => "true" }
104
- }
105
- secret = Kubeclient::Secret.new(type: secret_type, stringData: data, metadata: metadata)
106
- if secret_exists?(secret)
107
- KubernetesDeploy.logger.info("Updating secret #{secret_name}")
108
- @kubeclient.update_secret(secret)
109
- else
110
- KubernetesDeploy.logger.info("Creating secret #{secret_name}")
111
- @kubeclient.create_secret(secret)
105
+ msg = secret_exists?(secret_name) ? "Updating secret #{secret_name}" : "Creating secret #{secret_name}"
106
+ KubernetesDeploy.logger.info(msg)
107
+
108
+ secret_yaml = generate_secret_yaml(secret_name, secret_type, data)
109
+ file = Tempfile.new(secret_name)
110
+ file.write(secret_yaml)
111
+ file.close
112
+
113
+ out, err, st = run_kubectl("apply", "--filename=#{file.path}")
114
+ KubernetesDeploy.logger.debug(out)
115
+ raise EjsonSecretError, err unless st.success?
116
+ ensure
117
+ file.unlink if file
118
+ end
119
+
120
+ def generate_secret_yaml(secret_name, secret_type, data)
121
+ unless data.is_a?(Hash) && data.values.all? { |v| v.is_a?(String) } # Secret data is map[string]string
122
+ raise EjsonSecretError, "Data for secret #{secret_name} was invalid. Only key-value pairs are permitted."
123
+ end
124
+ encoded_data = data.each_with_object({}) do |(key, value), encoded|
125
+ encoded[key] = Base64.encode64(value)
112
126
  end
113
- rescue KubeException => e
114
- raise unless e.error_code == 400
115
- raise EjsonSecretError, "Data for secret #{secret_name} was invalid: #{e}"
127
+
128
+ secret = {
129
+ 'kind' => 'Secret',
130
+ 'apiVersion' => 'v1',
131
+ 'type' => secret_type,
132
+ 'metadata' => {
133
+ "name" => secret_name,
134
+ "labels" => { "name" => secret_name },
135
+ "namespace" => @namespace,
136
+ "annotations" => { MANAGEMENT_ANNOTATION => "true" }
137
+ },
138
+ "data" => encoded_data
139
+ }
140
+ secret.to_yaml
116
141
  end
117
142
 
118
- def secret_exists?(secret)
119
- @kubeclient.get_secret(secret.metadata.name, @namespace)
120
- true
121
- rescue KubeException => error
122
- raise unless error.error_code == 404
123
- false
143
+ def secret_exists?(secret_name)
144
+ _out, _err, st = run_kubectl("get", "secret", secret_name)
145
+ st.success?
124
146
  end
125
147
 
126
148
  def load_ejson_from_file
@@ -152,17 +174,26 @@ module KubernetesDeploy
152
174
 
153
175
  def fetch_private_key_from_secret
154
176
  KubernetesDeploy.logger.info("Fetching ejson private key from secret #{EJSON_KEYS_SECRET}")
155
- secret = @kubeclient.get_secret(EJSON_KEYS_SECRET, @namespace)
177
+
178
+ secret = run_kubectl_json("get", "secret", EJSON_KEYS_SECRET)
156
179
  encoded_private_key = secret["data"][public_key]
157
180
  unless encoded_private_key
158
181
  raise EjsonSecretError, "Private key for #{public_key} not found in #{EJSON_KEYS_SECRET} secret"
159
182
  end
160
183
 
161
184
  Base64.decode64(encoded_private_key)
162
- rescue KubeException => error
163
- raise unless error.error_code == 404
164
- secret_missing_err = "Failed to decrypt ejson: secret #{EJSON_KEYS_SECRET} not found in namespace #{@namespace}."
165
- raise EjsonSecretError, secret_missing_err
185
+ end
186
+
187
+ def run_kubectl_json(*args)
188
+ args += ["--output=json"]
189
+ out, err, st = run_kubectl(*args)
190
+ raise EjsonSecretError, err unless st.success?
191
+ result = JSON.parse(out)
192
+ result.fetch('items', result)
193
+ end
194
+
195
+ def run_kubectl(*args)
196
+ Kubectl.run_kubectl(*args, namespace: @namespace, context: @context)
166
197
  end
167
198
  end
168
199
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module KubernetesDeploy
3
3
  class FatalDeploymentError < StandardError; end
4
+ class KubectlError < StandardError; end
4
5
 
5
6
  class NamespaceNotFoundError < FatalDeploymentError
6
7
  def initialize(name, context)
@@ -113,11 +113,7 @@ MSG
113
113
  phase_heading("Checking initial resource statuses")
114
114
  resources.each(&:sync)
115
115
 
116
- ejson = EjsonSecretProvisioner.new(
117
- namespace: @namespace,
118
- template_dir: @template_dir,
119
- client: build_v1_kubeclient(@context)
120
- )
116
+ ejson = EjsonSecretProvisioner.new(namespace: @namespace, context: @context, template_dir: @template_dir)
121
117
  if ejson.secret_changes_required?
122
118
  phase_heading("Deploying kubernetes secrets from #{EjsonSecretProvisioner::EJSON_SECRETS_FILE}")
123
119
  ejson.run
@@ -1,3 +1,3 @@
1
1
  module KubernetesDeploy
2
- VERSION = "0.6.2"
2
+ VERSION = "0.6.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kubernetes-deploy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kir Shatrov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2017-05-08 00:00:00.000000000 Z
13
+ date: 2017-05-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport