1
0
Fork 0
mirror of https://github.com/imjasonh/client-go2 synced 2026-07-18 22:58:43 +00:00
client-go2/README.md

140 lines
4.1 KiB
Markdown
Raw Permalink Normal View History

2021-11-13 07:25:55 -05:00
## Experimenting with `k8s.io/client-go` and Go generics
2021-09-09 12:29:21 -04:00
2021-12-15 12:18:41 -05:00
[![Build](https://github.com/imjasonh/client-go2/actions/workflows/build.yaml/badge.svg)](https://github.com/imjasonh/client-go2/actions/workflows/build.yaml)
This is an experimental type-parameter-aware client that wraps [`k8s.io/client-go/rest`](https://pkg.go.dev/k8s.io/client-go/rest), in [about 570 lines of mostly-vibe-coded Go](./generic/client.go).
2021-09-09 12:29:21 -04:00
## Features
- **Type-safe generic client** - Work with strongly-typed Kubernetes objects instead of `unstructured.Unstructured`
- **Zero code generation** - Uses Go generics instead of code generation
- **Full CRUD operations** - List, Get, Create, Update, Delete, Patch, Watch, DeleteCollection, and UpdateStatus support
- **Informer support** - Watch for changes with type-safe event handlers
- **Automatic GVR inference** - No need to manually specify GroupVersionResource for standard Kubernetes types
- **Expansion methods** - Resource-specific operations like Pod.GetLogs() and Service.ProxyGet()
- **Label/Field selectors** - Filter resources using Kubernetes selectors
- **SubResource access** - Generic method to access any subresource
## Usage
See [the example](./main.go) for comprehensive usage examples.
### Quick Examples
#### Basic CRUD Operations
```go
// Create a client with automatic GVR inference
client, err := generic.NewClient[*corev1.Pod](config)
// List pods with label selector
pods, err := client.List(ctx, "default", &metav1.ListOptions{
LabelSelector: "app=nginx",
})
// Get a specific pod
pod, err := client.Get(ctx, "default", "my-pod", nil)
```
#### Expansion Methods for Pods (client-go compatible)
```go
// Start with a generic client for pods
client, err := generic.NewClient[*corev1.Pod](config)
// Get a namespace-scoped PodClient that implements typedcorev1.PodExpansion
podClient := client.PodClient("default") // Will panic if T is not *corev1.Pod
// Get pod logs (matches client-go API)
req := podClient.GetLogs("my-pod", &corev1.PodLogOptions{
Container: "nginx",
TailLines: &tailLines,
})
logs, err := req.DoRaw(ctx)
// Bind pod to node
err = podClient.Bind(ctx, binding, metav1.CreateOptions{})
// Evict pod
err = podClient.Evict(ctx, eviction)
// For cluster-scoped operations, use the generic client directly
pods, err := client.List(ctx, "default", nil)
```
#### Expansion Methods for Services (client-go compatible)
```go
// Start with a generic client for services
client, err := generic.NewClient[*corev1.Service](config)
// Get a namespace-scoped ServiceClient that implements typedcorev1.ServiceExpansion
serviceClient := client.ServiceClient("default") // Will panic if T is not *corev1.Service
// Use proxy to access service endpoints
req := serviceClient.ProxyGet("http", "my-service", "80", "api/health", nil)
resp, err := req.DoRaw(ctx)
```
#### Generic SubResource Access
```go
// Access any subresource using the generic method
req := client.SubResource("default", "my-pod", "status")
status, err := req.DoRaw(ctx)
```
#### Watch Resources
```go
// Watch for pod changes with label selector
watcher, err := client.Watch(ctx, "default", &metav1.ListOptions{
LabelSelector: "app=nginx",
})
defer watcher.Stop()
for event := range watcher.ResultChan() {
pod := event.Object.(*corev1.Pod)
fmt.Printf("Event: %s Pod: %s\n", event.Type, pod.Name)
}
```
#### Delete Collection
```go
// Delete all pods with specific label
err = client.DeleteCollection(ctx, "default", nil, &metav1.ListOptions{
LabelSelector: "app=test",
})
// Delete all pods in namespace
err = client.DeleteCollection(ctx, "default", nil, nil)
```
#### Update Status
```go
// Update only the status subresource
pod.Status.Phase = corev1.PodRunning
pod.Status.Conditions = append(pod.Status.Conditions, corev1.PodCondition{
Type: corev1.PodReady,
Status: corev1.ConditionTrue,
})
updated, err := client.UpdateStatus(ctx, "default", pod, nil)
```
## Testing
Unit tests against a mock REST client:
2021-09-09 12:29:21 -04:00
```
make test
```
End-to-end tests against a real K8s cluster:
```
make e2e
2021-09-09 12:29:21 -04:00
```
# ⚠️ THIS IS AN EXPERIMENT
This is just for demo purposes.
2021-09-09 12:29:21 -04:00
The name `client-go2` is a placeholder, and a joke.