Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add !-variants of request methods and improve yardocs #119

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions k8s-client.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "rspec", "~> 3.7"
spec.add_development_dependency "webmock", "~> 3.4.2"
spec.add_development_dependency "rubocop", "~> 0.59"
spec.add_development_dependency "yard", "~> 0.9"
end
3 changes: 3 additions & 0 deletions lib/k8s/api/metav1.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ module API
module MetaV1
# @see https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#TypeMeta
class Resource < Struct
# @!macro [attach] attribute
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes all of the api struct docs get documentation for their attributes.

Before:

image

After:

image

# @!attribute [r] $1

# XXX: making these optional seems dangerous, but some APIs (GET /api/v1) are missing these
attribute :kind, Types::Strict::String.optional.default(nil)
attribute :apiVersion, Types::Strict::String.optional.default(nil)
Expand Down
8 changes: 6 additions & 2 deletions lib/k8s/api_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module K8s
#
# Offers access to {ResourceClient} instances for the APIResource types defined in this apigroup/version
class APIClient
extend K8s::Util::ExceptionlessBangMethod

# @param api_version [String] either core version (v1) or apigroup/apiversion (apps/v1)
# @return [String]
def self.path(api_version)
Expand Down Expand Up @@ -36,7 +38,6 @@ def api_resources?
!!@api_resources
end

# @param api_resources [Array<K8s::API::MetaV1::APIResource>]
attr_writer :api_resources

# Force-update APIResources
Expand Down Expand Up @@ -64,6 +65,7 @@ def find_api_resource(resource_name)

found_resource
end
exceptionless_bang_method :find_api_resource

# @param resource_name [String]
# @param namespace [String, nil]
Expand All @@ -72,6 +74,7 @@ def find_api_resource(resource_name)
def resource(resource_name, namespace: nil)
ResourceClient.new(@transport, self, find_api_resource(resource_name), namespace: namespace)
end
exceptionless_bang_method :resource

# @param resource [K8s::Resource]
# @param namespace [String, nil] default if resource is missing namespace
Expand All @@ -88,6 +91,7 @@ def client_for_resource(resource, namespace: nil)

ResourceClient.new(@transport, self, found_resource, namespace: resource.metadata.namespace || namespace)
end
exceptionless_bang_method :client_for_resource

# TODO: skip non-namespaced resources if namespace is given, or ignore namespace?
#
Expand All @@ -105,7 +109,7 @@ def resources(namespace: nil)
# Returns flattened array with mixed resource kinds.
#
# @param resources [Array<K8s::ResourceClient>] default is all listable resources for api
# @param options @see [K8s::ResourceClient#list]
# @param (see K8s::ResourceClient#list)
# @return [Array<K8s::Resource>]
def list_resources(resources = nil, **options)
resources ||= self.resources.select(&:list?)
Expand Down
26 changes: 17 additions & 9 deletions lib/k8s/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

module K8s
# @param server [String] http/s URL
# @param options [Hash] @see Transport.new
# @param options [Hash]
# @param (see Transport#initialize)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This syntax copies the params from the referenced method to this one. The link didn't work anyway.

# @return [K8s::Client]
def self.client(server, **options)
Client.new(Transport.new(server, **options))
Expand All @@ -31,9 +32,11 @@ def self.client(server, **options)
# Uses a {Transport} instance to talk to the kube API.
# Offers access to {APIClient} and {ResourceClient} instances.
class Client
extend K8s::Util::ExceptionlessBangMethod

