k8s-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b5e15417577d1810e7aa7471b6f6f713f3c461ce
4
+ data.tar.gz: a9f881d9bc59b774f1cb57f5c66003b4a6d5080a
5
+ SHA512:
6
+ metadata.gz: 29076b2093df4f4cc795be596f592011f46c1f19739a68143ae901382665b320828927aa15743be487bac0df30765092211e09b71f8f9c16433de27b82cb2cba
7
+ data.tar.gz: 1752d5e67ee699d0a799dac014b5997cd60b5309351213a73597428a709e62e1442a4e34fed13603a34984ef1e9596e7727c1113411e44c23c8167ca84a37cd8
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,16 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - '2.4'
5
+ - '2.5'
6
+ - ruby-head
7
+ matrix:
8
+ allow_failures:
9
+ - rvm: ruby-head
10
+ before_install: gem install bundler -v 1.16.2
11
+ deploy:
12
+ provider: rubygems
13
+ api_key:
14
+ secure: VuKEUIKjQtxQmhd/bnJTdSS/xAlOkqecAl6GBqjITHX3Gt21nWalhzP37BOItYzxuAtLTptX9UgYJ5QRW/hBD0Rkv91+3E7QOX/L4E65xECzwrzVc03pcftxL/xTi28AIgrR5ML/BNsjDJQrOH+Drj9qH8KmJOGMLMCIL+xBkf8hwUmNfSu+eBBHkHHXJ1vP+JgMSOvdNh+cqUbUARBXvGOtz3jSEHDXbvUfyxxxJ1EcepP0SYBdv+JiYzi0AdLko+ZuMY7Q7A8sP3mMjlZVNJASE40yAmla2PIUuLtogNq5GcMox1b2oYt8JnxpJGBuTCic0nst2Rzt0UTimmBNVBbZyuWIRZnbzhBmCgfmX+1b3SmXIC1iZ/BboZKDR+Pz9LeAzepOYXOQWdTK+RsiBmiUC/GyoDVM6w0M01bTPj/vaNWCIhS7elBtsnATKtGI5ySjVedv+hqOUox646Vn1VkyMa73YHTk2vwV4dZIr98+v5Rnqnu++r92S0WpJwCtKhwg3vwsbhAi9DOuP5QQvK6eL6qsbH9qF7oMXk/sAr/7jG+ALY9oTgbRVLjHddP/q4EP/vxHbF4KJgfXtqZ8ljpRi//N7MKJqQMba2aplAwt0CdntEV9CLoJ9HriPz6PrdVFMsY3qLovIQ8dTZuNdiktCJjPFBaYGwPG0pppWFY=
15
+ on:
16
+ tags: true
@@ -0,0 +1,11 @@
1
+ FROM ruby:2.4.3
2
+
3
+ WORKDIR /app
4
+
5
+ COPY Gemfile *.gemspec ./
6
+ COPY lib/k8s/client/version.rb ./lib/k8s/client/
7
+ RUN bundle install
8
+
9
+ COPY . .
10
+
11
+ ENTRYPOINT ["bundle", "exec"]
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in k8s-client.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2018 Kontena Inc.
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,29 @@
1
+ # K8s::Client
2
+
3
+ [![Build Status](https://travis-ci.com/kontena/k8s-client.svg?branch=master)](https://travis-ci.com/kontena/k8s-client)
4
+
5
+ Ruby client library for the Kubernetes (1.10) API
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'k8s-client'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install k8s-client
22
+
23
+ ## Usage
24
+
25
+ WIP: See [`bin/k8s-client`](bin/k8s-client) for example code.
26
+
27
+ ## Contributing
28
+
29
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kontena/k8s-client.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'uri'
5
+ require 'k8s-client'
6
+
7
+ Options = Struct.new(
8
+ :in_cluster_config,
9
+ :config,
10
+ :server,
11
+ :insecure_skip_tls_verify,
12
+ :prefetch_resources,
13
+ :namespace,
14
+ :all_namespaces,
15
+ :label_selector,
16
+ :pipeline_list,
17
+ :list_resources,
18
+ :list_pods,
19
+ :update_node,
20
+ :node_unschedulable,
21
+ :delete_pod,
22
+ :delete_pods,
23
+ :create_service,
24
+ :service_type,
25
+ :service_port,
26
+ :resources,
27
+ :create_resources,
28
+ :update_resources,
29
+ :delete_resources,
30
+ :stack_name,
31
+ :stack,
32
+ :prune_stack,
33
+ :delete_stack,
34
+ :api,
35
+ :list_api_resources,
36
+ )
37
+
38
+ options = Options.new()
39
+ options.create_resources = []
40
+ options.update_resources = []
41
+ options.delete_resources = []
42
+
43
+ logger = Logger.new(STDERR)
44
+
45
+ parser = OptionParser.new do |parser|
46
+ parser.on('--debug-api') do
47
+ K8s::Logging.debug!
48
+ K8s::Transport.debug!
49
+ end
50
+ parser.on('--debug') do
51
+ K8s::Logging.debug!
52
+ K8s::Transport.verbose!
53
+ end
54
+ parser.on('--verbose') do
55
+ K8s::Logging.verbose!
56
+ K8s::Transport.quiet!
57
+ end
58
+ parser.on('--quiet') do
59
+ K8s::Logging.quiet!
60
+ K8s::Transport.quiet!
61
+ end
62
+ parser.on('--in-cluster-config') do
63
+ options.in_cluster_config = true
64
+ end
65
+ parser.on('--kubeconfig=PATH') do |path|
66
+ options.config = K8s::Config.load_file(path)
67
+ end
68
+ parser.on('--server=SERVER') do |server|
69
+ options.server = URI(server)
70
+ end
71
+ parser.on('--insecure-skip-tls-verify') do
72
+ options.insecure_skip_tls_verify = true
73
+ end
74
+ parser.on('--prefetch-resources', TrueClass) do |bool|
75
+ options.prefetch_resources = bool
76
+ end
77
+ parser.on('-n', '--namespace=NAMESPACE') do |namespace|
78
+ options.namespace = namespace
79
+ end
80
+ parser.on('--all-namespaces') do
81
+ options.all_namespaces = true
82
+ end
83
+ parser.on('-l', '--label-selector=LABEL=VALUE') do |selector|
84
+ options.label_selector = selector
85
+ end
86
+ parser.on('--pipeline-list') do
87
+ options.pipeline_list = true
88
+ end
89
+ parser.on('--list-resources') do
90
+ options.list_resources = true
91
+ end
92
+ parser.on('--list-pods') do
93
+ options.list_pods = true
94
+ end
95
+ parser.on('--update-node=NODE') do |node|
96
+ options.update_node = node
97
+ end
98
+ parser.on('--node-unschedulable=BOOL', TrueClass) do |bool|
99
+ options.node_unschedulable = bool
100
+ end
101
+ parser.on('--delete-pod=POD') do |pod|
102
+ options.delete_pod = pod
103
+ end
104
+ parser.on('--delete-pods') do
105
+ options.delete_pods = true
106
+ end
107
+ parser.on('--create-service=SERVICE') do |service|
108
+ options.create_service = service
109
+ end
110
+ parser.on('--service-type=SERVICE-TYPE') do |type|
111
+ options.service_type = type
112
+ end
113
+ parser.on('--service-port=PORT', Integer) do |port|
114
+ options.service_port = port
115
+ end
116
+ parser.on('--resource-file=path') do |path|
117
+ options.resources = K8s::Resource.from_files(path)
118
+ end
119
+ parser.on('--create') do
120
+ options.create_resources = options.resources
121
+ end
122
+ parser.on('--update') do
123
+ options.update_resources = options.resources
124
+ end
125
+ parser.on('--delete') do
126
+ options.delete_resources = options.resources
127
+ end
128
+ parser.on('--stack-name=NAME') do |name|
129
+ options.stack_name = name
130
+ end
131
+ parser.on('--stack=PATH') do |path|
132
+ options.stack = K8s::Stack.load(options.stack_name || File.basename(path, ".*"), path)
133
+ end
134
+ parser.on('--prune-stack', TrueClass) do |flag|
135
+ options.prune_stack = flag
136
+ end
137
+ parser.on('--delete-stack') do
138
+ options.delete_stack = options.stack
139
+ end
140
+ parser.on('--api=API') do |api|
141
+ options.api = api
142
+ end
143
+ parser.on('--list-api-resources') do
144
+ options.list_api_resources = options.api
145
+ end
146
+ end
147
+
148
+ parser.parse!
149
+
150
+ if options.config
151
+ client = K8s::Client.config(options.config)
152
+ elsif options.in_cluster_config
153
+ client = K8s::Client.in_cluster_config
154
+ else
155
+ client = K8s.client(options.server.to_s,
156
+ ssl_verify_peer: !options.insecure_skip_tls_verify,
157
+ )
158
+ end
159
+
160
+ logger.info "Kube server version: #{client.version.gitVersion}"
161
+
162
+ if options.prefetch_resources
163
+ client.apis(prefetch_resources: true)
164
+ end
165
+
166
+ if options.all_namespaces
167
+ namespace = nil # all
168
+ elsif options.namespace
169
+ namespace = options.namespace
170
+ elsif options.config && ns = options.config.context.namespace
171
+ namespace = ns
172
+ else
173
+ namespace = nil # all
174
+ end
175
+
176
+ if options.list_api_resources
177
+ logger.info "List resource types for api=#{options.list_api_resources}..."
178
+
179
+ client.api(options.list_api_resources).resources do |api_resource|
180
+ logger.info "api=#{api_resource.api_version} resource=#{api_resource.resource} subresource=#{api_resource.subresource}"
181
+ end
182
+ end
183
+
184
+ if options.pipeline_list
185
+ objects = client.list_resources(namespace: namespace, labelSelector: options.label_selector)
186
+ objects.each do |object|
187
+ logger.info "api=#{object.apiVersion} kind=#{object.kind} namespace=#{object.metadata.namespace} name=#{object.metadata.name}"
188
+ end
189
+ elsif options.list_resources
190
+ client.apis(prefetch_resources: true).each do |api|
191
+ logger.info "api=#{api.api_version}"
192
+
193
+ resources = api.resources.select{|resource| resource.list? }
194
+
195
+ resources.each do |resource|
196
+ logger.info "api=#{api.api_version} resource=#{resource.name}"
197
+
198
+ objects = resource.list(labelSelector: options.label_selector)
199
+ objects.each do |object|
200
+ logger.info "api=#{object.apiVersion} kind=#{object.kind} namespace=#{object.metadata.namespace} name=#{object.metadata.name}"
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ if options.list_pods
207
+ client.api('v1').resource('pods', namespace: namespace).list(labelSelector: options.label_selector).each do |pod|
208
+ puts "namespace=#{pod.metadata.namespace} pod: #{pod.metadata.name} node=#{pod.spec.nodeName}"
209
+ end
210
+ end
211
+
212
+ if options.update_node
213
+ node = client.api('v1').resource('nodes').get(options.update_node)
214
+
215
+ puts "Update node=#{node.metadata.name}..."
216
+
217
+ if !options.node_unschedulable.nil?
218
+ puts "Set node=#{node.metadata.name} unschedulable: #{node.spec.unschedulable} => #{options.node_unschedulable}"
219
+
220
+ node[:spec][:unschedulable] = options.node_unschedulable
221
+ end
222
+
223
+ client.api('v1').resource('nodes').update_resource(node)
224
+ end
225
+
226
+ if options.delete_pod
227
+ logger.info "Delete pod=#{options.delete_pod} in namespace=#{namespace}"
228
+
229
+ pod = client.api('v1').resource('pods', namespace: namespace).delete(options.delete_pod)
230
+
231
+ logger.debug { pod.metadata }
232
+ end
233
+
234
+ if options.delete_pods
235
+ logger.info "Delete pods with labelSelector=#{options.label_selector} in namespace=#{namespace}"
236
+
237
+ pods = client.api('v1').resource('pods', namespace: namespace).delete_collection(labelSelector: options.label_selector)
238
+
239
+ pods.each do |pod|
240
+ logger.info "Deleted pod=#{pod.metadata.name} in namespace=#{pod.metadata.namespace} on node=#{pod.spec.nodeName}"
241
+ end
242
+ end
243
+
244
+ if options.create_service
245
+ service = K8s::Resource.new(
246
+ apiVersion: 'v1',
247
+ kind: 'Service',
248
+ metadata: {
249
+ namespace: namespace,
250
+ name: options.create_service,
251
+ },
252
+ spec: {
253
+ type: options.service_type,
254
+ ports: [
255
+ { port: options.service_port },
256
+ ],
257
+ selector: Hash[options.label_selector.split('=', 2)],
258
+ },
259
+ )
260
+
261
+ logger.info "Create service=#{service.metadata.name} in namespace=#{service.metadata.namespace}"
262
+
263
+ service = client.api('v1').resource('services').create_resource(service)
264
+
265
+ logger.debug { service }
266
+ end
267
+
268
+ for resource in options.create_resources
269
+ resource = client.create_resource(resource)
270
+
271
+ logger.info "Created #{resource.apiVersion} resource #{resource.kind} #{resource.metadata.name} in namespace #{resource.metadata.namespace}:\n#{JSON.pretty_generate(resource)}"
272
+ end
273
+
274
+ for resource in options.update_resources
275
+ resource = client.update_resource(resource)
276
+
277
+ logger.info "Updated #{resource.apiVersion} resource #{resource.kind} #{resource.metadata.name} in namespace #{resource.metadata.namespace}:\n#{JSON.pretty_generate(resource)}"
278
+ end
279
+
280
+ for resource in options.delete_resources
281
+ begin
282
+ resource = client.delete_resource(resource)
283
+
284
+ logger.info "Deleted #{resource.apiVersion} resource #{resource.kind} #{resource.metadata.name} in namespace #{resource.metadata.namespace}:\n#{JSON.pretty_generate(resource)}"
285
+ rescue K8s::Error::NotFound => exc
286
+ logger.info "Skip #{resource.apiVersion} resource #{resource.kind} #{resource.metadata.name} in namespace #{resource.metadata.namespace}: #{exc}"
287
+ end
288
+ end
289
+
290
+ if stack = options.delete_stack
291
+ logger.info "Delete stack #{stack.name}..."
292
+
293
+ stack.delete(client)
294
+
295
+ elsif options.stack
296
+ logger.info "Apply stack #{options.stack.name}..."
297
+
298
+ options.stack.apply(client,
299
+ prune: options.prune_stack,
300
+ )
301
+ end