dapp 0.13.8 → 0.13.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/en/net_status.yml +4 -0
- data/lib/dapp.rb +16 -3
- data/lib/dapp/cli/command/update.rb +2 -0
- data/lib/dapp/dapp/dapp_config.rb +1 -1
- data/lib/dapp/deployment/kubernetes.rb +1 -1
- data/lib/dapp/dimg/build/stage/base.rb +1 -1
- data/lib/dapp/dimg/config/directive/docker/artifact.rb +5 -0
- data/lib/dapp/helper/yaml.rb +23 -0
- data/lib/dapp/kube/cli/command/kube.rb +3 -1
- data/lib/dapp/kube/cli/command/kube/chart_create.rb +19 -0
- data/lib/dapp/kube/cli/command/kube/secret_edit.rb +24 -0
- data/lib/dapp/kube/dapp/command/chart_create.rb +104 -0
- data/lib/dapp/kube/dapp/command/common.rb +21 -2
- data/lib/dapp/kube/dapp/command/deploy.rb +50 -25
- data/lib/dapp/kube/dapp/command/secret_edit.rb +45 -0
- data/lib/dapp/kube/dapp/command/secret_extract.rb +1 -2
- data/lib/dapp/kube/dapp/command/secret_generate.rb +1 -2
- data/lib/dapp/kube/dapp/command/secret_regenerate.rb +2 -3
- data/lib/dapp/kube/dapp/dapp.rb +4 -0
- data/lib/dapp/kube/kubernetes.rb +6 -0
- data/lib/dapp/kube/kubernetes/client.rb +255 -0
- data/lib/dapp/kube/{client → kubernetes/client}/error.rb +8 -4
- data/lib/dapp/kube/kubernetes/client/resource/base.rb +21 -0
- data/lib/dapp/kube/kubernetes/client/resource/job.rb +27 -0
- data/lib/dapp/kube/kubernetes/client/resource/pod.rb +49 -0
- data/lib/dapp/kube/kubernetes/manager/base.rb +15 -0
- data/lib/dapp/kube/kubernetes/manager/container.rb +88 -0
- data/lib/dapp/kube/kubernetes/manager/job.rb +65 -0
- data/lib/dapp/kube/kubernetes/manager/pod.rb +35 -0
- data/lib/dapp/version.rb +1 -1
- metadata +17 -4
- data/lib/dapp/kube/client.rb +0 -241
@@ -0,0 +1,45 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Kube
|
3
|
+
module Dapp
|
4
|
+
module Command
|
5
|
+
module SecretEdit
|
6
|
+
def kube_secret_edit(file_path)
|
7
|
+
secret_key_should_exist!
|
8
|
+
|
9
|
+
with_kube_tmp_chart_dir do
|
10
|
+
decoded_data = begin
|
11
|
+
raise Error::Command, code: :file_not_exist, data: { path: File.expand_path(file_path) } unless File.exist?(file_path)
|
12
|
+
|
13
|
+
if options[:values]
|
14
|
+
kube_extract_secret_values(file_path)
|
15
|
+
else
|
16
|
+
kube_extract_secret_file(file_path)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
tmp_file_path = kube_tmp_chart_path(file_path)
|
21
|
+
tmp_file_path.binwrite(decoded_data)
|
22
|
+
system(kube_secret_editor, tmp_file_path.to_s)
|
23
|
+
|
24
|
+
encoded_data = begin
|
25
|
+
if options[:values]
|
26
|
+
kube_secret_values(tmp_file_path)
|
27
|
+
else
|
28
|
+
kube_secret_file(tmp_file_path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
IO.binwrite(file_path, "#{encoded_data}\n")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def kube_secret_editor
|
37
|
+
return ENV['EDITOR'] unless ENV['EDITOR'].nil?
|
38
|
+
%w(vim vi nano).each { |editor| return editor unless shellout("which #{editor}").exitstatus.nonzero? }
|
39
|
+
raise Error::Command, code: :editor_not_found
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -46,8 +46,7 @@ module Dapp
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def kube_extract_secret_values(file_path)
|
49
|
-
|
50
|
-
kube_helm_decode_json(secret, json).to_yaml
|
49
|
+
kube_helm_decode_json(secret, yaml_load_file(file_path)).to_yaml
|
51
50
|
end
|
52
51
|
|
53
52
|
def kube_extract_secret_file(file_path)
|
@@ -46,8 +46,7 @@ module Dapp
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def kube_secret_values(file_path)
|
49
|
-
|
50
|
-
kube_helm_encode_json(secret, json).to_yaml
|
49
|
+
kube_helm_encode_json(secret, yaml_load_file(file_path)).to_yaml
|
51
50
|
end
|
52
51
|
|
53
52
|
def kube_secret_file(file_path)
|
@@ -12,7 +12,7 @@ module Dapp
|
|
12
12
|
regenerated_data[file_path] = kube_regenerate_secret_values(file_path)
|
13
13
|
end
|
14
14
|
|
15
|
-
Dir.glob(
|
15
|
+
Dir.glob(kube_chart_secret_path('**/*'), File::FNM_DOTMATCH).each do |file_path|
|
16
16
|
next if File.directory?(file_path)
|
17
17
|
regenerated_data[file_path] = kube_regenerate_secret_file(file_path)
|
18
18
|
end
|
@@ -25,8 +25,7 @@ module Dapp
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def kube_regenerate_secret_values(file_path)
|
28
|
-
|
29
|
-
kube_helm_encode_json(secret, kube_helm_decode_json(old_secret, json)).to_yaml
|
28
|
+
kube_helm_encode_json(secret, kube_helm_decode_json(old_secret, yaml_load_file(file_path))).to_yaml
|
30
29
|
end
|
31
30
|
|
32
31
|
def old_secret
|
data/lib/dapp/kube/dapp/dapp.rb
CHANGED
@@ -2,13 +2,17 @@ module Dapp
|
|
2
2
|
module Kube
|
3
3
|
module Dapp
|
4
4
|
module Dapp
|
5
|
+
include Helper::YAML
|
6
|
+
|
5
7
|
include Command::Deploy
|
6
8
|
include Command::Dismiss
|
7
9
|
include Command::SecretKeyGenerate
|
8
10
|
include Command::SecretGenerate
|
9
11
|
include Command::SecretExtract
|
10
12
|
include Command::SecretRegenerate
|
13
|
+
include Command::SecretEdit
|
11
14
|
include Command::MinikubeSetup
|
15
|
+
include Command::ChartCreate
|
12
16
|
include Command::Common
|
13
17
|
end
|
14
18
|
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Kube
|
3
|
+
module Kubernetes
|
4
|
+
class Client
|
5
|
+
include Helper::YAML
|
6
|
+
|
7
|
+
def initialize(namespace: nil)
|
8
|
+
@namespace = namespace
|
9
|
+
@query_parameters = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def namespace
|
13
|
+
@namespace || kube_context_config['context']['namespace'] || 'default'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Чтобы не перегружать методы явной передачей namespace.
|
17
|
+
# Данный метод может пригодиться только в ситуации, когда надо указать другой namespace,
|
18
|
+
# в большинстве случаев используется namespace из конструктора.
|
19
|
+
def with_namespace(namespace, &blk)
|
20
|
+
old_namespace = @namespace
|
21
|
+
begin
|
22
|
+
@namespace = namespace
|
23
|
+
return yield
|
24
|
+
ensure
|
25
|
+
@namespace = old_namespace
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def with_query(query, &blk)
|
30
|
+
old_query = @query_parameters
|
31
|
+
begin
|
32
|
+
@query_parameters = query
|
33
|
+
return yield
|
34
|
+
ensure
|
35
|
+
@query_parameters = old_query
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# NOTICE: Название метода аналогично kind'у выдаваемого результата.
|
40
|
+
# NOTICE: В данном случае в результате kind=DeploymentList.
|
41
|
+
# NOTICE: Методы создания/обновления/удаления сущностей kubernetes заканчиваются на '!'. Например, create_deployment!.
|
42
|
+
|
43
|
+
{
|
44
|
+
'/api/v1' => [:service, :replicationcontroller, :pod],
|
45
|
+
'/apis/extensions/v1beta1' => [:deployment, :replicaset],
|
46
|
+
'/apis/batch/v1' => [:job]
|
47
|
+
}.each do |api, objects|
|
48
|
+
objects.each do |object|
|
49
|
+
define_method :"#{object}_list" do |**query_parameters|
|
50
|
+
request!(:get, "#{api}/namespaces/#{namespace}/#{object}s", **query_parameters)
|
51
|
+
end
|
52
|
+
|
53
|
+
define_method object do |name, **query_parameters|
|
54
|
+
request!(:get, "#{api}/namespaces/#{namespace}/#{object}s/#{name}", **query_parameters)
|
55
|
+
end
|
56
|
+
|
57
|
+
define_method "#{object}_status" do |name, **query_parameters|
|
58
|
+
request!(:get, "#{api}/namespaces/#{namespace}/#{object}s/#{name}/status", **query_parameters)
|
59
|
+
end
|
60
|
+
|
61
|
+
define_method :"create_#{object}!" do |spec, **query_parameters|
|
62
|
+
request!(:post, "#{api}/namespaces/#{namespace}/#{object}s", body: spec, **query_parameters)
|
63
|
+
end
|
64
|
+
|
65
|
+
define_method :"replace_#{object}!" do |name, spec, **query_parameters|
|
66
|
+
request!(:put, "#{api}/namespaces/#{namespace}/#{object}s/#{name}", body: spec, **query_parameters)
|
67
|
+
end
|
68
|
+
|
69
|
+
define_method :"delete_#{object}!" do |name, **query_parameters|
|
70
|
+
request!(:delete, "#{api}/namespaces/#{namespace}/#{object}s/#{name}", **query_parameters)
|
71
|
+
end
|
72
|
+
|
73
|
+
define_method :"delete_#{object}s!" do |**query_parameters|
|
74
|
+
request!(:delete, "#{api}/namespaces/#{namespace}/#{object}s", **query_parameters)
|
75
|
+
end
|
76
|
+
|
77
|
+
define_method :"#{object}?" do |name, **query_parameters|
|
78
|
+
public_send(:"#{object}_list", **query_parameters)['items'].map { |item| item['metadata']['name'] }.include?(name)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def namespace_list(**query_parameters)
|
84
|
+
request!(:get, '/api/v1/namespaces', **query_parameters)
|
85
|
+
end
|
86
|
+
|
87
|
+
def namespace?(name, **query_parameters)
|
88
|
+
namespace_list(**query_parameters)['items'].map { |item| item['metadata']['name'] }.include?(name)
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_namespace!(name, **query_parameters)
|
92
|
+
request!(:post, '/api/v1/namespaces', body: { metadata: { name: name } }, **query_parameters)
|
93
|
+
end
|
94
|
+
|
95
|
+
def delete_namespace!(name, **query_parameters)
|
96
|
+
request!(:delete, "/api/v1/namespaces/#{name}", **query_parameters)
|
97
|
+
end
|
98
|
+
|
99
|
+
def pod_log(name, follow: false, **query_parameters, &blk)
|
100
|
+
excon_parameters = follow ? { response_block: blk } : {}
|
101
|
+
request!(:get,
|
102
|
+
"/api/v1/namespaces/#{namespace}/pods/#{name}/log",
|
103
|
+
excon_parameters: excon_parameters,
|
104
|
+
response_body_parameters: {json: false},
|
105
|
+
**{ follow: follow }.merge(query_parameters))
|
106
|
+
rescue Excon::Error::Timeout
|
107
|
+
raise Error::Timeout
|
108
|
+
end
|
109
|
+
|
110
|
+
def event_list(**query_parameters)
|
111
|
+
request!(:get, "/api/v1/namespaces/#{namespace}/events", **query_parameters)
|
112
|
+
end
|
113
|
+
|
114
|
+
protected
|
115
|
+
|
116
|
+
# query_parameters — соответствует 'Query Parameters' в документации kubernetes
|
117
|
+
# excon_parameters — соответствует опциям Excon
|
118
|
+
# body — hash для http-body, соответствует 'Body Parameters' в документации kubernetes, опционален
|
119
|
+
def request!(method, path, body: nil, excon_parameters: {}, response_body_parameters: {}, **query_parameters)
|
120
|
+
with_connection(excon_parameters: excon_parameters) do |conn|
|
121
|
+
request_parameters = {method: method, path: path, query: @query_parameters.merge(query_parameters)}
|
122
|
+
request_parameters[:body] = JSON.dump(body) if body
|
123
|
+
load_body! conn.request(request_parameters), request_parameters, **response_body_parameters
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def load_body!(response, request_parameters, json: true)
|
128
|
+
response_ok = response.status.to_s.start_with? '2'
|
129
|
+
|
130
|
+
if response_ok
|
131
|
+
if json
|
132
|
+
JSON.parse(response.body)
|
133
|
+
else
|
134
|
+
response.body
|
135
|
+
end
|
136
|
+
else
|
137
|
+
err_data = {}
|
138
|
+
err_data[:response_http_status] = response.status
|
139
|
+
if response_body = (JSON.parse(response.body) rescue nil)
|
140
|
+
err_data[:response_body] = response_body
|
141
|
+
else
|
142
|
+
err_data[:response_raw_body] = response.body
|
143
|
+
end
|
144
|
+
err_data[:request_parameters] = request_parameters
|
145
|
+
|
146
|
+
if response.status.to_s.start_with? '5'
|
147
|
+
raise Error::Base, code: :server_error, data: err_data
|
148
|
+
elsif response.status.to_s == '404'
|
149
|
+
case err_data.fetch(:response_body, {}).fetch('details', {})['kind']
|
150
|
+
when 'pods'
|
151
|
+
raise Error::Pod::NotFound, data: err_data
|
152
|
+
else
|
153
|
+
raise Error::NotFound, data: err_data
|
154
|
+
end
|
155
|
+
else not response.status.to_s.start_with? '2'
|
156
|
+
raise Error::Base, code: :bad_request, data: err_data
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def with_connection(excon_parameters: {}, &blk)
|
162
|
+
old_ssl_ca_file = Excon.defaults[:ssl_ca_file]
|
163
|
+
old_ssl_cert_store = Excon.defaults[:ssl_cert_store]
|
164
|
+
old_middlewares = Excon.defaults[:middlewares].dup
|
165
|
+
|
166
|
+
begin
|
167
|
+
ssl_cert_store = OpenSSL::X509::Store.new
|
168
|
+
if ssl_ca_file = kube_config.fetch('clusters', [{}]).first.fetch('cluster', {}).fetch('certificate-authority', nil)
|
169
|
+
ssl_cert_store.add_file ssl_ca_file
|
170
|
+
elsif ssl_ca_data = kube_config.fetch('clusters', [{}]).first.fetch('cluster', {}).fetch('certificate-authority-data', nil)
|
171
|
+
ssl_cert_store.add_cert OpenSSL::X509::Certificate.new(Base64.decode64(ssl_ca_data))
|
172
|
+
end
|
173
|
+
|
174
|
+
Excon.defaults[:ssl_ca_file] = nil
|
175
|
+
Excon.defaults[:ssl_cert_store] = ssl_cert_store
|
176
|
+
Excon.defaults[:middlewares] << Excon::Middleware::RedirectFollower
|
177
|
+
|
178
|
+
connection = begin
|
179
|
+
Excon.new(kube_cluster_config['cluster']['server'], **kube_server_options(excon_parameters)).tap(&:get)
|
180
|
+
rescue Excon::Error::Socket => err
|
181
|
+
raise Error::ConnectionRefused,
|
182
|
+
code: :kube_server_connection_refused,
|
183
|
+
data: { kube_cluster_config: kube_cluster_config, kube_user_config: kube_user_config, error: err.message }
|
184
|
+
end
|
185
|
+
|
186
|
+
return yield connection
|
187
|
+
ensure
|
188
|
+
Excon.defaults[:ssl_ca_file] = old_ssl_ca_file
|
189
|
+
Excon.defaults[:ssl_cert_store] = old_ssl_cert_store
|
190
|
+
Excon.defaults[:middlewares] = old_middlewares
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def kube_server_options(excon_parameters = {})
|
195
|
+
{}.tap do |opts|
|
196
|
+
client_cert = kube_config.fetch('users', [{}]).first.fetch('user', {}).fetch('client-certificate', nil)
|
197
|
+
opts[:client_cert] = client_cert if client_cert
|
198
|
+
|
199
|
+
client_cert_data = kube_config.fetch('users', [{}]).first.fetch('user', {}).fetch('client-certificate-data', nil)
|
200
|
+
opts[:client_cert_data] = Base64.decode64(client_cert_data) if client_cert_data
|
201
|
+
|
202
|
+
client_key = kube_config.fetch('users', [{}]).first.fetch('user', {}).fetch('client-key', nil)
|
203
|
+
opts[:client_key] = client_key if client_key
|
204
|
+
|
205
|
+
client_key_data = kube_config.fetch('users', [{}]).first.fetch('user', {}).fetch('client-key-data', nil)
|
206
|
+
opts[:client_key_data] = Base64.decode64(client_key_data) if client_key_data
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def kube_user_config
|
211
|
+
@kube_user_config ||= begin
|
212
|
+
kube_config.fetch('users', []).find {|user| user['name'] == kube_context_config['context']['user']} || begin
|
213
|
+
raise Error::BadConfig, code: :kube_user_not_found, data: {context: kube_context_config}
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def kube_cluster_config
|
219
|
+
@kube_cluster_config ||= begin
|
220
|
+
kube_config.fetch('clusters', []).find {|cluster| cluster['name'] == kube_context_config['context']['cluster']} || begin
|
221
|
+
raise Error::BadConfig, code: :kube_cluster_not_found, data: {context: kube_context_config}
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def kube_context_config
|
227
|
+
@kube_context_config ||= begin
|
228
|
+
kube_config.fetch('contexts', []).find {|context| context['name'] == kube_context_name} || begin
|
229
|
+
raise Error::BadConfig, code: :kube_context_not_found, data: {context_name: kube_context_name}
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def kube_context_name
|
235
|
+
@kube_context_name ||= kube_config['current-context'] || begin
|
236
|
+
if context = kube_config.fetch('contexts', []).first
|
237
|
+
warn "[WARN] .kube/config current-context is not set, using context '#{context['name']}'"
|
238
|
+
context['name']
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def kube_config
|
244
|
+
@kube_config ||= begin
|
245
|
+
if File.exist?((kube_config_path = File.join(ENV['HOME'], '.kube/config')))
|
246
|
+
yaml_load_file(kube_config_path)
|
247
|
+
else
|
248
|
+
raise Error::Base, code: :kube_config_not_found, data: { path: kube_config_path }
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end # Client
|
253
|
+
end # Kubernetes
|
254
|
+
end # Kube
|
255
|
+
end # Dapp
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Dapp
|
2
2
|
module Kube
|
3
|
-
module Client::Error
|
3
|
+
module Kubernetes::Client::Error
|
4
4
|
class Base < ::Dapp::Kube::Error::Kubernetes
|
5
5
|
def initialize(**net_status)
|
6
6
|
super(**net_status, context: :kubernetes)
|
@@ -16,6 +16,10 @@ module Dapp
|
|
16
16
|
class Timeout < Base; end
|
17
17
|
class ConnectionRefused < Base; end
|
18
18
|
class BadConfig < Base; end
|
19
|
-
|
20
|
-
|
21
|
-
end
|
19
|
+
|
20
|
+
module Pod
|
21
|
+
class NotFound < Kubernetes::Client::Error::NotFound ; end
|
22
|
+
end # Pod
|
23
|
+
end # Kubernetes::Client::Error
|
24
|
+
end # Kube
|
25
|
+
end # Dapp
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Kube
|
3
|
+
module Kubernetes::Client::Resource
|
4
|
+
class Base
|
5
|
+
attr_reader :spec
|
6
|
+
|
7
|
+
def initialize(spec)
|
8
|
+
@spec = spec
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
spec.fetch('metadata', {})['name']
|
13
|
+
end
|
14
|
+
|
15
|
+
def annotations
|
16
|
+
spec.fetch('metadata', {}).fetch('annotations', {})
|
17
|
+
end
|
18
|
+
end # Base
|
19
|
+
end # Kubernetes::Client::Resource
|
20
|
+
end # Kube
|
21
|
+
end # Dapp
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Kube
|
3
|
+
module Kubernetes::Client::Resource
|
4
|
+
class Job < Base
|
5
|
+
def uid
|
6
|
+
spec.fetch('metadata', {})['uid']
|
7
|
+
end
|
8
|
+
|
9
|
+
def terminated?
|
10
|
+
failed? || succeeded?
|
11
|
+
end
|
12
|
+
|
13
|
+
def failed?
|
14
|
+
!!spec.fetch('status', {}).fetch('conditions', []).find do |cond|
|
15
|
+
cond['type'] == 'Failed'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def succeeded?
|
20
|
+
!!spec.fetch('status', {}).fetch('conditions', []).find do |cond|
|
21
|
+
cond['type'] == 'Complete'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end # Job
|
25
|
+
end # Kubernetes::Client::Resource
|
26
|
+
end # Kube
|
27
|
+
end # Dapp
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Dapp
|
2
|
+
module Kube
|
3
|
+
module Kubernetes::Client::Resource
|
4
|
+
class Pod < Base
|
5
|
+
def container_id(container_name)
|
6
|
+
container_status = spec.fetch('status', {})
|
7
|
+
.fetch('containerStatuses')
|
8
|
+
.find {|cs| cs['name'] == container_name}
|
9
|
+
|
10
|
+
if container_status
|
11
|
+
container_status['containerID']
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def container_state(container_name)
|
18
|
+
container_status = spec
|
19
|
+
.fetch('status', {})
|
20
|
+
.fetch('containerStatuses', [])
|
21
|
+
.find {|cs| cs['name'] == container_name}
|
22
|
+
|
23
|
+
if container_status
|
24
|
+
container_state, container_state_data = container_status.fetch('state', {}).first
|
25
|
+
[container_state, container_state_data]
|
26
|
+
else
|
27
|
+
[nil, {}]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def phase
|
32
|
+
spec.fetch('status', {}).fetch('phase', nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
def containers_names
|
36
|
+
spec.fetch('spec', {})
|
37
|
+
.fetch('containers', [])
|
38
|
+
.map {|container_spec| container_spec['name']}
|
39
|
+
end
|
40
|
+
|
41
|
+
def restart_policy
|
42
|
+
spec
|
43
|
+
.fetch('spec', {})
|
44
|
+
.fetch('restartPolicy', nil)
|
45
|
+
end
|
46
|
+
end # Pod
|
47
|
+
end # Kubernetes::Client::Resource
|
48
|
+
end # Kube
|
49
|
+
end # Dapp
|