dapp 0.13.8 → 0.13.9
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 +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
|