From d8016d12059ed52435702959269e42c506e8a355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?And=C5=BEej=20Maciusovi=C4=8D?= Date: Sun, 31 Jul 2022 22:50:54 +0300 Subject: [PATCH] Add conformance test (#1) --- .github/workflows/pull_request.yaml | 11 +++++----- README.md | 33 ++++++++++++++++++++++++++++- client_test.go | 22 ++++++++++++++++++- conformance/job.yaml | 3 +++ conformance/main.go | 7 ++++-- conformance/run.sh | 14 ++++++++++-- 6 files changed, 79 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml index cd2e4ff..c1ffa24 100644 --- a/.github/workflows/pull_request.yaml +++ b/.github/workflows/pull_request.yaml @@ -1,9 +1,9 @@ -name: Test conformance +name: Test on: pull_request jobs: - create-cluster: + test: runs-on: ubuntu-latest steps: - name: Checkout @@ -24,7 +24,7 @@ jobs: - name: Build Go binary run: | cd ./conformance - go build -ldflags "-s -w" -o conformance . + go build -ldflags "-s -w" -o bin/conformance . env: GOOS: linux GOARCH: amd64 @@ -41,12 +41,13 @@ jobs: uses: docker/build-push-action@v2 with: context: ./conformance + push: true tags: ghcr.io/castai/k8s-client-go/conformance:${{ github.sha }} - name: Create k8s cluster uses: helm/kind-action@v1.3.0 - - name: Run conformance + - name: Run tests run: | cd ./conformance - ./run.sh \ No newline at end of file + IMG=ghcr.io/castai/k8s-client-go/conformance:${{ github.sha }} ./run.sh \ No newline at end of file diff --git a/README.md b/README.md index 5e0ca7d..6bc3161 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,34 @@ # k8s-client-go -Minimal Go Kubernetes client +Minimal Go Kubernetes client based on Generics + +## Usage + +```go +import ( + "context" + "log" + "fmt" + client "github.com/castai/k8s-client-go" +) + +func main() { + kc, err := client.NewInCluster() + if err != nil { + log.Fatal(err) + } + ctx := context.Backgroud() + endpoints, err := client.Get[*client.Endpoints](kc, ctx, "/api/v1/namespaces/kube-system/endpoints/kubelet", client.GetOptions{}) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%+v", endpoints) +} +``` + +See more in [Examples](https://github.com/castai/k8s-client-go/blob/master/client_test.go#L10) + +## Use cases + +* Embedding in Go applications for minimal binary size overhead. +* Service discovery by listing and watching [endpoints](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/endpoints-v1/). See [kuberesolver](https://github.com/sercand/kuberesolver) as example for gRPC client side load balancing. \ No newline at end of file diff --git a/client_test.go b/client_test.go index 5060326..74c2626 100644 --- a/client_test.go +++ b/client_test.go @@ -11,13 +11,33 @@ func ExampleClient() { kc, err := client.NewInCluster() if err != nil { // Handle err + return } ctx := context.Background() - endpoints, err := client.GetEndpoints(kc, ctx, "kube-system", "kubelet", client.GetOptions{}) + + // Generic get. + endpoints, err := client.Get[*client.Endpoints](kc, ctx, "/api/v1/namespaces/kube-system/endpoints/kubelet", client.GetOptions{}) if err != nil { // Handle err + return } + // Typed methods. Simple wrapper for Get. + endpoints, err = client.GetEndpoints(kc, ctx, "kube-system", "kubelet", client.GetOptions{}) + if err != nil { + // Handle err + return + } fmt.Printf("%+v", endpoints) + + // Watch support. + events, err := client.Watch[*client.Endpoints](kc, ctx, "/api/v1/namespaces/kube-system/endpoints/kubelet", client.ListOptions{}) + if err != nil { + // Handle err + return + } + for event := range events.ResultChan() { + fmt.Println(event.Type, event.Object) + } } diff --git a/conformance/job.yaml b/conformance/job.yaml index 0cc63b7..d357381 100644 --- a/conformance/job.yaml +++ b/conformance/job.yaml @@ -24,6 +24,9 @@ metadata: namespace: conformance spec: template: + metadata: + labels: + app: conformance spec: serviceAccount: conformance containers: diff --git a/conformance/main.go b/conformance/main.go index 207938d..ce5715b 100644 --- a/conformance/main.go +++ b/conformance/main.go @@ -58,6 +58,7 @@ func testEndpoints(nativeClient *kubernetes.Clientset, kc *client.Client) error } compare := func(a *corev1.Endpoints, b *client.Endpoints) error { + fmt.Printf("compare endpoints:\na=%+v\nb=%+v\n", a, b) ip1 := a.Subsets[0].Addresses[0].IP ip2 := b.Subsets[0].Addresses[0].IP if ip1 != ip2 { @@ -92,8 +93,10 @@ func testEndpoints(nativeClient *kubernetes.Clientset, kc *client.Client) error deleted = true } if added && deleted { - a = event.Object.(*corev1.Endpoints) - e.Stop() + if v, ok := event.Object.(*corev1.Endpoints); ok { + a = v + e.Stop() + } } } return nil diff --git a/conformance/run.sh b/conformance/run.sh index fcb4535..6d11325 100755 --- a/conformance/run.sh +++ b/conformance/run.sh @@ -11,7 +11,17 @@ if [ "$IMG" == "" ]; then docker push ${img} fi +function log() +{ + echo "Test failed!" + echo "Pods:" + kubectl get pods -owide -n conformance + echo "Logs:" + kubectl logs -l app=conformance -n conformance +} +trap log ERR + kubectl delete ns conformance || true kubectl create ns conformance -kubectl apply -f job.yaml --dry-run=client -oyaml | sed "s/replace-img/$(echo "$img" | sed 's/\//\\\//g')/" | kubectl apply -f - -kubectl wait --for=condition=complete --timeout=10s job/conformance \ No newline at end of file +kubectl apply -f job.yaml --dry-run=client -oyaml | sed "s/replace-img/$(echo "$img" | sed 's/\//\\\//g')/" | kubectl apply -f - -n conformance +kubectl wait --for=condition=complete --timeout=10s job/conformance -n conformance