kubeclient-3.0.0/0000755000004100000410000000000013255124405013670 5ustar www-datawww-datakubeclient-3.0.0/Rakefile0000644000004100000410000000027713255124405015343 0ustar www-datawww-datarequire 'bundler/gem_tasks' require 'rake/testtask' require 'rubocop/rake_task' require 'yaml' task default: %i[test rubocop] # same as .travis.yml Rake::TestTask.new RuboCop::RakeTask.new kubeclient-3.0.0/Gemfile0000644000004100000410000000013713255124405015164 0ustar www-datawww-datasource 'https://rubygems.org' # Specify your gem's dependencies in kubeclient.gemspec gemspec kubeclient-3.0.0/LICENSE.txt0000644000004100000410000000205513255124405015515 0ustar www-datawww-dataCopyright (c) 2014 Alissa Bonas MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. kubeclient-3.0.0/.travis.yml0000644000004100000410000000023613255124405016002 0ustar www-datawww-datalanguage: ruby rvm: - "2.2" - "2.3.0" - "2.4.0" - "2.5.0" sudo: false cache: bundler script: bundle exec rake $TASK env: - TASK=test - TASK=rubocop kubeclient-3.0.0/lib/0000755000004100000410000000000013255124405014436 5ustar www-datawww-datakubeclient-3.0.0/lib/kubeclient.rb0000644000004100000410000000121013255124405017102 0ustar www-datawww-datarequire 'json' require 'rest-client' require 'kubeclient/common' require 'kubeclient/config' require 'kubeclient/entity_list' require 'kubeclient/http_error' require 'kubeclient/missing_kind_compatibility' require 'kubeclient/resource' require 'kubeclient/resource_not_found_error' require 'kubeclient/version' require 'kubeclient/watch_notice' require 'kubeclient/watch_stream' module Kubeclient # Kubernetes Client class Client include ClientMixin def initialize( uri, version = 'v1', **options ) initialize_client( uri, '/api', version, options ) end end end kubeclient-3.0.0/lib/kubeclient/0000755000004100000410000000000013255124405016563 5ustar www-datawww-datakubeclient-3.0.0/lib/kubeclient/entity_list.rb0000644000004100000410000000057213255124405021463 0ustar www-datawww-datarequire 'delegate' module Kubeclient module Common # Kubernetes Entity List class EntityList < DelegateClass(Array) attr_reader :kind, :resourceVersion def initialize(kind, resource_version, list) @kind = kind # rubocop:disable Style/VariableName @resourceVersion = resource_version super(list) end end end end kubeclient-3.0.0/lib/kubeclient/common.rb0000644000004100000410000004342013255124405020403 0ustar www-datawww-datarequire 'json' require 'rest-client' module Kubeclient # Common methods # this is mixed in by other gems module ClientMixin ENTITY_METHODS = %w[get watch delete create update patch].freeze DEFAULT_SSL_OPTIONS = { client_cert: nil, client_key: nil, ca_file: nil, cert_store: nil, verify_ssl: OpenSSL::SSL::VERIFY_PEER }.freeze DEFAULT_AUTH_OPTIONS = { username: nil, password: nil, bearer_token: nil, bearer_token_file: nil }.freeze DEFAULT_SOCKET_OPTIONS = { socket_class: nil, ssl_socket_class: nil }.freeze DEFAULT_TIMEOUTS = { # These do NOT affect watch, watching never times out. open: Net::HTTP.new('127.0.0.1').open_timeout, # depends on ruby version read: Net::HTTP.new('127.0.0.1').read_timeout }.freeze DEFAULT_HTTP_PROXY_URI = nil SEARCH_ARGUMENTS = { 'labelSelector' => :label_selector, 'fieldSelector' => :field_selector }.freeze WATCH_ARGUMENTS = { 'resourceVersion' => :resource_version }.merge!(SEARCH_ARGUMENTS).freeze attr_reader :api_endpoint attr_reader :ssl_options attr_reader :auth_options attr_reader :http_proxy_uri attr_reader :headers attr_reader :discovered def initialize_client( uri, path, version, ssl_options: DEFAULT_SSL_OPTIONS, auth_options: DEFAULT_AUTH_OPTIONS, socket_options: DEFAULT_SOCKET_OPTIONS, timeouts: DEFAULT_TIMEOUTS, http_proxy_uri: DEFAULT_HTTP_PROXY_URI ) validate_auth_options(auth_options) handle_uri(uri, path) @entities = {} @discovered = false @api_version = version @headers = {} @ssl_options = ssl_options @auth_options = auth_options @socket_options = socket_options # Allow passing partial timeouts hash, without unspecified # @timeouts[:foo] == nil resulting in infinite timeout. @timeouts = DEFAULT_TIMEOUTS.merge(timeouts) @http_proxy_uri = http_proxy_uri ? http_proxy_uri.to_s : nil if auth_options[:bearer_token] bearer_token(@auth_options[:bearer_token]) elsif auth_options[:bearer_token_file] validate_bearer_token_file bearer_token(File.read(@auth_options[:bearer_token_file])) end end def method_missing(method_sym, *args, &block) if discovery_needed?(method_sym) discover send(method_sym, *args, &block) else super end end def respond_to_missing?(method_sym, include_private = false) if discovery_needed?(method_sym) discover respond_to?(method_sym, include_private) else super end end def discovery_needed?(method_sym) !@discovered && ENTITY_METHODS.any? { |x| method_sym.to_s.start_with?(x) } end def handle_exception yield rescue RestClient::Exception => e json_error_msg = begin JSON.parse(e.response || '') || {} rescue JSON::ParserError {} end err_message = json_error_msg['message'] || e.message error_klass = e.http_code == 404 ? ResourceNotFoundError : HttpError raise error_klass.new(e.http_code, err_message, e.response) end def discover load_entities define_entity_methods @discovered = true end def self.parse_definition(kind, name) # "name": "componentstatuses", networkpolicies, endpoints # "kind": "ComponentStatus" NetworkPolicy, Endpoints # maintain pre group api compatibility for endpoints and securitycontextconstraints. # See: https://github.com/kubernetes/kubernetes/issues/8115 kind = kind[0..-2] if %w[Endpoints SecurityContextConstraints].include?(kind) prefix = kind[0..kind.rindex(/[A-Z]/)] # NetworkP m = name.match(/^#{prefix.downcase}(.*)$/) m && OpenStruct.new( entity_type: kind, # ComponentStatus resource_name: name, # componentstatuses method_names: [ ClientMixin.underscore_entity(kind), # component_status ClientMixin.underscore_entity(prefix) + m[1] # component_statuses ] ) end def handle_uri(uri, path) raise ArgumentError, 'Missing uri' unless uri @api_endpoint = (uri.is_a?(URI) ? uri : URI.parse(uri)) @api_endpoint.path = path if @api_endpoint.path.empty? @api_endpoint.path = @api_endpoint.path.chop if @api_endpoint.path.end_with?('/') components = @api_endpoint.path.to_s.split('/') # ["", "api"] or ["", "apis", batch] @api_group = components.length > 2 ? components[2] + '/' : '' end def build_namespace_prefix(namespace) namespace.to_s.empty? ? '' : "namespaces/#{namespace}/" end def define_entity_methods @entities.values.each do |entity| # get all entities of a type e.g. get_nodes, get_pods, etc. define_singleton_method("get_#{entity.method_names[1]}") do |options = {}| get_entities(entity.entity_type, entity.resource_name, options) end # watch all entities of a type e.g. watch_nodes, watch_pods, etc. define_singleton_method("watch_#{entity.method_names[1]}") do |options = {}| # This method used to take resource_version as a param, so # this conversion is to keep backwards compatibility options = { resource_version: options } unless options.is_a?(Hash) watch_entities(entity.resource_name, options) end # get a single entity of a specific type by name define_singleton_method("get_#{entity.method_names[0]}") \ do |name, namespace = nil, opts = {}| get_entity(entity.resource_name, name, namespace, opts) end define_singleton_method("delete_#{entity.method_names[0]}") \ do |name, namespace = nil, opts = {}| delete_entity(entity.resource_name, name, namespace, opts) end define_singleton_method("create_#{entity.method_names[0]}") do |entity_config| create_entity(entity.entity_type, entity.resource_name, entity_config) end define_singleton_method("update_#{entity.method_names[0]}") do |entity_config| update_entity(entity.resource_name, entity_config) end define_singleton_method("patch_#{entity.method_names[0]}") do |name, patch, namespace = nil| patch_entity(entity.resource_name, name, patch, namespace) end end end def self.underscore_entity(entity_name) entity_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase end def create_rest_client(path = nil) path ||= @api_endpoint.path options = { ssl_ca_file: @ssl_options[:ca_file], ssl_cert_store: @ssl_options[:cert_store], verify_ssl: @ssl_options[:verify_ssl], ssl_client_cert: @ssl_options[:client_cert], ssl_client_key: @ssl_options[:client_key], proxy: @http_proxy_uri, user: @auth_options[:username], password: @auth_options[:password], open_timeout: @timeouts[:open], read_timeout: @timeouts[:read] } RestClient::Resource.new(@api_endpoint.merge(path).to_s, options) end def rest_client @rest_client ||= begin create_rest_client("#{@api_endpoint.path}/#{@api_version}") end end # Accepts the following options: # :namespace (string) - the namespace of the entity. # :name (string) - the name of the entity to watch. # :label_selector (string) - a selector to restrict the list of returned objects by labels. # :field_selector (string) - a selector to restrict the list of returned objects by fields. # :resource_version (string) - shows changes that occur after passed version of a resource. # :as (:raw|:ros) - defaults to :ros # :raw - return the raw response body as a string # :ros - return a collection of RecursiveOpenStruct objects def watch_entities(resource_name, options = {}) ns = build_namespace_prefix(options[:namespace]) path = "watch/#{ns}#{resource_name}" path += "/#{options[:name]}" if options[:name] uri = @api_endpoint.merge("#{@api_endpoint.path}/#{@api_version}/#{path}") params = {} WATCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] } uri.query = URI.encode_www_form(params) if params.any? Kubeclient::Common::WatchStream.new(uri, http_options(uri), as: options[:as] || :ros) end # Accepts the following options: # :namespace (string) - the namespace of the entity. # :label_selector (string) - a selector to restrict the list of returned objects by labels. # :field_selector (string) - a selector to restrict the list of returned objects by fields. # :as (:raw|:ros) - defaults to :ros # :raw - return the raw response body as a string # :ros - return a collection of RecursiveOpenStruct objects def get_entities(entity_type, resource_name, options = {}) params = {} SEARCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] } ns_prefix = build_namespace_prefix(options[:namespace]) response = handle_exception do rest_client[ns_prefix + resource_name] .get({ 'params' => params }.merge(@headers)) end return response.body if options[:as] == :raw result = JSON.parse(response) resource_version = result.fetch('resourceVersion') do result.fetch('metadata', {}).fetch('resourceVersion', nil) end # result['items'] might be nil due to https://github.com/kubernetes/kubernetes/issues/13096 collection = result['items'].to_a.map { |item| Kubeclient::Resource.new(item) } Kubeclient::Common::EntityList.new(entity_type, resource_version, collection) end # Accepts the following options: # :as (:raw|:ros) - defaults to :ros # :raw - return the raw response body as a string # :ros - return a collection of RecursiveOpenStruct objects def get_entity(resource_name, name, namespace = nil, options = {}) ns_prefix = build_namespace_prefix(namespace) response = handle_exception do rest_client[ns_prefix + resource_name + "/#{name}"] .get(@headers) end format_response(options[:as], response) end # delete_options are passed as a JSON payload in the delete request def delete_entity(resource_name, name, namespace = nil, delete_options: {}) delete_options_hash = delete_options.to_hash ns_prefix = build_namespace_prefix(namespace) payload = delete_options_hash.to_json unless delete_options_hash.empty? response = handle_exception do rs = rest_client[ns_prefix + resource_name + "/#{name}"] RestClient::Request.execute( rs.options.merge( method: :delete, url: rs.url, headers: { 'Content-Type' => 'application/json' }.merge(@headers), payload: payload ) ) end format_response(:ros, response) end def create_entity(entity_type, resource_name, entity_config) # Duplicate the entity_config to a hash so that when we assign # kind and apiVersion, this does not mutate original entity_config obj. hash = entity_config.to_hash ns_prefix = build_namespace_prefix(hash[:metadata][:namespace]) # TODO: temporary solution to add "kind" and apiVersion to request # until this issue is solved # https://github.com/GoogleCloudPlatform/kubernetes/issues/6439 # TODO: #2 solution for # https://github.com/kubernetes/kubernetes/issues/8115 hash[:kind] = (entity_type.eql?('Endpoint') ? 'Endpoints' : entity_type) hash[:apiVersion] = @api_group + @api_version response = handle_exception do rest_client[ns_prefix + resource_name] .post(hash.to_json, { 'Content-Type' => 'application/json' }.merge(@headers)) end format_response(:ros, response) end def update_entity(resource_name, entity_config) name = entity_config[:metadata][:name] ns_prefix = build_namespace_prefix(entity_config[:metadata][:namespace]) response = handle_exception do rest_client[ns_prefix + resource_name + "/#{name}"] .put(entity_config.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers)) end format_response(:ros, response) end def patch_entity(resource_name, name, patch, namespace = nil) ns_prefix = build_namespace_prefix(namespace) response = handle_exception do rest_client[ns_prefix + resource_name + "/#{name}"] .patch( patch.to_json, { 'Content-Type' => 'application/strategic-merge-patch+json' }.merge(@headers) ) end format_response(:ros, response) end def all_entities(options = {}) discover unless @discovered @entities.values.each_with_object({}) do |entity, result_hash| # method call for get each entities # build hash of entity name to array of the entities method_name = "get_#{entity.method_names[1]}" begin result_hash[entity.method_names[0]] = send(method_name, options) rescue Kubeclient::HttpError next # do not fail due to resources not supporting get end end end def get_pod_log(pod_name, namespace, container: nil, previous: false) params = {} params[:previous] = true if previous params[:container] = container if container ns = build_namespace_prefix(namespace) handle_exception do rest_client[ns + "pods/#{pod_name}/log"] .get({ 'params' => params }.merge(@headers)) end end def watch_pod_log(pod_name, namespace, container: nil) # Adding the "follow=true" query param tells the Kubernetes API to keep # the connection open and stream updates to the log. params = { follow: true } params[:container] = container if container ns = build_namespace_prefix(namespace) uri = @api_endpoint.dup uri.path += "/#{@api_version}/#{ns}pods/#{pod_name}/log" uri.query = URI.encode_www_form(params) Kubeclient::Common::WatchStream.new(uri, http_options(uri), as: :raw) end def proxy_url(kind, name, port, namespace = '') discover unless @discovered entity_name_plural = if %w[services pods nodes].include?(kind.to_s) kind.to_s else @entities[kind.to_s].resource_name end ns_prefix = build_namespace_prefix(namespace) # TODO: Change this once services supports the new scheme if entity_name_plural == 'pods' rest_client["#{ns_prefix}#{entity_name_plural}/#{name}:#{port}/proxy"].url else rest_client["proxy/#{ns_prefix}#{entity_name_plural}/#{name}:#{port}"].url end end def process_template(template) ns_prefix = build_namespace_prefix(template[:metadata][:namespace]) response = handle_exception do rest_client[ns_prefix + 'processedtemplates'] .post(template.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers)) end JSON.parse(response) end def api_valid? result = api result.is_a?(Hash) && (result['versions'] || []).any? do |group| @api_group.empty? ? group.include?(@api_version) : group['version'] == @api_version end end def api response = handle_exception { create_rest_client.get(@headers) } JSON.parse(response) end private def format_response(as, response) return response.body if as == :raw result = JSON.parse(response) Kubeclient::Resource.new(result) end def load_entities @entities = {} fetch_entities['resources'].each do |resource| next if resource['name'].include?('/') resource['kind'] ||= Kubeclient::Common::MissingKindCompatibility.resource_kind(resource['name']) entity = ClientMixin.parse_definition(resource['kind'], resource['name']) @entities[entity.method_names[0]] = entity if entity end end def fetch_entities JSON.parse(handle_exception { rest_client.get(@headers) }) end def bearer_token(bearer_token) @headers ||= {} @headers[:Authorization] = "Bearer #{bearer_token}" end def validate_auth_options(opts) # maintain backward compatibility: opts[:username] = opts[:user] if opts[:user] if %i[bearer_token bearer_token_file username].count { |key| opts[key] } > 1 raise( ArgumentError, 'Invalid auth options: specify only one of username/password,' \ ' bearer_token or bearer_token_file' ) elsif %i[username password].count { |key| opts[key] } == 1 raise ArgumentError, 'Basic auth requires both username & password' end end def validate_bearer_token_file msg = "Token file #{@auth_options[:bearer_token_file]} does not exist" raise ArgumentError, msg unless File.file?(@auth_options[:bearer_token_file]) msg = "Cannot read token file #{@auth_options[:bearer_token_file]}" raise ArgumentError, msg unless File.readable?(@auth_options[:bearer_token_file]) end def http_options(uri) options = { basic_auth_user: @auth_options[:username], basic_auth_password: @auth_options[:password], headers: @headers, http_proxy_uri: @http_proxy_uri } if uri.scheme == 'https' options[:ssl] = { ca_file: @ssl_options[:ca_file], cert: @ssl_options[:client_cert], cert_store: @ssl_options[:cert_store], key: @ssl_options[:client_key], # ruby HTTP uses verify_mode instead of verify_ssl # http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html verify_mode: @ssl_options[:verify_ssl] } end options.merge(@socket_options) end end end kubeclient-3.0.0/lib/kubeclient/version.rb0000644000004100000410000000011613255124405020573 0ustar www-datawww-data# Kubernetes REST-API Client module Kubeclient VERSION = '3.0.0'.freeze end kubeclient-3.0.0/lib/kubeclient/config.rb0000644000004100000410000000711113255124405020355 0ustar www-datawww-datarequire 'yaml' require 'base64' require 'pathname' module Kubeclient # Kubernetes client configuration class class Config # Kubernetes client configuration context class class Context attr_reader :api_endpoint, :api_version, :ssl_options, :auth_options def initialize(api_endpoint, api_version, ssl_options, auth_options) @api_endpoint = api_endpoint @api_version = api_version @ssl_options = ssl_options @auth_options = auth_options end end def initialize(kcfg, kcfg_path) @kcfg = kcfg @kcfg_path = kcfg_path raise 'Unknown kubeconfig version' if @kcfg['apiVersion'] != 'v1' end def self.read(filename) Config.new(YAML.load_file(filename), File.dirname(filename)) end def contexts @kcfg['contexts'].map { |x| x['name'] } end def context(context_name = nil) cluster, user = fetch_context(context_name || @kcfg['current-context']) ca_cert_data = fetch_cluster_ca_data(cluster) client_cert_data = fetch_user_cert_data(user) client_key_data = fetch_user_key_data(user) auth_options = fetch_user_auth_options(user) ssl_options = {} if !ca_cert_data.nil? cert_store = OpenSSL::X509::Store.new cert_store.add_cert(OpenSSL::X509::Certificate.new(ca_cert_data)) ssl_options[:verify_ssl] = OpenSSL::SSL::VERIFY_PEER ssl_options[:cert_store] = cert_store else ssl_options[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE end unless client_cert_data.nil? ssl_options[:client_cert] = OpenSSL::X509::Certificate.new(client_cert_data) end unless client_key_data.nil? ssl_options[:client_key] = OpenSSL::PKey.read(client_key_data) end Context.new(cluster['server'], @kcfg['apiVersion'], ssl_options, auth_options) end private def ext_file_path(path) Pathname(path).absolute? ? path : File.join(@kcfg_path, path) end def fetch_context(context_name) context = @kcfg['contexts'].detect do |x| break x['context'] if x['name'] == context_name end raise KeyError, "Unknown context #{context_name}" unless context cluster = @kcfg['clusters'].detect do |x| break x['cluster'] if x['name'] == context['cluster'] end raise KeyError, "Unknown cluster #{context['cluster']}" unless cluster user = @kcfg['users'].detect do |x| break x['user'] if x['name'] == context['user'] end || {} [cluster, user] end def fetch_cluster_ca_data(cluster) if cluster.key?('certificate-authority') File.read(ext_file_path(cluster['certificate-authority'])) elsif cluster.key?('certificate-authority-data') Base64.decode64(cluster['certificate-authority-data']) end end def fetch_user_cert_data(user) if user.key?('client-certificate') File.read(ext_file_path(user['client-certificate'])) elsif user.key?('client-certificate-data') Base64.decode64(user['client-certificate-data']) end end def fetch_user_key_data(user) if user.key?('client-key') File.read(ext_file_path(user['client-key'])) elsif user.key?('client-key-data') Base64.decode64(user['client-key-data']) end end def fetch_user_auth_options(user) options = {} if user.key?('token') options[:bearer_token] = user['token'] else %w[username password].each do |attr| options[attr.to_sym] = user[attr] if user.key?(attr) end end options end end end kubeclient-3.0.0/lib/kubeclient/missing_kind_compatibility.rb0000644000004100000410000000652013255124405024522 0ustar www-datawww-datamodule Kubeclient module Common # Backward compatibility for old versions where kind is missing (e.g. OpenShift Enterprise 3.1) class MissingKindCompatibility MAPPING = { 'bindings' => 'Binding', 'componentstatuses' => 'ComponentStatus', 'endpoints' => 'Endpoints', 'events' => 'Event', 'limitranges' => 'LimitRange', 'namespaces' => 'Namespace', 'nodes' => 'Node', 'persistentvolumeclaims' => 'PersistentVolumeClaim', 'persistentvolumes' => 'PersistentVolume', 'pods' => 'Pod', 'podtemplates' => 'PodTemplate', 'replicationcontrollers' => 'ReplicationController', 'resourcequotas' => 'ResourceQuota', 'secrets' => 'Secret', 'securitycontextconstraints' => 'SecurityContextConstraints', 'serviceaccounts' => 'ServiceAccount', 'services' => 'Service', 'buildconfigs' => 'BuildConfig', 'builds' => 'Build', 'clusternetworks' => 'ClusterNetwork', 'clusterpolicies' => 'ClusterPolicy', 'clusterpolicybindings' => 'ClusterPolicyBinding', 'clusterrolebindings' => 'ClusterRoleBinding', 'clusterroles' => 'ClusterRole', 'deploymentconfigrollbacks' => 'DeploymentConfigRollback', 'deploymentconfigs' => 'DeploymentConfig', 'generatedeploymentconfigs' => 'DeploymentConfig', 'groups' => 'Group', 'hostsubnets' => 'HostSubnet', 'identities' => 'Identity', 'images' => 'Image', 'imagestreamimages' => 'ImageStreamImage', 'imagestreammappings' => 'ImageStreamMapping', 'imagestreams' => 'ImageStream', 'imagestreamtags' => 'ImageStreamTag', 'localresourceaccessreviews' => 'LocalResourceAccessReview', 'localsubjectaccessreviews' => 'LocalSubjectAccessReview', 'netnamespaces' => 'NetNamespace', 'oauthaccesstokens' => 'OAuthAccessToken', 'oauthauthorizetokens' => 'OAuthAuthorizeToken', 'oauthclientauthorizations' => 'OAuthClientAuthorization', 'oauthclients' => 'OAuthClient', 'policies' => 'Policy', 'policybindings' => 'PolicyBinding', 'processedtemplates' => 'Template', 'projectrequests' => 'ProjectRequest', 'projects' => 'Project', 'resourceaccessreviews' => 'ResourceAccessReview', 'rolebindings' => 'RoleBinding', 'roles' => 'Role', 'routes' => 'Route', 'subjectaccessreviews' => 'SubjectAccessReview', 'templates' => 'Template', 'useridentitymappings' => 'UserIdentityMapping', 'users' => 'User' }.freeze def self.resource_kind(name) MAPPING[name] end end end end kubeclient-3.0.0/lib/kubeclient/http_error.rb0000644000004100000410000000122113255124405021274 0ustar www-datawww-data# TODO: remove this on next major version bump # Deprected http exception class KubeException < StandardError attr_reader :error_code, :message, :response def initialize(error_code, message, response) @error_code = error_code @message = message @response = response end def to_s string = "HTTP status code #{@error_code}, #{@message}" if @response.is_a?(RestClient::Response) && @response.request string << " for #{@response.request.method.upcase} #{@response.request.url}" end string end end module Kubeclient # Exception that is raised when a http request fails class HttpError < KubeException end end kubeclient-3.0.0/lib/kubeclient/resource.rb0000644000004100000410000000041413255124405020736 0ustar www-datawww-datarequire 'recursive_open_struct' module Kubeclient # Represents all the objects returned by Kubeclient class Resource < RecursiveOpenStruct def initialize(hash = nil, args = {}) args[:recurse_over_arrays] = true super(hash, args) end end end kubeclient-3.0.0/lib/kubeclient/watch_notice.rb0000644000004100000410000000050113255124405021553 0ustar www-datawww-datarequire 'recursive_open_struct' module Kubeclient module Common # Represents an individual notice received from a Kubernetes watch class WatchNotice < RecursiveOpenStruct def initialize(hash = nil, args = {}) args[:recurse_over_arrays] = true super(hash, args) end end end end kubeclient-3.0.0/lib/kubeclient/resource_not_found_error.rb0000644000004100000410000000010613255124405024220 0ustar www-datawww-datamodule Kubeclient class ResourceNotFoundError < HttpError end end kubeclient-3.0.0/lib/kubeclient/watch_stream.rb0000644000004100000410000000441613255124405021576 0ustar www-datawww-datarequire 'json' require 'http' module Kubeclient module Common # HTTP Stream used to watch changes on entities class WatchStream def initialize(uri, http_options, as:) @uri = uri @http_client = nil @http_options = http_options @as = as end def each @finished = false @http_client = build_client response = @http_client.request(:get, @uri, build_client_options) unless response.code < 300 raise Kubeclient::HttpError.new(response.code, response.reason, response) end buffer = '' response.body.each do |chunk| buffer << chunk while (line = buffer.slice!(/.+\n/)) result = case @as when :ros then WatchNotice.new(JSON.parse(line)) when :raw then line.chomp else raise NotImplementedError, "Unsupported as #{@as.inspect}" end yield(result) end end rescue IOError, Errno::EBADF raise unless @finished end def finish @finished = true @http_client.close unless @http_client.nil? end private def build_client if @http_options[:basic_auth_user] && @http_options[:basic_auth_password] HTTP.basic_auth( user: @http_options[:basic_auth_user], pass: @http_options[:basic_auth_password] ) else HTTP::Client.new end end def using_proxy proxy = @http_options[:http_proxy_uri] return nil unless proxy p_uri = URI.parse(proxy) { proxy_address: p_uri.hostname, proxy_port: p_uri.port, proxy_username: p_uri.user, proxy_password: p_uri.password } end def build_client_options client_options = { headers: @http_options[:headers], proxy: using_proxy } if @http_options[:ssl] client_options[:ssl] = @http_options[:ssl] socket_option = :ssl_socket_class else socket_option = :socket_class end client_options[socket_option] = @http_options[socket_option] if @http_options[socket_option] client_options end end end end kubeclient-3.0.0/.rubocop.yml0000644000004100000410000000122013255124405016135 0ustar www-datawww-dataAllCops: DisplayCopNames: true TargetRubyVersion: 2.2 # Oldest version kubeclient supports MethodLength: Enabled: false ClassLength: Enabled: false Metrics/AbcSize: Enabled: false Metrics/LineLength: Max: 100 Metrics/ParameterLists: Max: 5 CountKeywordArgs: false Metrics/CyclomaticComplexity: Max: 8 Metrics/ModuleLength: Enabled: false Style/MethodCallWithArgsParentheses: Enabled: true IgnoredMethods: [require, raise, include, attr_reader, refute, assert] Exclude: [Gemfile, Rakefile, kubeclient.gemspec] Security/MarshalLoad: Exclude: [test/**/*] Style/MethodCallWithArgsParentheses: IgnoredMethods: - require_relative kubeclient-3.0.0/test/0000755000004100000410000000000013255124405014647 5ustar www-datawww-datakubeclient-3.0.0/test/test_limit_range.rb0000644000004100000410000000166613255124405020536 0ustar www-datawww-datarequire_relative 'test_helper' # LimitRange tests class TestLimitRange < MiniTest::Test def test_get_from_json_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/limitranges}) .to_return(body: open_test_file('limit_range.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') limit_range = client.get_limit_range('limits', 'quota-example') assert_instance_of(Kubeclient::Resource, limit_range) assert_equal('limits', limit_range.metadata.name) assert_equal('Container', limit_range.spec.limits[0].type) assert_equal('100m', limit_range.spec.limits[0].default.cpu) assert_equal('512Mi', limit_range.spec.limits[0].default.memory) assert_requested( :get, 'http://localhost:8080/api/v1/namespaces/quota-example/limitranges/limits', times: 1 ) end end kubeclient-3.0.0/test/test_process_template.rb0000644000004100000410000000327413255124405021612 0ustar www-datawww-datarequire_relative 'test_helper' # Process Template tests class TestProcessTemplate < MiniTest::Test def test_process_template client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') template = {} template[:metadata] = {} template[:metadata][:name] = 'my-template' template[:metadata][:namespace] = 'default' template[:kind] = 'Template' template[:apiVersion] = 'v1' service = {} service[:metadata] = {} service[:metadata][:name] = '${NAME_PREFIX}my-service' service[:kind] = 'Service' service[:apiVersion] = 'v1' template[:objects] = [service] param = { name: 'NAME_PREFIX', value: 'test/' } template[:parameters] = [param] req_body = '{"metadata":{"name":"my-template","namespace":"default"},' \ '"kind":"Template","apiVersion":"v1","objects":[{"metadata":' \ '{"name":"${NAME_PREFIX}my-service"},"kind":"Service","apiVersion":"v1"}],' \ '"parameters":[{"name":"NAME_PREFIX","value":"test/"}]}' expected_url = 'http://localhost:8080/api/v1/namespaces/default/processedtemplates' stub_request(:post, expected_url) .with(body: req_body, headers: { 'Content-Type' => 'application/json' }) .to_return(body: open_test_file('processed_template.json'), status: 200) processed_template = client.process_template(template) assert_equal('test/my-service', processed_template['objects'].first['metadata']['name']) assert_requested(:post, expected_url, times: 1) do |req| data = JSON.parse(req.body) data['kind'] == 'Template' && data['apiVersion'] == 'v1' && data['metadata']['name'] == 'my-template' && data['metadata']['namespace'] == 'default' end end end kubeclient-3.0.0/test/test_config.rb0000644000004100000410000000545413255124405017510 0ustar www-datawww-datarequire_relative 'test_helper' # Testing Kubernetes client configuration class KubeclientConfigTest < MiniTest::Test def test_allinone config = Kubeclient::Config.read(config_file('allinone.kubeconfig')) assert_equal(['default/localhost:8443/system:admin'], config.contexts) check_context(config.context, ssl: true) end def test_external config = Kubeclient::Config.read(config_file('external.kubeconfig')) assert_equal(['default/localhost:8443/system:admin'], config.contexts) check_context(config.context, ssl: true) end def test_nouser config = Kubeclient::Config.read(config_file('nouser.kubeconfig')) assert_equal(['default/localhost:8443/nouser'], config.contexts) check_context(config.context, ssl: false) end def test_user_token config = Kubeclient::Config.read(config_file('userauth.kubeconfig')) assert_equal(['localhost/system:admin:token', 'localhost/system:admin:userpass'], config.contexts) context = config.context('localhost/system:admin:token') check_context(context, ssl: false) assert_equal('0123456789ABCDEF0123456789ABCDEF', context.auth_options[:bearer_token]) end def test_user_password config = Kubeclient::Config.read(config_file('userauth.kubeconfig')) assert_equal(['localhost/system:admin:token', 'localhost/system:admin:userpass'], config.contexts) context = config.context('localhost/system:admin:userpass') check_context(context, ssl: false) assert_equal('admin', context.auth_options[:username]) assert_equal('pAssw0rd123', context.auth_options[:password]) end private def check_context(context, ssl: true) assert_equal('https://localhost:8443', context.api_endpoint) assert_equal('v1', context.api_version) if ssl assert_equal(OpenSSL::SSL::VERIFY_PEER, context.ssl_options[:verify_ssl]) assert_kind_of(OpenSSL::X509::Store, context.ssl_options[:cert_store]) assert_kind_of(OpenSSL::X509::Certificate, context.ssl_options[:client_cert]) assert_kind_of(OpenSSL::PKey::RSA, context.ssl_options[:client_key]) # When certificates expire the quickest way to recreate them is using # an OpenShift tool (100% compatible with kubernetes): # # $ oc adm ca create-master-certs --hostnames=localhost # # At the time of this writing the files to be updated are: # # test/config/allinone.kubeconfig # test/config/external-ca.pem # test/config/external-cert.pem # test/config/external-key.rsa assert(context.ssl_options[:cert_store].verify(context.ssl_options[:client_cert])) else assert_equal(OpenSSL::SSL::VERIFY_NONE, context.ssl_options[:verify_ssl]) end end def config_file(name) File.new(File.join(File.dirname(__FILE__), 'config', name)) end end kubeclient-3.0.0/test/test_guestbook_go.rb0000644000004100000410000001662113255124405020730 0ustar www-datawww-datarequire_relative 'test_helper' require 'vcr' # creation of google's example of guest book class CreateGuestbookGo < MiniTest::Test def test_create_guestbook_entities VCR.configure do |c| c.cassette_library_dir = 'test/cassettes' c.hook_into(:webmock) end # WebMock.allow_net_connect! VCR.use_cassette('kubernetes_guestbook') do # , record: :new_episodes) do client = Kubeclient::Client.new('http://10.35.0.23:8080/api/', 'v1') testing_ns = Kubeclient::Resource.new testing_ns.metadata = {} testing_ns.metadata.name = 'kubeclient-ns' # delete in case they existed before so creation can be tested delete_namespace(client, testing_ns.metadata.name) delete_services( client, testing_ns.metadata.name, ['guestbook', 'redis-master', 'redis-slave'] ) delete_replication_controllers( client, testing_ns.metadata.name, ['guestbook', 'redis-master', 'redis-slave'] ) client.create_namespace(testing_ns) services = create_services(client, testing_ns.metadata.name) replicators = create_replication_controllers(client, testing_ns.metadata.name) get_namespaces(client) get_services(client, testing_ns.metadata.name) get_replication_controllers(client, testing_ns.metadata.name) delete_services(client, testing_ns.metadata.name, services) delete_replication_controllers(client, testing_ns.metadata.name, replicators) client.delete_namespace(testing_ns.metadata.name) end end def delete_namespace(client, namespace_name) client.delete_namespace(namespace_name) rescue Kubeclient::ResourceNotFoundError => exception assert_equal(404, exception.error_code) end def get_namespaces(client) namespaces = client.get_namespaces assert(true, namespaces.size > 2) end def get_services(client, ns) retrieved_services = client.get_services(namespace: ns) assert_equal(3, retrieved_services.size) end def get_replication_controllers(client, ns) retrieved_replicators = client.get_replication_controllers(namespace: ns) assert_equal(3, retrieved_replicators.size) end def create_services(client, ns) guestbook_service = client.create_service(guestbook_service(ns)) redis_service = client.create_service(redis_service(ns)) redis_slave_service = client.create_service(redis_slave_service(ns)) [guestbook_service, redis_service, redis_slave_service] end def create_replication_controllers(client, namespace) rc = client.create_replication_controller(guestbook_rc(namespace)) rc2 = client.create_replication_controller(redis_master_rc(namespace)) rc3 = client.create_replication_controller(redis_slave_rc(namespace)) [rc, rc2, rc3] end def delete_services(client, namespace, services) # if the entity is not found, no need to fail the test services.each do |service| begin if service.instance_of?(Kubeclient::Resource) client.delete_service(service.metadata.name, namespace) else # it's just a string - service name client.delete_service(service, namespace) end rescue Kubeclient::ResourceNotFoundError => exception assert_equal(404, exception.error_code) end end end def delete_replication_controllers(client, namespace, replication_controllers) # if the entity is not found, no need to fail the test replication_controllers.each do |rc| begin if rc.instance_of?(Kubeclient::Resource) client.delete_replication_controller(rc.metadata.name, namespace) else # it's just a string - rc name client.delete_replication_controller(rc, namespace) end rescue Kubeclient::ResourceNotFoundError => exception assert_equal(404, exception.error_code) end end end private def construct_base_rc(namespace) rc = Kubeclient::Resource.new rc.metadata = {} rc.metadata.namespace = namespace rc.metadata.labels = {} rc.spec = {} rc.spec.selector = {} rc.spec.template = {} rc.spec.template.metadata = {} rc.spec.template.spec = {} rc.spec.template.metadata.labels = {} rc end def redis_master_rc(namespace) rc = construct_base_rc(namespace) rc.metadata.name = 'redis-master' rc.metadata.labels.app = 'redis' rc.metadata.labels.role = 'master' rc.spec.replicas = 1 rc.spec.selector.app = 'redis' rc.spec.selector.role = 'master' rc.spec.template.metadata.labels.app = 'redis' rc.spec.template.metadata.labels.role = 'master' rc.spec.template.spec.containers = [{ 'name' => 'redis-master', 'image' => 'redis', 'ports' => [{ 'name' => 'redis-server', 'containerPort' => 6379 }] }] rc end def redis_slave_rc(namespace) rc = construct_base_rc(namespace) rc.metadata.name = 'redis-slave' rc.metadata.labels.app = 'redis' rc.metadata.labels.role = 'slave' rc.spec.replicas = 2 rc.spec.selector.app = 'redis' rc.spec.selector.role = 'slave' rc.spec.template.metadata.labels.app = 'redis' rc.spec.template.metadata.labels.role = 'slave' rc.spec.template.spec.containers = [{ 'name' => 'redis-slave', 'image' => 'kubernetes/redis-slave:v2', 'ports' => [{ 'name' => 'redis-server', 'containerPort' => 6379 }] }] rc end def guestbook_rc(namespace) rc = construct_base_rc(namespace) rc.metadata.name = 'guestbook' rc.metadata.labels.app = 'guestbook' rc.metadata.labels.role = 'slave' rc.spec.replicas = 3 rc.spec.selector.app = 'guestbook' rc.spec.template.metadata.labels.app = 'guestbook' rc.spec.template.spec.containers = [ { 'name' => 'guestbook', 'image' => 'kubernetes/guestbook:v2', 'ports' => [ { 'name' => 'http-server', 'containerPort' => 3000 } ] } ] rc end def base_service(namespace) our_service = Kubeclient::Resource.new our_service.metadata = {} our_service.metadata.namespace = namespace our_service.metadata.labels = {} our_service.spec = {} our_service.spec.selector = {} our_service end def redis_slave_service(namespace) our_service = base_service(namespace) our_service.metadata.name = 'redis-slave' our_service.metadata.labels.app = 'redis' our_service.metadata.labels.role = 'slave' our_service.spec.ports = [{ 'port' => 6379, 'targetPort' => 'redis-server' }] our_service.spec.selector.app = 'redis' our_service.spec.selector.role = 'slave' our_service end def redis_service(namespace) our_service = base_service(namespace) our_service.metadata.name = 'redis-master' our_service.metadata.labels.app = 'redis' our_service.metadata.labels.role = 'master' our_service.spec.ports = [{ 'port' => 6379, 'targetPort' => 'redis-server' }] our_service.spec.selector.app = 'redis' our_service.spec.selector.role = 'master' our_service end def guestbook_service(namespace) our_service = base_service(namespace) our_service.metadata.name = 'guestbook' our_service.metadata.labels.name = 'guestbook' our_service.spec.ports = [{ 'port' => 3000, 'targetPort' => 'http-server' }] our_service.spec.selector.app = 'guestbook' our_service.type = 'LoadBalancer' our_service end end kubeclient-3.0.0/test/test_endpoint.rb0000644000004100000410000000230213255124405020050 0ustar www-datawww-datarequire_relative 'test_helper' # Endpoint entity tests class TestEndpoint < MiniTest::Test def test_create_endpoint stub_request(:get, %r{/api/v1$}) .to_return( body: open_test_file('core_api_resource_list.json'), status: 200 ) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') testing_ep = Kubeclient::Resource.new testing_ep.metadata = {} testing_ep.metadata.name = 'myendpoint' testing_ep.metadata.namespace = 'default' testing_ep.subsets = [ { 'addresses' => [{ 'ip' => '172.17.0.25' }], 'ports' => [{ 'name' => 'https', 'port' => 6443, 'protocol' => 'TCP' }] } ] req_body = '{"metadata":{"name":"myendpoint","namespace":"default"},' \ '"subsets":[{"addresses":[{"ip":"172.17.0.25"}],"ports":[{"name":"https",' \ '"port":6443,"protocol":"TCP"}]}],"kind":"Endpoints","apiVersion":"v1"}' stub_request(:post, 'http://localhost:8080/api/v1/namespaces/default/endpoints') .with(body: req_body) .to_return(body: open_test_file('created_endpoint.json'), status: 201) created_ep = client.create_endpoint(testing_ep) assert_equal('Endpoints', created_ep.kind) end end kubeclient-3.0.0/test/test_missing_methods.rb0000644000004100000410000000322613255124405021432 0ustar www-datawww-datarequire_relative 'test_helper' # Test method_missing, respond_to? and respond_to_missing behaviour class TestMissingMethods < MiniTest::Test def test_missing stub_request(:get, %r{/api/v1$}).to_return( body: open_test_file('core_api_resource_list.json'), status: 200 ) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') assert_equal(true, client.respond_to?(:get_pod)) assert_equal(true, client.respond_to?(:get_pods)) assert_equal(false, client.respond_to?(:get_pie)) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery assert_equal(false, client.respond_to?(:get_pie)) assert_equal(true, client.respond_to?(:get_pods)) assert_equal(true, client.respond_to?(:get_pod)) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery assert_instance_of(Method, client.method(:get_pods)) assert_raises(NameError) do client.method(:get_pies) end client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery assert_raises(NameError) do client.method(:get_pies) end assert_instance_of(Method, client.method(:get_pods)) stub_request(:get, %r{/api/v1$}).to_return( body: '', status: 404 ) # If discovery fails we expect the below raise an exception client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') assert_raises(Kubeclient::HttpError) do client.method(:get_pods) end client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') assert_raises(Kubeclient::HttpError) do client.respond_to?(:get_pods) end end end kubeclient-3.0.0/test/test_common.rb0000644000004100000410000000156613255124405017533 0ustar www-datawww-datarequire_relative 'test_helper' # Unit tests for the common module class CommonTest < MiniTest::Test def test_underscore_entity %w[ Pod pod Service service ReplicationController replication_controller Node node Event event Endpoint endpoint Namespace namespace Secret secret ResourceQuota resource_quota LimitRange limit_range PersistentVolume persistent_volume PersistentVolumeClaim persistent_volume_claim ComponentStatus component_status ServiceAccount service_account Project project Route route ClusterRoleBinding cluster_role_binding Build build BuildConfig build_config Image image ImageStream image_stream ].each_slice(2) do |singular, plural| assert_equal(Kubeclient::ClientMixin.underscore_entity(singular), plural) end end end kubeclient-3.0.0/test/test_resource_list_without_kind.rb0000644000004100000410000000402013255124405023701 0ustar www-datawww-datarequire_relative 'test_helper' # Core api resource list without kind tests class TestResourceListWithoutKind < MiniTest::Test def test_get_from_json_api_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list_without_kind.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') client.discover [ { entity: 'pod', type: 'Pod', name: 'pods', methods: %w[pod pods] }, { entity: 'node', type: 'Node', name: 'nodes', methods: %w[node nodes] }, { entity: 'service', type: 'Service', name: 'services', methods: %w[service services] } ].each { |h| assert_entities(client.instance_variable_get(:@entities)[h[:entity]], h) } assert_requested(:get, 'http://localhost:8080/api/v1', times: 1) end def test_get_from_json_oapi_v1 stub_request(:get, %r{/oapi/v1$}) .to_return(body: open_test_file('core_oapi_resource_list_without_kind.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/oapi/', 'v1') client.discover [ { entity: 'template', type: 'Template', name: 'templates', methods: %w[template templates] }, { entity: 'build', type: 'Build', name: 'builds', methods: %w[build builds] }, { entity: 'project', type: 'Project', name: 'projects', methods: %w[project projects] } ].each { |h| assert_entities(client.instance_variable_get(:@entities)[h[:entity]], h) } assert_requested(:get, 'http://localhost:8080/oapi/v1', times: 1) end def assert_entities(entity, h) assert_equal(entity.entity_type, h[:type]) assert_equal(entity.resource_name, h[:name]) assert_equal(entity.method_names, h[:methods]) end end kubeclient-3.0.0/test/test_kubeclient.rb0000644000004100000410000007254313255124405020373 0ustar www-datawww-datarequire_relative 'test_helper' # Kubernetes client entity tests class KubeclientTest < MiniTest::Test def test_json our_object = Kubeclient::Resource.new our_object.foo = 'bar' our_object.nested = {} our_object.nested.again = {} our_object.nested.again.again = {} our_object.nested.again.again.name = 'aaron' expected = { 'foo' => 'bar', 'nested' => { 'again' => { 'again' => { 'name' => 'aaron' } } } } assert_equal(expected, JSON.parse(JSON.dump(our_object.to_h))) end def test_pass_uri # URI::Generic#hostname= was added in ruby 1.9.3 and will automatically # wrap an ipv6 address in [] uri = URI::HTTP.build(port: 8080) uri.hostname = 'localhost' client = Kubeclient::Client.new(uri) rest_client = client.rest_client assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s) end def test_no_path_in_uri client = Kubeclient::Client.new('http://localhost:8080', 'v1') rest_client = client.rest_client assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s) end def test_no_version_passed client = Kubeclient::Client.new('http://localhost:8080') rest_client = client.rest_client assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s) end def test_pass_proxy uri = URI::HTTP.build(host: 'localhost', port: 8080) proxy_uri = URI::HTTP.build(host: 'myproxyhost', port: 8888) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new(uri, http_proxy_uri: proxy_uri) rest_client = client.rest_client assert_equal(proxy_uri.to_s, rest_client.options[:proxy]) watch_client = client.watch_pods assert_equal(watch_client.send(:build_client_options)[:proxy][:proxy_address], proxy_uri.host) assert_equal(watch_client.send(:build_client_options)[:proxy][:proxy_port], proxy_uri.port) end def test_exception stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:post, %r{/services}) .to_return(body: open_test_file('namespace_exception.json'), status: 409) service = Kubeclient::Resource.new service.metadata = {} service.metadata.name = 'redisslave' service.metadata.namespace = 'default' # service.port = 80 # service.container_port = 6379 # service.protocol = 'TCP' client = Kubeclient::Client.new('http://localhost:8080/api/') exception = assert_raises(Kubeclient::HttpError) do service = client.create_service(service) end assert_instance_of(Kubeclient::HttpError, exception) assert_equal("converting to : type names don't match (Pod, Namespace)", exception.message) assert_includes(exception.to_s, ' for POST http://localhost:8080/api') assert_equal(409, exception.error_code) end def test_deprecated_exception error_message = 'certificate verify failed' stub_request(:get, 'http://localhost:8080/api') .to_raise(OpenSSL::SSL::SSLError.new(error_message)) client = Kubeclient::Client.new('http://localhost:8080/api/') exception = assert_raises(KubeException) { client.api } assert_equal(error_message, exception.message) end def test_api stub_request(:get, 'http://localhost:8080/api') .to_return(status: 200, body: open_test_file('versions_list.json')) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') response = client.api assert_includes(response, 'versions') end def test_api_ssl_failure error_message = 'certificate verify failed' stub_request(:get, 'http://localhost:8080/api') .to_raise(OpenSSL::SSL::SSLError.new(error_message)) client = Kubeclient::Client.new('http://localhost:8080/api/') exception = assert_raises(Kubeclient::HttpError) { client.api } assert_equal(error_message, exception.message) end def test_api_timeout stub_request(:get, 'http://localhost:8080/api').to_timeout client = Kubeclient::Client.new('http://localhost:8080/api/') exception = assert_raises(Kubeclient::HttpError) { client.api } assert_match(/(timed out|timeout)/i, exception.message) end def test_api_valid stub_request(:get, 'http://localhost:8080/api') .to_return(status: 200, body: open_test_file('versions_list.json')) args = ['http://localhost:8080/api/'] [nil, 'v1beta3', 'v1'].each do |version| client = Kubeclient::Client.new(*(version ? args + [version] : args)) assert client.api_valid? end end def test_api_valid_with_invalid_version stub_request(:get, 'http://localhost:8080/api') .to_return(status: 200, body: open_test_file('versions_list.json')) client = Kubeclient::Client.new('http://localhost:8080/api/', 'foobar1') refute client.api_valid? end def test_api_valid_with_unreported_versions stub_request(:get, 'http://localhost:8080/api') .to_return(status: 200, body: '{}') client = Kubeclient::Client.new('http://localhost:8080/api/') refute client.api_valid? end def test_api_valid_with_invalid_json stub_request(:get, 'http://localhost:8080/api') .to_return(status: 200, body: '[]') client = Kubeclient::Client.new('http://localhost:8080/api/') refute client.api_valid? end def test_api_valid_with_bad_endpoint stub_request(:get, 'http://localhost:8080/api') .to_return(status: [404, 'Resource Not Found']) client = Kubeclient::Client.new('http://localhost:8080/api/') assert_raises(Kubeclient::HttpError) { client.api_valid? } end def test_api_valid_with_non_json stub_request(:get, 'http://localhost:8080/api') .to_return(status: 200, body: '') client = Kubeclient::Client.new('http://localhost:8080/api/') assert_raises(JSON::ParserError) { client.api_valid? } end def test_nonjson_exception stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/servic}) .to_return(body: open_test_file('service_illegal_json_404.json'), status: 404) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') exception = assert_raises(Kubeclient::ResourceNotFoundError) do client.get_services end assert(exception.message.include?('Not Found')) assert_equal(404, exception.error_code) end def test_nonjson_exception_raw stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/servic}) .to_return(body: open_test_file('service_illegal_json_404.json'), status: 404) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') exception = assert_raises(Kubeclient::ResourceNotFoundError) do client.get_services(as: :raw) end assert(exception.message.include?('Not Found')) assert_equal(404, exception.error_code) end def test_entity_list stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/services}) .to_return(body: open_test_file('entity_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') services = client.get_services refute_empty(services) assert_instance_of(Kubeclient::Common::EntityList, services) assert_equal('Service', services.kind) assert_equal(2, services.size) assert_instance_of(Kubeclient::Resource, services[0]) assert_instance_of(Kubeclient::Resource, services[1]) assert_requested(:get, 'http://localhost:8080/api/v1/services', times: 1) end def test_entity_list_raw stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/services}) .to_return(body: open_test_file('entity_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') response = client.get_services(as: :raw) refute_empty(response) assert_equal(open_test_file('entity_list.json').read, response) assert_requested(:get, 'http://localhost:8080/api/v1/services', times: 1) end def test_entity_list_raw_failure stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/services}) .to_return(body: open_test_file('entity_list.json'), status: 500) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') exception = assert_raises(Kubeclient::HttpError) { client.get_services(as: :raw) } assert_equal('500 Internal Server Error', exception.message) assert_equal(500, exception.error_code) end def test_entities_with_label_selector selector = 'component=apiserver' stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/services}) .to_return(body: open_test_file('entity_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') services = client.get_services(label_selector: selector) assert_instance_of(Kubeclient::Common::EntityList, services) assert_requested( :get, "http://localhost:8080/api/v1/services?labelSelector=#{selector}", times: 1 ) end def test_entities_with_field_selector selector = 'involvedObject.name=redis-master' stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/services}) .to_return(body: open_test_file('entity_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') services = client.get_services(field_selector: selector) assert_instance_of(Kubeclient::Common::EntityList, services) assert_requested( :get, "http://localhost:8080/api/v1/services?fieldSelector=#{selector}", times: 1 ) end def test_empty_list stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/pods}) .to_return(body: open_test_file('empty_pod_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') pods = client.get_pods assert_instance_of(Kubeclient::Common::EntityList, pods) assert_equal(0, pods.size) end def test_get_all stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/bindings}) .to_return(body: open_test_file('bindings_list.json'), status: 404) stub_request(:get, %r{/configmaps}) .to_return(body: open_test_file('config_map_list.json'), status: 200) stub_request(:get, %r{/podtemplates}) .to_return(body: open_test_file('pod_template_list.json'), status: 200) stub_request(:get, %r{/services}) .to_return(body: open_test_file('service_list.json'), status: 200) stub_request(:get, %r{/pods}) .to_return(body: open_test_file('pod_list.json'), status: 200) stub_request(:get, %r{/nodes}) .to_return(body: open_test_file('node_list.json'), status: 200) stub_request(:get, %r{/replicationcontrollers}) .to_return(body: open_test_file('replication_controller_list.json'), status: 200) stub_request(:get, %r{/events}) .to_return(body: open_test_file('event_list.json'), status: 200) stub_request(:get, %r{/endpoints}) .to_return(body: open_test_file('endpoint_list.json'), status: 200) stub_request(:get, %r{/namespaces}) .to_return(body: open_test_file('namespace_list.json'), status: 200) stub_request(:get, %r{/secrets}) .to_return(body: open_test_file('secret_list.json'), status: 200) stub_request(:get, %r{/resourcequotas}) .to_return(body: open_test_file('resource_quota_list.json'), status: 200) stub_request(:get, %r{/limitranges}) .to_return(body: open_test_file('limit_range_list.json'), status: 200) stub_request(:get, %r{/persistentvolumes}) .to_return(body: open_test_file('persistent_volume_list.json'), status: 200) stub_request(:get, %r{/persistentvolumeclaims}) .to_return(body: open_test_file('persistent_volume_claim_list.json'), status: 200) stub_request(:get, %r{/componentstatuses}) .to_return(body: open_test_file('component_status_list.json'), status: 200) stub_request(:get, %r{/serviceaccounts}) .to_return(body: open_test_file('service_account_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') result = client.all_entities assert_equal(16, result.keys.size) assert_instance_of(Kubeclient::Common::EntityList, result['node']) assert_instance_of(Kubeclient::Common::EntityList, result['service']) assert_instance_of(Kubeclient::Common::EntityList, result['replication_controller']) assert_instance_of(Kubeclient::Common::EntityList, result['pod']) assert_instance_of(Kubeclient::Common::EntityList, result['event']) assert_instance_of(Kubeclient::Common::EntityList, result['namespace']) assert_instance_of(Kubeclient::Common::EntityList, result['secret']) assert_instance_of(Kubeclient::Resource, result['service'][0]) assert_instance_of(Kubeclient::Resource, result['node'][0]) assert_instance_of(Kubeclient::Resource, result['event'][0]) assert_instance_of(Kubeclient::Resource, result['endpoint'][0]) assert_instance_of(Kubeclient::Resource, result['namespace'][0]) assert_instance_of(Kubeclient::Resource, result['secret'][0]) assert_instance_of(Kubeclient::Resource, result['resource_quota'][0]) assert_instance_of(Kubeclient::Resource, result['limit_range'][0]) assert_instance_of(Kubeclient::Resource, result['persistent_volume'][0]) assert_instance_of(Kubeclient::Resource, result['persistent_volume_claim'][0]) assert_instance_of(Kubeclient::Resource, result['component_status'][0]) assert_instance_of(Kubeclient::Resource, result['service_account'][0]) end def test_get_all_raw stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/bindings}) .to_return(body: open_test_file('bindings_list.json'), status: 404) stub_request(:get, %r{/configmaps}) .to_return(body: open_test_file('config_map_list.json'), status: 200) stub_request(:get, %r{/podtemplates}) .to_return(body: open_test_file('pod_template_list.json'), status: 200) stub_request(:get, %r{/services}) .to_return(body: open_test_file('service_list.json'), status: 200) stub_request(:get, %r{/pods}) .to_return(body: open_test_file('pod_list.json'), status: 200) stub_request(:get, %r{/nodes}) .to_return(body: open_test_file('node_list.json'), status: 200) stub_request(:get, %r{/replicationcontrollers}) .to_return(body: open_test_file('replication_controller_list.json'), status: 200) stub_request(:get, %r{/events}) .to_return(body: open_test_file('event_list.json'), status: 200) stub_request(:get, %r{/endpoints}) .to_return(body: open_test_file('endpoint_list.json'), status: 200) stub_request(:get, %r{/namespaces}) .to_return(body: open_test_file('namespace_list.json'), status: 200) stub_request(:get, %r{/secrets}) .to_return(body: open_test_file('secret_list.json'), status: 200) stub_request(:get, %r{/resourcequotas}) .to_return(body: open_test_file('resource_quota_list.json'), status: 200) stub_request(:get, %r{/limitranges}) .to_return(body: open_test_file('limit_range_list.json'), status: 200) stub_request(:get, %r{/persistentvolumes}) .to_return(body: open_test_file('persistent_volume_list.json'), status: 200) stub_request(:get, %r{/persistentvolumeclaims}) .to_return(body: open_test_file('persistent_volume_claim_list.json'), status: 200) stub_request(:get, %r{/componentstatuses}) .to_return(body: open_test_file('component_status_list.json'), status: 200) stub_request(:get, %r{/serviceaccounts}) .to_return(body: open_test_file('service_account_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') result = client.all_entities(as: :raw) assert_equal(16, result.keys.size) %w[ component_status config_map endpoint event limit_range namespace node persistent_volume persistent_volume_claim pod replication_controller resource_quota secret service service_account ].each do |entity| assert_equal(open_test_file("#{entity}_list.json").read, result[entity]) end end def test_api_bearer_token_with_params_success stub_request(:get, 'http://localhost:8080/api/v1/pods?labelSelector=name=redis-master') .with(headers: { Authorization: 'Bearer valid_token' }) .to_return(body: open_test_file('pod_list.json'), status: 200) stub_request(:get, %r{/api/v1$}) .with(headers: { Authorization: 'Bearer valid_token' }) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { bearer_token: 'valid_token' } ) pods = client.get_pods(label_selector: 'name=redis-master') assert_equal('Pod', pods.kind) assert_equal(1, pods.size) end def test_api_bearer_token_success stub_request(:get, %r{/api/v1$}) .to_return( body: open_test_file('core_api_resource_list.json'), status: 200 ) stub_request(:get, 'http://localhost:8080/api/v1/pods') .with(headers: { Authorization: 'Bearer valid_token' }) .to_return( body: open_test_file('pod_list.json'), status: 200 ) client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { bearer_token: 'valid_token' } ) pods = client.get_pods assert_equal('Pod', pods.kind) assert_equal(1, pods.size) end def test_api_bearer_token_failure error_message = '"/api/v1" is forbidden because ' \ 'system:anonymous cannot list on pods in' response = OpenStruct.new(code: 401, message: error_message) stub_request(:get, 'http://localhost:8080/api/v1') .with(headers: { Authorization: 'Bearer invalid_token' }) .to_raise(Kubeclient::HttpError.new(403, error_message, response)) client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { bearer_token: 'invalid_token' } ) exception = assert_raises(Kubeclient::HttpError) { client.get_pods } assert_equal(403, exception.error_code) assert_equal(error_message, exception.message) assert_equal(response, exception.response) end def test_api_bearer_token_failure_raw error_message = '"/api/v1" is forbidden because ' \ 'system:anonymous cannot list on pods in' response = OpenStruct.new(code: 401, message: error_message) stub_request(:get, 'http://localhost:8080/api/v1') .with(headers: { Authorization: 'Bearer invalid_token' }) .to_raise(Kubeclient::HttpError.new(403, error_message, response)) client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { bearer_token: 'invalid_token' } ) exception = assert_raises(Kubeclient::HttpError) { client.get_pods(as: :raw) } assert_equal(403, exception.error_code) assert_equal(error_message, exception.message) assert_equal(response, exception.response) end def test_api_basic_auth_success stub_request(:get, 'http://localhost:8080/api/v1') .with(basic_auth: %w[username password]) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, 'http://localhost:8080/api/v1/pods') .with(basic_auth: %w[username password]) .to_return(body: open_test_file('pod_list.json'), status: 200) client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { username: 'username', password: 'password' } ) pods = client.get_pods assert_equal('Pod', pods.kind) assert_equal(1, pods.size) assert_requested( :get, 'http://localhost:8080/api/v1/pods', times: 1 ) end def test_api_basic_auth_back_comp_success stub_request(:get, 'http://localhost:8080/api/v1') .with(basic_auth: %w[username password]) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, 'http://localhost:8080/api/v1/pods') .with(basic_auth: %w[username password]) .to_return(body: open_test_file('pod_list.json'), status: 200) client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { user: 'username', password: 'password' } ) pods = client.get_pods assert_equal('Pod', pods.kind) assert_equal(1, pods.size) assert_requested(:get, 'http://localhost:8080/api/v1/pods', times: 1) end def test_api_basic_auth_failure error_message = 'HTTP status code 401, 401 Unauthorized' response = OpenStruct.new(code: 401, message: '401 Unauthorized') stub_request(:get, 'http://localhost:8080/api/v1') .with(basic_auth: %w[username password]) .to_raise(Kubeclient::HttpError.new(401, error_message, response)) client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { username: 'username', password: 'password' } ) exception = assert_raises(Kubeclient::HttpError) { client.get_pods } assert_equal(401, exception.error_code) assert_equal(error_message, exception.message) assert_equal(response, exception.response) assert_requested(:get, 'http://localhost:8080/api/v1', times: 1) end def test_api_basic_auth_failure_raw error_message = 'HTTP status code 401, 401 Unauthorized' response = OpenStruct.new(code: 401, message: '401 Unauthorized') stub_request(:get, 'http://localhost:8080/api/v1') .with(basic_auth: %w[username password]) .to_raise(Kubeclient::HttpError.new(401, error_message, response)) client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { username: 'username', password: 'password' } ) exception = assert_raises(Kubeclient::HttpError) { client.get_pods(as: :raw) } assert_equal(401, exception.error_code) assert_equal(error_message, exception.message) assert_equal(response, exception.response) assert_requested(:get, 'http://localhost:8080/api/v1', times: 1) end def test_init_username_no_password expected_msg = 'Basic auth requires both username & password' exception = assert_raises(ArgumentError) do Kubeclient::Client.new( 'http://localhost:8080', auth_options: { username: 'username' } ) end assert_equal(expected_msg, exception.message) end def test_init_user_no_password expected_msg = 'Basic auth requires both username & password' exception = assert_raises(ArgumentError) do Kubeclient::Client.new( 'http://localhost:8080', auth_options: { user: 'username' } ) end assert_equal(expected_msg, exception.message) end def test_init_username_and_bearer_token expected_msg = 'Invalid auth options: specify only one of username/password,' \ ' bearer_token or bearer_token_file' exception = assert_raises(ArgumentError) do Kubeclient::Client.new( 'http://localhost:8080', auth_options: { username: 'username', bearer_token: 'token' } ) end assert_equal(expected_msg, exception.message) end def test_init_user_and_bearer_token expected_msg = 'Invalid auth options: specify only one of username/password,' \ ' bearer_token or bearer_token_file' exception = assert_raises(ArgumentError) do Kubeclient::Client.new( 'http://localhost:8080', auth_options: { username: 'username', bearer_token: 'token' } ) end assert_equal(expected_msg, exception.message) end def test_bearer_token_and_bearer_token_file expected_msg = 'Invalid auth options: specify only one of username/password,' \ ' bearer_token or bearer_token_file' exception = assert_raises(ArgumentError) do Kubeclient::Client.new( 'http://localhost:8080', auth_options: { bearer_token: 'token', bearer_token_file: 'token-file' } ) end assert_equal(expected_msg, exception.message) end def test_bearer_token_file_not_exist expected_msg = 'Token file token-file does not exist' exception = assert_raises(ArgumentError) do Kubeclient::Client.new( 'http://localhost:8080', auth_options: { bearer_token_file: 'token-file' } ) end assert_equal(expected_msg, exception.message) end def test_api_bearer_token_file_success stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, 'http://localhost:8080/api/v1/pods') .with(headers: { Authorization: 'Bearer valid_token' }) .to_return(body: open_test_file('pod_list.json'), status: 200) file = File.join(File.dirname(__FILE__), 'valid_token_file') client = Kubeclient::Client.new( 'http://localhost:8080/api/', auth_options: { bearer_token_file: file } ) pods = client.get_pods assert_equal('Pod', pods.kind) assert_equal(1, pods.size) end def test_proxy_url stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://host:8080', 'v1') assert_equal( 'http://host:8080/api/v1/proxy/namespaces/ns/services/srvname:srvportname', client.proxy_url('service', 'srvname', 'srvportname', 'ns') ) assert_equal( 'http://host:8080/api/v1/proxy/namespaces/ns/services/srvname:srvportname', client.proxy_url('services', 'srvname', 'srvportname', 'ns') ) assert_equal( 'http://host:8080/api/v1/namespaces/ns/pods/srvname:srvportname/proxy', client.proxy_url('pod', 'srvname', 'srvportname', 'ns') ) assert_equal( 'http://host:8080/api/v1/namespaces/ns/pods/srvname:srvportname/proxy', client.proxy_url('pods', 'srvname', 'srvportname', 'ns') ) # Check no namespace provided assert_equal( 'http://host:8080/api/v1/proxy/nodes/srvname:srvportname', client.proxy_url('nodes', 'srvname', 'srvportname') ) assert_equal( 'http://host:8080/api/v1/proxy/nodes/srvname:srvportname', client.proxy_url('node', 'srvname', 'srvportname') ) # Check integer port assert_equal( 'http://host:8080/api/v1/proxy/nodes/srvname:5001', client.proxy_url('nodes', 'srvname', 5001) ) assert_equal( 'http://host:8080/api/v1/proxy/nodes/srvname:5001', client.proxy_url('node', 'srvname', 5001) ) end def test_attr_readers client = Kubeclient::Client.new( 'http://localhost:8080/api/', ssl_options: { client_key: 'secret' }, auth_options: { bearer_token: 'token' } ) assert_equal('/api', client.api_endpoint.path) assert_equal('secret', client.ssl_options[:client_key]) assert_equal('token', client.auth_options[:bearer_token]) assert_equal('Bearer token', client.headers[:Authorization]) end def test_nil_items # handle https://github.com/kubernetes/kubernetes/issues/13096 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/persistentvolumeclaims}) .to_return(body: open_test_file('persistent_volume_claims_nil_items.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') client.get_persistent_volume_claims end # Timeouts def test_timeouts_defaults client = Kubeclient::Client.new( 'http://localhost:8080/api/' ) rest_client = client.rest_client assert_default_open_timeout(rest_client.open_timeout) assert_equal(60, rest_client.read_timeout) end def test_timeouts_open client = Kubeclient::Client.new( 'http://localhost:8080/api/', timeouts: { open: 10 } ) rest_client = client.rest_client assert_equal(10, rest_client.open_timeout) assert_equal(60, rest_client.read_timeout) end def test_timeouts_read client = Kubeclient::Client.new( 'http://localhost:8080/api/', timeouts: { read: 300 } ) rest_client = client.rest_client assert_default_open_timeout(rest_client.open_timeout) assert_equal(300, rest_client.read_timeout) end def test_timeouts_both client = Kubeclient::Client.new( 'http://localhost:8080/api/', timeouts: { open: 10, read: 300 } ) rest_client = client.rest_client assert_equal(10, rest_client.open_timeout) assert_equal(300, rest_client.read_timeout) end def test_timeouts_infinite client = Kubeclient::Client.new( 'http://localhost:8080/api/', timeouts: { open: nil, read: nil } ) rest_client = client.rest_client assert_nil(rest_client.open_timeout) assert_nil(rest_client.read_timeout) end def assert_default_open_timeout(actual) if RUBY_VERSION >= '2.3' assert_equal(60, actual) else assert_nil(actual) end end private # dup method creates a shallow copy which is not good in this case # since rename_keys changes the input hash # hence need to create a deep_copy def deep_copy(hash) Marshal.load(Marshal.dump(hash)) end end kubeclient-3.0.0/test/valid_token_file0000644000004100000410000000001413255124405020063 0ustar www-datawww-datavalid_token kubeclient-3.0.0/test/test_pod.rb0000644000004100000410000000154513255124405017022 0ustar www-datawww-datarequire_relative 'test_helper' # Pod entity tests class TestPod < MiniTest::Test def test_get_from_json_v1 stub_request(:get, %r{/pods}) .to_return(body: open_test_file('pod.json'), status: 200) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') pod = client.get_pod('redis-master-pod', 'default') assert_instance_of(Kubeclient::Resource, pod) assert_equal('redis-master3', pod.metadata.name) assert_equal('dockerfile/redis', pod.spec.containers[0]['image']) assert_requested( :get, 'http://localhost:8080/api/v1', times: 1 ) assert_requested( :get, 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod', times: 1 ) end end kubeclient-3.0.0/test/cassettes/0000755000004100000410000000000013255124405016645 5ustar www-datawww-datakubeclient-3.0.0/test/cassettes/kubernetes_guestbook.yml0000644000004100000410000010072013255124405023621 0ustar www-datawww-data--- http_interactions: - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 404 message: Not Found headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '253' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "namespaces \"kubeclient-ns\" not found", "reason": "NotFound", "details": { "name": "kubeclient-ns", "kind": "namespaces" }, "code": 404 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/guestbook body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 404 message: Not Found headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '239' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "service \"guestbook\" not found", "reason": "NotFound", "details": { "name": "guestbook", "kind": "service" }, "code": 404 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-master body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 404 message: Not Found headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '245' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "service \"redis-master\" not found", "reason": "NotFound", "details": { "name": "redis-master", "kind": "service" }, "code": 404 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-slave body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 404 message: Not Found headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '243' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "service \"redis-slave\" not found", "reason": "NotFound", "details": { "name": "redis-slave", "kind": "service" }, "code": 404 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 404 message: Not Found headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '269' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "replicationControllers \"guestbook\" not found", "reason": "NotFound", "details": { "name": "guestbook", "kind": "replicationControllers" }, "code": 404 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 404 message: Not Found headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '275' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "replicationControllers \"redis-master\" not found", "reason": "NotFound", "details": { "name": "redis-master", "kind": "replicationControllers" }, "code": 404 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 404 message: Not Found headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '273' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "replicationControllers \"redis-slave\" not found", "reason": "NotFound", "details": { "name": "redis-slave", "kind": "replicationControllers" }, "code": 404 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: post uri: http://10.35.0.23:8080/api/v1/namespaces body: encoding: UTF-8 string: '{"metadata":{"name":"kubeclient-ns"},"kind":"Namespace","apiVersion":"v1"}' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate Content-Length: - '74' User-Agent: - Ruby response: status: code: 201 message: Created headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '297' body: encoding: UTF-8 string: '{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"534","creationTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: post uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services body: encoding: UTF-8 string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"name":"guestbook"},"name":"guestbook"},"spec":{"selector":{"app":"guestbook"},"ports":[{"port":3000,"targetPort":"http-server"}]},"type":"LoadBalancer","kind":"Service","apiVersion":"v1"}' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate Content-Length: - '239' User-Agent: - Ruby response: status: code: 201 message: Created headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '521' body: encoding: UTF-8 string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/guestbook","uid":"f42187e1-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"538","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"name":"guestbook"}},"spec":{"ports":[{"protocol":"TCP","port":3000,"targetPort":"http-server","nodePort":0}],"selector":{"app":"guestbook"},"clusterIP":"10.0.0.80","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: post uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services body: encoding: UTF-8 string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"master"},"name":"redis-master"},"spec":{"selector":{"app":"redis","role":"master"},"ports":[{"port":6379,"targetPort":"redis-server"}]},"kind":"Service","apiVersion":"v1"}' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate Content-Length: - '244' User-Agent: - Ruby response: status: code: 201 message: Created headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '552' body: encoding: UTF-8 string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-master","uid":"f423bf8b-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"542","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"master"},"clusterIP":"10.0.0.140","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: post uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services body: encoding: UTF-8 string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"slave"},"name":"redis-slave"},"spec":{"selector":{"app":"redis","role":"slave"},"ports":[{"port":6379,"targetPort":"redis-server"}]},"kind":"Service","apiVersion":"v1"}' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate Content-Length: - '241' User-Agent: - Ruby response: status: code: 201 message: Created headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '548' body: encoding: UTF-8 string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-slave","uid":"f4264678-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"545","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"slave"},"clusterIP":"10.0.0.154","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: post uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers body: encoding: UTF-8 string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"guestbook","role":"slave"},"name":"guestbook"},"spec":{"selector":{"app":"guestbook"},"template":{"metadata":{"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000}]}]}},"replicas":3},"kind":"ReplicationController","apiVersion":"v1"}' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate Content-Length: - '395' User-Agent: - Ruby response: status: code: 201 message: Created headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '815' body: encoding: UTF-8 string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook","uid":"f4287784-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"547","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"guestbook","role":"slave"}},"spec":{"replicas":3,"selector":{"app":"guestbook"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: post uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers body: encoding: UTF-8 string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"master"},"name":"redis-master"},"spec":{"selector":{"app":"redis","role":"master"},"template":{"metadata":{"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379}]}]}},"replicas":1},"kind":"ReplicationController","apiVersion":"v1"}' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate Content-Length: - '405' User-Agent: - Ruby response: status: code: 201 message: Created headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '828' body: encoding: UTF-8 string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master","uid":"f42a9800-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"558","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"replicas":1,"selector":{"app":"redis","role":"master"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: post uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers body: encoding: UTF-8 string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"slave"},"name":"redis-slave"},"spec":{"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379}]}]}},"replicas":2},"kind":"ReplicationController","apiVersion":"v1"}' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate Content-Length: - '420' User-Agent: - Ruby response: status: code: 201 message: Created headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '842' body: encoding: UTF-8 string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave","uid":"f42e1d09-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"567","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"replicas":2,"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: get uri: http://10.35.0.23:8080/api/v1/namespaces body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '629' body: encoding: UTF-8 string: '{"kind":"NamespaceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces","resourceVersion":"570"},"items":[{"metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"37360c82-3e77-11e5-a75a-18037327aaeb","resourceVersion":"6","creationTimestamp":"2015-08-09T09:15:45Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"534","creationTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}]}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: get uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '1661' body: encoding: UTF-8 string: '{"kind":"ServiceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces/kubeclient-ns/services","resourceVersion":"571"},"items":[{"metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/guestbook","uid":"f42187e1-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"538","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"name":"guestbook"}},"spec":{"ports":[{"protocol":"TCP","port":3000,"targetPort":"http-server","nodePort":0}],"selector":{"app":"guestbook"},"clusterIP":"10.0.0.80","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}},{"metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-master","uid":"f423bf8b-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"542","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"master"},"clusterIP":"10.0.0.140","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}},{"metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-slave","uid":"f4264678-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"545","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"slave"},"clusterIP":"10.0.0.154","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}]}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: get uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Transfer-Encoding: - chunked body: encoding: UTF-8 string: '{"kind":"ReplicationControllerList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers","resourceVersion":"571"},"items":[{"metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook","uid":"f4287784-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"557","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"guestbook","role":"slave"}},"spec":{"replicas":3,"selector":{"app":"guestbook"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":3,"observedGeneration":1}},{"metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master","uid":"f42a9800-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"565","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"replicas":1,"selector":{"app":"redis","role":"master"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0,"observedGeneration":1}},{"metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave","uid":"f42e1d09-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"567","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"replicas":2,"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}]}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/guestbook body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '100' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Success", "code": 200 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-master body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '100' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Success", "code": 200 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-slave body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '100' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Success", "code": 200 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '100' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Success", "code": 200 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '100' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Success", "code": 200 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '100' body: encoding: UTF-8 string: |- { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Success", "code": 200 } http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: delete uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns body: encoding: US-ASCII string: '' headers: Accept: - '*/*; q=0.5, application/xml' Accept-Encoding: - gzip, deflate User-Agent: - Ruby response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Sun, 09 Aug 2015 10:03:59 GMT Content-Length: - '345' body: encoding: UTF-8 string: '{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"584","creationTimestamp":"2015-08-09T10:03:59Z","deletionTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Terminating"}}' http_version: recorded_at: Sun, 09 Aug 2015 10:00:02 GMT - request: method: get uri: http://10.35.0.23:8080/api/v1 body: encoding: US-ASCII string: '' headers: Accept: - "*/*" Accept-Encoding: - gzip, deflate User-Agent: - rest-client/2.0.0 (linux-gnu x86_64) ruby/2.3.0p0 Host: - localhost:8080 response: status: code: 200 message: OK headers: Content-Type: - application/json Date: - Mon, 29 Aug 2016 15:51:30 GMT Transfer-Encoding: - chunked body: encoding: UTF-8 string: '{"kind":"APIResourceList","groupVersion":"v1","resources":[{"name":"bindings","namespaced":true,"kind":"Binding"},{"name":"componentstatuses","namespaced":false,"kind":"ComponentStatus"},{"name":"configmaps","namespaced":true,"kind":"ConfigMap"},{"name":"endpoints","namespaced":true,"kind":"Endpoints"},{"name":"events","namespaced":true,"kind":"Event"},{"name":"limitranges","namespaced":true,"kind":"LimitRange"},{"name":"namespaces","namespaced":false,"kind":"Namespace"},{"name":"namespaces/finalize","namespaced":false,"kind":"Namespace"},{"name":"namespaces/status","namespaced":false,"kind":"Namespace"},{"name":"nodes","namespaced":false,"kind":"Node"},{"name":"nodes/proxy","namespaced":false,"kind":"Node"},{"name":"nodes/status","namespaced":false,"kind":"Node"},{"name":"persistentvolumeclaims","namespaced":true,"kind":"PersistentVolumeClaim"},{"name":"persistentvolumeclaims/status","namespaced":true,"kind":"PersistentVolumeClaim"},{"name":"persistentvolumes","namespaced":false,"kind":"PersistentVolume"},{"name":"persistentvolumes/status","namespaced":false,"kind":"PersistentVolume"},{"name":"pods","namespaced":true,"kind":"Pod"},{"name":"pods/attach","namespaced":true,"kind":"Pod"},{"name":"pods/binding","namespaced":true,"kind":"Binding"},{"name":"pods/exec","namespaced":true,"kind":"Pod"},{"name":"pods/log","namespaced":true,"kind":"Pod"},{"name":"pods/portforward","namespaced":true,"kind":"Pod"},{"name":"pods/proxy","namespaced":true,"kind":"Pod"},{"name":"pods/status","namespaced":true,"kind":"Pod"},{"name":"podtemplates","namespaced":true,"kind":"PodTemplate"},{"name":"replicationcontrollers","namespaced":true,"kind":"ReplicationController"},{"name":"replicationcontrollers/scale","namespaced":true,"kind":"Scale"},{"name":"replicationcontrollers/status","namespaced":true,"kind":"ReplicationController"},{"name":"resourcequotas","namespaced":true,"kind":"ResourceQuota"},{"name":"resourcequotas/status","namespaced":true,"kind":"ResourceQuota"},{"name":"secrets","namespaced":true,"kind":"Secret"},{"name":"serviceaccounts","namespaced":true,"kind":"ServiceAccount"},{"name":"services","namespaced":true,"kind":"Service"},{"name":"services/proxy","namespaced":true,"kind":"Service"},{"name":"services/status","namespaced":true,"kind":"Service"}]} ' http_version: recorded_at: Mon, 29 Aug 2016 15:51:30 GMT recorded_with: VCR 3.0.3 kubeclient-3.0.0/test/test_persistent_volume.rb0000644000004100000410000000165213255124405022026 0ustar www-datawww-datarequire_relative 'test_helper' # PersistentVolume tests class TestPersistentVolume < MiniTest::Test def test_get_from_json_v1 stub_request(:get, %r{/persistentvolumes}) .to_return(body: open_test_file('persistent_volume.json'), status: 200) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') volume = client.get_persistent_volume('pv0001') assert_instance_of(Kubeclient::Resource, volume) assert_equal('pv0001', volume.metadata.name) assert_equal('10Gi', volume.spec.capacity.storage) assert_equal('/tmp/data01', volume.spec.hostPath.path) assert_requested( :get, 'http://localhost:8080/api/v1', times: 1 ) assert_requested( :get, 'http://localhost:8080/api/v1/persistentvolumes/pv0001', times: 1 ) end end kubeclient-3.0.0/test/test_component_status.rb0000644000004100000410000000176113255124405021645 0ustar www-datawww-datarequire_relative 'test_helper' # ComponentStatus tests class TestComponentStatus < MiniTest::Test def test_get_from_json_v3 stub_request(:get, %r{/componentstatuses}) .to_return(body: open_test_file('component_status.json'), status: 200) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') component_status = client.get_component_status('etcd-0', 'default') assert_instance_of(Kubeclient::Resource, component_status) assert_equal('etcd-0', component_status.metadata.name) assert_equal('Healthy', component_status.conditions[0].type) assert_equal('True', component_status.conditions[0].status) assert_requested( :get, 'http://localhost:8080/api/v1', times: 1 ) assert_requested( :get, 'http://localhost:8080/api/v1/namespaces/default/componentstatuses/etcd-0', times: 1 ) end end kubeclient-3.0.0/test/test_helper.rb0000644000004100000410000000060413255124405017512 0ustar www-datawww-datarequire 'bundler/setup' require 'minitest/autorun' require 'minitest/rg' require 'webmock/minitest' require 'json' require 'kubeclient' # Assumes test files will be in a subdirectory with the same name as the # file suffix. e.g. a file named foo.json would be a "json" subdirectory. def open_test_file(name) File.new(File.join(File.dirname(__FILE__), name.split('.').last, name)) end kubeclient-3.0.0/test/config/0000755000004100000410000000000013255124405016114 5ustar www-datawww-datakubeclient-3.0.0/test/config/userauth.kubeconfig0000644000004100000410000000120613255124405022011 0ustar www-datawww-dataapiVersion: v1 clusters: - cluster: server: https://localhost:8443 insecure-skip-tls-verify: true name: localhost:8443 contexts: - context: cluster: localhost:8443 namespace: default user: system:admin:token name: localhost/system:admin:token - context: cluster: localhost:8443 namespace: default user: system:admin:userpass name: localhost/system:admin:userpass current-context: localhost/system:admin:token kind: Config preferences: {} users: - name: system:admin:token user: token: 0123456789ABCDEF0123456789ABCDEF - name: system:admin:userpass user: username: admin password: pAssw0rd123 kubeclient-3.0.0/test/config/allinone.kubeconfig0000644000004100000410000001276613255124405021767 0ustar www-datawww-dataapiVersion: v1 clusters: - cluster: certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM2akNDQWRLZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREFtTVNRd0lnWURWUVFEREJ0dmNHVnUKYzJocFpuUXRjMmxuYm1WeVFERTBOemd3TURFNE1ERXdIaGNOTVRZeE1UQXhNVEl3TXpJd1doY05NakV4TURNeApNVEl3TXpJeFdqQW1NU1F3SWdZRFZRUUREQnR2Y0dWdWMyaHBablF0YzJsbmJtVnlRREUwTnpnd01ERTRNREV3CmdnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUUNzNHdCTEFQQnNaU2Q0Q3JBWFV3eFUKczJ1cGdwb1IrWS8vN2hWLzVaUzRBYjdCQnFGYk90ZDVnN3lnY2hSQXBkNTdMcjZhL0JDRTVZOHFGeE56WUVncwpOT05LcVlaWUNSVk9tNnRGUUkrUGxVNEdWM2dTa2sxOUZDTDQySFI2SjRDZTlPaHgxcjlBWDRpRFJPb01EbVhtCnI5MnZ1NDBSNUdJdnhRV3crMkMvcmh3aTB4MjdYODg2VzI2djM4RUtOUWZYRlhLS1BWRnBLOTFySWZISmM3b1AKNTZWVWRXSURKSjlIMW0zeHpENis1Sk96WWVxMFpYVzRzclZVNW41MGZOanU4SEZRNjVKNEZuWG9ZeXcxWjV3MwpqRGVtYW9LbjdITFpxbnJjR0thejY5WDdPTitrWlUxUy9nblRuWFFkSFVvb0VMblpnTTlJWjhMWndabGFQWHJKCkFnTUJBQUdqSXpBaE1BNEdBMVVkRHdFQi93UUVBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUcKU0liM0RRRUJDd1VBQTRJQkFRQlB1N2hkTmNoaWdxN2Y2eWFKcE1FZWRRS1hPOGdDMWJGb0JmTUVZcWZ4WHpjQgpITmpUZjkvdWpqYTlKK2hsRWdlNUJpTElnVDV5a3huOHdOelorNER6N1hkaEFzOEViRmpORUtocXFZd1dBWEo1CnFHa1BJbmdyYy80N3R2YkFFaEJoKzNOV0Z3ZEZkbzZkVFBIRTdXVTQ4MUhtLzQ5Lzg3Q3Z5dnVRSmZGVUJ1bEIKdjcxSFVzMHd2SFZURVBLK3pHdFBYVzdJV2NNdmdiczNOYTFwMkRKTmJGRTFSamEvWUxpZjZJSnZFQ0xkZ1d5YgpRSHZpZFc3Z2l0VktncmJsdEhNOXRhTkYxVVB5b0xlTDF2TWdMaDRoVDc5eFhLL2VOOTVMelB3QTBOUnlKdGxLCmRXb0xJZTVSZkZ4NlRLQlhUcGRDQUNXbWQ5V1JSWksyc0Z2RjROTWMKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= server: https://localhost:8443 name: localhost:8443 contexts: - context: cluster: localhost:8443 namespace: default user: system:admin/localhost:8443 name: default/localhost:8443/system:admin current-context: default/localhost:8443/system:admin kind: Config preferences: {} users: - name: system:admin/localhost:8443 user: client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lCQ0RBTkJna3Foa2lHOXcwQkFRc0ZBREFtTVNRd0lnWURWUVFEREJ0dmNHVnUKYzJocFpuUXRjMmxuYm1WeVFERTBOemd3TURFNE1ERXdIaGNOTVRZeE1UQXhNVEl3TXpJeFdoY05NVGd4TVRBeApNVEl3TXpJeVdqQTNNUjR3SEFZRFZRUUtFeFZ6ZVhOMFpXMDZZMngxYzNSbGNpMWhaRzFwYm5NeEZUQVRCZ05WCkJBTVRESE41YzNSbGJUcGhaRzFwYmpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUIKQU5ta2FudldoODR1dWNHOTJPdkE4KzJ1NUYxNnA1ay9wNG0rRzhRcCtKMDhZaElzU1NLb3EzWlp0RlhkRCtmeQozNFBpTW91c05PbEE4QTVtQ2FJMy9xTWhaNXhGd1E4L0ZHZTYxMG5sMENyYVN5VXFRdDFneEZsVjIwVHJPNG9GCks2STlXTFdNUHIySm5FcHNQRWtoWU9rSDIrNjF5bVVLeDdQMEdMUnVaMDNHVVhUQnBFOXJ2S3lsb01QRHkyK3UKenNmWG45bi9iWE1nV21Cbk0zZ1BTeElEQUxKUSs3WEhnYkFUMllxR002SWJHQ0tMQk5lWVprYk1FbitXd3NudgpScVpMQ3BOaDkxUjJIM0ZZLzhPV1p3L0pHQmVMbElRbndxdGpJeWczRWpzUGdHUlhGZFBqNWR1Tno2aTlEN1FoCks4S2JDaXNKNDRKWUM5UWUxS205T3I4Q0F3RUFBYU0xTURNd0RnWURWUjBQQVFIL0JBUURBZ1dnTUJNR0ExVWQKSlFRTU1Bb0dDQ3NHQVFVRkJ3TUNNQXdHQTFVZEV3RUIvd1FDTUFBd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnpuSWNOT2dmQkZvMUdtcnR2U01EL2lSMUZiNnkrMXZhVTBKQVBxRzFEQ0xtMHBBbnF1TWJLUVFkTDBRSkI5Ck40aHZVWjlRcHFsYVltVlk4KzFLbXdacFRvRjlpUTVqQUVidmFUWlhYTDQ3akxwS2tJcWlZUjlZcWNCQ2pQbDMKOXBFWExwc0tOeldKWVRyNkhVZzVGZ0drQkVScFdIVkh4ZDkzR2tKTUZlU0hBQ2lFNFBqTHY1YUNUQzF5TlRhYwp1RmhQeEwzcjFqQmliQSt0azN0djhSVFQ0MW9sV2pwZ2grTUJXWVBxNEhwcThtbFdBUVVWUFJudjN3TlBDazV1CjkwY1l5bytEZjBUWDFUQkxVYWtIKzFYZzJZWFZWWTFpb2dFVzVlZXh5VHNRMXllQzBJUisyNTBzMzg2bm9DS28KTDJudS9SWDBmd1doZDIzc3I4ZmY2Skk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBMmFScWU5YUh6aTY1d2IzWTY4RHo3YTdrWFhxbm1UK25pYjRieENuNG5UeGlFaXhKCklxaXJkbG0wVmQwUDUvTGZnK0l5aTZ3MDZVRHdEbVlKb2pmK295Rm5uRVhCRHo4VVo3clhTZVhRS3RwTEpTcEMKM1dERVdWWGJST3M3aWdVcm9qMVl0WXcrdlltY1NtdzhTU0ZnNlFmYjdyWEtaUXJIcy9RWXRHNW5UY1pSZE1HawpUMnU4cktXZ3c4UExiNjdPeDllZjJmOXRjeUJhWUdjemVBOUxFZ01Bc2xEN3RjZUJzQlBaaW9Zem9oc1lJb3NFCjE1aG1Sc3dTZjViQ3llOUdwa3NLazJIM1ZIWWZjVmovdzVabkQ4a1lGNHVVaENmQ3EyTWpLRGNTT3crQVpGY1YKMCtQbDI0M1BxTDBQdENFcndwc0tLd25qZ2xnTDFCN1VxYjA2dndJREFRQUJBb0lCQURhVVA4dnNnY1FYL2FkegpaNW0vbXF4cFpvVjJ3OTd2a3FFOVZwTTcvMGZYSTdUdy9Dby82RGZXeVIyYlFXam1oRno3ZGJlSEtRR3hza0c2Ckh3SmFUblkwWTFwU045Y045NTBId3dPYUtUa0Y0MEJmdDhMeWlHcnEyQUVSaUszVkhCc2tqVUdCK1IzcEM1T3kKVHUvNytlU1dmdlgvQ3RHS0FZakVWd213Z2lHRGV2aFhaYk45QWZkTFc3dUcvRFFtaW43QzFPVW9kQVExZmNxYwpTUXBLZXJlMTZRT1U5cWgxWExJL0NOZ2YyL0thTW5qM29kN0VXby9EVmpoZlN2dlpoeGJxVGgxdmRqMU9nSFBkCmVxTWIzdEp6T2dCcUFySlFzTCs0cThRUVI4Mk0zbUIvd0orczJIczlOTmtXaGg0bjBwN2VjWXc1UE05QTVEZWsKclNTUzlkRUNnWUVBNjlqMlBVcDFqNXo5RFpMM3ZmQW9PZ1A0emNicWVVYTUra0lSQXpTQ3JQRGU5RDBub0wrVwpwWllydHR1U0Q2VHd4QUl4S2hVWnVPanVNNnY2Qlp5b1ZRbm5JazZZNWd0OXZnQmQ1QTRHSjZQU0MyODlNSXRGCnhzb2dXdExzY2ZsT0lUazlrckxaRzExNExnZFUvZXMrYmRVbmJVbXNjWFZYRWM3cy9aUFowQ2NDZ1lFQTdEMDUKUzBlR1RHVjY0MzFFUHN1eTV0MDlUQ25WYmhpWUlIaWw2aUVoOXhWKzBUcGtSd3hmR3FHbEM4aVE2c1Rxa3FIaQpOcitZRjh5V0RDQ3RScE0zcWdlbzJUWFNydXhIUjRnbzZUTjE1TEw2UkVscDlZK1FYS3A4d0REWGZJcmtaNHIwCm5BdDZHU3NOREI5ZU5OSS9oT1FpeDZDaDQyQzdjNG80UXRNSVI2a0NnWUFrM0lVbjhUSk1udW5DTEYxQ04zM2kKQzJyZ3BwMVJGU2ZPSUhOT1ArL0luZUVLNVdBRE5NNlQxTlBDUWJFamR0RVdvWTBUbWJhcWV1VjMrQUljekc1VwoxRFJtM1VmeWRJdFRuZlVPeHM1WmRiWkhpVHhVRVFCMzRIR01JSGxLR3dBR0cwOHZWWHF2VnoySVhDY0JoTG4rCktwbDk4RXplY3N1SUFnSnlZNkJnY3dLQmdHejRHTE9HdklZRTBWaVo4WjdkcXhvZXR5V29ybEJvZTlPT2swbWEKR3VhMFBaa1pUQ1FScXRUSDl5K21SbUpranFjd2tQNGNCbllENHJxWllCUUwyRU5QNFN6QVRQeHU5TG9rTG1yVApWL0EwTm9qRkxHRWU1Y0k0eWU2RkdRRFR1R09panc1anBPQnpJVU9VUElvMDZTUE5iOVdSWE50YlJWd1lSN2RiClRKaHhBb0dBR3V1MWY3NmtUeDFvSFdvT2pPazNiSmNSeVdtOVFkUVZFQjZTMlpyc0hCUnpmaW5nRGVESzlsaVQKUlpRUVMzdFpKR05ocXZiaENwdVZzbVdQSnJaMHQ0elBZckhNcEkwczR2ZVRnSmVTQXlaSXFUZ1NvSG03S0E0cQpnUFFUOTZQQkxvWWZCMEt1S0FCcU5OVkc3Y3o0bEJ6MHdOTXl1WitVdHI3R3B4V0I0ZWM9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== kubeclient-3.0.0/test/config/external-cert.pem0000644000004100000410000000213713255124405021377 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIDDTCCAfWgAwIBAgIBCDANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu c2hpZnQtc2lnbmVyQDE0NzgwMDE4MDEwHhcNMTYxMTAxMTIwMzIxWhcNMTgxMTAx MTIwMzIyWjA3MR4wHAYDVQQKExVzeXN0ZW06Y2x1c3Rlci1hZG1pbnMxFTATBgNV BAMTDHN5c3RlbTphZG1pbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANmkanvWh84uucG92OvA8+2u5F16p5k/p4m+G8Qp+J08YhIsSSKoq3ZZtFXdD+fy 34PiMousNOlA8A5mCaI3/qMhZ5xFwQ8/FGe610nl0CraSyUqQt1gxFlV20TrO4oF K6I9WLWMPr2JnEpsPEkhYOkH2+61ymUKx7P0GLRuZ03GUXTBpE9rvKyloMPDy2+u zsfXn9n/bXMgWmBnM3gPSxIDALJQ+7XHgbAT2YqGM6IbGCKLBNeYZkbMEn+Wwsnv RqZLCpNh91R2H3FY/8OWZw/JGBeLlIQnwqtjIyg3EjsPgGRXFdPj5duNz6i9D7Qh K8KbCisJ44JYC9Qe1Km9Or8CAwEAAaM1MDMwDgYDVR0PAQH/BAQDAgWgMBMGA1Ud JQQMMAoGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEB AFznIcNOgfBFo1GmrtvSMD/iR1Fb6y+1vaU0JAPqG1DCLm0pAnquMbKQQdL0QJB9 N4hvUZ9QpqlaYmVY8+1KmwZpToF9iQ5jAEbvaTZXXL47jLpKkIqiYR9YqcBCjPl3 9pEXLpsKNzWJYTr6HUg5FgGkBERpWHVHxd93GkJMFeSHACiE4PjLv5aCTC1yNTac uFhPxL3r1jBibA+tk3tv8RTT41olWjpgh+MBWYPq4Hpq8mlWAQUVPRnv3wNPCk5u 90cYyo+Df0TX1TBLUakH+1Xg2YXVVY1iogEW5eexyTsQ1yeC0IR+250s386noCKo L2nu/RX0fwWhd23sr8ff6JI= -----END CERTIFICATE----- kubeclient-3.0.0/test/config/nouser.kubeconfig0000644000004100000410000000052213255124405021464 0ustar www-datawww-dataapiVersion: v1 clusters: - cluster: server: https://localhost:8443 insecure-skip-tls-verify: true name: localhost:8443 contexts: - context: cluster: localhost:8443 namespace: default user: "" name: default/localhost:8443/nouser current-context: default/localhost:8443/nouser kind: Config preferences: {} users: [] kubeclient-3.0.0/test/config/external.kubeconfig0000644000004100000410000000076313255124405022002 0ustar www-datawww-dataapiVersion: v1 clusters: - cluster: certificate-authority: external-ca.pem server: https://localhost:8443 name: localhost:8443 contexts: - context: cluster: localhost:8443 namespace: default user: system:admin/localhost:8443 name: default/localhost:8443/system:admin current-context: default/localhost:8443/system:admin kind: Config preferences: {} users: - name: system:admin/localhost:8443 user: client-certificate: external-cert.pem client-key: external-key.rsa kubeclient-3.0.0/test/config/external-ca.pem0000644000004100000410000000205613255124405021025 0ustar www-datawww-data-----BEGIN CERTIFICATE----- MIIC6jCCAdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu c2hpZnQtc2lnbmVyQDE0NzgwMDE4MDEwHhcNMTYxMTAxMTIwMzIwWhcNMjExMDMx MTIwMzIxWjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE0NzgwMDE4MDEw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs4wBLAPBsZSd4CrAXUwxU s2upgpoR+Y//7hV/5ZS4Ab7BBqFbOtd5g7ygchRApd57Lr6a/BCE5Y8qFxNzYEgs NONKqYZYCRVOm6tFQI+PlU4GV3gSkk19FCL42HR6J4Ce9Ohx1r9AX4iDROoMDmXm r92vu40R5GIvxQWw+2C/rhwi0x27X886W26v38EKNQfXFXKKPVFpK91rIfHJc7oP 56VUdWIDJJ9H1m3xzD6+5JOzYeq0ZXW4srVU5n50fNju8HFQ65J4FnXoYyw1Z5w3 jDemaoKn7HLZqnrcGKaz69X7ON+kZU1S/gnTnXQdHUooELnZgM9IZ8LZwZlaPXrJ AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG SIb3DQEBCwUAA4IBAQBPu7hdNchigq7f6yaJpMEedQKXO8gC1bFoBfMEYqfxXzcB HNjTf9/ujja9J+hlEge5BiLIgT5ykxn8wNzZ+4Dz7XdhAs8EbFjNEKhqqYwWAXJ5 qGkPIngrc/47tvbAEhBh+3NWFwdFdo6dTPHE7WU481Hm/49/87CvyvuQJfFUBulB v71HUs0wvHVTEPK+zGtPXW7IWcMvgbs3Na1p2DJNbFE1Rja/YLif6IJvECLdgWyb QHvidW7gitVKgrbltHM9taNF1UPyoLeL1vMgLh4hT79xXK/eN95LzPwA0NRyJtlK dWoLIe5RfFx6TKBXTpdCACWmd9WRRZK2sFvF4NMc -----END CERTIFICATE----- kubeclient-3.0.0/test/config/external-key.rsa0000644000004100000410000000321313255124405021232 0ustar www-datawww-data-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEA2aRqe9aHzi65wb3Y68Dz7a7kXXqnmT+nib4bxCn4nTxiEixJ Iqirdlm0Vd0P5/Lfg+Iyi6w06UDwDmYJojf+oyFnnEXBDz8UZ7rXSeXQKtpLJSpC 3WDEWVXbROs7igUroj1YtYw+vYmcSmw8SSFg6Qfb7rXKZQrHs/QYtG5nTcZRdMGk T2u8rKWgw8PLb67Ox9ef2f9tcyBaYGczeA9LEgMAslD7tceBsBPZioYzohsYIosE 15hmRswSf5bCye9GpksKk2H3VHYfcVj/w5ZnD8kYF4uUhCfCq2MjKDcSOw+AZFcV 0+Pl243PqL0PtCErwpsKKwnjglgL1B7Uqb06vwIDAQABAoIBADaUP8vsgcQX/adz Z5m/mqxpZoV2w97vkqE9VpM7/0fXI7Tw/Co/6DfWyR2bQWjmhFz7dbeHKQGxskG6 HwJaTnY0Y1pSN9cN950HwwOaKTkF40Bft8LyiGrq2AERiK3VHBskjUGB+R3pC5Oy Tu/7+eSWfvX/CtGKAYjEVwmwgiGDevhXZbN9AfdLW7uG/DQmin7C1OUodAQ1fcqc SQpKere16QOU9qh1XLI/CNgf2/KaMnj3od7EWo/DVjhfSvvZhxbqTh1vdj1OgHPd eqMb3tJzOgBqArJQsL+4q8QQR82M3mB/wJ+s2Hs9NNkWhh4n0p7ecYw5PM9A5Dek rSSS9dECgYEA69j2PUp1j5z9DZL3vfAoOgP4zcbqeUa5+kIRAzSCrPDe9D0noL+W pZYrttuSD6TwxAIxKhUZuOjuM6v6BZyoVQnnIk6Y5gt9vgBd5A4GJ6PSC289MItF xsogWtLscflOITk9krLZG114LgdU/es+bdUnbUmscXVXEc7s/ZPZ0CcCgYEA7D05 S0eGTGV6431EPsuy5t09TCnVbhiYIHil6iEh9xV+0TpkRwxfGqGlC8iQ6sTqkqHi Nr+YF8yWDCCtRpM3qgeo2TXSruxHR4go6TN15LL6RElp9Y+QXKp8wDDXfIrkZ4r0 nAt6GSsNDB9eNNI/hOQix6Ch42C7c4o4QtMIR6kCgYAk3IUn8TJMnunCLF1CN33i C2rgpp1RFSfOIHNOP+/IneEK5WADNM6T1NPCQbEjdtEWoY0TmbaqeuV3+AIczG5W 1DRm3UfydItTnfUOxs5ZdbZHiTxUEQB34HGMIHlKGwAGG08vVXqvVz2IXCcBhLn+ Kpl98EzecsuIAgJyY6BgcwKBgGz4GLOGvIYE0ViZ8Z7dqxoetyWorlBoe9OOk0ma Gua0PZkZTCQRqtTH9y+mRmJkjqcwkP4cBnYD4rqZYBQL2ENP4SzATPxu9LokLmrT V/A0NojFLGEe5cI4ye6FGQDTuGOijw5jpOBzIUOUPIo06SPNb9WRXNtbRVwYR7db TJhxAoGAGuu1f76kTx1oHWoOjOk3bJcRyWm9QdQVEB6S2ZrsHBRzfingDeDK9liT RZQQS3tZJGNhqvbhCpuVsmWPJrZ0t4zPYrHMpI0s4veTgJeSAyZIqTgSoHm7KA4q gPQT96PBLoYfB0KuKABqNNVG7cz4lBz0wNMyuZ+Utr7GpxWB4ec= -----END RSA PRIVATE KEY----- kubeclient-3.0.0/test/test_watch_notice.rb0000644000004100000410000000315613255124405020707 0ustar www-datawww-datarequire_relative 'test_helper' class TestWatchNotice < MiniTest::Test # # Checks that elements of arrays are converted to instances of `RecursiveOpenStruct`, and that the # items can be accessed using the dot notation. # def test_recurse_over_arrays json = JSON.parse(open_test_file('node_notice.json').read) notice = Kubeclient::Common::WatchNotice.new(json) assert_kind_of(Array, notice.object.status.addresses) notice.object.status.addresses.each do |address| assert_kind_of(RecursiveOpenStruct, address) end assert_equal('InternalIP', notice.object.status.addresses[0].type) assert_equal('192.168.122.40', notice.object.status.addresses[0].address) assert_equal('Hostname', notice.object.status.addresses[1].type) assert_equal('openshift.local', notice.object.status.addresses[1].address) end # # Checks that even when arrays are converted to instances of `RecursiveOpenStruct` the items can # be accessed using the hash notation. # def test_access_array_items_as_hash json = JSON.parse(open_test_file('node_notice.json').read) notice = Kubeclient::Common::WatchNotice.new(json) assert_kind_of(Array, notice.object.status.addresses) notice.object.status.addresses.each do |address| assert_kind_of(RecursiveOpenStruct, address) end assert_equal('InternalIP', notice.object.status.addresses[0]['type']) assert_equal('192.168.122.40', notice.object.status.addresses[0]['address']) assert_equal('Hostname', notice.object.status.addresses[1]['type']) assert_equal('openshift.local', notice.object.status.addresses[1]['address']) end end kubeclient-3.0.0/test/test_node.rb0000644000004100000410000000430413255124405017161 0ustar www-datawww-datarequire_relative 'test_helper' # Node entity tests class TestNode < MiniTest::Test def test_get_from_json_v1 stub_request(:get, %r{/nodes}) .to_return(body: open_test_file('node.json'), status: 200) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') node = client.get_node('127.0.0.1') assert_instance_of(Kubeclient::Resource, node) assert_equal('041143c5-ce39-11e4-ac24-3c970e4a436a', node.metadata.uid) assert_equal('127.0.0.1', node.metadata.name) assert_equal('1724', node.metadata.resourceVersion) assert_equal('v1', node.apiVersion) assert_equal('2015-03-19T15:08:20+02:00', node.metadata.creationTimestamp) assert_requested( :get, 'http://localhost:8080/api/v1', times: 1 ) assert_requested( :get, 'http://localhost:8080/api/v1/nodes/127.0.0.1', times: 1 ) end def test_get_from_json_v1_raw stub_request(:get, %r{/nodes}) .to_return(body: open_test_file('node.json'), status: 200) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') response = client.get_node('127.0.0.1', nil, as: :raw) assert_equal(open_test_file('node.json').read, response) assert_requested( :get, 'http://localhost:8080/api/v1', times: 1 ) assert_requested( :get, 'http://localhost:8080/api/v1/nodes/127.0.0.1', times: 1 ) end def test_get_from_json_v1_raw_error stub_request(:get, %r{/nodes}) .to_return(body: open_test_file('node.json'), status: 200) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 500) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') exception = assert_raises(Kubeclient::HttpError) do client.get_node('127.0.0.1', nil, as: :raw) end assert_instance_of(Kubeclient::HttpError, exception) assert_equal('500 Internal Server Error', exception.message) end end kubeclient-3.0.0/test/test_replication_controller.rb0000644000004100000410000000407513255124405023015 0ustar www-datawww-datarequire_relative 'test_helper' # Replication Controller entity tests class TestReplicationController < MiniTest::Test def test_get_from_json_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/replicationcontrollers}) .to_return(body: open_test_file('replication_controller.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') rc = client.get_replication_controller('frontendController', 'default') assert_instance_of(Kubeclient::Resource, rc) assert_equal('guestbook-controller', rc.metadata.name) assert_equal('c71aa4c0-a240-11e4-a265-3c970e4a436a', rc.metadata.uid) assert_equal('default', rc.metadata.namespace) assert_equal(3, rc.spec.replicas) assert_equal('guestbook', rc.spec.selector.name) assert_requested(:get, 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController', times: 1) end def test_delete_replicaset_cascade stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') opts = Kubeclient::Resource.new( apiVersion: 'meta/v1', gracePeriodSeconds: 0, kind: 'DeleteOptions', propagationPolicy: 'Foreground' ) stub_request(:delete, 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController') .with(body: opts.to_hash.to_json) .to_return(status: 200, body: open_test_file('replication_controller.json'), headers: {}) rc = client.delete_replication_controller('frontendController', 'default', delete_options: opts) assert_kind_of(RecursiveOpenStruct, rc) assert_requested(:delete, 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController', times: 1) end end kubeclient-3.0.0/test/test_secret.rb0000644000004100000410000000475213255124405017530 0ustar www-datawww-datarequire_relative 'test_helper' # Namespace entity tests class TestSecret < MiniTest::Test def test_get_secret_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/secrets}) .to_return(body: open_test_file('created_secret.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') secret = client.get_secret('test-secret', 'dev') assert_instance_of(Kubeclient::Resource, secret) assert_equal('4e38a198-2bcb-11e5-a483-0e840567604d', secret.metadata.uid) assert_equal('test-secret', secret.metadata.name) assert_equal('v1', secret.apiVersion) assert_equal('Y2F0J3MgYXJlIGF3ZXNvbWUK', secret.data['super-secret']) assert_requested(:get, 'http://localhost:8080/api/v1/namespaces/dev/secrets/test-secret', times: 1) end def test_delete_secret_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:delete, %r{/secrets}) .to_return(status: 200, body: open_test_file('created_secret.json')) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') secret = client.delete_secret('test-secret', 'dev') assert_kind_of(RecursiveOpenStruct, secret) assert_requested(:delete, 'http://localhost:8080/api/v1/namespaces/dev/secrets/test-secret', times: 1) end def test_create_secret_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:post, %r{/secrets}) .to_return(body: open_test_file('created_secret.json'), status: 201) secret = Kubeclient::Resource.new secret.metadata = {} secret.metadata.name = 'test-secret' secret.metadata.namespace = 'dev' secret.data = {} secret.data['super-secret'] = 'Y2F0J3MgYXJlIGF3ZXNvbWUK' client = Kubeclient::Client.new('http://localhost:8080/api/') created_secret = client.create_secret(secret) assert_instance_of(Kubeclient::Resource, created_secret) assert_equal(secret.metadata.name, created_secret.metadata.name) assert_equal(secret.metadata.namespace, created_secret.metadata.namespace) assert_equal( secret.data['super-secret'], created_secret.data['super-secret'] ) end end kubeclient-3.0.0/test/test_service.rb0000644000004100000410000002414413255124405017700 0ustar www-datawww-datarequire_relative 'test_helper' # Service entity tests class TestService < MiniTest::Test def test_construct_our_own_service our_service = Kubeclient::Resource.new our_service.metadata = {} our_service.metadata.name = 'guestbook' our_service.metadata.namespace = 'staging' our_service.metadata.labels = {} our_service.metadata.labels.name = 'guestbook' our_service.spec = {} our_service.spec.ports = [{ 'port' => 3000, 'targetPort' => 'http-server', 'protocol' => 'TCP' }] assert_equal('guestbook', our_service.metadata.labels.name) hash = our_service.to_h assert_equal(our_service.metadata.labels.name, hash[:metadata][:labels][:name]) expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services' stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:post, expected_url) .to_return(body: open_test_file('created_service.json'), status: 201) client = Kubeclient::Client.new('http://localhost:8080/api/') created = client.create_service(our_service) assert_instance_of(Kubeclient::Resource, created) assert_equal(created.metadata.name, our_service.metadata.name) assert_equal(created.spec.ports.size, our_service.spec.ports.size) # Check that original entity_config is not modified by kind/apiVersion patches: assert_nil(our_service.kind) assert_requested(:post, expected_url, times: 1) do |req| data = JSON.parse(req.body) data['kind'] == 'Service' && data['apiVersion'] == 'v1' && data['metadata']['name'] == 'guestbook' && data['metadata']['namespace'] == 'staging' end end def test_construct_service_from_symbol_keys service = Kubeclient::Resource.new service.metadata = { labels: { tier: 'frontend' }, name: 'test-service', namespace: 'staging' } service.spec = { ports: [{ port: 3000, targetPort: 'http-server', protocol: 'TCP' }] } expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services' stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:post, expected_url) .to_return(body: open_test_file('created_service.json'), status: 201) client = Kubeclient::Client.new('http://localhost:8080/api/') client.create_service(service) assert_requested(:post, expected_url, times: 1) do |req| data = JSON.parse(req.body) data['kind'] == 'Service' && data['apiVersion'] == 'v1' && data['metadata']['name'] == 'test-service' && data['metadata']['labels']['tier'] == 'frontend' && data['metadata']['namespace'] == 'staging' end end def test_construct_service_from_string_keys service = Kubeclient::Resource.new service.metadata = { 'labels' => { 'tier' => 'frontend' }, 'name' => 'test-service', 'namespace' => 'staging' } service.spec = { 'ports' => [{ 'port' => 3000, 'targetPort' => 'http-server', 'protocol' => 'TCP' }] } stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services' stub_request(:post, %r{namespaces/staging/services}) .to_return(body: open_test_file('created_service.json'), status: 201) client = Kubeclient::Client.new('http://localhost:8080/api/') client.create_service(service) assert_requested(:post, expected_url, times: 1) do |req| data = JSON.parse(req.body) data['kind'] == 'Service' && data['apiVersion'] == 'v1' && data['metadata']['name'] == 'test-service' && data['metadata']['labels']['tier'] == 'frontend' && data['metadata']['namespace'] == 'staging' end end def test_conversion_from_json_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/services}) .to_return(body: open_test_file('service.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/') service = client.get_service('redis-slave', 'development') assert_instance_of(Kubeclient::Resource, service) assert_equal('2015-04-05T13:00:31Z', service.metadata.creationTimestamp) assert_equal('bdb80a8f-db93-11e4-b293-f8b156af4ae1', service.metadata.uid) assert_equal('redis-slave', service.metadata.name) assert_equal('2815', service.metadata.resourceVersion) assert_equal('v1', service.apiVersion) assert_equal('10.0.0.140', service.spec.clusterIP) assert_equal('development', service.metadata.namespace) assert_equal('TCP', service.spec.ports[0].protocol) assert_equal(6379, service.spec.ports[0].port) assert_equal('', service.spec.ports[0].name) assert_equal('redis-server', service.spec.ports[0].targetPort) assert_requested(:get, 'http://localhost:8080/api/v1/namespaces/development/services/redis-slave', times: 1) end def test_delete_service our_service = Kubeclient::Resource.new our_service.name = 'redis-service' # TODO, new ports assignment to be added our_service.labels = {} our_service.labels.component = 'apiserver' our_service.labels.provider = 'kubernetes' stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:delete, %r{/namespaces/default/services}) .to_return(body: open_test_file('service.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') our_service = client.delete_service(our_service.name, 'default') assert_kind_of(RecursiveOpenStruct, our_service) assert_requested(:delete, 'http://localhost:8080/api/v1/namespaces/default/services/redis-service', times: 1) end def test_get_service_no_ns stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) # when not specifying namespace for entities which # are not node or namespace, the request will fail stub_request(:get, %r{/services/redis-slave}) .to_return(status: 404) client = Kubeclient::Client.new('http://localhost:8080/api/') exception = assert_raises(Kubeclient::HttpError) do client.get_service('redis-slave') end assert_equal(404, exception.error_code) end def test_get_service stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/namespaces/development/services/redis-slave}) .to_return(body: open_test_file('service.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/') service = client.get_service('redis-slave', 'development') assert_equal('redis-slave', service.metadata.name) assert_requested(:get, 'http://localhost:8080/api/v1/namespaces/development/services/redis-slave', times: 1) end def test_update_service service = Kubeclient::Resource.new name = 'my_service' service.metadata = {} service.metadata.name = name service.metadata.namespace = 'development' stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}" stub_request(:put, expected_url) .to_return(body: open_test_file('service_update.json'), status: 201) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') service = client.update_service(service) assert_kind_of(RecursiveOpenStruct, service) assert_requested(:put, expected_url, times: 1) do |req| data = JSON.parse(req.body) data['metadata']['name'] == name && data['metadata']['namespace'] == 'development' end end def test_update_service_with_string_keys service = Kubeclient::Resource.new name = 'my_service' service.metadata = { 'name' => name, 'namespace' => 'development' } stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}" stub_request(:put, expected_url) .to_return(body: open_test_file('service_update.json'), status: 201) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') service = client.update_service(service) assert_kind_of(RecursiveOpenStruct, service) assert_requested(:put, expected_url, times: 1) do |req| data = JSON.parse(req.body) data['metadata']['name'] == name && data['metadata']['namespace'] == 'development' end end def test_patch_service service = Kubeclient::Resource.new name = 'my_service' service.metadata = {} service.metadata.name = name service.metadata.namespace = 'development' stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}" stub_request(:patch, expected_url) .to_return(body: open_test_file('service_patch.json'), status: 200) patch = { metadata: { annotations: { key: 'value' } } } client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') service = client.patch_service(name, patch, 'development') assert_kind_of(RecursiveOpenStruct, service) assert_requested(:patch, expected_url, times: 1) do |req| data = JSON.parse(req.body) data['metadata']['annotations']['key'] == 'value' end end end kubeclient-3.0.0/test/test_resource_quota.rb0000644000004100000410000000157513255124405021303 0ustar www-datawww-datarequire_relative 'test_helper' # ResourceQuota tests class TestResourceQuota < MiniTest::Test def test_get_from_json_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/resourcequotas}) .to_return(body: open_test_file('resource_quota.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') quota = client.get_resource_quota('quota', 'quota-example') assert_instance_of(Kubeclient::Resource, quota) assert_equal('quota', quota.metadata.name) assert_equal('20', quota.spec.hard.cpu) assert_equal('10', quota.spec.hard.secrets) assert_requested(:get, 'http://localhost:8080/api/v1/namespaces/quota-example/resourcequotas/quota', times: 1) end end kubeclient-3.0.0/test/test_persistent_volume_claim.rb0000644000004100000410000000175513255124405023177 0ustar www-datawww-datarequire_relative 'test_helper' # PersistentVolumeClaim tests class TestPersistentVolumeClaim < MiniTest::Test def test_get_from_json_v1 stub_request(:get, %r{/persistentvolumeclaims}) .to_return(body: open_test_file('persistent_volume_claim.json'), status: 200) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') claim = client.get_persistent_volume_claim('myclaim-1', 'default') assert_instance_of(Kubeclient::Resource, claim) assert_equal('myclaim-1', claim.metadata.name) assert_equal('3Gi', claim.spec.resources.requests.storage) assert_equal('pv0001', claim.spec.volumeName) assert_requested( :get, 'http://localhost:8080/api/v1', times: 1 ) assert_requested( :get, 'http://localhost:8080/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1', times: 1 ) end end kubeclient-3.0.0/test/test_watch.rb0000644000004100000410000001152013255124405017340 0ustar www-datawww-datarequire_relative 'test_helper' # Watch entity tests class TestWatch < MiniTest::Test def test_watch_pod_success stub_resource_list expected = [ { 'type' => 'ADDED', 'resourceVersion' => '1389' }, { 'type' => 'MODIFIED', 'resourceVersion' => '1390' }, { 'type' => 'DELETED', 'resourceVersion' => '1398' } ] stub_request(:get, %r{/watch/pods}) .to_return(body: open_test_file('watch_stream.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') client.watch_pods.to_enum.with_index do |notice, index| assert_instance_of(Kubeclient::Common::WatchNotice, notice) assert_equal(expected[index]['type'], notice.type) assert_equal('Pod', notice.object.kind) assert_equal('php', notice.object.metadata.name) assert_equal(expected[index]['resourceVersion'], notice.object.metadata.resourceVersion) end end def test_watch_pod_raw stub_resource_list stub_request(:get, %r{/watch/pods}).to_return( body: open_test_file('watch_stream.json'), status: 200 ) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') got = nil client.watch_pods(as: :raw).each { |notice| got = notice } assert_match(/\A{"type":"DELETED"/, got) end def test_watch_pod_failure stub_resource_list stub_request(:get, %r{/watch/pods}).to_return(status: 404) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') assert_raises(Kubeclient::HttpError) do client.watch_pods.each do end end end # Ensure that WatchStream respects a format that's not JSON def test_watch_stream_text url = 'http://www.example.com/foobar' expected_lines = open_test_file('pod_log.txt').read.split("\n") stub_request(:get, url) .to_return(body: open_test_file('pod_log.txt'), status: 200) stream = Kubeclient::Common::WatchStream.new(URI.parse(url), {}, as: :raw) stream.to_enum.with_index do |line, index| assert_instance_of(String, line) assert_equal(expected_lines[index], line) end end # Ensure that WatchStream respects a format that's not JSON def test_watch_stream_unknown url = 'http://www.example.com/foobar' stub_request(:get, url) .to_return(body: open_test_file('pod_log.txt'), status: 200) stream = Kubeclient::Common::WatchStream.new(URI.parse(url), {}, as: :foo) assert_raises(NotImplementedError) { stream.each {} } end def test_watch_with_resource_version api_host = 'http://localhost:8080/api' version = '1995' stub_resource_list stub_request(:get, %r{.*\/watch/events}) .to_return(body: open_test_file('watch_stream.json'), status: 200) client = Kubeclient::Client.new(api_host, 'v1') results = client.watch_events(version).to_enum assert_equal(3, results.count) assert_requested(:get, "#{api_host}/v1/watch/events?resourceVersion=#{version}", times: 1) end def test_watch_with_label_selector api_host = 'http://localhost:8080/api' selector = 'name=redis-master' stub_resource_list stub_request(:get, %r{.*\/watch/events}) .to_return(body: open_test_file('watch_stream.json'), status: 200) client = Kubeclient::Client.new(api_host, 'v1') results = client.watch_events(label_selector: selector).to_enum assert_equal(3, results.count) assert_requested(:get, "#{api_host}/v1/watch/events?labelSelector=#{selector}", times: 1) end def test_watch_with_field_selector api_host = 'http://localhost:8080/api' selector = 'involvedObject.kind=Pod' stub_resource_list stub_request(:get, %r{.*\/watch/events}) .to_return(body: open_test_file('watch_stream.json'), status: 200) client = Kubeclient::Client.new(api_host, 'v1') results = client.watch_events(field_selector: selector).to_enum assert_equal(3, results.count) assert_requested(:get, "#{api_host}/v1/watch/events?fieldSelector=#{selector}", times: 1) end def test_watch_with_finish_and_ebadf api_host = 'http://localhost:8080/api' stub_resource_list stub_request(:get, %r{.*\/watch/events}) .to_return(body: open_test_file('watch_stream.json'), status: 200) client = Kubeclient::Client.new(api_host, 'v1') watcher = client.watch_events # explodes when Errno::EBADF is not caught watcher.each do watcher.finish raise Errno::EBADF end assert_requested(:get, "#{api_host}/v1/watch/events", times: 1) end private def stub_resource_list stub_request(:get, %r{/api/v1$}).to_return( body: open_test_file('core_api_resource_list.json'), status: 200 ) end end kubeclient-3.0.0/test/txt/0000755000004100000410000000000013255124405015466 5ustar www-datawww-datakubeclient-3.0.0/test/txt/pod_log.txt0000644000004100000410000000017513255124405017655 0ustar www-datawww-dataInitializing server... ...loaded configuration ...updated settings ...discovered local servers ...frobinated disks Complete! kubeclient-3.0.0/test/test_namespace.rb0000644000004100000410000000431713255124405020174 0ustar www-datawww-datarequire_relative 'test_helper' # Namespace entity tests class TestNamespace < MiniTest::Test def test_get_namespace_v1 stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:get, %r{/namespaces}) .to_return(body: open_test_file('namespace.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') namespace = client.get_namespace('staging') assert_instance_of(Kubeclient::Resource, namespace) assert_equal('e388bc10-c021-11e4-a514-3c970e4a436a', namespace.metadata.uid) assert_equal('staging', namespace.metadata.name) assert_equal('1168', namespace.metadata.resourceVersion) assert_equal('v1', namespace.apiVersion) assert_requested( :get, 'http://localhost:8080/api/v1/namespaces/staging', times: 1 ) end def test_delete_namespace_v1 our_namespace = Kubeclient::Resource.new our_namespace.metadata = {} our_namespace.metadata.name = 'staging' stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:delete, %r{/namespaces}) .to_return(body: open_test_file('namespace.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') our_namespace = client.delete_namespace(our_namespace.metadata.name) assert_kind_of(RecursiveOpenStruct, our_namespace) assert_requested( :delete, 'http://localhost:8080/api/v1/namespaces/staging', times: 1 ) end def test_create_namespace stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) stub_request(:post, %r{/namespaces}) .to_return(body: open_test_file('created_namespace.json'), status: 201) namespace = Kubeclient::Resource.new namespace.metadata = {} namespace.metadata.name = 'development' client = Kubeclient::Client.new('http://localhost:8080/api/') created_namespace = client.create_namespace(namespace) assert_instance_of(Kubeclient::Resource, created_namespace) assert_equal(namespace.metadata.name, created_namespace.metadata.name) end end kubeclient-3.0.0/test/test_pod_log.rb0000644000004100000410000000336513255124405017665 0ustar www-datawww-datarequire_relative 'test_helper' # Pod log tests class TestPodLog < MiniTest::Test def test_get_pod_log stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log}) .to_return(body: open_test_file('pod_log.txt'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') retrieved_log = client.get_pod_log('redis-master-pod', 'default') assert_equal(open_test_file('pod_log.txt').read, retrieved_log) assert_requested(:get, 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log', times: 1) end def test_get_pod_log_container stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log}) .to_return(body: open_test_file('pod_log.txt'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') retrieved_log = client.get_pod_log('redis-master-pod', 'default', container: 'ruby') assert_equal(open_test_file('pod_log.txt').read, retrieved_log) assert_requested(:get, 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?container=ruby', times: 1) end def test_watch_pod_log expected_lines = open_test_file('pod_log.txt').read.split("\n") stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow}) .to_return(body: open_test_file('pod_log.txt'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') stream = client.watch_pod_log('redis-master-pod', 'default') stream.to_enum.with_index do |notice, index| assert_instance_of(String, notice) assert_equal(expected_lines[index], notice) end end end kubeclient-3.0.0/test/test_service_account.rb0000644000004100000410000000177613255124405021422 0ustar www-datawww-datarequire_relative 'test_helper' # ServiceAccount tests class TestServiceAccount < MiniTest::Test def test_get_from_json_v1 stub_request(:get, %r{/serviceaccounts}) .to_return(body: open_test_file('service_account.json'), status: 200) stub_request(:get, %r{/api/v1$}) .to_return(body: open_test_file('core_api_resource_list.json'), status: 200) client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') account = client.get_service_account('default') assert_instance_of(Kubeclient::Resource, account) assert_equal('default', account.metadata.name) assert_equal('default-token-6s23q', account.secrets[0].name) assert_equal('default-dockercfg-62tf3', account.secrets[1].name) assert_requested(:get, 'http://localhost:8080/api/v1/serviceaccounts/default', times: 1) assert_requested(:get, 'http://localhost:8080/api/v1', times: 1) end end kubeclient-3.0.0/test/json/0000755000004100000410000000000013255124405015620 5ustar www-datawww-datakubeclient-3.0.0/test/json/config_map_list.json0000644000004100000410000000023213255124405021645 0ustar www-datawww-data{ "kind": "ConfigMapList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/configmaps", "resourceVersion": "665" }, "items": [] }kubeclient-3.0.0/test/json/empty_pod_list.json0000644000004100000410000000022213255124405021542 0ustar www-datawww-data{ "kind": "PodList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/pods", "resourceVersion": "565" }, "items": [] }kubeclient-3.0.0/test/json/pod.json0000644000004100000410000000545613255124405017307 0ustar www-datawww-data{ "kind": "Pod", "apiVersion": "v1", "metadata": { "name": "redis-master3", "namespace": "default", "selfLink": "/api/v1/pods/redis-master3?namespace=default", "uid": "a344023f-a23c-11e4-a36b-3c970e4a436a", "resourceVersion": "9", "creationTimestamp": "2015-01-22T15:43:24+02:00", "labels": { "name": "redis-master" } }, "spec": { "volumes": null, "containers": [ { "name": "master", "image": "dockerfile/redis", "ports": [ { "hostPort": 6379, "containerPort": 6379, "protocol": "TCP" } ], "memory": "0", "cpu": "100m", "imagePullPolicy": "" }, { "name": "php-redis", "image": "kubernetes/example-guestbook-php-redis", "ports": [ { "hostPort": 8000, "containerPort": 80, "protocol": "TCP" } ], "memory": "50000000", "cpu": "100m", "imagePullPolicy": "" } ], "restartPolicy": { "always": { } }, "dnsPolicy": "ClusterFirst" }, "status": { "phase": "Running", "host": "127.0.0.1", "podIP": "172.17.0.2", "info": { "master": { "state": { "running": { "startedAt": "2015-01-22T13:43:29Z" } }, "restartCount": 0, "containerID": "docker://87458d9a12f9dc9a01b52c1eee5f09cf48939380271c0eaf31af298ce67b125e", "image": "dockerfile/redis" }, "net": { "state": { "running": { "startedAt": "2015-01-22T13:43:27Z" } }, "restartCount": 0, "containerID": "docker://3bb5ced1f831322d370f70b58137e1dd41216c2960b7a99394542b5230cbd259", "podIP": "172.17.0.2", "image": "kubernetes/pause:latest" }, "php-redis": { "state": { "running": { "startedAt": "2015-01-22T13:43:31Z" } }, "restartCount": 0, "containerID": "docker://5f08685c0a7a5c974d438a52c6560d72bb0aae7e805d2a34302b9b460f1297c7", "image": "kubernetes/example-guestbook-php-redis" } } } } kubeclient-3.0.0/test/json/core_api_resource_list_without_kind.json0000644000004100000410000000427113255124405026032 0ustar www-datawww-data{ "groupVersion": "v1", "resources": [ { "name": "bindings", "namespaced": true }, { "name": "componentstatuses", "namespaced": true }, { "name": "endpoints", "namespaced": true }, { "name": "events", "namespaced": true }, { "name": "limitranges", "namespaced": true }, { "name": "namespaces", "namespaced": false }, { "name": "namespaces/finalize", "namespaced": false }, { "name": "namespaces/status", "namespaced": false }, { "name": "nodes", "namespaced": false }, { "name": "nodes/status", "namespaced": false }, { "name": "persistentvolumeclaims", "namespaced": true }, { "name": "persistentvolumeclaims/status", "namespaced": true }, { "name": "persistentvolumes", "namespaced": false }, { "name": "persistentvolumes/status", "namespaced": false }, { "name": "pods", "namespaced": true }, { "name": "pods/attach", "namespaced": true }, { "name": "pods/binding", "namespaced": true }, { "name": "pods/exec", "namespaced": true }, { "name": "pods/log", "namespaced": true }, { "name": "pods/portforward", "namespaced": true }, { "name": "pods/proxy", "namespaced": true }, { "name": "pods/status", "namespaced": true }, { "name": "podtemplates", "namespaced": true }, { "name": "replicationcontrollers", "namespaced": true }, { "name": "replicationcontrollers/status", "namespaced": true }, { "name": "resourcequotas", "namespaced": true }, { "name": "resourcequotas/status", "namespaced": true }, { "name": "secrets", "namespaced": true }, { "name": "securitycontextconstraints", "namespaced": false }, { "name": "serviceaccounts", "namespaced": true }, { "name": "services", "namespaced": true } ] } kubeclient-3.0.0/test/json/created_service.json0000644000004100000410000000141013255124405021636 0ustar www-datawww-data{ "kind": "Service", "apiVersion": "v1", "metadata": { "name": "guestbook", "namespace": "staging", "selfLink": "/api/v1/namespaces/staging/services/guestbook", "uid": "29885239-df58-11e4-bd42-f8b156af4ae1", "resourceVersion": "1908", "creationTimestamp": "2015-04-10T08:04:07Z", "labels": { "name": "guestbook" } }, "spec": { "ports": [ { "name": "", "protocol": "TCP", "port": 3000, "targetPort": "http-server" } ], "selector": { "name": "guestbook" }, "clusterIP": "10.0.0.99", "sessionAffinity": "None" }, "status": {} }kubeclient-3.0.0/test/json/service_list.json0000644000004100000410000000605113255124405021210 0ustar www-datawww-data{ "kind": "ServiceList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/services", "resourceVersion": "36727" }, "items": [ { "metadata": { "name": "kubernetes", "namespace": "default", "selfLink": "/api/v1/namespaces/default/services/kubernetes", "uid": "b6606490-db86-11e4-b293-f8b156af4ae1", "resourceVersion": "6", "creationTimestamp": "2015-04-05T11:27:15Z", "labels": { "component": "apiserver", "provider": "kubernetes" } }, "spec": { "ports": [ { "name": "", "protocol": "TCP", "port": 443, "targetPort": 443 } ], "selector": null, "clusterIP": "10.0.0.2", "sessionAffinity": "None" }, "status": {} }, { "metadata": { "name": "kubernetes-ro", "namespace": "default", "selfLink": "/api/v1/namespaces/default/services/kubernetes-ro", "uid": "b6606694-db86-11e4-b293-f8b156af4ae1", "resourceVersion": "5", "creationTimestamp": "2015-04-05T11:27:15Z", "labels": { "component": "apiserver", "provider": "kubernetes" } }, "spec": { "ports": [ { "name": "", "protocol": "TCP", "port": 80, "targetPort": 80 } ], "selector": null, "clusterIP": "10.0.0.1", "sessionAffinity": "None" }, "status": {} }, { "metadata": { "name": "redis-slave", "namespace": "development", "selfLink": "/api/v1/namespaces/development/services/redis-slave", "uid": "bdb80a8f-db93-11e4-b293-f8b156af4ae1", "resourceVersion": "2815", "creationTimestamp": "2015-04-05T13:00:31Z", "labels": { "name": "redis", "role": "slave" } }, "spec": { "ports": [ { "name": "", "protocol": "TCP", "port": 6379, "targetPort": "redis-server" } ], "selector": { "name": "redis", "role": "slave" }, "clusterIP": "10.0.0.140", "sessionAffinity": "None" }, "status": {} } ] }kubeclient-3.0.0/test/json/created_endpoint.json0000644000004100000410000000105213255124405022020 0ustar www-datawww-data{ "kind": "Endpoints", "apiVersion": "v1", "metadata": { "name": "myendpoint", "namespace": "default", "selfLink": "/api/v1/namespaces/default/endpoints/myendpoint", "uid": "59d05b48-dadb-11e5-937e-18037327aaeb", "resourceVersion": "393", "creationTimestamp": "2016-02-24T09:45:34Z" }, "subsets": [ { "addresses": [ { "ip": "172.17.0.25" } ], "ports": [ { "name": "https", "port": 6443, "protocol": "TCP" } ] } ] }kubeclient-3.0.0/test/json/service_update.json0000644000004100000410000000065613255124405021524 0ustar www-datawww-data{ "status" : {}, "kind" : "Service", "apiVersion" : "v1", "spec" : { "ports" : [ { "targetPort" : 80, "nodePort" : 0, "port" : 80, "protocol" : "TCP" } ], "clusterIP" : "1.2.3.4" }, "metadata" : { "name" : "my_service", "creationTimestamp" : null, "namespace" : "default", "resourceVersion" : "2" } } kubeclient-3.0.0/test/json/pod_template_list.json0000644000004100000410000000023613255124405022224 0ustar www-datawww-data{ "kind": "PodTemplateList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/podtemplates", "resourceVersion": "672" }, "items": [] }kubeclient-3.0.0/test/json/component_status_list.json0000644000004100000410000000237713255124405023164 0ustar www-datawww-data{ "kind": "ComponentStatusList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/componentstatuses" }, "items": [ { "metadata": { "name": "controller-manager", "selfLink": "/api/v1/namespaces/componentstatuses/controller-manager", "creationTimestamp": null }, "conditions": [ { "type": "Healthy", "status": "Unknown", "error": "Get http://127.0.0.1:10252/healthz: dial tcp 127.0.0.1:10252: connection refused" } ] }, { "metadata": { "name": "scheduler", "selfLink": "/api/v1/namespaces/componentstatuses/scheduler", "creationTimestamp": null }, "conditions": [ { "type": "Healthy", "status": "Unknown", "error": "Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: connection refused" } ] }, { "metadata": { "name": "etcd-0", "selfLink": "/api/v1/namespaces/componentstatuses/etcd-0", "creationTimestamp": null }, "conditions": [ { "type": "Healthy", "status": "True", "message": "{\"health\": \"true\"}", "error": "nil" } ] } ] }kubeclient-3.0.0/test/json/persistent_volume_list.json0000644000004100000410000000206113255124405023334 0ustar www-datawww-data{ "kind": "PersistentVolumeList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/persistentvolumes", "resourceVersion": "2999" }, "items": [ { "metadata": { "name": "pv0001", "selfLink": "/api/v1/persistentvolumes/pv0001", "uid": "c83eece1-4b38-11e5-8d27-28d2447dcefe", "resourceVersion": "1585", "creationTimestamp": "2015-08-25T14:51:35Z", "labels": { "type": "local" } }, "spec": { "capacity": { "storage": "10Gi" }, "hostPath": { "path": "/tmp/data01" }, "accessModes": [ "ReadWriteOnce" ], "claimRef": { "kind": "PersistentVolumeClaim", "namespace": "default", "name": "myclaim-1", "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe", "apiVersion": "v1", "resourceVersion": "1582" }, "persistentVolumeReclaimPolicy": "Retain" }, "status": { "phase": "Bound" } } ] } kubeclient-3.0.0/test/json/namespace_list.json0000644000004100000410000000163413255124405021506 0ustar www-datawww-data{ "kind": "NamespaceList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/namespaces", "resourceVersion": "1707" }, "items": [ { "metadata": { "name": "default", "selfLink": "/api/v1/namespaces/default", "uid": "56c3eb7c-c009-11e4-a514-3c970e4a436a", "resourceVersion": "4", "creationTimestamp": "2015-03-01T13:51:47+02:00" }, "spec": {}, "status": {} }, { "metadata": { "name": "staging", "selfLink": "/api/v1/namespaces/staging", "uid": "e388bc10-c021-11e4-a514-3c970e4a436a", "resourceVersion": "1168", "creationTimestamp": "2015-03-01T16:47:31+02:00" }, "spec": {}, "status": {} } ] }kubeclient-3.0.0/test/json/bindings_list.json0000644000004100000410000000031613255124405021343 0ustar www-datawww-data{ "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "the server could not find the requested resource", "reason": "NotFound", "details": {}, "code": 404 }kubeclient-3.0.0/test/json/entity_list.json0000644000004100000410000000336413255124405021070 0ustar www-datawww-data{ "kind": "ServiceList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/services", "resourceVersion": "59" }, "items": [ { "metadata": { "name": "kubernetes", "namespace": "default", "selfLink": "/api/v1/services/kubernetes?namespace=default", "uid": "016e9dcd-ce39-11e4-ac24-3c970e4a436a", "resourceVersion": "6", "creationTimestamp": "2015-03-19T15:08:16+02:00", "labels": { "component": "apiserver", "provider": "kubernetes" } }, "spec": { "port": 443, "protocol": "TCP", "selector": null, "clusterIP": "10.0.0.2", "containerPort": 0, "sessionAffinity": "None" }, "status": {} }, { "metadata": { "name": "kubernetes-ro", "namespace": "default", "selfLink": "/api/v1/services/kubernetes-ro?namespace=default", "uid": "015b78bf-ce39-11e4-ac24-3c970e4a436a", "resourceVersion": "5", "creationTimestamp": "2015-03-19T15:08:15+02:00", "labels": { "component": "apiserver", "provider": "kubernetes" } }, "spec": { "port": 80, "protocol": "TCP", "selector": null, "clusterIP": "10.0.0.1", "containerPort": 0, "sessionAffinity": "None" }, "status": {} } ] }kubeclient-3.0.0/test/json/watch_stream.json0000644000004100000410000000431313255124405021175 0ustar www-datawww-data{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1389","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending"}}} {"type":"MODIFIED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1390","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending","host":"127.0.0.1"}}} {"type":"DELETED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1398","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending","host":"127.0.0.1"}}} kubeclient-3.0.0/test/json/namespace_exception.json0000644000004100000410000000027113255124405022525 0ustar www-datawww-data{ "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "converting to : type names don't match (Pod, Namespace)", "code": 500 }kubeclient-3.0.0/test/json/processed_template.json0000644000004100000410000000106313255124405022375 0ustar www-datawww-data{ "kind": "Template", "apiVersion": "v1", "metadata": { "name": "my-templtae", "namespace": "default", "selfLink": "/oapi/v1/namespaces/default/processedtemplates/my-templtae", "uid": "2240c61c-8f70-11e5-a806-001a4a231290", "resourceVersion": "1399", "creationTimestamp": "2015-11-20T10:19:07Z" }, "objects": [ { "apiVersion": "v1", "kind": "Service", "metadata": { "name": "test/my-service" } } ], "parameters": [ { "name": "NAME_PREFIX", "value": "test/" } ] } kubeclient-3.0.0/test/json/persistent_volume_claim.json0000644000004100000410000000121713255124405023450 0ustar www-datawww-data{ "kind": "PersistentVolumeClaim", "apiVersion": "v1", "metadata": { "name": "myclaim-1", "namespace": "default", "selfLink": "/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1", "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe", "resourceVersion": "1584", "creationTimestamp": "2015-08-25T14:51:55Z" }, "spec": { "accessModes": [ "ReadWriteOnce" ], "resources": { "requests": { "storage": "3Gi" } }, "volumeName": "pv0001" }, "status": { "phase": "Bound", "accessModes": [ "ReadWriteOnce" ], "capacity": { "storage": "10Gi" } } } kubeclient-3.0.0/test/json/resource_quota.json0000644000004100000410000000204113255124405021550 0ustar www-datawww-data{ "kind": "ResourceQuota", "apiVersion": "v1", "metadata": { "name": "quota", "namespace": "quota-example", "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/quota", "uid": "ab9f24a4-3c43-11e5-8214-0aaeec44370e", "resourceVersion": "12919", "creationTimestamp": "2015-08-06T14:01:44Z" }, "spec": { "hard": { "cpu": "20", "memory": "1Gi", "persistentvolumeclaims": "10", "pods": "10", "replicationcontrollers": "20", "resourcequotas": "1", "secrets": "10", "services": "5" } }, "status": { "hard": { "cpu": "20", "memory": "1Gi", "persistentvolumeclaims": "10", "pods": "10", "replicationcontrollers": "20", "resourcequotas": "1", "secrets": "10", "services": "5" }, "used": { "cpu": "0", "memory": "0", "persistentvolumeclaims": "0", "pods": "0", "replicationcontrollers": "1", "resourcequotas": "1", "secrets": "9", "services": "0" } } }kubeclient-3.0.0/test/json/pod_list.json0000644000004100000410000000534013255124405020332 0ustar www-datawww-data{ "kind": "PodList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/pods", "resourceVersion": "1315" }, "items": [ { "metadata": { "name": "redis-master3", "namespace": "default", "selfLink": "/api/v1/pods/redis-master3?namespace=default", "uid": "1da148b4-cef5-11e4-ac24-3c970e4a436a", "resourceVersion": "1301", "creationTimestamp": "2015-03-20T13:34:48+02:00", "labels": { "mylabel": "mylabelvalue", "role": "pod" } }, "spec": { "volumes": null, "containers": [ { "name": "master", "image": "dockerfile/redis", "ports": [ { "hostPort": 6379, "containerPort": 6379, "protocol": "TCP" } ], "resources": { "limits": { "cpu": "100m" } }, "terminationMessagePath": "/dev/termination-log", "imagePullPolicy": "IfNotPresent", "securityContext": { "capabilities": {} } }, { "name": "php-redis", "image": "kubernetes/example-guestbook-php-redis", "ports": [ { "hostPort": 8000, "containerPort": 80, "protocol": "TCP" } ], "resources": { "limits": { "cpu": "100m", "memory": "50000000" } }, "terminationMessagePath": "/dev/termination-log", "imagePullPolicy": "IfNotPresent", "securityContext": { "capabilities": {} } } ], "restartPolicy": { "always": {} }, "dnsPolicy": "ClusterFirst" }, "status": { "phase": "Pending" } } ] }kubeclient-3.0.0/test/json/limit_range.json0000644000004100000410000000076013255124405021010 0ustar www-datawww-data{ "kind": "LimitRange", "apiVersion": "v1", "metadata": { "name": "limits", "namespace": "quota-example", "selfLink": "/api/v1/namespaces/quota-example/limitranges/limits", "uid": "7a76a44c-3e9d-11e5-8214-0aaeec44370e", "resourceVersion": "103384", "creationTimestamp": "2015-08-09T13:49:39Z" }, "spec": { "limits": [ { "type": "Container", "default": { "cpu": "100m", "memory": "512Mi" } } ] } }kubeclient-3.0.0/test/json/persistent_volume_claims_nil_items.json0000644000004100000410000000024713255124405025700 0ustar www-datawww-data{ "kind": "PersistentVolumeClaimList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/persistentvolumeclaims", "resourceVersion": "1089012" } }kubeclient-3.0.0/test/json/event_list.json0000644000004100000410000000226113255124405020670 0ustar www-datawww-data{ "kind": "EventList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/events", "resourceVersion": "152" }, "items": [ { "metadata": { "name": "php.13c130f78da4641e", "namespace": "default", "selfLink": "/api/v1/events/php.13c130f78da4641e?namespace=default", "uid": "f3a454d2-b03a-11e4-89e4-525400c903c1", "resourceVersion": "178", "creationTimestamp": "2015-02-09T04:06:37-05:00" }, "involvedObject": { "kind": "BoundPod", "namespace": "default", "name": "php", "uid": "64273d20-b03a-11e4-89e4-525400c903c1", "apiVersion": "v1beta1", "fieldPath": "spec.containers{nginx}" }, "reason": "created", "message": "Created with docker id 9ba2a714411d2d0dd1e826b2fe5c3222b5cbfd9dd9133c841585cbb96b8c2c0f", "source": { "component": "kubelet", "host": "127.0.0.1" }, "timestamp": "2015-02-09T04:06:37-05:00" } ] } kubeclient-3.0.0/test/json/created_namespace.json0000644000004100000410000000050613255124405022137 0ustar www-datawww-data{ "kind": "Namespace", "apiVersion": "v1", "metadata": { "name": "development", "selfLink": "/api/v1/namespaces/development", "uid": "13d820d6-df5b-11e4-bd42-f8b156af4ae1", "resourceVersion": "2533", "creationTimestamp": "2015-04-10T08:24:59Z" }, "spec": { "finalizers": [ "kubernetes" ] }, "status": { "phase": "Active" } } kubeclient-3.0.0/test/json/secret_list.json0000644000004100000410000000221213255124405021030 0ustar www-datawww-data{ "kind": "SecretList", "apiVersion":"v1", "metadata":{ "selfLink":"/api/v1/secrets", "resourceVersion":"256788" }, "items": [ { "metadata": { "name":"default-token-my2pi", "namespace":"default", "selfLink":"/api/v1/namespaces/default/secrets/default-token-my2pi", "uid":"07b60654-2a65-11e5-a483-0e840567604d", "resourceVersion":"11", "creationTimestamp":"2015-07-14T20:15:11Z", "annotations": { "kubernetes.io/service-account.name":"default", "kubernetes.io/service-account.uid":"07b350a0-2a65-11e5-a483-0e840567604d" } }, "data":{ "ca.crt":"Y2F0J3MgYXJlIGF3ZXNvbWUK", "token":"Y2F0J3MgYXJlIGF3ZXNvbWUK" }, "type":"kubernetes.io/service-account-token" }, { "metadata": { "name": "test-secret", "namespace": "dev", "selfLink": "/api/v1/namespaces/dev/secrets/test-secret", "uid": "4e38a198-2bcb-11e5-a483-0e840567604d", "resourceVersion": "245569", "creationTimestamp": "2015-07-16T14:59:49Z" }, "data": { "super-secret": "Y2F0J3MgYXJlIGF3ZXNvbWUK" }, "type": "Opaque" } ] } kubeclient-3.0.0/test/json/limit_range_list.json0000644000004100000410000000132313255124405022037 0ustar www-datawww-data{ "kind": "LimitRangeList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/namespaces/quota-example/limitranges/", "resourceVersion": "103421" }, "items": [ { "metadata": { "name": "limits", "namespace": "quota-example", "selfLink": "/api/v1/namespaces/quota-example/limitranges/limits", "uid": "7a76a44c-3e9d-11e5-8214-0aaeec44370e", "resourceVersion": "103384", "creationTimestamp": "2015-08-09T13:49:39Z" }, "spec": { "limits": [ { "type": "Container", "default": { "cpu": "100m", "memory": "512Mi" } } ] } } ] }kubeclient-3.0.0/test/json/core_oapi_resource_list_without_kind.json0000644000004100000410000000665713255124405026223 0ustar www-datawww-data{ "groupVersion": "v1", "resources": [ { "name": "buildconfigs", "namespaced": true }, { "name": "buildconfigs/instantiate", "namespaced": true }, { "name": "buildconfigs/instantiatebinary", "namespaced": true }, { "name": "buildconfigs/webhooks", "namespaced": true }, { "name": "builds", "namespaced": true }, { "name": "builds/clone", "namespaced": true }, { "name": "builds/details", "namespaced": true }, { "name": "builds/log", "namespaced": true }, { "name": "clusternetworks", "namespaced": false }, { "name": "clusterpolicies", "namespaced": false }, { "name": "clusterpolicybindings", "namespaced": false }, { "name": "clusterrolebindings", "namespaced": false }, { "name": "clusterroles", "namespaced": false }, { "name": "deploymentconfigrollbacks", "namespaced": true }, { "name": "deploymentconfigs", "namespaced": true }, { "name": "deploymentconfigs/log", "namespaced": true }, { "name": "deploymentconfigs/scale", "namespaced": true }, { "name": "generatedeploymentconfigs", "namespaced": true }, { "name": "groups", "namespaced": false }, { "name": "hostsubnets", "namespaced": false }, { "name": "identities", "namespaced": false }, { "name": "images", "namespaced": false }, { "name": "imagestreamimages", "namespaced": true }, { "name": "imagestreammappings", "namespaced": true }, { "name": "imagestreams", "namespaced": true }, { "name": "imagestreams/status", "namespaced": true }, { "name": "imagestreamtags", "namespaced": true }, { "name": "localresourceaccessreviews", "namespaced": true }, { "name": "localsubjectaccessreviews", "namespaced": true }, { "name": "netnamespaces", "namespaced": false }, { "name": "oauthaccesstokens", "namespaced": false }, { "name": "oauthauthorizetokens", "namespaced": false }, { "name": "oauthclientauthorizations", "namespaced": false }, { "name": "oauthclients", "namespaced": false }, { "name": "policies", "namespaced": true }, { "name": "policybindings", "namespaced": true }, { "name": "processedtemplates", "namespaced": true }, { "name": "projectrequests", "namespaced": false }, { "name": "projects", "namespaced": false }, { "name": "resourceaccessreviews", "namespaced": true }, { "name": "rolebindings", "namespaced": true }, { "name": "roles", "namespaced": true }, { "name": "routes", "namespaced": true }, { "name": "routes/status", "namespaced": true }, { "name": "subjectaccessreviews", "namespaced": true }, { "name": "templates", "namespaced": true }, { "name": "useridentitymappings", "namespaced": false }, { "name": "users", "namespaced": false } ] } kubeclient-3.0.0/test/json/resource_quota_list.json0000644000004100000410000000254313255124405022612 0ustar www-datawww-data{ "kind": "ResourceQuotaList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/", "resourceVersion": "102452" }, "items": [ { "metadata": { "name": "quota", "namespace": "quota-example", "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/quota", "uid": "ab9f24a4-3c43-11e5-8214-0aaeec44370e", "resourceVersion": "12919", "creationTimestamp": "2015-08-06T14:01:44Z" }, "spec": { "hard": { "cpu": "20", "memory": "1Gi", "persistentvolumeclaims": "10", "pods": "10", "replicationcontrollers": "20", "resourcequotas": "1", "secrets": "10", "services": "5" } }, "status": { "hard": { "cpu": "20", "memory": "1Gi", "persistentvolumeclaims": "10", "pods": "10", "replicationcontrollers": "20", "resourcequotas": "1", "secrets": "10", "services": "5" }, "used": { "cpu": "0", "memory": "0", "persistentvolumeclaims": "0", "pods": "0", "replicationcontrollers": "1", "resourcequotas": "1", "secrets": "9", "services": "0" } } } ] }kubeclient-3.0.0/test/json/core_api_resource_list.json0000644000004100000410000000664213255124405023246 0ustar www-datawww-data{ "kind": "APIResourceList", "groupVersion": "v1", "resources": [ { "name": "bindings", "namespaced": true, "kind": "Binding" }, { "name": "componentstatuses", "namespaced": false, "kind": "ComponentStatus" }, { "name": "configmaps", "namespaced": true, "kind": "ConfigMap" }, { "name": "endpoints", "namespaced": true, "kind": "Endpoints" }, { "name": "events", "namespaced": true, "kind": "Event" }, { "name": "limitranges", "namespaced": true, "kind": "LimitRange" }, { "name": "namespaces", "namespaced": false, "kind": "Namespace" }, { "name": "namespaces/finalize", "namespaced": false, "kind": "Namespace" }, { "name": "namespaces/status", "namespaced": false, "kind": "Namespace" }, { "name": "nodes", "namespaced": false, "kind": "Node" }, { "name": "nodes/proxy", "namespaced": false, "kind": "Node" }, { "name": "nodes/status", "namespaced": false, "kind": "Node" }, { "name": "persistentvolumeclaims", "namespaced": true, "kind": "PersistentVolumeClaim" }, { "name": "persistentvolumeclaims/status", "namespaced": true, "kind": "PersistentVolumeClaim" }, { "name": "persistentvolumes", "namespaced": false, "kind": "PersistentVolume" }, { "name": "persistentvolumes/status", "namespaced": false, "kind": "PersistentVolume" }, { "name": "pods", "namespaced": true, "kind": "Pod" }, { "name": "pods/attach", "namespaced": true, "kind": "Pod" }, { "name": "pods/binding", "namespaced": true, "kind": "Binding" }, { "name": "pods/exec", "namespaced": true, "kind": "Pod" }, { "name": "pods/log", "namespaced": true, "kind": "Pod" }, { "name": "pods/portforward", "namespaced": true, "kind": "Pod" }, { "name": "pods/proxy", "namespaced": true, "kind": "Pod" }, { "name": "pods/status", "namespaced": true, "kind": "Pod" }, { "name": "podtemplates", "namespaced": true, "kind": "PodTemplate" }, { "name": "replicationcontrollers", "namespaced": true, "kind": "ReplicationController" }, { "name": "replicationcontrollers/scale", "namespaced": true, "kind": "Scale" }, { "name": "replicationcontrollers/status", "namespaced": true, "kind": "ReplicationController" }, { "name": "resourcequotas", "namespaced": true, "kind": "ResourceQuota" }, { "name": "resourcequotas/status", "namespaced": true, "kind": "ResourceQuota" }, { "name": "secrets", "namespaced": true, "kind": "Secret" }, { "name": "serviceaccounts", "namespaced": true, "kind": "ServiceAccount" }, { "name": "services", "namespaced": true, "kind": "Service" }, { "name": "services/proxy", "namespaced": true, "kind": "Service" }, { "name": "services/status", "namespaced": true, "kind": "Service" } ] } kubeclient-3.0.0/test/json/persistent_volume.json0000644000004100000410000000145413255124405022306 0ustar www-datawww-data{ "kind": "PersistentVolume", "apiVersion": "v1", "metadata": { "name": "pv0001", "selfLink": "/api/v1/persistentvolumes/pv0001", "uid": "c83eece1-4b38-11e5-8d27-28d2447dcefe", "resourceVersion": "1585", "creationTimestamp": "2015-08-25T14:51:35Z", "labels": { "type": "local" } }, "spec": { "capacity": { "storage": "10Gi" }, "hostPath": { "path": "/tmp/data01" }, "accessModes": [ "ReadWriteOnce" ], "claimRef": { "kind": "PersistentVolumeClaim", "namespace": "default", "name": "myclaim-1", "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe", "apiVersion": "v1", "resourceVersion": "1582" }, "persistentVolumeReclaimPolicy": "Retain" }, "status": { "phase": "Bound" } } kubeclient-3.0.0/test/json/replication_controller_list.json0000644000004100000410000000455513255124405024333 0ustar www-datawww-data{ "kind": "ReplicationControllerList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/namespaces/default/replicationcontrollers", "resourceVersion": "1636" }, "items": [ { "metadata": { "name": "redis-master-controller", "namespace": "default", "selfLink": "/api/v1/namespaces/default/replicationcontrollers/redis-master-controller?namespace=default", "uid": "108eb547-cefa-11e4-ac24-3c970e4a436a", "resourceVersion": "1631", "creationTimestamp": "2015-03-20T14:10:14+02:00", "labels": { "name": "redis-master" } }, "spec": { "replicas": 1, "selector": { "name": "redis-master" }, "template": { "metadata": { "creationTimestamp": null, "labels": { "app": "redis", "name": "redis-master" } }, "spec": { "volumes": null, "containers": [ { "name": "redis-master", "image": "dockerfile/redis", "ports": [ { "containerPort": 6379, "protocol": "TCP" } ], "resources": {}, "terminationMessagePath": "/dev/termination-log", "imagePullPolicy": "IfNotPresent", "securityContext": { "capabilities": {} } } ], "restartPolicy": { "always": {} }, "dnsPolicy": "ClusterFirst" } } }, "status": { "replicas": 1 } } ] }kubeclient-3.0.0/test/json/service_patch.json0000644000004100000410000000067213255124405021337 0ustar www-datawww-data{ "status" : {}, "kind" : "Service", "apiVersion" : "v1", "spec" : { "ports" : [ { "targetPort" : 80, "nodePort" : 0, "port" : 80, "protocol" : "TCP" } ], "clusterIP" : "1.2.3.4" }, "metadata" : { "name" : "my_service", "creationTimestamp" : null, "namespace" : "development", "resourceVersion" : "2", "annotations" : { "key" : "value" } } } kubeclient-3.0.0/test/json/service_illegal_json_404.json0000644000004100000410000000002313255124405023257 0ustar www-datawww-data404: Page Not Foundkubeclient-3.0.0/test/json/created_secret.json0000644000004100000410000000061313255124405021467 0ustar www-datawww-data{ "kind": "Secret", "apiVersion": "v1", "metadata": { "name": "test-secret", "namespace": "dev", "selfLink": "/api/v1/namespaces/dev/secrets/test-secret", "uid": "4e38a198-2bcb-11e5-a483-0e840567604d", "resourceVersion": "245569", "creationTimestamp": "2015-07-16T14:59:49Z" }, "data": { "super-secret": "Y2F0J3MgYXJlIGF3ZXNvbWUK" }, "type": "Opaque" } kubeclient-3.0.0/test/json/component_status.json0000644000004100000410000000052113255124405022116 0ustar www-datawww-data{ "kind": "ComponentStatus", "apiVersion": "v1", "metadata": { "name": "etcd-0", "selfLink": "/api/v1/namespaces/componentstatuses/etcd-0", "creationTimestamp": null }, "conditions": [ { "type": "Healthy", "status": "True", "message": "{\"health\": \"true\"}", "error": "nil" } ] }kubeclient-3.0.0/test/json/node_list.json0000644000004100000410000000217113255124405020474 0ustar www-datawww-data{ "kind": "NodeList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/nodes", "resourceVersion": "137" }, "items": [ { "metadata": { "name": "127.0.0.1", "selfLink": "/api/v1/nodes/127.0.0.1", "uid": "041143c5-ce39-11e4-ac24-3c970e4a436a", "resourceVersion": "137", "creationTimestamp": "2015-03-19T15:08:20+02:00" }, "spec": { "capacity": { "cpu": "1", "memory": "3Gi" } }, "status": { "hostIP": "127.0.0.1", "conditions": [ { "kind": "Ready", "status": "None", "lastProbeTime": "2015-03-19T15:29:33+02:00", "lastTransitionTime": "2015-03-19T15:08:20+02:00", "reason": "Node health check failed: kubelet /healthz endpoint returns not ok" } ] } } ] }kubeclient-3.0.0/test/json/service.json0000644000004100000410000000151013255124405020150 0ustar www-datawww-data{ "kind": "Service", "apiVersion": "v1", "metadata": { "name": "redis-slave", "namespace": "development", "selfLink": "/api/v1/namespaces/development/services/redis-slave", "uid": "bdb80a8f-db93-11e4-b293-f8b156af4ae1", "resourceVersion": "2815", "creationTimestamp": "2015-04-05T13:00:31Z", "labels": { "name": "redis", "role": "slave" } }, "spec": { "ports": [ { "name": "", "protocol": "TCP", "port": 6379, "targetPort": "redis-server" } ], "selector": { "name": "redis", "role": "slave" }, "clusterIP": "10.0.0.140", "sessionAffinity": "None" }, "status": {} }kubeclient-3.0.0/test/json/service_account.json0000644000004100000410000000113713255124405021671 0ustar www-datawww-data{ "kind": "ServiceAccount", "apiVersion": "v1", "metadata": { "name": "default", "namespace": "default", "selfLink": "/api/v1/namespaces/default/serviceaccounts/default", "uid": "d3d773f4-6bf0-11e5-843a-525400f8b93e", "resourceVersion": "94", "creationTimestamp": "2015-10-06T06:09:39Z" }, "secrets": [ { "name": "default-token-6s23q" }, { "name": "default-dockercfg-62tf3" } ], "imagePullSecrets": [ { "name": "default-dockercfg-62tf3" } ] } kubeclient-3.0.0/test/json/endpoint_list.json0000644000004100000410000000221413255124405021365 0ustar www-datawww-data{ "kind": "EndpointsList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/namespaces/endpoints", "resourceVersion": "39" }, "items": [ { "metadata": { "name": "example", "namespace": "default", "selfLink": "/api/v1/namespaces/default/endpoints/example", "uid": "db467530-b6aa-11e4-974a-525400c903c1", "resourceVersion": "38", "creationTimestamp": "2015-02-17T08:42:46-05:00" }, "endpoints": [ "172.17.0.63:80", "172.17.0.64:80" ] }, { "metadata": { "name": "kubernetes", "namespace": "default", "selfLink": "/api/v1/namespaces/default/endpoints/kubernetes", "resourceVersion": "8", "creationTimestamp": null }, "endpoints": [ "192.168.122.4:6443" ] }, { "metadata": { "name": "kubernetes-ro", "namespace": "default", "selfLink": "/api/v1/namespaces/default/endpoints/kubernetes-ro", "resourceVersion": "7", "creationTimestamp": null }, "endpoints": [ "192.168.122.4:7080" ] } ] } kubeclient-3.0.0/test/json/persistent_volume_claim_list.json0000644000004100000410000000160513255124405024504 0ustar www-datawww-data{ "kind": "PersistentVolumeClaimList", "apiVersion": "v1", "metadata": { "selfLink": "/api/v1/persistentvolumeclaims", "resourceVersion": "3188" }, "items": [ { "metadata": { "name": "myclaim-1", "namespace": "default", "selfLink": "/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1", "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe", "resourceVersion": "1584", "creationTimestamp": "2015-08-25T14:51:55Z" }, "spec": { "accessModes": [ "ReadWriteOnce" ], "resources": { "requests": { "storage": "3Gi" } }, "volumeName": "pv0001" }, "status": { "phase": "Bound", "accessModes": [ "ReadWriteOnce" ], "capacity": { "storage": "10Gi" } } } ] } kubeclient-3.0.0/test/json/versions_list.json0000644000004100000410000000007413255124405021417 0ustar www-datawww-data{ "versions": [ "v1beta3", "v1" ] } kubeclient-3.0.0/test/json/node_notice.json0000644000004100000410000001206513255124405021005 0ustar www-datawww-data{ "type": "ADDED", "object": { "apiVersion": "v1", "kind": "Node", "metadata": { "annotations": { "volumes.kubernetes.io/controller-managed-attach-detach": "true" }, "creationTimestamp": "2017-12-11T12:00:13Z", "labels": { "beta.kubernetes.io/arch": "amd64", "beta.kubernetes.io/os": "linux", "kubernetes.io/hostname": "openshift.local", "openshift-infra": "apiserver" }, "name": "openshift.local", "resourceVersion": "367410", "selfLink": "/api/v1/nodes/openshift.local", "uid": "d88c7af6-de6a-11e7-8725-52540080f1d2" }, "spec": { "externalID": "openshift.local" }, "status": { "addresses": [ { "address": "192.168.122.40", "type": "InternalIP" }, { "address": "openshift.local", "type": "Hostname" } ], "allocatable": { "cpu": "2", "memory": "8072896Ki", "pods": "20" }, "capacity": { "cpu": "2", "memory": "8175296Ki", "pods": "20" }, "conditions": [ { "lastHeartbeatTime": "2017-12-15T00:36:13Z", "lastTransitionTime": "2017-12-11T12:00:13Z", "message": "kubelet has sufficient disk space available", "reason": "KubeletHasSufficientDisk", "status": "False", "type": "OutOfDisk" }, { "lastHeartbeatTime": "2017-12-15T00:36:13Z", "lastTransitionTime": "2017-12-11T12:00:13Z", "message": "kubelet has sufficient memory available", "reason": "KubeletHasSufficientMemory", "status": "False", "type": "MemoryPressure" }, { "lastHeartbeatTime": "2017-12-15T00:36:13Z", "lastTransitionTime": "2017-12-11T12:00:13Z", "message": "kubelet has no disk pressure", "reason": "KubeletHasNoDiskPressure", "status": "False", "type": "DiskPressure" }, { "lastHeartbeatTime": "2017-12-15T00:36:13Z", "lastTransitionTime": "2017-12-14T15:43:39Z", "message": "kubelet is posting ready status", "reason": "KubeletReady", "status": "True", "type": "Ready" } ], "daemonEndpoints": { "kubeletEndpoint": { "Port": 10250 } }, "images": [ { "names": [ "docker.io/openshift/origin@sha256:908c6c9ccf0e0feefe2658899656c6e73d2854777fa340738fb903f0a40c328d", "docker.io/openshift/origin:latest" ], "sizeBytes": 1222636603 }, { "names": [ "docker.io/openshift/origin-deployer@sha256:3d324bce1870047edc418041cefdec88e0a5bbb5b3b9f6fd35b43f14919a656c", "docker.io/openshift/origin-deployer:v3.7.0" ], "sizeBytes": 1098951248 }, { "names": [ "docker.io/cockpit/kubernetes@sha256:a8e58cd5e6f5a4d12d1e2dfd339686b74f3c22586952ca7aa184dc254ab49714", "docker.io/cockpit/kubernetes:latest" ], "sizeBytes": 375926556 }, { "names": [ "docker.io/cockpit/kubernetes@sha256:0745b3823efc57e03a5ef378614dfcb6c2b1e3964220bbf908fb3046a91cef70" ], "sizeBytes": 350062743 }, { "names": [ "docker.io/openshift/origin-service-catalog@sha256:ef851e06276af96838a93320d0e4be51cc8de6e5afb2fb0efd4e56cec114b937" ], "sizeBytes": 284732029 }, { "names": [ "docker.io/openshift/origin-service-catalog@sha256:8addfd742d92d8da819b091d6bda40edc45e88d1446ffd1ad658b6d21b3c36fd" ], "sizeBytes": 284731998 }, { "names": [ "docker.io/openshift/origin-service-catalog@sha256:b3a737cc346b3cae85ef2f5d020b607781a1cac38fe70678cb78fee2c2a3bf8a" ], "sizeBytes": 284731943 }, { "names": [ "docker.io/openshift/origin-service-catalog@sha256:957934537721da33362693d4f1590dc79dc5da7438799bf14d645165768e53ef", "docker.io/openshift/origin-service-catalog:latest" ], "sizeBytes": 283929631 }, { "names": [ "docker.io/openshift/origin-pod@sha256:2c257d83a01607b229ef5e3dca09f52c3a2a2788c09dc33f0444ec4e572a9e1d", "docker.io/openshift/origin-pod:v3.7.0" ], "sizeBytes": 218423400 } ], "nodeInfo": { "architecture": "amd64", "bootID": "75be791d-88a2-4f56-a588-c071a80bf7cf", "containerRuntimeVersion": "docker://1.12.6", "kernelVersion": "3.10.0-693.11.1.el7.x86_64", "kubeProxyVersion": "v1.7.6+a08f5eeb62", "kubeletVersion": "v1.7.6+a08f5eeb62", "machineID": "adf09ffc2de2624aa5ed335727c7400d", "operatingSystem": "linux", "osImage": "CentOS Linux 7 (Core)", "systemUUID": "FC9FF0AD-E22D-4A62-A5ED-335727C7400D" } } } } kubeclient-3.0.0/test/json/service_account_list.json0000644000004100000410000000472713255124405022734 0ustar www-datawww-data{ "kind": "List", "apiVersion": "v1", "metadata": {}, "items": [ { "kind": "ServiceAccount", "apiVersion": "v1", "metadata": { "name": "builder", "namespace": "default", "selfLink": "/api/v1/namespaces/default/serviceaccounts/builder", "uid": "d40655f6-6bf0-11e5-843a-525400f8b93e", "resourceVersion": "133", "creationTimestamp": "2015-10-06T06:09:39Z" }, "secrets": [ { "name": "builder-token-5v6z2" }, { "name": "builder-dockercfg-qe2re" } ], "imagePullSecrets": [ { "name": "builder-dockercfg-qe2re" } ] }, { "kind": "ServiceAccount", "apiVersion": "v1", "metadata": { "name": "default", "namespace": "default", "selfLink": "/api/v1/namespaces/default/serviceaccounts/default", "uid": "d3d773f4-6bf0-11e5-843a-525400f8b93e", "resourceVersion": "94", "creationTimestamp": "2015-10-06T06:09:39Z" }, "secrets": [ { "name": "default-token-6s23q" }, { "name": "default-dockercfg-62tf3" } ], "imagePullSecrets": [ { "name": "default-dockercfg-62tf3" } ] }, { "kind": "ServiceAccount", "apiVersion": "v1", "metadata": { "name": "deployer", "namespace": "default", "selfLink": "/api/v1/namespaces/default/serviceaccounts/deployer", "uid": "d41d385e-6bf0-11e5-843a-525400f8b93e", "resourceVersion": "137", "creationTimestamp": "2015-10-06T06:09:39Z" }, "secrets": [ { "name": "deployer-token-h3i57" }, { "name": "deployer-dockercfg-qgjjj" } ], "imagePullSecrets": [ { "name": "deployer-dockercfg-qgjjj" } ] } ] } kubeclient-3.0.0/test/json/replication_controller.json0000644000004100000410000000315013255124405023266 0ustar www-datawww-data{ "kind": "ReplicationController", "apiVersion": "v1", "metadata": { "name": "guestbook-controller", "namespace": "default", "selfLink": "/api/v1/replicationcontrollers/guestbook-controller?namespace=default", "uid": "c71aa4c0-a240-11e4-a265-3c970e4a436a", "resourceVersion": "8", "creationTimestamp": "2015-01-22T16:13:02+02:00", "labels": { "name": "guestbook" } }, "spec": { "replicas": 3, "selector": { "name": "guestbook" }, "template": { "metadata": { "creationTimestamp": null, "labels": { "name": "guestbook" } }, "spec": { "volumes": null, "containers": [ { "name": "guestbook", "image": "kubernetes/guestbook", "ports": [ { "name": "http-server", "containerPort": 3000, "protocol": "TCP" } ], "memory": "0", "cpu": "0m", "imagePullPolicy": "" } ], "restartPolicy": { "always": { } }, "dnsPolicy": "ClusterFirst" } } }, "status": { "replicas": 3 } } kubeclient-3.0.0/test/json/node.json0000644000004100000410000000144613255124405017445 0ustar www-datawww-data{ "kind": "Node", "apiVersion": "v1", "metadata": { "name": "127.0.0.1", "selfLink": "/api/v1/nodes/127.0.0.1", "uid": "041143c5-ce39-11e4-ac24-3c970e4a436a", "resourceVersion": "1724", "creationTimestamp": "2015-03-19T15:08:20+02:00" }, "spec": { "capacity": { "cpu": "1", "memory": "3Gi" } }, "status": { "hostIP": "127.0.0.1", "conditions": [ { "kind": "Ready", "status": "None", "lastProbeTime": "2015-03-20T14:16:52+02:00", "lastTransitionTime": "2015-03-19T15:08:20+02:00", "reason": "Node health check failed: kubelet /healthz endpoint returns not ok" } ] } }kubeclient-3.0.0/test/json/namespace.json0000644000004100000410000000051613255124405020451 0ustar www-datawww-data{ "kind": "Namespace", "apiVersion": "v1", "metadata": { "name": "staging", "selfLink": "/api/v1/namespaces/staging", "uid": "e388bc10-c021-11e4-a514-3c970e4a436a", "resourceVersion": "1168", "creationTimestamp": "2015-03-01T16:47:31+02:00" }, "spec": {}, "status": {} }kubeclient-3.0.0/.gitignore0000644000004100000410000000017613255124405015664 0ustar www-datawww-data/.bundle/ /.yardoc /Gemfile.lock /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ *.bundle *.so *.o *.a mkmf.log *.idea* kubeclient-3.0.0/kubeclient.gemspec0000644000004100000410000000245113255124405017364 0ustar www-datawww-data# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'kubeclient/version' Gem::Specification.new do |spec| spec.name = 'kubeclient' spec.version = Kubeclient::VERSION spec.authors = ['Alissa Bonas'] spec.email = ['abonas@redhat.com'] spec.summary = 'A client for Kubernetes REST api' spec.description = 'A client for Kubernetes REST api' spec.homepage = 'https://github.com/abonas/kubeclient' spec.license = 'MIT' spec.files = `git ls-files -z`.split("\x0") spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] spec.required_ruby_version = '>= 2.2.0' spec.add_development_dependency 'bundler', '~> 1.6' spec.add_development_dependency 'rake', '~> 12.0' spec.add_development_dependency 'minitest' spec.add_development_dependency 'minitest-rg' spec.add_development_dependency 'webmock', '~> 3.0.1' spec.add_development_dependency 'vcr' spec.add_development_dependency 'rubocop', '= 0.49.1' spec.add_dependency 'rest-client', '~> 2.0' spec.add_dependency 'recursive-open-struct', '~> 1.0.4' spec.add_dependency 'http', '~> 2.2.2' end kubeclient-3.0.0/CHANGELOG.md0000644000004100000410000000323313255124405015502 0ustar www-datawww-data# Changelog Notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ## 3.0.0 - 2018-02-01 ### Removed - Dropped entity classes (`Kubeclient::Pod` etc.), only `Kubeclient::Resource` exists now (#292, #288). - Ruby 2.0, 2.1 no longer supported (#253, #291). ### Fixed - Watch results are now `RecursiveOpenStruct` inside arrays too (#279). - Fixed watch `.finish` sometimes caused `Errno::EBADF` exception from the reading loop (#280). - Added missing singular `get_security_context_constraint`, fixed `get_security_context_constraints` to mean plural (#261). - Fixed `@http_proxy_uri` undefined warning (#261). - Documentation fixes & improvements (#225, #229, #243, #296). ### Added - `delete_options:` parameter to `delete_*` methods, useful for cascade delete (#267). - `as: :raw` option for watch (#285). - Now raises `Kubeclient::HttpError`. Rescuing `KubeException` still works but is deprecated. (#195, #288) - 404 error raise `Kubeclient::ResourceNotFoundError`, a subclass of `HttpError` (#233). - Include request info in exception message (#221). - Ruby 2.4 and 2.5 are now supported & tested (#247, #295). ### Changed - `Kubeclient::Config#context(nonexistent_context_name)` raises `KeyError` instead of `RuntimeError`. - `update_*`, `delete_*`, `patch_*` now all return `RecursiveOpenStruct` consistently (#290). - Many dependencies bumped (#204, #231, #253, #269). ## 2.5.1 - 2017-10-12 No changes since 2.5.0, fixed packaging mistake. ## [2.5.0 - 2017-10-12 was YANKED] ### Added - `as: raw` option for `get_*` methods returning a string (#262 via #271) ## 2.4.0 - 2017-05-10 kubeclient-3.0.0/README.md0000644000004100000410000003711513255124405015156 0ustar www-datawww-data# Kubeclient [![Gem Version](https://badge.fury.io/rb/kubeclient.svg)](http://badge.fury.io/rb/kubeclient) [![Build Status](https://travis-ci.org/abonas/kubeclient.svg?branch=master)](https://travis-ci.org/abonas/kubeclient) [![Code Climate](http://img.shields.io/codeclimate/github/abonas/kubeclient.svg)](https://codeclimate.com/github/abonas/kubeclient) [![Dependency Status](https://gemnasium.com/abonas/kubeclient.svg)](https://gemnasium.com/abonas/kubeclient) A Ruby client for Kubernetes REST api. The client supports GET, POST, PUT, DELETE on all the entities available in kubernetes in both the core and group apis. The client currently supports Kubernetes REST api version v1. To learn more about groups and versions in kubernetes refer to [k8s docs](https://kubernetes.io/docs/api/) ## Installation Add this line to your application's Gemfile: ```ruby gem 'kubeclient' ``` And then execute: ```Bash bundle ``` Or install it yourself as: ```Bash gem install kubeclient ``` ## Usage Initialize the client: ```ruby client = Kubeclient::Client.new('http://localhost:8080/api/', "v1") ``` Or without specifying version (it will be set by default to "v1") ```ruby client = Kubeclient::Client.new('http://localhost:8080/api/') ``` For A Group Api: ```ruby client = Kubeclient::Client.new('http://localhost:8080/apis/batch', 'v1') ``` Another option is to initialize the client with URI object: ```ruby uri = URI::HTTP.build(host: "somehostname", port: 8080) client = Kubeclient::Client.new(uri) ``` ### SSL It is also possible to use https and configure ssl with: ```ruby ssl_options = { client_cert: OpenSSL::X509::Certificate.new(File.read('/path/to/client.crt')), client_key: OpenSSL::PKey::RSA.new(File.read('/path/to/client.key')), ca_file: '/path/to/ca.crt', verify_ssl: OpenSSL::SSL::VERIFY_PEER } client = Kubeclient::Client.new( 'https://localhost:8443/api/', "v1", ssl_options: ssl_options ) ``` As an alternative to the `ca_file` it's possible to use the `cert_store`: ```ruby cert_store = OpenSSL::X509::Store.new cert_store.add_cert(OpenSSL::X509::Certificate.new(ca_cert_data)) ssl_options = { cert_store: cert_store, verify_ssl: OpenSSL::SSL::VERIFY_PEER } client = Kubeclient::Client.new( 'https://localhost:8443/api/', "v1", ssl_options: ssl_options ) ``` For testing and development purpose you can disable the ssl check with: ```ruby ssl_options = { verify_ssl: OpenSSL::SSL::VERIFY_NONE } client = Kubeclient::Client.new( 'https://localhost:8443/api/', 'v1', ssl_options: ssl_options ) ``` ### Authentication If you are using basic authentication or bearer tokens as described [here](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authentication.md) then you can specify one of the following: ```ruby auth_options = { username: 'username', password: 'password' } client = Kubeclient::Client.new( 'https://localhost:8443/api/', 'v1', auth_options: auth_options ) ``` or ```ruby auth_options = { bearer_token: 'MDExMWJkMjItOWY1Ny00OGM5LWJlNDEtMjBiMzgxODkxYzYz' } client = Kubeclient::Client.new( 'https://localhost:8443/api/', 'v1', auth_options: auth_options ) ``` or ```ruby auth_options = { bearer_token_file: '/path/to/token_file' } client = Kubeclient::Client.new( 'https://localhost:8443/api/', 'v1', auth_options: auth_options ) ``` If you are running your app using kubeclient inside a Kubernetes cluster, then you can have a bearer token file mounted inside your pod by using a [Service Account](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/design/service_accounts.md). This will mount a bearer token [secret](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/design/secrets.md) a/ `/var/run/secrets/kubernetes.io/serviceaccount/token` (see [here](https://github.com/GoogleCloudPlatform/kubernetes/pull/7101) for more details). For example: ```ruby auth_options = { bearer_token_file: '/var/run/secrets/kubernetes.io/serviceaccount/token' } client = Kubeclient::Client.new( 'https://localhost:8443/api/', 'v1', auth_options: auth_options ) ``` You can find information about tokens in [this guide](http://kubernetes.io/docs/user-guide/accessing-the-cluster/) and in [this reference](http://kubernetes.io/docs/admin/authentication/). ### Non-blocking IO You can also use kubeclient with non-blocking sockets such as Celluloid::IO, see [here](https://github.com/httprb/http/wiki/Parallel-requests-with-Celluloid%3A%3AIO) for details. For example: ```ruby require 'celluloid/io' socket_options = { socket_class: Celluloid::IO::TCPSocket, ssl_socket_class: Celluloid::IO::SSLSocket } client = Kubeclient::Client.new( 'https://localhost:8443/api/', 'v1', socket_options: socket_options ) ``` This affects only `.watch_*` sockets, not one-off actions like `.get_*`, `.delete_*` etc. ### Proxies You can also use kubeclient with an http proxy server such as tinyproxy. It can be entered as a string or a URI object. For example: ```ruby proxy_uri = URI::HTTP.build(host: "myproxyhost", port: 8443) client = Kubeclient::Client.new( 'https://localhost:8443/api/', http_proxy_uri: proxy_uri ) ``` ### Timeouts Watching never times out. One-off actions like `.get_*`, `.delete_*` have a configurable timeout: ```ruby timeouts = { open: 10, # unit is seconds read: nil # nil means never time out } client = Kubeclient::Client.new( 'https://localhost:8443/api/', timeouts: timeouts ) ``` Default timeouts match `Net::HTTP` and `RestClient`, which unfortunately depends on ruby version: - open was infinite up to ruby 2.2, 60 seconds in 2.3+. - read is 60 seconds. If you want ruby-independent behavior, always specify `:open`. ### Discovery Discovery from the kube-apiserver is done lazily on method calls so it would not change behavior. It can also be done explicitly: ```ruby client = Kubeclient::Client.new('http://localhost:8080/api', 'v1') client.discover ``` It is possible to check the status of discovery ```ruby unless client.discovered client.discover end ``` ### Kubeclient::Config If you've been using `kubectl` and have a `.kube/config` file, you can auto-populate a config object using `Kubeclient::Config`: ```ruby config = Kubeclient::Config.read('/path/to/.kube/config') ``` ...and then pass that object to `Kubeclient::Client`: ``` Kubeclient::Client.new( config.context.api_endpoint, config.context.api_version, { ssl_options: config.context.ssl_options, auth_options: config.context.auth_options } ) ``` You can also load your JSONified config in from an ENV variable (e.g. `KUBE_CONFIG`) like so: ```ruby Kubeclient::Config.new(JSON.parse(ENV['KUBE_CONFIG']), nil) ``` ### Supported kubernetes versions For 1.1 only the core api v1 is supported, all api groups are supported in later versions. ## Examples: #### Get all instances of a specific entity type Such as: `get_pods`, `get_secrets`, `get_services`, `get_nodes`, `get_replication_controllers`, `get_resource_quotas`, `get_limit_ranges`, `get_persistent_volumes`, `get_persistent_volume_claims`, `get_component_statuses`, `get_service_accounts` ```ruby pods = client.get_pods ``` Get all entities of a specific type in a namespace:
```ruby services = client.get_services(namespace: 'development') ``` You can get entities which have specific labels by specifying a parameter named `label_selector` (named `labelSelector` in Kubernetes server): ```ruby pods = client.get_pods(label_selector: 'name=redis-master') ``` You can specify multiple labels (that option will return entities which have both labels: ```ruby pods = client.get_pods(label_selector: 'name=redis-master,app=redis') ``` #### Get a specific instance of an entity (by name) Such as: `get_service "service name"` , `get_pod "pod name"` , `get_replication_controller "rc name"`, `get_secret "secret name"`, `get_resource_quota "resource quota name"`, `get_limit_range "limit range name"` , `get_persistent_volume "persistent volume name"` , `get_persistent_volume_claim "persistent volume claim name"`, `get_component_status "component name"`, `get_service_account "service account name"` The GET request should include the namespace name, except for nodes and namespaces entities. ```ruby node = client.get_node "127.0.0.1" ``` ```ruby service = client.get_service "guestbook", 'development' ``` Note - Kubernetes doesn't work with the uid, but rather with the 'name' property. Querying with uid causes 404. #### Getting raw responses By passing `as: :raw`, the response from the client is given as a string, which is the raw JSON body from openshift: ```ruby pods = client.get_pods as: :raw node = client.get_node "127.0.0.1", as: :raw ``` #### Delete an entity (by name) For example: `delete_pod "pod name"` , `delete_replication_controller "rc name"`, `delete_node "node name"`, `delete_secret "secret name"` Input parameter - name (string) specifying service name, pod name, replication controller name. ```ruby deleted = client.delete_service("redis-service") ``` If you want to cascade delete, for example a deployment, you can use the `delete_options` parameter. ```ruby deployment_name = 'redis-deployment' namespace = 'default' delete_options = Kubeclient::Resource.new( apiVersion: 'meta/v1', gracePeriodSeconds: 0, kind: 'DeleteOptions', propagationPolicy: 'Foreground' # Orphan, Foreground, or Background ) client.delete_deployment(deployment_name, namespace, delete_options: delete_options) ``` #### Create an entity For example: `create_pod pod_object`, `create_replication_controller rc_obj`, `create_secret secret_object`, `create_resource_quota resource_quota_object`, `create_limit_range limit_range_object`, `create_persistent_volume persistent_volume_object`, `create_persistent_volume_claim persistent_volume_claim_object`, `create_service_account service_account_object` Input parameter - object of type `Service`, `Pod`, `ReplicationController`. The below example is for v1 ```ruby service = Kubeclient::Resource.new service.metadata = {} service.metadata.name = "redis-master" service.metadata.namespace = 'staging' service.spec = {} service.spec.ports = [{ 'port' => 6379, 'targetPort' => 'redis-server' }] service.spec.selector = {} service.spec.selector.name = "redis" service.spec.selector.role = "master" service.metadata.labels = {} service.metadata.labels.app = 'redis' service.metadata.labels.role = 'slave' client.create_service(service) ``` #### Update an entity For example: `update_pod`, `update_service`, `update_replication_controller`, `update_secret`, `update_resource_quota`, `update_limit_range`, `update_persistent_volume`, `update_persistent_volume_claim`, `update_service_account` Input parameter - object of type `Pod`, `Service`, `ReplicationController` etc. The below example is for v1 ```ruby updated = client.update_service(service1) ``` #### Patch an entity (by name) For example: `patch_pod`, `patch_service`, `patch_secret`, `patch_resource_quota`, `patch_persistent_volume` Input parameters - name (string) specifying the entity name, patch (hash) to be applied to the resource, optional: namespace name (string) The PATCH request should include the namespace name, except for nodes and namespaces entities. The below example is for v1 ```ruby patched = client.patch_pod("docker-registry", {metadata: {annotations: {key: 'value'}}}, "default") ``` #### Get all entities of all types : all_entities Returns a hash with the following keys (node, secret, service, pod, replication_controller, namespace, resource_quota, limit_range, endpoint, event, persistent_volume, persistent_volume_claim, component_status and service_account). Each key points to an EntityList of same type. This method is a convenience method instead of calling each entity's get method separately. ```ruby client.all_entities ``` #### Receive entity updates It is possible to receive live update notices watching the relevant entities: ```ruby watcher = client.watch_pods watcher.each do |notice| # process notice data end ``` It is possible to interrupt the watcher from another thread with: ```ruby watcher.finish ``` Pass `as: :raw` to `watch_*` get raw replies. #### Watch events for a particular object You can use the `field_selector` option as part of the watch methods. ```ruby watcher = client.watch_events(namespace: 'development', field_selector: 'involvedObject.name=redis-master') watcher.each do |notice| # process notice date end ``` #### Get a proxy URL You can get a complete URL for connecting a kubernetes entity via the proxy. ```ruby client.proxy_url('service', 'srvname', 'srvportname', 'ns') # => "https://localhost.localdomain:8443/api/v1/proxy/namespaces/ns/services/srvname:srvportname" ``` Note the third parameter, port, is a port name for services and an integer for pods: ```ruby client.proxy_url('pod', 'podname', 5001, 'ns') # => "https://localhost.localdomain:8443/api/v1/namespaces/ns/pods/podname:5001/proxy" ``` #### Get the logs of a pod You can get the logs of a running pod, specifying the name of the pod and the namespace where the pod is running: ```ruby client.get_pod_log('pod-name', 'default') # => "Running...\nRunning...\nRunning...\n" ``` If that pod has more than one container, you must specify the container: ```ruby client.get_pod_log('pod-name', 'default', container: 'ruby') # => "..." ``` If a container in a pod terminates, a new container is started, and you want to retrieve the logs of the dead container, you can pass in the `:previous` option: ```ruby client.get_pod_log('pod-name', 'default', previous: true) # => "..." ``` You can also watch the logs of a pod to get a stream of data: ```ruby watcher = client.watch_pod_log('pod-name', 'default', container: 'ruby') watcher.each do |line| puts line end ``` #### Process a template Returns a processed template containing a list of objects to create. Input parameter - template (hash) Besides its metadata, the template should include a list of objects to be processed and a list of parameters to be substituted. Note that for a required parameter that does not provide a generated value, you must supply a value. ##### Note: This functionality is not supported by K8s at this moment. See the following [issue](https://github.com/kubernetes/kubernetes/issues/23896) ```ruby client.process_template template ``` ## Upgrading See [CHANGELOG.md](CHANGELOG.md) for full changelog. #### past version 3.0 Ruby versions < 2.2 are no longer supported Specific entity classes mentioned in [past version 1.2.0](#past_version_1.2.0) have been dropped. Return values and expected classes are always Kubeclient::Resource. Checking the type of a resource can be done using: ``` > pod.kind => "Pod" ``` update_* delete_* and patch_* now return a RecursiveOpenStruct like the get_* methods The gem raises Kubeclient::HttpError or subclasses now. Catching KubeException still works but is deprecated. `Kubeclient::Config#context` raises KeyError instead of RuntimeError for non-existent context name. #### past version 1.2.0 Replace Specific Entity class references: ```ruby Kubeclient::Service ``` with the generic ```ruby Kubeclient::Resource.new ``` Where ever possible. ## Contributing 1. Fork it ( https://github.com/[my-github-username]/kubeclient/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Test your changes with `rake test rubocop`, add new tests if needed. 4. If you added a new functionality, add it to README 5. Commit your changes (`git commit -am 'Add some feature'`) 6. Push to the branch (`git push origin my-new-feature`) 7. Create a new Pull Request ## Tests This client is tested with Minitest and also uses VCR recordings in some tests. Please run all tests before submitting a Pull Request, and add new tests for new functionality. Running tests: ```ruby rake test ```