k8s-ruby 0.10.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.rubocop.relaxed.yml +176 -0
- data/.rubocop.yml +57 -0
- data/Dockerfile +11 -0
- data/Gemfile +6 -0
- data/LICENSE +201 -0
- data/README.md +214 -0
- data/Rakefile +16 -0
- data/bin/k8s-client +337 -0
- data/docker-compose.yaml +10 -0
- data/k8s-ruby.gemspec +40 -0
- data/lib/k8s-ruby.rb +4 -0
- data/lib/k8s/api.rb +31 -0
- data/lib/k8s/api/metav1.rb +26 -0
- data/lib/k8s/api/metav1/api_group.rb +26 -0
- data/lib/k8s/api/metav1/api_resource.rb +26 -0
- data/lib/k8s/api/metav1/list.rb +20 -0
- data/lib/k8s/api/metav1/object.rb +53 -0
- data/lib/k8s/api/metav1/status.rb +34 -0
- data/lib/k8s/api/metav1/watch_event.rb +20 -0
- data/lib/k8s/api/version.rb +17 -0
- data/lib/k8s/api_client.rb +116 -0
- data/lib/k8s/client.rb +283 -0
- data/lib/k8s/config.rb +208 -0
- data/lib/k8s/error.rb +66 -0
- data/lib/k8s/logging.rb +87 -0
- data/lib/k8s/resource.rb +117 -0
- data/lib/k8s/resource_client.rb +349 -0
- data/lib/k8s/ruby/version.rb +8 -0
- data/lib/k8s/stack.rb +186 -0
- data/lib/k8s/transport.rb +385 -0
- data/lib/k8s/util.rb +139 -0
- metadata +265 -0
data/README.md
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
# K8s::Client provided by k8s-ruby
|
2
|
+
|
3
|
+
Ruby client library for the Kubernetes (1.9+) API
|
4
|
+
|
5
|
+
## Highlights
|
6
|
+
|
7
|
+
* Clean API for dynamic Kubernetes API Groups / Resources
|
8
|
+
* Fast API requests using HTTP connection keepalive
|
9
|
+
* Fast API discovery and resource listings using pipelined HTTP requests
|
10
|
+
* Typed errors with useful debugging information
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'k8s-ruby'
|
18
|
+
```
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install k8s-ruby
|
27
|
+
|
28
|
+
And then load the code using:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'k8s-ruby'
|
32
|
+
```
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
### Overview
|
37
|
+
The top-level `K8s::Client` provides access to separate `APIClient` instances for each Kubernetes API Group (`v1`, `apps/v1`, etc.), which in turns provides access to separate `ResourceClient` instances for each API resource type (`nodes`, `pods`, `deployments`, etc.).
|
38
|
+
|
39
|
+
Individual resources are returned as `K8s::Resource` instances, which are `RecursiveOpenStruct` instances providing attribute access (`resource.metadata.name`). The resource instances are returned by methods such as `client.api('v1').resource('nodes').get('foo')`, and passed as arguments for `client.api('v1').resource('nodes').create_resource(res)`. Resources can also be loaded from disk using `K8s::Resource.from_files(path)`, and passed to the top-level methods such as `client.create_resource(res)`, which lookup the correct API/Resource client from the resource `apiVersion` and `kind`.
|
40
|
+
|
41
|
+
The different `K8s::Error::API` subclasses represent different HTTP response codes, such as `K8s::Error::NotFound` or `K8s::Error::Conflict`.
|
42
|
+
|
43
|
+
### Creating a client
|
44
|
+
|
45
|
+
#### Unauthenticated client
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
client = K8s.client('https://localhost:6443', ssl_verify_peer: false)
|
49
|
+
```
|
50
|
+
|
51
|
+
The keyword options are [Excon](https://github.com/excon/excon/) options.
|
52
|
+
|
53
|
+
#### Client from kubeconfig
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
client = K8s::Client.config(
|
57
|
+
K8s::Config.load_file(
|
58
|
+
File.expand_path '~/.kube/config'
|
59
|
+
)
|
60
|
+
)
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Supported kubeconfig options
|
64
|
+
|
65
|
+
Not all kubeconfig options are supported, only the following kubeconfig options work:
|
66
|
+
|
67
|
+
* `current-context`
|
68
|
+
* `context.cluster`
|
69
|
+
* `context.user`
|
70
|
+
* `cluster.server`
|
71
|
+
* `cluster.insecure_skip_tls_verify`
|
72
|
+
* `cluster.certificate_authority`
|
73
|
+
* `cluster.certificate_authority_data`
|
74
|
+
* `user.client_certificate` + `user.client_key`
|
75
|
+
* `user.client_certificate_data` + `user.client_key_data`
|
76
|
+
* `user.token`
|
77
|
+
|
78
|
+
##### With overrides
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
client = K8s::Client.config(K8s::Config.load_file('~/.kube/config'),
|
82
|
+
server: 'http://localhost:8001',
|
83
|
+
)
|
84
|
+
```
|
85
|
+
|
86
|
+
#### In-cluster client from pod envs/secrets
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
client = K8s::Client.in_cluster_config
|
90
|
+
```
|
91
|
+
|
92
|
+
### Logging
|
93
|
+
|
94
|
+
#### Quiet
|
95
|
+
|
96
|
+
To supress any warning messages:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
K8s::Logging.quiet!
|
100
|
+
K8s::Transport.quiet!
|
101
|
+
```
|
102
|
+
|
103
|
+
The `K8s::Transport` is quiet by default, but other components may log warnings in the future.
|
104
|
+
|
105
|
+
#### Debugging
|
106
|
+
|
107
|
+
Log all API requests
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
K8s::Logging.debug!
|
111
|
+
K8s::Transport.verbose!
|
112
|
+
```
|
113
|
+
|
114
|
+
```
|
115
|
+
I, [2018-08-09T14:19:50.404739 #1] INFO -- K8s::Transport: Using config with server=https://167.99.39.233:6443
|
116
|
+
I, [2018-08-09T14:19:50.629521 #1] INFO -- K8s::Transport<https://167.99.39.233:6443>: GET /version => HTTP 200: <K8s::API::Version> in 0.224s
|
117
|
+
I, [2018-08-09T14:19:50.681367 #1] INFO -- K8s::Transport<https://167.99.39.233:6443>: GET /api/v1 => HTTP 200: <K8s::API::MetaV1::APIResourceList> in 0.046s
|
118
|
+
I, [2018-08-09T14:19:51.018740 #1] INFO -- K8s::Transport<https://167.99.39.233:6443>: GET /api/v1/pods => HTTP 200: <K8s::API::MetaV1::List> in 0.316s
|
119
|
+
```
|
120
|
+
|
121
|
+
Using `K8s::Transport.debug!` will also log request/response bodies. The `EXCON_DEBUG=true` env will log all request/response attributes, including headers.
|
122
|
+
|
123
|
+
### Prefetching API resources
|
124
|
+
|
125
|
+
Operations like mapping a resource `kind` to an API resource URL require knowledge of the API resource lists for the API group. Mapping resources for multiple API groups would require fetching the API resource lists for each API group in turn, leading to additional request latency. This can be optimized using resource prefetching:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
client.apis(prefetch_resources: true)
|
129
|
+
```
|
130
|
+
|
131
|
+
This will fetch the API resource lists for all API groups in a single pipelined request.
|
132
|
+
|
133
|
+
### Listing resources
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
client.api('v1').resource('pods', namespace: 'default').list(labelSelector: {'role' => 'test'}).each do |pod|
|
137
|
+
puts "namespace=#{pod.metadata.namespace} pod: #{pod.metadata.name} node=#{pod.spec.nodeName}"
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
### Updating resources
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
node = client.api('v1').resource('nodes').get('test-node')
|
145
|
+
|
146
|
+
node[:spec][:unschedulable] = true
|
147
|
+
|
148
|
+
client.api('v1').resource('nodes').update_resource(node)
|
149
|
+
```
|
150
|
+
|
151
|
+
### Deleting resources
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
pod = client.api('v1').resource('pods', namespace: 'default').delete('test-pod')
|
155
|
+
```
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
pods = client.api('v1').resource('pods', namespace: 'default').delete_collection(labelSelector: {'role' => 'test'})
|
159
|
+
```
|
160
|
+
|
161
|
+
### Creating resources
|
162
|
+
|
163
|
+
#### Programmatically defined resources
|
164
|
+
```ruby
|
165
|
+
service = K8s::Resource.new(
|
166
|
+
apiVersion: 'v1',
|
167
|
+
kind: 'Service',
|
168
|
+
metadata: {
|
169
|
+
namespace: 'default',
|
170
|
+
name: 'test',
|
171
|
+
},
|
172
|
+
spec: {
|
173
|
+
type: 'ClusterIP',
|
174
|
+
ports: [
|
175
|
+
{ port: 80 },
|
176
|
+
],
|
177
|
+
selector: {'app' => 'test'},
|
178
|
+
},
|
179
|
+
)
|
180
|
+
|
181
|
+
logger.info "Create service=#{service.metadata.name} in namespace=#{service.metadata.namespace}"
|
182
|
+
|
183
|
+
service = client.api('v1').resource('services').create_resource(service)
|
184
|
+
```
|
185
|
+
|
186
|
+
#### From file(s)
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
resources = K8s::Resource.from_files('./test.yaml')
|
190
|
+
|
191
|
+
for resource in resources
|
192
|
+
resource = client.create_resource(resource)
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
196
|
+
### Patching resources
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
client.api('apps/v1').resource('deployments', namespace: 'default').merge_patch('test', {
|
200
|
+
spec: { replicas: 3 },
|
201
|
+
})
|
202
|
+
```
|
203
|
+
|
204
|
+
### Watching resources
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
client.api('v1').resource('pods', namespace: 'default').watch(labelSelector: {'role' => 'test'}) do |watch_event|
|
208
|
+
puts "type=#{watch_event.type} pod=#{watch_event.resource.metadata.name}"
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
## Contributing
|
213
|
+
|
214
|
+
Bug reports and pull requests are welcome on GitHub at [rdxnet/k8s-ruby](https://github.com/rdxnet/k8s-ruby).
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
|
9
|
+
RuboCop::RakeTask.new(:rubocop).tap do |task|
|
10
|
+
task.options = %w(--fail-level A -S --format c)
|
11
|
+
if RUBY_ENGINE == 'ruby' && RbConfig::CONFIG['host_os'] !~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
12
|
+
task.options << '--parallel'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
task default: [:spec, :rubocop]
|
data/bin/k8s-client
ADDED
@@ -0,0 +1,337 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'uri'
|
6
|
+
require 'k8s-ruby'
|
7
|
+
|
8
|
+
Options = Struct.new(
|
9
|
+
:in_cluster_config,
|
10
|
+
:config,
|
11
|
+
:server,
|
12
|
+
:insecure_skip_tls_verify,
|
13
|
+
:prefetch_resources,
|
14
|
+
:list_resource_kinds,
|
15
|
+
:namespace,
|
16
|
+
:all_namespaces,
|
17
|
+
:label_selector,
|
18
|
+
:pipeline_list,
|
19
|
+
:list_resources,
|
20
|
+
:list_pods,
|
21
|
+
:update_node,
|
22
|
+
:node_unschedulable,
|
23
|
+
:delete_pod,
|
24
|
+
:delete_pods,
|
25
|
+
:create_service,
|
26
|
+
:service_type,
|
27
|
+
:service_port,
|
28
|
+
:resources,
|
29
|
+
:create_resources,
|
30
|
+
:update_resources,
|
31
|
+
:delete_resources,
|
32
|
+
:stack_name,
|
33
|
+
:stack,
|
34
|
+
:prune_stack,
|
35
|
+
:delete_stack,
|
36
|
+
:api,
|
37
|
+
:list_api_resources,
|
38
|
+
:patch_deployment,
|
39
|
+
:replicas,
|
40
|
+
:version
|
41
|
+
)
|
42
|
+
|
43
|
+
options = Options.new
|
44
|
+
options.create_resources = []
|
45
|
+
options.update_resources = []
|
46
|
+
options.delete_resources = []
|
47
|
+
|
48
|
+
logger = Logger.new(STDERR)
|
49
|
+
|
50
|
+
opt_parser = OptionParser.new do |parser|
|
51
|
+
parser.on('--debug-api') do
|
52
|
+
K8s::Logging.debug!
|
53
|
+
K8s::Transport.debug!
|
54
|
+
end
|
55
|
+
parser.on('--debug') do
|
56
|
+
K8s::Logging.debug!
|
57
|
+
K8s::Transport.verbose!
|
58
|
+
end
|
59
|
+
parser.on('--verbose') do
|
60
|
+
K8s::Logging.verbose!
|
61
|
+
K8s::Transport.quiet!
|
62
|
+
end
|
63
|
+
parser.on('--quiet') do
|
64
|
+
K8s::Logging.quiet!
|
65
|
+
K8s::Transport.quiet!
|
66
|
+
end
|
67
|
+
parser.on('--version') do
|
68
|
+
options.version = true
|
69
|
+
end
|
70
|
+
parser.on('--in-cluster-config') do
|
71
|
+
options.in_cluster_config = true
|
72
|
+
end
|
73
|
+
parser.on('--kubeconfig=PATH') do |path|
|
74
|
+
options.config = K8s::Config.load_file(path)
|
75
|
+
end
|
76
|
+
parser.on('--server=SERVER') do |server|
|
77
|
+
options.server = server
|
78
|
+
end
|
79
|
+
parser.on('--insecure-skip-tls-verify', TrueClass) do |bool|
|
80
|
+
options.insecure_skip_tls_verify = bool
|
81
|
+
end
|
82
|
+
parser.on('--prefetch-resources', TrueClass) do |bool|
|
83
|
+
options.prefetch_resources = bool
|
84
|
+
end
|
85
|
+
parser.on('--list-resource-kinds', TrueClass) do |_bool|
|
86
|
+
options.list_resource_kinds = true
|
87
|
+
end
|
88
|
+
parser.on('-n', '--namespace=NAMESPACE') do |namespace|
|
89
|
+
options.namespace = namespace
|
90
|
+
end
|
91
|
+
parser.on('--all-namespaces') do
|
92
|
+
options.all_namespaces = true
|
93
|
+
end
|
94
|
+
parser.on('-l', '--label-selector=LABEL=VALUE') do |selector|
|
95
|
+
options.label_selector = selector
|
96
|
+
end
|
97
|
+
parser.on('--pipeline-list') do
|
98
|
+
options.pipeline_list = true
|
99
|
+
end
|
100
|
+
parser.on('--list-resources') do
|
101
|
+
options.list_resources = true
|
102
|
+
end
|
103
|
+
parser.on('--list-pods') do
|
104
|
+
options.list_pods = true
|
105
|
+
end
|
106
|
+
parser.on('--update-node=NODE') do |node|
|
107
|
+
options.update_node = node
|
108
|
+
end
|
109
|
+
parser.on('--node-unschedulable=BOOL', TrueClass) do |bool|
|
110
|
+
options.node_unschedulable = bool
|
111
|
+
end
|
112
|
+
parser.on('--delete-pod=POD') do |pod|
|
113
|
+
options.delete_pod = pod
|
114
|
+
end
|
115
|
+
parser.on('--delete-pods') do
|
116
|
+
options.delete_pods = true
|
117
|
+
end
|
118
|
+
parser.on('--create-service=SERVICE') do |service|
|
119
|
+
options.create_service = service
|
120
|
+
end
|
121
|
+
parser.on('--service-type=SERVICE-TYPE') do |type|
|
122
|
+
options.service_type = type
|
123
|
+
end
|
124
|
+
parser.on('--service-port=PORT', Integer) do |port|
|
125
|
+
options.service_port = port
|
126
|
+
end
|
127
|
+
parser.on('--resource-file=path') do |path|
|
128
|
+
options.resources = K8s::Resource.from_files(path)
|
129
|
+
end
|
130
|
+
parser.on('--create') do
|
131
|
+
options.create_resources = options.resources
|
132
|
+
end
|
133
|
+
parser.on('--update') do
|
134
|
+
options.update_resources = options.resources
|
135
|
+
end
|
136
|
+
parser.on('--delete') do
|
137
|
+
options.delete_resources = options.resources
|
138
|
+
end
|
139
|
+
parser.on('--stack-name=NAME') do |name|
|
140
|
+
options.stack_name = name
|
141
|
+
end
|
142
|
+
parser.on('--stack=PATH') do |path|
|
143
|
+
options.stack = K8s::Stack.load(options.stack_name || File.basename(path, ".*"), path)
|
144
|
+
end
|
145
|
+
parser.on('--prune-stack', TrueClass) do |flag|
|
146
|
+
options.prune_stack = flag
|
147
|
+
end
|
148
|
+
parser.on('--delete-stack') do
|
149
|
+
options.delete_stack = options.stack
|
150
|
+
end
|
151
|
+
parser.on('--api=API') do |api|
|
152
|
+
options.api = api
|
153
|
+
end
|
154
|
+
parser.on('--list-api-resources') do
|
155
|
+
options.list_api_resources = options.api
|
156
|
+
end
|
157
|
+
parser.on('--patch-deployment=NAME') do |name|
|
158
|
+
options.patch_deployment = name
|
159
|
+
end
|
160
|
+
parser.on('--replicas=COUNT', Integer) do |count|
|
161
|
+
options.replicas = count
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
opt_parser.parse!
|
166
|
+
|
167
|
+
if options.config
|
168
|
+
overrides = {}
|
169
|
+
overrides[:ssl_verify_peer] = false if options.insecure_skip_tls_verify
|
170
|
+
|
171
|
+
client = K8s::Client.config(options.config,
|
172
|
+
server: options.server,
|
173
|
+
**overrides)
|
174
|
+
elsif options.in_cluster_config
|
175
|
+
client = K8s::Client.in_cluster_config
|
176
|
+
else
|
177
|
+
client = K8s.client(options.server,
|
178
|
+
ssl_verify_peer: !options.insecure_skip_tls_verify)
|
179
|
+
end
|
180
|
+
|
181
|
+
if options.version
|
182
|
+
logger.info client.version
|
183
|
+
else
|
184
|
+
logger.info "Kube server version: #{client.version.gitVersion}"
|
185
|
+
end
|
186
|
+
|
187
|
+
if options.prefetch_resources
|
188
|
+
client.apis(prefetch_resources: true)
|
189
|
+
end
|
190
|
+
|
191
|
+
if options.list_resource_kinds
|
192
|
+
client.resources.sort_by(&:kind).each do |resource_client|
|
193
|
+
next if resource_client.subresource?
|
194
|
+
|
195
|
+
puts "#{resource_client.kind} => #{resource_client.api_version} #{resource_client.name}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
namespace = if options.all_namespaces
|
200
|
+
nil # all
|
201
|
+
elsif options.namespace
|
202
|
+
options.namespace
|
203
|
+
elsif options.config && ns = options.config.context.namespace
|
204
|
+
ns
|
205
|
+
end
|
206
|
+
|
207
|
+
if options.list_api_resources
|
208
|
+
logger.info "List resource types for api=#{options.list_api_resources}..."
|
209
|
+
|
210
|
+
client.api(options.list_api_resources).resources do |api_resource|
|
211
|
+
logger.info "api=#{api_resource.api_version} resource=#{api_resource.resource} subresource=#{api_resource.subresource}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
if options.pipeline_list
|
216
|
+
objects = client.list_resources(namespace: namespace, labelSelector: options.label_selector)
|
217
|
+
objects.each do |object|
|
218
|
+
logger.info "api=#{object.apiVersion} kind=#{object.kind} namespace=#{object.metadata.namespace} name=#{object.metadata.name}"
|
219
|
+
end
|
220
|
+
elsif options.list_resources
|
221
|
+
client.apis(prefetch_resources: true).each do |api|
|
222
|
+
logger.info "api=#{api.api_version}"
|
223
|
+
|
224
|
+
resources = api.resources.select(&:list?)
|
225
|
+
|
226
|
+
resources.each do |resource|
|
227
|
+
logger.info "api=#{api.api_version} resource=#{resource.name}"
|
228
|
+
|
229
|
+
objects = resource.list(labelSelector: options.label_selector)
|
230
|
+
objects.each do |object|
|
231
|
+
logger.info "api=#{object.apiVersion} kind=#{object.kind} namespace=#{object.metadata.namespace} name=#{object.metadata.name}"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
if options.list_pods
|
238
|
+
client.api('v1').resource('pods', namespace: namespace).list(labelSelector: options.label_selector).each do |pod|
|
239
|
+
puts "namespace=#{pod.metadata.namespace} pod: #{pod.metadata.name} node=#{pod.spec.nodeName}"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
if options.update_node
|
244
|
+
node = client.api('v1').resource('nodes').get(options.update_node)
|
245
|
+
|
246
|
+
puts "Update node=#{node.metadata.name}..."
|
247
|
+
|
248
|
+
if !options.node_unschedulable.nil?
|
249
|
+
puts "Set node=#{node.metadata.name} unschedulable: #{node.spec.unschedulable} => #{options.node_unschedulable}"
|
250
|
+
|
251
|
+
node[:spec][:unschedulable] = options.node_unschedulable
|
252
|
+
end
|
253
|
+
|
254
|
+
client.api('v1').resource('nodes').update_resource(node)
|
255
|
+
end
|
256
|
+
|
257
|
+
if options.delete_pod
|
258
|
+
logger.info "Delete pod=#{options.delete_pod} in namespace=#{namespace}"
|
259
|
+
|
260
|
+
pod = client.api('v1').resource('pods', namespace: namespace).delete(options.delete_pod)
|
261
|
+
|
262
|
+
logger.debug { pod.metadata }
|
263
|
+
end
|
264
|
+
|
265
|
+
if options.delete_pods
|
266
|
+
logger.info "Delete pods with labelSelector=#{options.label_selector} in namespace=#{namespace}"
|
267
|
+
|
268
|
+
pods = client.api('v1').resource('pods', namespace: namespace).delete_collection(labelSelector: options.label_selector)
|
269
|
+
|
270
|
+
pods.each do |pod_instance|
|
271
|
+
logger.info "Deleted pod=#{pod_instance.metadata.name} in namespace=#{pod_instance.metadata.namespace} on node=#{pod_instance.spec.nodeName}"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
if options.create_service
|
276
|
+
service = K8s::Resource.new(
|
277
|
+
apiVersion: 'v1',
|
278
|
+
kind: 'Service',
|
279
|
+
metadata: {
|
280
|
+
namespace: namespace,
|
281
|
+
name: options.create_service
|
282
|
+
},
|
283
|
+
spec: {
|
284
|
+
type: options.service_type,
|
285
|
+
ports: [
|
286
|
+
{ port: options.service_port }
|
287
|
+
],
|
288
|
+
selector: Hash[options.label_selector.split('=', 2)]
|
289
|
+
}
|
290
|
+
)
|
291
|
+
|
292
|
+
logger.info "Create service=#{service.metadata.name} in namespace=#{service.metadata.namespace}"
|
293
|
+
|
294
|
+
service = client.api('v1').resource('services').create_resource(service)
|
295
|
+
|
296
|
+
logger.debug { service }
|
297
|
+
end
|
298
|
+
|
299
|
+
options.create_resources.each do |resource|
|
300
|
+
resource = client.create_resource(resource)
|
301
|
+
|
302
|
+
logger.info "Created #{resource.apiVersion} resource #{resource.kind} #{resource.metadata.name} in namespace #{resource.metadata.namespace}:\n#{JSON.pretty_generate(resource)}"
|
303
|
+
end
|
304
|
+
|
305
|
+
options.update_resources.each do |resource|
|
306
|
+
resource = client.update_resource(resource)
|
307
|
+
|
308
|
+
logger.info "Updated #{resource.apiVersion} resource #{resource.kind} #{resource.metadata.name} in namespace #{resource.metadata.namespace}:\n#{JSON.pretty_generate(resource)}"
|
309
|
+
end
|
310
|
+
|
311
|
+
options.delete_resources.each do |resource|
|
312
|
+
begin
|
313
|
+
resource = client.delete_resource(resource)
|
314
|
+
|
315
|
+
logger.info "Deleted #{resource.apiVersion} resource #{resource.kind} #{resource.metadata.name} in namespace #{resource.metadata.namespace}:\n#{JSON.pretty_generate(resource)}"
|
316
|
+
rescue K8s::Error::NotFound => e
|
317
|
+
logger.info "Skip #{resource.apiVersion} resource #{resource.kind} #{resource.metadata.name} in namespace #{resource.metadata.namespace}: #{e}"
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
if stack = options.delete_stack
|
322
|
+
logger.info "Delete stack #{stack.name}..."
|
323
|
+
|
324
|
+
stack.delete(client)
|
325
|
+
|
326
|
+
elsif options.stack
|
327
|
+
logger.info "Apply stack #{options.stack.name}..."
|
328
|
+
|
329
|
+
options.stack.apply(client, prune: options.prune_stack)
|
330
|
+
end
|
331
|
+
|
332
|
+
if name = options.patch_deployment
|
333
|
+
client.api('apps/v1').resource('deployments', namespace: namespace).merge_patch(
|
334
|
+
name,
|
335
|
+
spec: { replicas: options.replicas }
|
336
|
+
)
|
337
|
+
end
|