# @param config [Phraos::Kube::Config]
# @param namespace [String] @see #initialize
# @param options [Hash] @see Transport.config
# @param namespace [String] default namespace for all operations
# @param (see K8s::Transport.config)
# @return [K8s::Client]
def self.config(config, namespace: nil, **options)
new(
Expand All @@ -43,10 +46,9 @@ def self.config(config, namespace: nil, **options)
end

# An K8s::Client instance from in-cluster config within a kube pod, using the kubernetes service envs and serviceaccount secrets
# @see K8s::Transport#in_cluster_config
#
# @param namespace [String] default namespace for all operations
# @param options [Hash] options passed to transport, @see Transport#in_cluster_config
# @param (see K8s::Transport.in_cluster_config)
# @return [K8s::Client]
# @raise [K8s::Error::Config,Errno::ENOENT,Errno::EACCES]
def self.in_cluster_config(namespace: nil, **options)
Expand All @@ -64,7 +66,8 @@ def self.in_cluster_config(namespace: nil, **options)
#
# Will raise when no means of configuration is available
#
# @param options [Hash] default namespace for all operations
# @param namespace [String] default namespace for all operations
# @param (see K8s::Transport.config)
# @raise [K8s::Error::Config,Errno::ENOENT,Errno::EACCES]
# @return [K8s::Client]
def self.autoconfig(namespace: nil, **options)
Expand Down Expand Up @@ -95,6 +98,7 @@ def self.autoconfig(namespace: nil, **options)

include MonitorMixin

# @return [K8s::Transport]
attr_reader :transport

# @param transport [K8s::Transport]
Expand Down Expand Up @@ -187,7 +191,7 @@ def resources(namespace: nil)
# Returns flattened array with mixed resource kinds.
#
# @param resources [Array<K8s::ResourceClient>] default is all listable resources for api
# @param options @see K8s::ResourceClient#list
# @param (see K8s::ResourceClient.list)
# @return [Array<K8s::Resource>]
def list_resources(resources = nil, **options)
cached_clients = @api_clients.size.positive?
Expand Down Expand Up @@ -218,12 +222,14 @@ def client_for_resource(resource, namespace: nil)
def create_resource(resource)
client_for_resource(resource).create_resource(resource)
end
exceptionless_bang_method :create_resource

# @param resource [K8s::Resource]
# @return [K8s::Resource]
def get_resource(resource)
client_for_resource(resource).get_resource(resource)
end
exceptionless_bang_method :get_resource

# Returns nils for any resources that do not exist.
# This includes custom resources that were not yet defined.
Expand Down Expand Up @@ -258,20 +264,22 @@ def get_resources(resources)
def update_resource(resource)
client_for_resource(resource).update_resource(resource)
end
exceptionless_bang_method :update_resource

# @param resource [K8s::Resource]
# @param options [Hash]
# @see ResourceClient#delete for options
# @param (see ResourceClient.delete)
# @return [K8s::Resource]
def delete_resource(resource, **options)
client_for_resource(resource).delete_resource(resource, **options)
end
exceptionless_bang_method :delete_resource

# @param resource [K8s::Resource]
# @param attrs [Hash]
# @return [K8s::Client]
def patch_resource(resource, attrs)
client_for_resource(resource).json_patch(resource.metadata.name, attrs)
end
exceptionless_bang_method :patch_resource
end
end
2 changes: 1 addition & 1 deletion lib/k8s/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def self.from_kubeconfig_env(kubeconfig = nil)
#
# @param server [String] kubernetes server address
# @param ca [String] server certificate authority data (base64 encoded)
# @param token [String] access token
# @param auth_token [String] access token
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong attribute name, yardoc warns about these when generating, we could add rubocop-like test step for yardoc validity.

# @param cluster_name [String] cluster name
# @param user [String] user name
# @param context [String] context name
Expand Down
11 changes: 10 additions & 1 deletion lib/k8s/resource_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def make_query(options)

include Utils
extend Utils
extend K8s::Util::ExceptionlessBangMethod

# Pipeline list requests for multiple resource types.
#
Expand Down Expand Up @@ -152,6 +153,7 @@ def create_resource(resource)
response_class: @resource_class
)
end
exceptionless_bang_method :create_resource

# @return [Bool]
def get?
Expand All @@ -168,6 +170,7 @@ def get(name, namespace: @namespace)
response_class: @resource_class
)
end
exceptionless_bang_method :get

# @param resource [resource_class]
# @return [Object] instance of resource_class
Expand All @@ -178,6 +181,7 @@ def get_resource(resource)
response_class: @resource_class
)
end
exceptionless_bang_method :get_resource

# @return [Bool]
def list?
Expand Down Expand Up @@ -264,6 +268,7 @@ def update_resource(resource)
response_class: @resource_class
)
end
exceptionless_bang_method :update_resource

# @return [Boolean]
def patch?
Expand All @@ -284,6 +289,7 @@ def merge_patch(name, obj, namespace: @namespace, strategic_merge: true)
response_class: @resource_class
)
end
exceptionless_bang_method :merge_patch

# @param name [String]
# @param ops [Hash] json-patch operations
Expand All @@ -298,6 +304,7 @@ def json_patch(name, ops, namespace: @namespace)
response_class: @resource_class
)
end
exceptionless_bang_method :json_patch

# @return [Boolean]
def delete?
Expand All @@ -318,6 +325,7 @@ def delete(name, namespace: @namespace, propagationPolicy: nil)
response_class: @resource_class # XXX: documented as returning Status
)
end
exceptionless_bang_method :delete

