Skip to content

Commit

Permalink
Merge pull request #3 from spoved/k8scr-update
Browse files Browse the repository at this point in the history
updates required for new k8s.cr changes
  • Loading branch information
kalinon authored Apr 21, 2022
2 parents 7ecdfe2 + 718d057 commit 65f66f1
Show file tree
Hide file tree
Showing 11 changed files with 40 additions and 33 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

on:
push:
branches: [master]
pull_request:
branches: [master]
schedule:
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ spec: ## Run tests
@k3d cluster delete k3d-cluster-test


gen: ## Generate version files
@crystal ./bin/gen
# gen: ## Generate version files
# @crystal ./bin/gen

docs: ## Generate docs
@crystal ./bin/gen_docs.cr
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ $ crystal build -Dk8s_v1.20 kube-client.cr

The top-level `Kube::Client` provides access to separate `APIClient` instances for each Kubernetes API Group (`v1`, `apps/v1`, etc.), which in turns provides access to separate `ResourceClient` instances for each API resource type (`nodes`, `pods`, `deployments`, etc.).

Individual resources are returned as `K8S::Resource` instances, which provide attribute access (`resource.metadata.name`). The resource instances are returned by methods such as `client.api("v1").resource("nodes").get("foo")`, and passed as arguments for `client.api("v1").resource("nodes").create_resource(res)`. Resources can also be loaded from disk using `Kube::Resource.from_files(path)`, and passed to the top-level methods such as `client.create_resource(res)`, which lookup the correct API/Resource client from the resource `apiVersion` and `kind`.
Individual resources are returned as `K8S::Kubernetes::Resource` instances, which provide attribute access (`resource.metadata.name`). The resource instances are returned by methods such as `client.api("v1").resource("nodes").get("foo")`, and passed as arguments for `client.api("v1").resource("nodes").create_resource(res)`. Resources can also be loaded from disk using `Kube::Resource.from_files(path)`, and passed to the top-level methods such as `client.create_resource(res)`, which lookup the correct API/Resource client from the resource `apiVersion` and `kind`.

The different `Kube::Error::API` subclasses represent different HTTP response codes, such as `Kube::Error::NotFound` or `Kube::Error::Conflict`.

Expand Down Expand Up @@ -169,7 +169,7 @@ pod = client.api("v1").resource("pods").create_resource(pod)
#### From file(s)

```crystal
resources = K8S::Resource.from_file("./test.yaml")
resources = K8S::Kubernetes::Resource.from_file("./test.yaml")
resources = client.create_resources(resources)
```
Expand Down
12 changes: 6 additions & 6 deletions shard.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
name: kube-client
version: 0.3.2

crystal: ">= 1.2.2, < 2.0.0"

description: Kubernetes Object Mappings for Crystal
authors:
- Holden Omans <[email protected]>

repository: "https://github.com/spoved/kube-client.cr"
license: MIT

version: 0.3.2
crystal: ">= 1.2.2, < 2.0.0"

dependencies:
k8s:
github: spoved/k8s.cr
version: "~> 0.0.5"
version: "~> 0.1.0"
spoved:
github: spoved/spoved.cr
db:
Expand Down
4 changes: 2 additions & 2 deletions spec/kube/api_client_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Spectator.describe Kube::ApiClient do

describe "#client_for_resource" do
describe "for an invalid resource apiVersion" do
# let(resource) { K8S::Resource.new(
# let(resource) { K8S::Kubernetes::Resource.new(
# api_version: "test/v1",
# kind: "Test",
# ) }
Expand All @@ -118,7 +118,7 @@ Spectator.describe Kube::ApiClient do
end

describe "for an invalid resource kind" do
# let(resource) { K8S::Resource.new(
# let(resource) { K8S::Kubernetes::Resource.new(
# api_version: "v1",
# kind: "Wtf",
# ) }
Expand Down
2 changes: 1 addition & 1 deletion spec/kube/client_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ Spectator.describe Kube::Client do
client = Kube::Client.new(new_transport)
resources = client.list_resources
expect(resources).to_not be_empty
expect(resources).to be_a Array(K8S::Resource)
# expect(resources).to be_a Array(K8S::Kubernetes::Resource)
end
end
14 changes: 9 additions & 5 deletions spec/kube/resource_client_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ Spectator.describe Kube::ResourceClient do
it "returns an array of resources" do
list = subject.list

