k8s-client 0.1.0
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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +16 -0
- data/Dockerfile +11 -0
- data/Gemfile +6 -0
- data/LICENSE +201 -0
- data/README.md +29 -0
- data/Rakefile +6 -0
- data/bin/k8s-client +301 -0
- data/docker-compose.yaml +10 -0
- data/k8s-client.gemspec +35 -0
- data/lib/k8s-client.rb +13 -0
- data/lib/k8s/api.rb +26 -0
- data/lib/k8s/api/metav1.rb +20 -0
- data/lib/k8s/api/metav1/api_group.rb +22 -0
- data/lib/k8s/api/metav1/api_resource.rb +24 -0
- data/lib/k8s/api/metav1/list.rb +18 -0
- data/lib/k8s/api/metav1/object.rb +51 -0
- data/lib/k8s/api/metav1/status.rb +31 -0
- data/lib/k8s/api/version.rb +14 -0
- data/lib/k8s/api_client.rb +109 -0
- data/lib/k8s/client.rb +148 -0
- data/lib/k8s/client/version.rb +5 -0
- data/lib/k8s/config.rb +100 -0
- data/lib/k8s/error.rb +47 -0
- data/lib/k8s/logging.rb +58 -0
- data/lib/k8s/resource.rb +67 -0
- data/lib/k8s/resource_client.rb +259 -0
- data/lib/k8s/stack.rb +137 -0
- data/lib/k8s/transport.rb +251 -0
- metadata +186 -0
data/lib/k8s/config.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'dry-struct'
|
2
|
+
require 'dry-types'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module K8s
|
6
|
+
class ConfigStruct < Dry::Struct
|
7
|
+
# convert string keys to symbols
|
8
|
+
# normalize foo-bar to foo_bar
|
9
|
+
transform_keys do |key|
|
10
|
+
case key
|
11
|
+
when String
|
12
|
+
key.gsub('-', '_').to_sym
|
13
|
+
else
|
14
|
+
key
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @see https://godoc.org/k8s.io/client-go/tools/clientcmd/api/v1#Config
|
20
|
+
class Config < ConfigStruct
|
21
|
+
class Types
|
22
|
+
include Dry::Types.module
|
23
|
+
end
|
24
|
+
|
25
|
+
class Cluster < ConfigStruct
|
26
|
+
attribute :server, Types::String
|
27
|
+
attribute :insecure_skip_tls_verify, Types::Bool.optional.default(nil)
|
28
|
+
attribute :certificate_authority, Types::String.optional.default(nil)
|
29
|
+
attribute :certificate_authority_data, Types::String.optional.default(nil)
|
30
|
+
attribute :extensions, Types::Strict::Array.optional.default(nil)
|
31
|
+
end
|
32
|
+
class NamedCluster < ConfigStruct
|
33
|
+
attribute :name, Types::String
|
34
|
+
attribute :cluster, Cluster
|
35
|
+
end
|
36
|
+
|
37
|
+
class User < ConfigStruct
|
38
|
+
attribute :client_certificate, Types::String.optional.default(nil)
|
39
|
+
attribute :client_certificate_data, Types::String.optional.default(nil)
|
40
|
+
attribute :client_key, Types::String.optional.default(nil)
|
41
|
+
attribute :client_key_data, Types::String.optional.default(nil)
|
42
|
+
attribute :token, Types::String.optional.default(nil)
|
43
|
+
attribute :tokenFile, Types::String.optional.default(nil)
|
44
|
+
attribute :as, Types::String.optional.default(nil)
|
45
|
+
attribute :as_groups, Types::Array.of(Types::String).optional.default(nil)
|
46
|
+
attribute :as_user_extra, Types::Hash.optional.default(nil)
|
47
|
+
attribute :username, Types::String.optional.default(nil)
|
48
|
+
attribute :password, Types::String.optional.default(nil)
|
49
|
+
attribute :auth_provider, Types::Strict::Hash.optional.default(nil)
|
50
|
+
attribute :exec, Types::Strict::Hash.optional.default(nil)
|
51
|
+
attribute :extensions, Types::Strict::Array.optional.default(nil)
|
52
|
+
end
|
53
|
+
class NamedUser < ConfigStruct
|
54
|
+
attribute :name, Types::String
|
55
|
+
attribute :user, User
|
56
|
+
end
|
57
|
+
|
58
|
+
class Context < ConfigStruct
|
59
|
+
attribute :cluster, Types::Strict::String
|
60
|
+
attribute :user, Types::Strict::String
|
61
|
+
attribute :namespace, Types::Strict::String.optional.default(nil)
|
62
|
+
attribute :extensions, Types::Strict::Array.optional.default(nil)
|
63
|
+
end
|
64
|
+
class NamedContext < ConfigStruct
|
65
|
+
attribute :name, Types::String
|
66
|
+
attribute :context, Context
|
67
|
+
end
|
68
|
+
|
69
|
+
attribute :kind, Types::Strict::String.optional.default(nil)
|
70
|
+
attribute :apiVersion, Types::Strict::String.optional.default(nil)
|
71
|
+
attribute :preferences, Types::Strict::Hash.optional
|
72
|
+
attribute :clusters, Types::Strict::Array.of(NamedCluster)
|
73
|
+
attribute :users, Types::Strict::Array.of(NamedUser)
|
74
|
+
attribute :contexts, Types::Strict::Array.of(NamedContext)
|
75
|
+
attribute :current_context, Types::Strict::String
|
76
|
+
attribute :extensions, Types::Strict::Array.optional.default(nil)
|
77
|
+
|
78
|
+
# @param path [String]
|
79
|
+
# @return [K8s::Config]
|
80
|
+
def self.load_file(path)
|
81
|
+
return new(YAML.load_file(path))
|
82
|
+
end
|
83
|
+
|
84
|
+
# TODO: raise error if not found
|
85
|
+
# @return [K8s::Config::Context]
|
86
|
+
def context(name = current_context)
|
87
|
+
contexts.find{|context| context.name == name}.context
|
88
|
+
end
|
89
|
+
|
90
|
+
# @return [K8s::Config::Cluster]
|
91
|
+
def cluster(name = context.cluster)
|
92
|
+
clusters.find{|cluster| cluster.name == name}.cluster
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [K8s::Config::User]
|
96
|
+
def user(name = context.user)
|
97
|
+
users.find{|user| user.name == name}.user
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/k8s/error.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module K8s
|
4
|
+
class Error < StandardError
|
5
|
+
class API < Error
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
attr_reader :method, :path, :code, :reason, :status
|
9
|
+
|
10
|
+
# @param method [Integer] HTTP request method
|
11
|
+
# @param path [Integer] HTTP request path
|
12
|
+
# @param code [Integer] HTTP response code
|
13
|
+
# @param reason [String] HTTP response reason
|
14
|
+
# @param status [K8s::API::MetaV1::Status]
|
15
|
+
def initialize(method, path, code, reason, status = nil)
|
16
|
+
@method = method
|
17
|
+
@path = path
|
18
|
+
@code = code
|
19
|
+
@reason = reason
|
20
|
+
@status = status
|
21
|
+
|
22
|
+
if status
|
23
|
+
super("#{@method} #{@path} => HTTP #{@code} #{@reason}: #{@status.message}")
|
24
|
+
else
|
25
|
+
super("#{@method} #{@path} => HTTP #{@code} #{@reason}")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
HTTP_STATUS_ERRORS = {}
|
31
|
+
|
32
|
+
def self.define_status_error(code, name)
|
33
|
+
HTTP_STATUS_ERRORS[code] = self.const_set(name, Class.new(API))
|
34
|
+
end
|
35
|
+
|
36
|
+
define_status_error 400, :BadRequest
|
37
|
+
define_status_error 401, :Unauthorized
|
38
|
+
define_status_error 403, :Forbidden
|
39
|
+
define_status_error 404, :NotFound
|
40
|
+
define_status_error 405, :MethodNotAllowed
|
41
|
+
define_status_error 409, :Conflict # XXX: also AlreadyExists?
|
42
|
+
define_status_error 422, :Invalid
|
43
|
+
define_status_error 429, :Timeout
|
44
|
+
define_status_error 500, :InternalError
|
45
|
+
define_status_error 504, :ServerTimeout
|
46
|
+
end
|
47
|
+
end
|
data/lib/k8s/logging.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module K8s
|
4
|
+
module Logging
|
5
|
+
LOG_TARGET = STDERR
|
6
|
+
LOG_LEVEL = Logger::WARN
|
7
|
+
|
8
|
+
module ModuleMethods
|
9
|
+
# global log_level shared across all including classes
|
10
|
+
def log_level
|
11
|
+
@log_level
|
12
|
+
end
|
13
|
+
def log_level=(level)
|
14
|
+
@log_level = level
|
15
|
+
end
|
16
|
+
def debug!
|
17
|
+
self.log_level = Logger::DEBUG
|
18
|
+
end
|
19
|
+
def verbose!
|
20
|
+
self.log_level = Logger::INFO
|
21
|
+
end
|
22
|
+
def quiet!
|
23
|
+
self.log_level = Logger::ERROR
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
extend ModuleMethods # global @log_level
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
def logger(target: LOG_TARGET, level: nil)
|
31
|
+
@logger ||= Logger.new(target).tap do |logger|
|
32
|
+
logger.progname = self.name
|
33
|
+
logger.level = level || self.log_level || K8s::Logging.log_level || LOG_LEVEL
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.included(base)
|
39
|
+
base.extend(ModuleMethods) # per-class @log_level
|
40
|
+
base.extend(ClassMethods)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Use per-instance logger
|
44
|
+
def logger!(progname: self.class.name, target: LOG_TARGET, level: nil, debug: false)
|
45
|
+
@logger = Logger.new(target).tap do |logger|
|
46
|
+
level = Logger::DEBUG if debug
|
47
|
+
|
48
|
+
logger.progname = "#{self.class.name}<#{progname}>"
|
49
|
+
logger.level = level || self.class.log_level || K8s::Logging.log_level || LOG_LEVEL
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Logger]
|
54
|
+
def logger
|
55
|
+
@logger || self.class.logger
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/k8s/resource.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'deep_merge'
|
2
|
+
require 'recursive-open-struct'
|
3
|
+
|
4
|
+
module K8s
|
5
|
+
# generic untyped resource
|
6
|
+
class Resource < RecursiveOpenStruct
|
7
|
+
extend Forwardable
|
8
|
+
include Comparable
|
9
|
+
|
10
|
+
# @param data [Hash]
|
11
|
+
# @return [self]
|
12
|
+
def self.from_json(data)
|
13
|
+
return new(data)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param filename [String] file path
|
17
|
+
# @return [K8s::Resource]
|
18
|
+
def self.from_file(filename)
|
19
|
+
new(YAML.load_file(filename))
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param filename [String] file path
|
23
|
+
# @return [Array<K8s::Resource>]
|
24
|
+
def self.from_files(path)
|
25
|
+
stat = File.stat(path)
|
26
|
+
|
27
|
+
if stat.directory?
|
28
|
+
Dir.glob("#{path}/*.{yml,yaml}").map{|path| self.load_files(path) }.flatten
|
29
|
+
else
|
30
|
+
::YAML.load_stream(File.read(path), path).map{|doc| new(doc) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param attrs [Hash]
|
35
|
+
def initialize(hash, recurse_over_arrays: true, **options)
|
36
|
+
super(hash,
|
37
|
+
recurse_over_arrays: recurse_over_arrays,
|
38
|
+
**options
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [String]
|
43
|
+
def to_json(**options)
|
44
|
+
to_hash.to_json(**options)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param other [K8s::Resource]
|
48
|
+
# @return [Boolean]
|
49
|
+
def <=>(other)
|
50
|
+
to_hash <=> other.to_hash
|
51
|
+
end
|
52
|
+
|
53
|
+
# merge in fields
|
54
|
+
#
|
55
|
+
# @param attrs [Hash, K8s::Resource]
|
56
|
+
# @return [K8s::Resource]
|
57
|
+
def merge(attrs)
|
58
|
+
# deep clone of attrs
|
59
|
+
h = to_hash
|
60
|
+
|
61
|
+
# merge in-place
|
62
|
+
h.deep_merge!(attrs.to_hash, overwrite_arrays: true)
|
63
|
+
|
64
|
+
self.class.new(h)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
module K8s
|
2
|
+
class ResourceClient
|
3
|
+
module Utils
|
4
|
+
# @param selector [nil, String, Hash{String => String}]
|
5
|
+
# @return [nil, String]
|
6
|
+
def selector_query(selector)
|
7
|
+
case selector
|
8
|
+
when nil
|
9
|
+
nil
|
10
|
+
when String
|
11
|
+
selector
|
12
|
+
when Hash
|
13
|
+
selector.map{|k, v| "#{k}=#{v}"}.join ','
|
14
|
+
else
|
15
|
+
fail "Invalid selector type. #{selector.inspect}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param options [Hash]
|
20
|
+
# @return [Hash, nil]
|
21
|
+
def make_query(options)
|
22
|
+
query = options.compact
|
23
|
+
|
24
|
+
return nil if query.empty?
|
25
|
+
|
26
|
+
query
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
include Utils
|
31
|
+
extend Utils
|
32
|
+
|
33
|
+
# Pipeline list requests for multiple resource types.
|
34
|
+
#
|
35
|
+
# Returns flattened array with mixed resource kinds.
|
36
|
+
#
|
37
|
+
# @param resources [Array<K8s::ResourceClient>]
|
38
|
+
# @param transport [K8s::Transport]
|
39
|
+
# @param namespace [String, nil]
|
40
|
+
# @param labelSelector [nil, String, Hash{String => String}]
|
41
|
+
# @param fieldSelector [nil, String, Hash{String => String}]
|
42
|
+
# @return [Array<K8s::Resource>]
|
43
|
+
def self.list(resources, transport, namespace: nil, labelSelector: nil, fieldSelector: nil)
|
44
|
+
api_paths = resources.map{|resource| resource.path(namespace: namespace) }
|
45
|
+
api_lists = transport.gets(*api_paths,
|
46
|
+
response_class: K8s::API::MetaV1::List,
|
47
|
+
query: make_query(
|
48
|
+
'labelSelector' => selector_query(labelSelector),
|
49
|
+
'fieldSelector' => selector_query(fieldSelector),
|
50
|
+
),
|
51
|
+
)
|
52
|
+
|
53
|
+
resources.zip(api_lists).map {|resource, api_list| resource.process_list(api_list) }.flatten
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param transport [K8s::Transport]
|
57
|
+
# @param api_client [K8s::APIClient]
|
58
|
+
# @param api_resource [K8s::API::MetaV1::APIResource]
|
59
|
+
# @param namespace [String]
|
60
|
+
def initialize(transport, api_client, api_resource, namespace: nil, resource_class: K8s::Resource)
|
61
|
+
@transport = transport
|
62
|
+
@api_client = api_client
|
63
|
+
@api_resource = api_resource
|
64
|
+
@namespace = namespace
|
65
|
+
@resource_class = resource_class
|
66
|
+
|
67
|
+
if @api_resource.name.include? '/'
|
68
|
+
@resource, @subresource = @api_resource.name.split('/', 2)
|
69
|
+
else
|
70
|
+
@resource = @api_resource.name
|
71
|
+
@subresource = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
fail "Resource #{api_resource.name} is not namespaced" if namespace unless api_resource.namespaced
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [String]
|
78
|
+
def api_version
|
79
|
+
@api_client.api_version
|
80
|
+
end
|
81
|
+
|
82
|
+
# @return [String] resource or resource/subresource
|
83
|
+
def name
|
84
|
+
@api_resource.name
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [String, nil]
|
88
|
+
def namespace
|
89
|
+
@namespace
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [String]
|
93
|
+
def resource
|
94
|
+
@resource
|
95
|
+
end
|
96
|
+
|
97
|
+
# @return [String, nil]
|
98
|
+
def subresource
|
99
|
+
@subresource
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [String]
|
103
|
+
def kind
|
104
|
+
@api_resource.kind
|
105
|
+
end
|
106
|
+
|
107
|
+
# @return [class] K8s::Resource
|
108
|
+
def resource_class
|
109
|
+
@resource_class
|
110
|
+
end
|
111
|
+
|
112
|
+
# @return [Bool]
|
113
|
+
def namespaced?
|
114
|
+
!!@api_resource.namespaced
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [String]
|
118
|
+
def path(name = nil, subresource: @subresource, namespace: @namespace)
|
119
|
+
namespace_part = namespace ? ['namespaces', namespace] : []
|
120
|
+
|
121
|
+
if name && subresource
|
122
|
+
@api_client.path(*namespace_part, @resource, name, subresource)
|
123
|
+
elsif name
|
124
|
+
@api_client.path(*namespace_part, @resource, name)
|
125
|
+
else
|
126
|
+
@api_client.path(*namespace_part, @resource)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# @return [Bool]
|
131
|
+
def create?
|
132
|
+
@api_resource.verbs.include? 'create'
|
133
|
+
end
|
134
|
+
|
135
|
+
# @param resource [resource_class] with metadata.namespace and metadata.name set
|
136
|
+
# @return [resource_class]
|
137
|
+
def create_resource(resource)
|
138
|
+
@transport.request(
|
139
|
+
method: 'POST',
|
140
|
+
path: self.path(namespace: resource.metadata.namespace),
|
141
|
+
request_object: resource,
|
142
|
+
response_class: @resource_class,
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
# @return [Bool]
|
147
|
+
def get?
|
148
|
+
@api_resource.verbs.include? 'get'
|
149
|
+
end
|
150
|
+
|
151
|
+
# @return [resource_class]
|
152
|
+
def get(name, namespace: @namespace)
|
153
|
+
@transport.request(
|
154
|
+
method: 'GET',
|
155
|
+
path: self.path(name, namespace: namespace),
|
156
|
+
response_class: @resource_class,
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
# @param resource [resource_class]
|
161
|
+
# @return [resource_class]
|
162
|
+
def get_resource(resource)
|
163
|
+
@transport.request(
|
164
|
+
method: 'GET',
|
165
|
+
path: self.path(resource.metadata.name, namespace: resource.metadata.namespace),
|
166
|
+
response_class: @resource_class,
|
167
|
+
)
|
168
|
+
end
|
169
|
+
|
170
|
+
# @return [Bool]
|
171
|
+
def list?
|
172
|
+
@api_resource.verbs.include? 'list'
|
173
|
+
end
|
174
|
+
|
175
|
+
# @param list [K8s::API::MetaV1::List]
|
176
|
+
# @return [Array<resource_class>]
|
177
|
+
def process_list(list)
|
178
|
+
list.items.map {|item|
|
179
|
+
# list items omit kind/apiVersion
|
180
|
+
@resource_class.new(item.merge('apiVersion' => list.apiVersion, 'kind' => @api_resource.kind))
|
181
|
+
}
|
182
|
+
end
|
183
|
+
|
184
|
+
# @param labelSelector [nil, String, Hash{String => String}]
|
185
|
+
# @param fieldSelector [nil, String, Hash{String => String}]
|
186
|
+
# @return [Array<resource_class>]
|
187
|
+
def list(labelSelector: nil, fieldSelector: nil, namespace: @namespace)
|
188
|
+
list = @transport.request(
|
189
|
+
method: 'GET',
|
190
|
+
path: self.path(namespace: namespace),
|
191
|
+
response_class: K8s::API::MetaV1::List,
|
192
|
+
query: make_query(
|
193
|
+
'labelSelector' => selector_query(labelSelector),
|
194
|
+
'fieldSelector' => selector_query(fieldSelector),
|
195
|
+
),
|
196
|
+
)
|
197
|
+
process_list(list)
|
198
|
+
end
|
199
|
+
|
200
|
+
# @return [Bool]
|
201
|
+
def update?
|
202
|
+
@api_resource.verbs.include? 'update'
|
203
|
+
end
|
204
|
+
|
205
|
+
# @param resource [resource_class] with metadata.resourceVersion set
|
206
|
+
# @return [resource_class]
|
207
|
+
def update_resource(resource)
|
208
|
+
@transport.request(
|
209
|
+
method: 'PUT',
|
210
|
+
path: self.path(resource.metadata.name, namespace: resource.metadata.namespace),
|
211
|
+
request_object: resource,
|
212
|
+
response_class: @resource_class,
|
213
|
+
)
|
214
|
+
end
|
215
|
+
|
216
|
+
# @return [Bool]
|
217
|
+
def delete?
|
218
|
+
@api_resource.verbs.include? 'delete'
|
219
|
+
end
|
220
|
+
|
221
|
+
# @param name [String]
|
222
|
+
# @param namespace [String]
|
223
|
+
# @return [K8s::API::MetaV1::Status]
|
224
|
+
def delete(name, namespace: @namespace, propagationPolicy: nil)
|
225
|
+
@transport.request(
|
226
|
+
method: 'DELETE',
|
227
|
+
path: self.path(name, namespace: namespace),
|
228
|
+
query: make_query(
|
229
|
+
'propagationPolicy' => propagationPolicy,
|
230
|
+
),
|
231
|
+
response_class: @resource_class, # XXX: documented as returning Status
|
232
|
+
)
|
233
|
+
end
|
234
|
+
|
235
|
+
# @param namespace [String]
|
236
|
+
# @param labelSelector [nil, String, Hash{String => String}]
|
237
|
+
# @param fieldSelector [nil, String, Hash{String => String}]
|
238
|
+
# @return [K8s::API::MetaV1::Status]
|
239
|
+
def delete_collection(namespace: @namespace, labelSelector: nil, fieldSelector: nil, propagationPolicy: nil)
|
240
|
+
list = @transport.request(
|
241
|
+
method: 'DELETE',
|
242
|
+
path: self.path(namespace: namespace),
|
243
|
+
query: make_query(
|
244
|
+
'labelSelector' => selector_query(labelSelector),
|
245
|
+
'fieldSelector' => selector_query(fieldSelector),
|
246
|
+
'propagationPolicy' => propagationPolicy,
|
247
|
+
),
|
248
|
+
response_class: K8s::API::MetaV1::List, # XXX: documented as returning Status
|
249
|
+
)
|
250
|
+
process_list(list)
|
251
|
+
end
|
252
|
+
|
253
|
+
# @param resource [resource_class] with metadata
|
254
|
+
# @return [K8s::API::MetaV1::Status]
|
255
|
+
def delete_resource(resource, **options)
|
256
|
+
delete(resource.metadata.name, namespace: resource.metadata.namespace, **options)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|