# @param namespace [String, nil]
# @param labelSelector [nil, String, Hash{String => String}]
Expand All @@ -340,10 +348,11 @@ def delete_collection(namespace: @namespace, labelSelector: nil, fieldSelector:

# @param resource [resource_class] with metadata
# @param options [Hash]
# @see #delete for possible options
# @param (see #delete)
# @return [K8s::API::MetaV1::Status]
def delete_resource(resource, **options)
delete(resource.metadata.name, namespace: resource.metadata.namespace, **options)
end
exceptionless_bang_method :delete_resource
end
end
8 changes: 6 additions & 2 deletions lib/k8s/stack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,18 @@ def self.delete(name, client, **options)
new(name, **options).delete(client)
end

attr_reader :name, :resources
# @return [String]
attr_reader :name

# @return [Array<K8s::Resource>]
attr_reader :resources

# @param name [String]
# @param resources [Array<K8s::Resource>]
# @param debug [Boolean]
# @param label [String]
# @param checksum_annotation [String]
# @param last_config_annotation [String]
# @param last_configuration_annotation [String]
def initialize(name, resources = [], debug: false, label: self.class::LABEL, checksum_annotation: self.class::CHECKSUM_ANNOTATION, last_configuration_annotation: self.class::LAST_CONFIG_ANNOTATION)
@name = name
@resources = resources
Expand Down
23 changes: 16 additions & 7 deletions lib/k8s/transport.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module K8s
# Excon-based HTTP transport handling request/response body JSON encoding
class Transport
include Logging
extend K8s::Util::ExceptionlessBangMethod

quiet! # do not log warnings by default

Expand All @@ -29,7 +30,7 @@ class Transport
#
# @param config [K8s::Config]
# @param server [String] override cluster.server from config
# @param overrides @see #initialize
# @param (see #initialize)
# @return [K8s::Transport]
def self.config(config, server: nil, **overrides)
options = {}
Expand Down Expand Up @@ -142,13 +143,20 @@ def self.in_cluster_config(**options)
)
end

attr_reader :server, :options, :path_prefix
# @return [String] server URL
attr_reader :server

# @return [Hash]
attr_reader :options

# @return [String] query path perfix
attr_reader :path_prefix

# @param server [String] URL with protocol://host:port (paths are preserved as well)
# @param auth_token [String] optional Authorization: Bearer token
# @param auth_username [String] optional Basic authentication username
# @param auth_password [String] optional Basic authentication password
# @param options [Hash] @see Excon.new
# @param options [Hash] see https://www.rubydoc.info/github/excon/excon/Excon.new
def initialize(server, auth_token: nil, auth_username: nil, auth_password: nil, **options)
uri = URI.parse(server)
@server = "#{uri.scheme}://#{uri.host}:#{uri.port}"
Expand Down Expand Up @@ -185,7 +193,7 @@ def path(*parts)

# @param request_object [Object] include request body using to_json
# @param content_type [String] request body content-type
# @param options [Hash] @see Excon#request
# @param options see https://www.rubydoc.info/github/excon/excon/Excon%2FConnection:request
# @return [Hash]
def request_options(request_object: nil, content_type: 'application/json', **options)
options[:headers] ||= {}
Expand Down Expand Up @@ -268,8 +276,8 @@ def parse_response(response, request_options, response_class: nil)
end
end

# @param response_class [Class] coerce into response class using #new
# @param options [Hash] @see Excon#request
# @param response_class [Class] coerce into response class using response_class.new
# @param options [Hash] see https://www.rubydoc.info/github/excon/excon/Excon%2FConnection:request
# @return [response_class, Hash]
def request(response_class: nil, **options)
if options[:method] == 'DELETE' && need_delete_body?
Expand Down Expand Up @@ -365,9 +373,10 @@ def get(*path, **options)
**options
)
end
exceptionless_bang_method :get

# @param paths [Array<String>]
# @param options [Hash] @see #request
# @param (see #request)
# @return [Array<response_class, Hash, NilClass>]
def gets(*paths, **options)
requests(
Expand Down
17 changes: 17 additions & 0 deletions lib/k8s/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
module K8s
# Miscellaneous helpers
module Util
module ExceptionlessBangMethod
private

# @!macro [attach] exceptionless_bang_method
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This documents the dynamically generated bang! methods, but I couldn't find any way to replicate the param list / return value, so the bang-variants just show (*args, **options) => Object in the final doc.

# @method $1!
# Same as $1 but all exceptions are suppressed
def exceptionless_bang_method(meth)
define_method(meth.to_s.concat('!')) do |*args, **options|
begin
send(meth, *args, **options)
rescue StandardError
nil
end
end
end
end

module HashDeepMerge
refine Hash do
# @param other [Hash]
Expand Down
Loading