kubernetes-api is a Clojure library that acts as a kubernetes client
Motivation
We had a good experience with cognitect-labs/aws-api, and missed something like that for Kubernetes API. We had some client libraries that generated a lot of code, but it lacked discoverability and documentation.
clojure.deps
{:deps {nubank/k8s-api {:mvn/version "1.1.0"}}}Leiningen
[nubank/k8s-api "1.1.0"];; In your ns statement (ns my.ns (:require [kubernetes-api.core :as k8s]))
Usage
Instantiate a client
There're multiple options for authentication while instantiating a client. You can explicit set a token:
(def k8s (k8s/client "http://some.host" {:token "..."}))
Or a function that returns the token
(def k8s (k8s/client "http://some.host" {:token-fn (constantly "...")}))
You can also define client certificates
(def k8s (k8s/client "http://some.host" {:ca-cert "/some/path/ca-docker.crt" :client-cert "/some/path/client-cert.pem" :client-key "/some/path/client-java.key"}))
kubeconfig loader
You can load configuration from a kubeconfig file, either by explicit setting it, or by setting the environment variable KUBECONFIG. It also supports multiple files
(def k8s (->> (loader.kubeconfig/load-context {:kubeconfig "/path/to/some/kubeconfig.yaml" :context "prod-xpto-000-context"}) (k8s/from-context))) ; load from KUBECONFIG or defaulting to ~/.kube/config (def k8s (->> (loader.kubeconfig/load-context {:context "prod-xpto-000-context"}) (k8s/from-context))) ; load multiple files. It will find the first context that matches. (def k8s (->> (loader.kubeconfig/load-context {:kubeconfig ["/path/to/some/kubeconfig.yaml" "/path/to/another/kubeconfig.yaml"] :context "prod-xpto-000-context"}) (k8s/from-context)))
OpenAPI config
Discovery
It's possible but NOT RECOMMENDED to disable the OpenAPI specification discovery. This will prevent requests to
/openapi/... endpoints and use the specification from the resources folder. This specification has no guarantees in
terms of versioning, so it will be outdated.
(def k8s (k8s/client "http://some.host" {:token "..." :openapi {:discovery :disabled}}))
Filter paths from api
You can filter the paths from the OpenAPI specification. This is useful when you want to use a specific version of the api, or when you want to use a specific group of resources.
(def k8s (k8s/client "http://some.host" {:token "..." :apis ["some.api/v1alpha1", "another.api"]}))
Discover
You can list all operations with
(k8s/explore k8s)or specify a specific entity
(k8s/explore k8s :Deployment) ;=> [:Deployment [:get "read the specified Deployment"] [:update "replace the specified Deployment"] [:delete "delete a Deployment"] [:patch "partially update the specified Deployment"] [:list "list or watch objects of kind Deployment"] [:create "create a Deployment"] [:deletecollection "delete collection of Deployment"] [:list-all "list or watch objects of kind Deployment"]]
get info on an operation
(k8s/info k8s {:kind :Deployment :action :create}) ;=> {:summary "create a Deployment", :parameters {:namespace java.lang.String, #schema.core.OptionalKey{:k :pretty} (maybe Str), #schema.core.OptionalKey{:k :dry-run} (maybe Str), #schema.core.OptionalKey{:k :field-manager} (maybe Str), :body ...}, :returns {200 {#schema.core.OptionalKey{:k :apiVersion} (maybe Str), #schema.core.OptionalKey{:k :kind} (maybe Str), #schema.core.OptionalKey{:k :metadata} ..., #schema.core.OptionalKey{:k :spec} ..., #schema.core.OptionalKey{:k :status} ...}, 201 {#schema.core.OptionalKey{:k :apiVersion} (maybe Str), #schema.core.OptionalKey{:k :kind} (maybe Str), #schema.core.OptionalKey{:k :metadata} ..., #schema.core.OptionalKey{:k :spec} ..., #schema.core.OptionalKey{:k :status} ...}, 202 {#schema.core.OptionalKey{:k :apiVersion} (maybe Str), #schema.core.OptionalKey{:k :kind} (maybe Str), #schema.core.OptionalKey{:k :metadata} ..., #schema.core.OptionalKey{:k :spec} ..., #schema.core.OptionalKey{:k :status} ...}, 401 Any}}
Invoke
You can call an operation with
(k8s/invoke k8s {:kind :ConfigMap :action :create :request {:namespace "default" :body {:api-version "v1" :data {"foo" "bar"}}}})
invoke it will return the body, with :request and :response in metadata
(meta (k8s/invoke ...)) ;=> {:request ... :response {:status ... :body ...}}
You can debug the request map with
(k8s/request k8s {:kind :ConfigMap :action :create :request {:namespace "default" :body {:api-version "v1" :data {"foo" "bar"}}}})
If you want to read more about all different patch strategies Kubernetes offers, check this document