expect(list).to match Array(K8S::Api::Core::V1::Node)
expect(list).to be_a Indexable(K8S::Api::Core::V1::Node)
expect(list).to be_a K8S::Kubernetes::Resource::ListWrapper(K8S::Api::Core::V1::Node)
list.each do |node|
expect(node).to be_a K8S::Api::Core::V1::Node
end
expect(list.map { |item| {
kind: item.kind,
namespace: item.metadata!.namespace,
Expand All @@ -89,7 +93,7 @@ Spectator.describe Kube::ResourceClient do
describe "#get" do
it "returns a resource" do
obj = subject.get(node_name)
expect(obj).to be_a K8S::Resource
expect(obj).to be_a K8S::Kubernetes::Resource
expect(obj).to be_a K8S::Api::Core::V1::Node
expect(obj.kind).to eq "Node"
expect(obj.metadata!.namespace).to be nil
Expand All @@ -116,7 +120,7 @@ Spectator.describe Kube::ResourceClient do
it "returns a resource" do
expect(subject.patch?).to be_true
obj = subject.merge_patch(node_name, {spec: {unschedulable: true}})
expect(obj).to match K8S::Resource
expect(obj).to match K8S::Kubernetes::Resource
expect(obj.kind).to eq "Node"
expect(obj.metadata!.name).to eq node_name
expect(obj.spec.try(&.unschedulable)).to be true
Expand Down Expand Up @@ -201,7 +205,7 @@ Spectator.describe Kube::ResourceClient do
end

let(resource) { pod_resource }
let(resource_list) { K8S::ResourceList(K8S::Api::Core::V1::Pod).new(metadata: K8S::ListMeta.new, items: [resource]) }
let(resource_list) { K8S::Kubernetes::ResourceList(K8S::Api::Core::V1::Pod).new(metadata: K8S::ListMeta.new, items: [resource]) }

context "POST /api/v1/pods/namespaces/default/pods" do
describe "#create_resource" do
Expand Down Expand Up @@ -254,7 +258,7 @@ Spectator.describe Kube::ResourceClient do
sleep(0.2)
items = subject.delete_collection(namespace: "default", label_selector: "app=kube-client-test")

expect(items).to match Array(K8S::Api::Core::V1::Pod)
expect(items).to match Indexable(K8S::Api::Core::V1::Pod)
expect(items.map(&.kind)).to all eq "Pod"
expect(items.map(&.metadata!.name)).to have r.metadata!.name
end
Expand Down
2 changes: 1 addition & 1 deletion spec/kube/transport_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Spectator.describe Kube::Transport do
resp = trans.get(path)
expect(resp).to_not be_nil
expect(resp).to be_a(K8S::Api::Core::V1::NamespaceList)
expect(resp.as(K8S::Api::Core::V1::NamespaceList).items).to be_a(Array(K8S::Api::Core::V1::Namespace))
expect(resp.as(K8S::Api::Core::V1::NamespaceList).items).to be_a(Indexable(K8S::Api::Core::V1::Namespace))
end

it "#gets" do
Expand Down
8 changes: 4 additions & 4 deletions src/kube/api_client.cr
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ module Kube
end

def client_for_resource(resource : T, namespace : String? = nil) : ResourceClient(T) forall T
if resource.is_a?(::K8S::Kubernetes::Resource::Object)
client_for_resource(resource.api_version, resource.kind, resource.metadata.try(&.namespace) || namespace)
if resource.is_a?(::K8S::Kubernetes::Resource)
client_for_resource(resource.api_version, resource.kind, resource.metadata.try(&.namespace) || namespace).as(ResourceClient(T))
else
client_for_resource(resource.api_version, resource.kind, namespace)
client_for_resource(resource.api_version, resource.kind, namespace).as(ResourceClient(T))
end
end

Expand All @@ -90,7 +90,7 @@ module Kube
# Pipeline list requests for multiple resource types.
#
# Returns flattened array with mixed resource kinds.
def list_resources(resources : Array(Kube::ResourceClient)? = nil, **options) : Array(K8S::Resource)
def list_resources(resources : Array(Kube::ResourceClient)? = nil, **options) : Indexable
Log.trace { "list_resources(#{resources}, #{options})" }
resources ||= self.resources.select(&.list?)
ResourceClient.list(resources, @transport, **options)
Expand Down
18 changes: 10 additions & 8 deletions src/kube/resource_client.cr
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module Kube
#
# `skip_forbidden` [Boolean] skip resources that return HTTP 403 errors
def self.list(resources : Array(ResourceClient), transport : Transport, namespace : String? = nil,
label_selector = nil, field_selector = nil, skip_forbidden = false) : Array(K8S::Resource)
label_selector = nil, field_selector = nil, skip_forbidden = false) : Indexable
api_paths = resources.map(&.path(namespace: namespace))

api_lists = transport.gets(
Expand Down Expand Up @@ -99,7 +99,9 @@ module Kube
end
end

define_new
macro finished
define_new
end

def initialize(@transport, @api_client, @api_resource, @namespace, @resource_class)
@logger = ::Log.for("Kube::ResourceClient(#{@resource_class}")
Expand Down Expand Up @@ -169,8 +171,8 @@ module Kube
).as(T)
end

# returns response body as a String instead of T
def get_as_string(name, namespace = @namespace)
# returns response body as a String instead of T
def get_as_string(name, namespace = @namespace)
@transport.request(
method: "GET",
path: path(name, namespace: namespace),
Expand All @@ -191,8 +193,8 @@ module Kube
@api_resource.verbs.includes? "list"
end

def process_list(list) : Array(T)
if (list.is_a?(K8S::Kubernetes::ResourceList(T)))
def process_list(list) : Indexable(T)
if (list.is_a?(K8S::Kubernetes::Resource::List(T)))
list.items
else
Array(T).new
Expand All @@ -201,7 +203,7 @@ module Kube

# returns array of instances of resource_class
def list(label_selector : String | Hash(String, String) | Nil = nil,
field_selector : String | Hash(String, String) | Nil = nil, namespace = @namespace) : Array(T)
field_selector : String | Hash(String, String) | Nil = nil, namespace = @namespace) : Indexable(T)
list = meta_list(label_selector: label_selector, field_selector: field_selector, namespace: namespace)
process_list(list)
end
Expand Down Expand Up @@ -306,7 +308,7 @@ module Kube
def delete_collection(namespace = @namespace,
label_selector : String | Hash(String, String) | Nil = nil,
field_selector : String | Hash(String, String) | Nil = nil,
propagation_policy : String? = nil) : Array(T)
propagation_policy : String? = nil) : Indexable(T)
list = @transport.request(
method: "DELETE",
path: path(namespace: namespace),
Expand Down
4 changes: 2 additions & 2 deletions src/kube/transport/requests.cr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module Kube
headers["Authorization"] = "Basic #{Base64.strict_encode("#{@auth_username}:#{@auth_password}")}"
end

if request_object.is_a?(::JSON::Serializable) || request_object.is_a?(NamedTuple) || request_object.is_a?(Hash)
if request_object.is_a?(::JSON::Serializable) || request_object.is_a?(NamedTuple) || request_object.is_a?(Hash) || request_object.is_a?(K8S::Kubernetes::Object)
options.merge(
headers: headers,
body: request_object.to_json,
Expand Down Expand Up @@ -165,9 +165,9 @@ module Kube
logger.debug { "Response: #{response.body}" } unless response.nil?
raise ex
else
logger.info { "#{format_request(options)} => HTTP #{response.status}: #{obj.inspect} in #{t}s" }
logger.debug { "Request: #{req_options}" } unless req_options.nil?
logger.debug { "Response: #{response.body}" }
logger.info { "#{format_request(options)} => HTTP #{response.status}: #{obj.inspect} in #{t}s" }
obj
end

Expand Down

0 comments on commit 65f66f1

Please sign in to comment.