|
| 1 | +## Purpose |
| 2 | +- **Project:** PHP client for Kubernetes clusters with HTTP/WebSocket support, CRD ergonomics, exec/logs/watch, and JSON Patch/Merge Patch. |
| 3 | +- **Audience:** Human contributors and code agents working on features, fixes, or docs. |
| 4 | + |
| 5 | +## Quick Repo Map |
| 6 | +- `src/KubernetesCluster.php`: Core client; builds URLs, performs operations (get/create/replace/delete, exec, attach, watch, logs, patch). |
| 7 | +- `src/Kinds/*`: First‑class resource wrappers (Pod, Deployment, Service, …) extending `K8sResource` with convenience traits. |
| 8 | +- `src/Traits/Cluster/*`: HTTP/WebSocket, auth, kubeconfig loaders, version checks. |
| 9 | +- `src/Auth/*`: Token providers (ExecCredential, EKS, OpenShift OAuth, ServiceAccount TokenRequest) with automatic refresh. |
| 10 | +- `src/Traits/Resource/*`: Reusable capabilities (spec/status/labels/annotations/templates/scale/etc.). |
| 11 | +- `src/K8s.php`: Facade/helper for resource construction, YAML parsing, and CRD registration via macros. |
| 12 | +- `src/Patches/*`: `JsonPatch` (RFC 6902) and `JsonMergePatch` (RFC 7396). |
| 13 | +- `tests/*`: PHPUnit tests (unit + integration) including testing‑only CRDs under `tests/Kinds`. |
| 14 | + |
| 15 | +## Code Style Requirements |
| 16 | + |
| 17 | +This project uses [Laravel Pint](https://laravel.com/docs/pint) with the Laravel preset to enforce PSR-12 coding standards. |
| 18 | + |
| 19 | +**CRITICAL: Always run Pint before committing PHP code changes:** |
| 20 | +```bash |
| 21 | +./vendor/bin/pint |
| 22 | +``` |
| 23 | + |
| 24 | +Pint auto-fixes: |
| 25 | +- String concatenation spacing (no spaces around `.`) |
| 26 | +- Negation operator spacing (space after `!`) |
| 27 | +- Trailing commas in multiline arrays |
| 28 | +- Doc block formatting |
| 29 | +- Use statement ordering |
| 30 | +- Class definition formatting |
| 31 | +- PSR-12 compliance |
| 32 | + |
| 33 | +**Manual checks after running Pint:** |
| 34 | +1. Doc comments must end with periods: `/** Comment. */` |
| 35 | +2. No blank lines before `finally` blocks |
| 36 | + |
| 37 | +**If StyleCI reports issues on PR:** |
| 38 | +1. Run `./vendor/bin/pint` |
| 39 | +2. Fix any remaining manual issues |
| 40 | +3. Commit and push fixes |
| 41 | + |
| 42 | +## Stack & Requirements |
| 43 | +- **PHP:** `^8.2` (CI also exercises 8.5). |
| 44 | +- **Composer deps:** Guzzle 7, Symfony Process 7.3, Illuminate components, Ratchet Pawl, ext‑json; optional `ext-yaml` for YAML helpers, optional `aws/aws-sdk-php` for native EKS authentication. |
| 45 | +- **Static analysis:** Psalm (see `psalm.xml`). |
| 46 | +- **License:** Apache‑2.0. |
| 47 | +- **Authentication:** Supports tokens, certificates, kubeconfig, in-cluster config, exec credential plugins, AWS EKS native, OpenShift OAuth, and ServiceAccount TokenRequest API. |
| 48 | + |
| 49 | +## Local Dev Setup |
| 50 | +- **Install deps:** `composer install`. |
| 51 | +- **Update deps:** `composer update`. |
| 52 | +- **Run all tests:** `vendor/bin/phpunit`. |
| 53 | +- **Run tests (unit only):** `vendor/bin/phpunit --filter Test$` (or target specific files) to avoid cluster requirements. |
| 54 | +- **Run specific test file:** `vendor/bin/phpunit tests/PriorityClassTest.php`. |
| 55 | +- **Run specific test method:** `vendor/bin/phpunit tests/PriorityClassTest.php --filter test_priority_class_build`. |
| 56 | +- **Run with CI environment:** `CI=true vendor/bin/phpunit` (requires running Kubernetes cluster). |
| 57 | +- **Static analysis:** `vendor/bin/psalm`. |
| 58 | +- **Coding style:** Run `./vendor/bin/pint` before all commits (see "Code Style Requirements" above). |
| 59 | + |
| 60 | +## Running Full Integration Tests Locally |
| 61 | +These hit a live Kubernetes cluster and mirror CI. |
| 62 | +- **Start cluster:** Minikube is the reference. Example: `minikube start --kubernetes-version=v1.33.1`. |
| 63 | +- **Enable addons:** `minikube addons enable volumesnapshots && minikube addons enable csi-hostpath-driver && minikube addons enable metrics-server`. |
| 64 | +- **Install VPA:** Clone `kubernetes/autoscaler` and run `./vertical-pod-autoscaler/hack/vpa-up.sh`. Alternatively: |
| 65 | + ```bash |
| 66 | + git clone https://github.com/kubernetes/autoscaler.git /tmp/autoscaler |
| 67 | + kubectl apply -f /tmp/autoscaler/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml |
| 68 | + kubectl apply -f /tmp/autoscaler/vertical-pod-autoscaler/deploy/recommender-deployment.yaml |
| 69 | + kubectl apply -f /tmp/autoscaler/vertical-pod-autoscaler/deploy/updater-deployment.yaml |
| 70 | + kubectl apply -f /tmp/autoscaler/vertical-pod-autoscaler/deploy/admission-controller-deployment.yaml |
| 71 | + ``` |
| 72 | +- **Install CRDs:** |
| 73 | + - Sealed Secrets CRD: `kubectl apply -f https://raw.githubusercontent.com/bitnami-labs/sealed-secrets/main/helm/sealed-secrets/crds/bitnami.com_sealedsecrets.yaml` |
| 74 | + - Gateway API: `kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml` |
| 75 | +- **Expose API:** `kubectl proxy --port=8080 --reject-paths="^/non-existent-path" &` (tests use `http://127.0.0.1:8080`). |
| 76 | +- **Verify connectivity:** `curl -s http://127.0.0.1:8080/version`. |
| 77 | +- **Run tests:** `CI=true vendor/bin/phpunit`. |
| 78 | +- **Important:** Tests expect the Kubernetes API accessible at `http://127.0.0.1:8080` (see `tests/TestCase.php`). |
| 79 | + |
| 80 | +## Key Concepts |
| 81 | +- **Resources:** Each kind extends `Kinds\K8sResource` and composes traits from `Traits\Resource` for spec/status/metadata helpers. |
| 82 | + - Resource pattern: `K8sResource` (base) → Uses Traits (HasSpec, HasStatus, etc.) → Implements Contracts (InteractsWithK8sCluster, Watchable, etc.) → Extended by specific classes (K8sPod, K8sDeployment, etc.) |
| 83 | + - Namespaced resources: Set `protected static $namespaceable = true` (most resources) |
| 84 | + - Cluster-scoped resources: Set `protected static $namespaceable = false` (nodes, PriorityClass, ClusterRole, etc.) |
| 85 | +- **Traits:** Provide composable functionality (`src/Traits/Resource/`) |
| 86 | + - `HasSpec` - Manage spec section (most resources) |
| 87 | + - `HasStatus` - Read-only status information |
| 88 | + - `HasSelector` - Label/field selectors |
| 89 | + - `HasMetadata` - Labels, annotations, name, namespace |
| 90 | + - `HasReplicas` - Replica management (Deployments, StatefulSets, ReplicaSets) |
| 91 | + - `HasPodTemplate` - Pod template spec (workload resources) |
| 92 | + - `HasStorage` - Storage configuration (PVCs, PVs) |
| 93 | +- **Contracts (Interfaces):** Define capabilities (`src/Contracts/`) |
| 94 | + - `InteractsWithK8sCluster` - Basic CRUD operations (get, create, update, delete) |
| 95 | + - `Watchable` - Watch operations (event streaming) |
| 96 | + - `Scalable` - Scale subresource support |
| 97 | + - `Loggable` - Log retrieval (pods, jobs) |
| 98 | + - `Executable` - Exec operations (pods) |
| 99 | +- **Cluster Ops:** `KubernetesCluster` provides typed creators/getters (e.g., `pod()`, `getPodByName()`, `getAllPods()`), plus `exec`, `attach`, `watch`, `logs`, and patch operations. |
| 100 | +- **YAML helpers:** `K8s::fromYaml($cluster, $yaml)` and `K8s::fromYamlFile($cluster, $path)` create object(s) from YAML. Templating is supported via `fromTemplatedYamlFile`. |
| 101 | +- **CRDs:** Register custom kinds at runtime with `K8s::registerCrd(YourClass::class, 'alias')` or rely on the unique CRD macro computed from kind + apiVersion. |
| 102 | +- **Patching:** Use `$resource->jsonPatch($patch)` or `$resource->jsonMergePatch($patch)` with `Patches\JsonPatch`/`JsonMergePatch` or raw arrays. |
| 103 | +- **State tracking:** `isSynced()` - resource has been synced with cluster; `exists()` - resource currently exists in cluster. |
| 104 | + |
| 105 | +## Common Tasks |
| 106 | +- **Add a new built-in kind:** |
| 107 | + 1. Create `src/Kinds/K8sYourKind.php` extending `K8sResource`: |
| 108 | + ```php |
| 109 | + <?php |
| 110 | + namespace RenokiCo\PhpK8s\Kinds; |
| 111 | + use RenokiCo\PhpK8s\Contracts\InteractsWithK8sCluster; |
| 112 | + |
| 113 | + class K8sYourKind extends K8sResource implements InteractsWithK8sCluster |
| 114 | + { |
| 115 | + protected static $kind = 'YourKind'; |
| 116 | + protected static $defaultVersion = 'v1'; // or appropriate apiVersion |
| 117 | + protected static $namespaceable = true; // or false for cluster-scoped |
| 118 | + |
| 119 | + // Add resource-specific methods |
| 120 | + } |
| 121 | + ``` |
| 122 | + 2. Add factory method in `src/Traits/InitializesResources.php`: |
| 123 | + ```php |
| 124 | + public static function yourKind($cluster = null, array $attributes = []) |
| 125 | + { |
| 126 | + return new K8sYourKind($cluster, $attributes); |
| 127 | + } |
| 128 | + ``` |
| 129 | + 3. Create test file `tests/YourKindTest.php` with: |
| 130 | + - Unit tests: `test_your_kind_build()`, `test_your_kind_from_yaml()` |
| 131 | + - Integration test: `test_your_kind_api_interaction()` |
| 132 | + - Run methods: `runCreationTests()`, `runGetAllTests()`, `runGetTests()`, `runUpdateTests()`, `runWatchAllTests()`, `runWatchTests()`, `runDeletionTests()` |
| 133 | + - Note: Cluster-scoped resources typically omit watch tests |
| 134 | + 4. Create YAML fixture in `tests/yaml/yourkind.yaml` for YAML parsing tests |
| 135 | + |
| 136 | +- **Test structure:** (`tests/TestCase.php` sets up cluster at `http://127.0.0.1:8080`) |
| 137 | + - Build test: Verify resource construction with fluent API |
| 138 | + - YAML test: Load and validate from YAML file |
| 139 | + - API interaction test: Orchestrate full CRUD lifecycle |
| 140 | + - Creation tests: Create resource, verify `isSynced()` and `exists()` |
| 141 | + - Deletion tests: Delete resource, wait for deletion, expect `KubernetesAPIException` on get |
| 142 | +- **Add support for a CRD (without bundling it):** |
| 143 | + - Create a kind class under `tests/Kinds` (for testing) or a separate package. |
| 144 | + - Register with `K8s::registerCrd(...)` in tests or userland. |
| 145 | + - Provide YAML examples for `K8s::fromYaml*()` parsing. |
| 146 | +- **Extend cluster operations:** Add behavior in `Traits/Cluster/*` or `Traits/RunsClusterOperations.php` with matching tests. |
| 147 | + |
| 148 | +## Style & Quality |
| 149 | +- **Tests first:** Add/adjust tests for all behavior changes. Use PHPUnit; integration tests may require a live cluster. |
| 150 | +- **API stability:** Follow SemVer; avoid breaking public APIs. Prefer additive changes. |
| 151 | +- **Consistency:** Mirror naming and patterns used by existing kinds and traits. Keep methods fluent and chainable where appropriate. |
| 152 | +- **Docs:** Update `README.md` and/or add focused docs in `docs/` for new features. Keep examples runnable. |
| 153 | +- **Static analysis:** Keep Psalm clean (config at `psalm.xml`). |
| 154 | + |
| 155 | +## PR Checklist |
| 156 | +- **Code style:** Run `./vendor/bin/pint` and fix any manual style issues before committing. |
| 157 | +- `composer install` completes and `vendor/bin/psalm` passes. |
| 158 | +- `vendor/bin/phpunit` passes for unit tests; integration suite passes if you ran a local cluster. |
| 159 | +- New options/settings covered with tests. |
| 160 | +- Changes are scoped; one concern per PR. |
| 161 | + |
| 162 | +## Gotchas |
| 163 | +- **Cluster URL:** Tests default to `http://127.0.0.1:8080` via `kubectl proxy` and disable SSL verification for local runs. |
| 164 | +- **Namespace handling:** Cluster-scoped resources (`$namespaceable = false`) should not include namespace in specs or API calls. |
| 165 | +- **YAML extension:** `ext-yaml` is optional but required for YAML helpers (parsing/serialization). Guard features accordingly. Tests using `fromYamlFile()` will fail without the yaml PHP extension installed. |
| 166 | +- **kubectl Proxy:** Integration tests expect proxy on `http://127.0.0.1:8080` - verify with `curl http://127.0.0.1:8080/version`. |
| 167 | +- **Watch tests:** Cluster-scoped resources typically don't implement watch tests (pattern varies). |
| 168 | +- **Status vs Spec:** Status is read-only from API; modifications go in spec section. |
| 169 | +- **WebSockets:** Exec/attach/watch rely on Ratchet Pawl; ensure TLS headers/certs are passed through from `KubernetesCluster` when touching WS paths. |
| 170 | +- **Patches:** Use proper content types (`application/json-patch+json` vs `application/merge-patch+json`). The client handles this if you use the provided patch helpers. |
| 171 | + |
| 172 | +## Current Resource Types (33+) |
| 173 | +- **Workload:** Pod, Deployment, StatefulSet, DaemonSet, Job, CronJob, ReplicaSet |
| 174 | +- **Networking:** Service, Ingress, NetworkPolicy, EndpointSlice |
| 175 | +- **Storage:** PersistentVolume, PersistentVolumeClaim, StorageClass |
| 176 | +- **Configuration:** ConfigMap, Secret |
| 177 | +- **Autoscaling:** HorizontalPodAutoscaler, VerticalPodAutoscaler |
| 178 | +- **Policy:** ResourceQuota, LimitRange, PodDisruptionBudget, NetworkPolicy, PriorityClass |
| 179 | +- **RBAC:** ServiceAccount, Role, ClusterRole, RoleBinding, ClusterRoleBinding |
| 180 | +- **Webhooks:** ValidatingWebhookConfiguration, MutatingWebhookConfiguration |
| 181 | +- **Cluster:** Namespace, Node, Event |
| 182 | + |
| 183 | +## Kubernetes API Versions Reference |
| 184 | +- Core resources (Pod, Service, etc.): `v1` |
| 185 | +- Apps resources (Deployment, StatefulSet, etc.): `apps/v1` |
| 186 | +- Networking: `networking.k8s.io/v1` |
| 187 | +- Autoscaling: `autoscaling/v2` (HPA), `autoscaling.k8s.io/v1` (VPA) |
| 188 | +- Scheduling: `scheduling.k8s.io/v1` |
| 189 | +- Policy: `policy/v1` |
| 190 | +- RBAC: `rbac.authorization.k8s.io/v1` |
| 191 | + |
| 192 | +## Releasing & CI (Reference) |
| 193 | +- CI matrix runs PHP 8.3/8.4/8.5 across Kubernetes v1.32.9, v1.33.5, v1.34.1 and Laravel 11/12 with both `prefer-lowest` and `prefer-stable`. |
| 194 | +- Minikube v1.37.0 is provisioned in CI with VolumeSnapshots, CSI hostpath, metrics‑server, VPA, Sealed Secrets CRD, and Gateway API CRDs before running tests. |
| 195 | +- Timeout: 25 minutes per job. |
| 196 | + |
| 197 | +## Useful References |
| 198 | +- [Documentation](https://php-k8s.renoki.org) |
| 199 | +- [Upstream Repository](https://github.com/renoki-co/php-k8s) |
| 200 | +- [Kubernetes API Reference](https://kubernetes.io/docs/reference/kubernetes-api/) |
| 201 | + |
| 202 | +If anything is unclear or you need deeper context for a change, open a draft PR with your approach and questions. Keeping changes small and well‑tested speeds up reviews. |
| 203 | + |
0 commit comments