diff --git a/.agents/skills/README.md b/.agents/skills/README.md new file mode 100644 index 0000000..bb4fac3 --- /dev/null +++ b/.agents/skills/README.md @@ -0,0 +1,13 @@ +# Claude Skills + +AI-powered skills for the bootc-operator project. These are reusable instructions that AI agents (Claude Code, Copilot, etc.) can invoke to perform common development tasks — so you don't have to remember every command or worry about missing a step. + +Each skill lives in its own directory as a `SKILL.md` file. When invoked, the agent follows the instructions step by step, checking prerequisites, running commands, and verifying results on your behalf. + +## Available Skills + +| Skill | Description | +|-------|-------------| +| [deploy-cluster](deploy-cluster/SKILL.md) | Build and deploy bootc-operator to a local bink cluster | +| [destroy-cluster](destroy-cluster/SKILL.md) | Tear down a local bink cluster and clean up resources | +| [k8s-api-review](k8s-api-review/SKILL.md) | Review Kubernetes API changes for convention compliance | diff --git a/.agents/skills/deploy-cluster/SKILL.md b/.agents/skills/deploy-cluster/SKILL.md new file mode 100644 index 0000000..a3769d4 --- /dev/null +++ b/.agents/skills/deploy-cluster/SKILL.md @@ -0,0 +1,238 @@ +--- +name: deploy-cluster +description: Deploy the bootc-operator to a local bink cluster for development and testing +--- + +## What I do + +I guide you through building and deploying the bootc-operator to a local bink cluster from scratch. I check all prerequisites, build the operator image, create the cluster, deploy the operator, and verify everything is healthy. + +## When to use me + +- Setting up a local development cluster for the first time +- Redeploying after code changes +- Troubleshooting a broken cluster by tearing down and redeploying +- Preparing to run e2e tests + +--- + +## Instructions for AI Agent + +All commands run from the project root: `/home/ptalgulk/VSCode/bootc/bootc-operator` + +### Step 1: Check prerequisites + +Run each check. If any tool is missing, tell the user how to install it before continuing. + +```bash +echo "=== Checking prerequisites ===" + +echo -n "Go: "; go version 2>/dev/null || echo "MISSING - install from https://go.dev/dl/ (need >= 1.26)" +echo -n "Make: "; make --version 2>/dev/null | head -1 || echo "MISSING - dnf install make" +echo -n "Podman: "; podman --version 2>/dev/null || echo "MISSING - dnf install podman" +echo -n "kubectl: "; kubectl version --client 2>/dev/null | head -1 || echo "MISSING - https://kubernetes.io/docs/tasks/tools/" +echo -n "bink: "; bink version 2>/dev/null || echo "MISSING - go install github.com/bootc-dev/bink@latest" +echo -n "skopeo: "; skopeo --version 2>/dev/null || echo "MISSING - dnf install skopeo" +``` + +Check the Go version meets the `go.mod` requirement (>= 1.26): + +```bash +go_ver=$(go version | grep -oP 'go\K[0-9]+\.[0-9]+') +echo "Go version: $go_ver (need >= 1.26)" +``` + +Check Podman socket is running: + +```bash +systemctl --user is-active podman.socket +``` + +If inactive, start it: + +```bash +systemctl --user start podman.socket +``` + +Check port 5000 is available (used by the local registry): + +```bash +ss -tlnp | grep :5000 || echo "Port 5000 is available" +``` + +If port 5000 is already in use by something other than a bink registry, tell the user to free it. + +**Stop here if any prerequisite is missing. Do not proceed until all tools are installed.** + +### Step 2: Build the operator image + +```bash +make buildimg +``` + +**What this does:** Builds the `bootc-operator:dev` container image using Podman. The image contains both the controller and daemon binaries. + +**Expected output:** The last line should say `Successfully tagged localhost/bootc-operator:dev`. + +If the build fails, check: +- Is `podman.socket` running? (`systemctl --user start podman.socket`) +- Are there Go compilation errors? (fix the code first) + +### Step 3: Deploy to bink cluster + +```bash +make deploy-bink +``` + +**What this does (in order):** +1. Starts a local container registry at `localhost:5000` +2. Pulls the bootc node disk image and pushes it to the registry +3. Creates a bink cluster named `e2e` with a control-plane node (skips if already running) +4. Builds a derived node image for update testing +5. Pushes the operator image to the in-cluster registry +6. Deploys the operator via kustomize with `--allow-insecure-registry` and short tag resolution +7. Waits for the controller deployment to roll out + +**Expected output:** The last line should say `deployment "bootc-operator-controller-manager" successfully rolled out`. + +This step takes 2-5 minutes on first run (pulling images). Subsequent runs are faster. + +To use a separate dev cluster (so e2e tests don't interfere): + +```bash +make deploy-bink BINK_CLUSTER_NAME=dev +``` + +### Step 4: Set up kubeconfig + +Tell the user to run this in their terminal: + +```bash +export KUBECONFIG=$(pwd)/kubeconfig-e2e +``` + +For a named cluster (e.g. `dev`): + +```bash +export KUBECONFIG=$(pwd)/kubeconfig-dev +``` + +### Step 5: Verify deployment health + +Run these checks and report results to the user: + +```bash +echo "=== Cluster Health Check ===" + +echo "--- Nodes ---" +kubectl get nodes + +echo "--- CRDs ---" +kubectl get crd | grep bootc + +echo "--- Operator Pods ---" +kubectl -n bootc-operator get pods + +echo "--- Controller Deployment ---" +kubectl -n bootc-operator get deployment bootc-operator-controller-manager + +echo "--- Daemon DaemonSet ---" +kubectl -n bootc-operator get daemonset bootc-operator-daemon +``` + +**Healthy state checklist:** +- [ ] Controller node is `Ready` +- [ ] CRDs `bootcnodes.node.bootc.dev` and `bootcnodepools.node.bootc.dev` exist +- [ ] Controller manager pod is `Running` (1/1) +- [ ] Daemon DaemonSet has desired count matching available nodes + +If any check fails: + +**Controller pod not running:** +```bash +kubectl -n bootc-operator describe deployment bootc-operator-controller-manager +kubectl -n bootc-operator logs deployment/bootc-operator-controller-manager +``` + +**Daemon pod not running:** +```bash +kubectl -n bootc-operator describe daemonset bootc-operator-daemon +kubectl -n bootc-operator get events -n bootc-operator --sort-by='.lastTimestamp' | tail -20 +``` + +**CRDs missing:** +```bash +make install KUBECONFIG=./kubeconfig-e2e +``` + +**Node not Ready:** +```bash +kubectl describe node controller +``` + +### Step 6 (optional): Smoke test + +If the user wants to verify end-to-end functionality: + +```bash +make e2e V=1 RUN=TestControllerMembership +``` + +This runs a single fast test that provisions a worker node, creates a pool, and verifies a BootcNode is created. Takes about 40 seconds. + +To run the full e2e suite: + +```bash +make e2e V=1 +``` + +To run a specific test: + +```bash +make e2e V=1 RUN=TestUpdateReboot +``` + +### Redeploying after code changes + +```bash +make buildimg +make deploy-bink +``` + +If API types in `api/` were changed, regenerate manifests first: + +```bash +make manifests generate +make buildimg +make deploy-bink +``` + +### Gathering diagnostic logs + +```bash +make gather-bink +``` + +Logs are written to `_output/logs/gather-bink/`. + +### Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `podman.socket` not running | `systemctl --user start podman.socket` | +| Port 5000 in use | Stop the process using it, or tear down and recreate | +| Cluster unhealthy | `make teardown-bink && make buildimg && make deploy-bink` | +| Image not updating | Verify `make buildimg` succeeded, check `skopeo inspect --tls-verify=false docker://localhost:5000/bootc-operator-e2e:latest` | +| CRDs not installed | `make install KUBECONFIG=./kubeconfig-e2e` | +| `bink` not found | `go install github.com/bootc-dev/bink@latest` | +| `skopeo` not found | `dnf install skopeo` | +| Go version too old | Install Go >= 1.26 from https://go.dev/dl/ | + +### Key variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `IMG` | `bootc-operator:dev` | Operator container image name | +| `CONTAINER_TOOL` | `podman` | Container runtime | +| `BINK_CLUSTER_NAME` | `e2e` | Cluster name (change to avoid conflicts) | +| `KUBECONFIG_BINK` | `./kubeconfig-e2e` | Kubeconfig path (derived from cluster name) | diff --git a/.agents/skills/destroy-cluster/SKILL.md b/.agents/skills/destroy-cluster/SKILL.md new file mode 100644 index 0000000..647b3d4 --- /dev/null +++ b/.agents/skills/destroy-cluster/SKILL.md @@ -0,0 +1,115 @@ +--- +name: destroy-cluster +description: Tear down a local bink cluster and clean up all associated resources +--- + +## What I do + +I safely tear down a local bink cluster used for bootc-operator development and testing. I verify the cluster exists, remove it, clean up the kubeconfig, and confirm everything is gone. + +## When to use me + +- Done with development/testing and want to free resources +- Cluster is in a bad state and you want a clean start (destroy then redeploy) +- Cleaning up after e2e test runs + +--- + +## Instructions for AI Agent + +All commands run from the project root: `/home/ptalgulk/VSCode/bootc/bootc-operator` + +### Step 1: Check prerequisites + +```bash +echo -n "Make: "; make --version 2>/dev/null | head -1 || echo "MISSING" +echo -n "bink: "; bink version 2>/dev/null || echo "MISSING" +echo -n "Podman: "; podman --version 2>/dev/null || echo "MISSING" +``` + +### Step 2: Check if cluster exists + +```bash +bink cluster list 2>/dev/null +``` + +If the default `e2e` cluster is not listed, tell the user there is nothing to tear down. + +For a named cluster: + +```bash +bink cluster list 2>/dev/null | grep +``` + +### Step 3: Tear down the cluster + +Default cluster (`e2e`): + +```bash +make teardown-bink +``` + +Named cluster: + +```bash +make teardown-bink BINK_CLUSTER_NAME= +``` + +**What this does:** +1. Removes all bink worker nodes +2. Stops and removes the control-plane container +3. Stops the local container registry + +This typically takes 10-30 seconds. + +### Step 4: Clean up kubeconfig + +```bash +rm -f kubeconfig-e2e +``` + +For a named cluster: + +```bash +rm -f kubeconfig- +``` + +Tell the user to unset KUBECONFIG in their terminal if it was pointing at the deleted file: + +```bash +unset KUBECONFIG +``` + +### Step 5: Verify teardown + +```bash +echo "=== Teardown Verification ===" + +echo "--- Remaining bink clusters ---" +bink cluster list 2>/dev/null || echo "No clusters found" + +echo "--- Remaining containers (bootc/bink related) ---" +podman ps -a --filter "name=e2e" --format "{{.Names}}" 2>/dev/null || echo "None" + +echo "--- Registry on port 5000 ---" +ss -tlnp | grep :5000 || echo "Port 5000 is free" + +echo "--- Kubeconfig file ---" +ls kubeconfig-e2e 2>/dev/null || echo "Kubeconfig removed" +``` + +**Clean state checklist:** +- [ ] No bink clusters listed (or the target cluster is gone) +- [ ] No containers with the cluster name running +- [ ] Port 5000 is free (registry stopped) +- [ ] Kubeconfig file removed + +### Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `make teardown-bink` fails | Try `bink cluster delete e2e --force` directly | +| Containers still running | `podman rm -f ` | +| Port 5000 still in use | `podman stop ` then `podman rm ` | +| Volumes left behind | `podman volume prune` (ask user first — affects all unused volumes) | +| Teardown hangs | Ctrl+C, then manually remove with `bink cluster delete e2e --force` | diff --git a/.claude/skills/README.md b/.claude/skills/README.md new file mode 100644 index 0000000..bb4fac3 --- /dev/null +++ b/.claude/skills/README.md @@ -0,0 +1,13 @@ +# Claude Skills + +AI-powered skills for the bootc-operator project. These are reusable instructions that AI agents (Claude Code, Copilot, etc.) can invoke to perform common development tasks — so you don't have to remember every command or worry about missing a step. + +Each skill lives in its own directory as a `SKILL.md` file. When invoked, the agent follows the instructions step by step, checking prerequisites, running commands, and verifying results on your behalf. + +## Available Skills + +| Skill | Description | +|-------|-------------| +| [deploy-cluster](deploy-cluster/SKILL.md) | Build and deploy bootc-operator to a local bink cluster | +| [destroy-cluster](destroy-cluster/SKILL.md) | Tear down a local bink cluster and clean up resources | +| [k8s-api-review](k8s-api-review/SKILL.md) | Review Kubernetes API changes for convention compliance | diff --git a/.claude/skills/deploy-cluster/SKILL.md b/.claude/skills/deploy-cluster/SKILL.md new file mode 100644 index 0000000..a3769d4 --- /dev/null +++ b/.claude/skills/deploy-cluster/SKILL.md @@ -0,0 +1,238 @@ +--- +name: deploy-cluster +description: Deploy the bootc-operator to a local bink cluster for development and testing +--- + +## What I do + +I guide you through building and deploying the bootc-operator to a local bink cluster from scratch. I check all prerequisites, build the operator image, create the cluster, deploy the operator, and verify everything is healthy. + +## When to use me + +- Setting up a local development cluster for the first time +- Redeploying after code changes +- Troubleshooting a broken cluster by tearing down and redeploying +- Preparing to run e2e tests + +--- + +## Instructions for AI Agent + +All commands run from the project root: `/home/ptalgulk/VSCode/bootc/bootc-operator` + +### Step 1: Check prerequisites + +Run each check. If any tool is missing, tell the user how to install it before continuing. + +```bash +echo "=== Checking prerequisites ===" + +echo -n "Go: "; go version 2>/dev/null || echo "MISSING - install from https://go.dev/dl/ (need >= 1.26)" +echo -n "Make: "; make --version 2>/dev/null | head -1 || echo "MISSING - dnf install make" +echo -n "Podman: "; podman --version 2>/dev/null || echo "MISSING - dnf install podman" +echo -n "kubectl: "; kubectl version --client 2>/dev/null | head -1 || echo "MISSING - https://kubernetes.io/docs/tasks/tools/" +echo -n "bink: "; bink version 2>/dev/null || echo "MISSING - go install github.com/bootc-dev/bink@latest" +echo -n "skopeo: "; skopeo --version 2>/dev/null || echo "MISSING - dnf install skopeo" +``` + +Check the Go version meets the `go.mod` requirement (>= 1.26): + +```bash +go_ver=$(go version | grep -oP 'go\K[0-9]+\.[0-9]+') +echo "Go version: $go_ver (need >= 1.26)" +``` + +Check Podman socket is running: + +```bash +systemctl --user is-active podman.socket +``` + +If inactive, start it: + +```bash +systemctl --user start podman.socket +``` + +Check port 5000 is available (used by the local registry): + +```bash +ss -tlnp | grep :5000 || echo "Port 5000 is available" +``` + +If port 5000 is already in use by something other than a bink registry, tell the user to free it. + +**Stop here if any prerequisite is missing. Do not proceed until all tools are installed.** + +### Step 2: Build the operator image + +```bash +make buildimg +``` + +**What this does:** Builds the `bootc-operator:dev` container image using Podman. The image contains both the controller and daemon binaries. + +**Expected output:** The last line should say `Successfully tagged localhost/bootc-operator:dev`. + +If the build fails, check: +- Is `podman.socket` running? (`systemctl --user start podman.socket`) +- Are there Go compilation errors? (fix the code first) + +### Step 3: Deploy to bink cluster + +```bash +make deploy-bink +``` + +**What this does (in order):** +1. Starts a local container registry at `localhost:5000` +2. Pulls the bootc node disk image and pushes it to the registry +3. Creates a bink cluster named `e2e` with a control-plane node (skips if already running) +4. Builds a derived node image for update testing +5. Pushes the operator image to the in-cluster registry +6. Deploys the operator via kustomize with `--allow-insecure-registry` and short tag resolution +7. Waits for the controller deployment to roll out + +**Expected output:** The last line should say `deployment "bootc-operator-controller-manager" successfully rolled out`. + +This step takes 2-5 minutes on first run (pulling images). Subsequent runs are faster. + +To use a separate dev cluster (so e2e tests don't interfere): + +```bash +make deploy-bink BINK_CLUSTER_NAME=dev +``` + +### Step 4: Set up kubeconfig + +Tell the user to run this in their terminal: + +```bash +export KUBECONFIG=$(pwd)/kubeconfig-e2e +``` + +For a named cluster (e.g. `dev`): + +```bash +export KUBECONFIG=$(pwd)/kubeconfig-dev +``` + +### Step 5: Verify deployment health + +Run these checks and report results to the user: + +```bash +echo "=== Cluster Health Check ===" + +echo "--- Nodes ---" +kubectl get nodes + +echo "--- CRDs ---" +kubectl get crd | grep bootc + +echo "--- Operator Pods ---" +kubectl -n bootc-operator get pods + +echo "--- Controller Deployment ---" +kubectl -n bootc-operator get deployment bootc-operator-controller-manager + +echo "--- Daemon DaemonSet ---" +kubectl -n bootc-operator get daemonset bootc-operator-daemon +``` + +**Healthy state checklist:** +- [ ] Controller node is `Ready` +- [ ] CRDs `bootcnodes.node.bootc.dev` and `bootcnodepools.node.bootc.dev` exist +- [ ] Controller manager pod is `Running` (1/1) +- [ ] Daemon DaemonSet has desired count matching available nodes + +If any check fails: + +**Controller pod not running:** +```bash +kubectl -n bootc-operator describe deployment bootc-operator-controller-manager +kubectl -n bootc-operator logs deployment/bootc-operator-controller-manager +``` + +**Daemon pod not running:** +```bash +kubectl -n bootc-operator describe daemonset bootc-operator-daemon +kubectl -n bootc-operator get events -n bootc-operator --sort-by='.lastTimestamp' | tail -20 +``` + +**CRDs missing:** +```bash +make install KUBECONFIG=./kubeconfig-e2e +``` + +**Node not Ready:** +```bash +kubectl describe node controller +``` + +### Step 6 (optional): Smoke test + +If the user wants to verify end-to-end functionality: + +```bash +make e2e V=1 RUN=TestControllerMembership +``` + +This runs a single fast test that provisions a worker node, creates a pool, and verifies a BootcNode is created. Takes about 40 seconds. + +To run the full e2e suite: + +```bash +make e2e V=1 +``` + +To run a specific test: + +```bash +make e2e V=1 RUN=TestUpdateReboot +``` + +### Redeploying after code changes + +```bash +make buildimg +make deploy-bink +``` + +If API types in `api/` were changed, regenerate manifests first: + +```bash +make manifests generate +make buildimg +make deploy-bink +``` + +### Gathering diagnostic logs + +```bash +make gather-bink +``` + +Logs are written to `_output/logs/gather-bink/`. + +### Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `podman.socket` not running | `systemctl --user start podman.socket` | +| Port 5000 in use | Stop the process using it, or tear down and recreate | +| Cluster unhealthy | `make teardown-bink && make buildimg && make deploy-bink` | +| Image not updating | Verify `make buildimg` succeeded, check `skopeo inspect --tls-verify=false docker://localhost:5000/bootc-operator-e2e:latest` | +| CRDs not installed | `make install KUBECONFIG=./kubeconfig-e2e` | +| `bink` not found | `go install github.com/bootc-dev/bink@latest` | +| `skopeo` not found | `dnf install skopeo` | +| Go version too old | Install Go >= 1.26 from https://go.dev/dl/ | + +### Key variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `IMG` | `bootc-operator:dev` | Operator container image name | +| `CONTAINER_TOOL` | `podman` | Container runtime | +| `BINK_CLUSTER_NAME` | `e2e` | Cluster name (change to avoid conflicts) | +| `KUBECONFIG_BINK` | `./kubeconfig-e2e` | Kubeconfig path (derived from cluster name) | diff --git a/.claude/skills/destroy-cluster/SKILL.md b/.claude/skills/destroy-cluster/SKILL.md new file mode 100644 index 0000000..647b3d4 --- /dev/null +++ b/.claude/skills/destroy-cluster/SKILL.md @@ -0,0 +1,115 @@ +--- +name: destroy-cluster +description: Tear down a local bink cluster and clean up all associated resources +--- + +## What I do + +I safely tear down a local bink cluster used for bootc-operator development and testing. I verify the cluster exists, remove it, clean up the kubeconfig, and confirm everything is gone. + +## When to use me + +- Done with development/testing and want to free resources +- Cluster is in a bad state and you want a clean start (destroy then redeploy) +- Cleaning up after e2e test runs + +--- + +## Instructions for AI Agent + +All commands run from the project root: `/home/ptalgulk/VSCode/bootc/bootc-operator` + +### Step 1: Check prerequisites + +```bash +echo -n "Make: "; make --version 2>/dev/null | head -1 || echo "MISSING" +echo -n "bink: "; bink version 2>/dev/null || echo "MISSING" +echo -n "Podman: "; podman --version 2>/dev/null || echo "MISSING" +``` + +### Step 2: Check if cluster exists + +```bash +bink cluster list 2>/dev/null +``` + +If the default `e2e` cluster is not listed, tell the user there is nothing to tear down. + +For a named cluster: + +```bash +bink cluster list 2>/dev/null | grep +``` + +### Step 3: Tear down the cluster + +Default cluster (`e2e`): + +```bash +make teardown-bink +``` + +Named cluster: + +```bash +make teardown-bink BINK_CLUSTER_NAME= +``` + +**What this does:** +1. Removes all bink worker nodes +2. Stops and removes the control-plane container +3. Stops the local container registry + +This typically takes 10-30 seconds. + +### Step 4: Clean up kubeconfig + +```bash +rm -f kubeconfig-e2e +``` + +For a named cluster: + +```bash +rm -f kubeconfig- +``` + +Tell the user to unset KUBECONFIG in their terminal if it was pointing at the deleted file: + +```bash +unset KUBECONFIG +``` + +### Step 5: Verify teardown + +```bash +echo "=== Teardown Verification ===" + +echo "--- Remaining bink clusters ---" +bink cluster list 2>/dev/null || echo "No clusters found" + +echo "--- Remaining containers (bootc/bink related) ---" +podman ps -a --filter "name=e2e" --format "{{.Names}}" 2>/dev/null || echo "None" + +echo "--- Registry on port 5000 ---" +ss -tlnp | grep :5000 || echo "Port 5000 is free" + +echo "--- Kubeconfig file ---" +ls kubeconfig-e2e 2>/dev/null || echo "Kubeconfig removed" +``` + +**Clean state checklist:** +- [ ] No bink clusters listed (or the target cluster is gone) +- [ ] No containers with the cluster name running +- [ ] Port 5000 is free (registry stopped) +- [ ] Kubeconfig file removed + +### Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `make teardown-bink` fails | Try `bink cluster delete e2e --force` directly | +| Containers still running | `podman rm -f ` | +| Port 5000 still in use | `podman stop ` then `podman rm ` | +| Volumes left behind | `podman volume prune` (ask user first — affects all unused volumes) | +| Teardown hangs | Ctrl+C, then manually remove with `bink cluster delete e2e --force` |