|
1 | | -# Contributing to Kedge |
| 1 | +# Contributing to kedge |
2 | 2 |
|
3 | | -## Prerequisites |
| 3 | +Thanks for your interest in contributing! This document covers building from source, running tests, understanding the architecture, and the PR workflow. |
4 | 4 |
|
5 | | -- Go 1.25+ |
6 | | -- [kind](https://kind.sigs.k8s.io/) (for running a local agent cluster) |
7 | | -- `openssl` (for generating dev TLS certs) |
8 | | -- `golangci-lint` (for linting) |
| 5 | +## Table of Contents |
9 | 6 |
|
10 | | -Tools like kcp, Dex, controller-gen, and apigen are installed automatically by Make on first use into `hack/tools/`. |
| 7 | +- [Prerequisites](#prerequisites) |
| 8 | +- [Building from Source](#building-from-source) |
| 9 | +- [Local Development Stack](#local-development-stack) |
| 10 | +- [Running Tests](#running-tests) |
| 11 | +- [Architecture Overview](#architecture-overview) |
| 12 | +- [PR Workflow](#pr-workflow) |
11 | 13 |
|
12 | | -## Development environment |
| 14 | +--- |
13 | 15 |
|
14 | | -### Quick start with `kedge dev` |
| 16 | +## Prerequisites |
15 | 17 |
|
16 | | -The fastest way to get a full local environment: |
| 18 | +| Tool | Version | Notes | |
| 19 | +|------|---------|-------| |
| 20 | +| Go | 1.25+ | `go env GOVERSION` | |
| 21 | +| Docker | any recent | must be running | |
| 22 | +| kind | latest | for local clusters | |
| 23 | +| kubectl | 1.28+ | | |
| 24 | +| Helm | 3.x | for chart testing | |
17 | 25 |
|
18 | | -```bash |
19 | | -kedge dev create |
20 | | -``` |
| 26 | +--- |
21 | 27 |
|
22 | | -This sets up Kind clusters, a hub, and an agent automatically. Follow the printed next steps to log in, create an edge, and connect the agent. |
| 28 | +## Building from Source |
23 | 29 |
|
24 | 30 | ```bash |
25 | | -# Clean up |
26 | | -kedge dev delete |
| 31 | +git clone https://github.com/faroshq/kedge.git |
| 32 | +cd kedge |
| 33 | + |
| 34 | +# Build all binaries into bin/ |
| 35 | +make build |
| 36 | + |
| 37 | +# Build just the CLI |
| 38 | +make build-kedge |
| 39 | + |
| 40 | +# Cross-compile for all platforms |
| 41 | +make build-all |
27 | 42 | ``` |
28 | 43 |
|
29 | | -### Running from source |
| 44 | +Binaries produced: |
30 | 45 |
|
31 | | -#### Standalone (embedded kcp + static token) |
| 46 | +| Binary | Description | |
| 47 | +|--------|-------------| |
| 48 | +| `bin/kedge` | User CLI | |
| 49 | +| `bin/kedge-hub` | Hub server | |
| 50 | +| `bin/kedge-agent` | Edge agent (standalone binary) | |
32 | 51 |
|
33 | | -```bash |
34 | | -# Terminal 1: Run the hub (no external dependencies) |
35 | | -make run-hub-embedded-static |
| 52 | +--- |
36 | 53 |
|
37 | | -# Terminal 2: Login and register an edge |
38 | | -make dev-login-static # Authenticate with static token |
39 | | -make dev-edge-create # Register an edge (default: kubernetes type) |
40 | | -make dev-run-edge # Start the agent on a local kind cluster |
41 | | -``` |
| 54 | +## Local Development Stack |
42 | 55 |
|
43 | | -#### Full stack (kcp + Dex + OIDC) |
| 56 | +`kedge dev create` spins up a complete local environment with two kind clusters (hub + one agent), deploys the hub via Helm, and wires everything together. |
44 | 57 |
|
45 | 58 | ```bash |
46 | | -# Terminal 1: Start kcp, Dex, and the hub |
47 | | -make dev |
| 59 | +# Build first |
| 60 | +make build |
48 | 61 |
|
49 | | -# Terminal 2: Log in and register an edge |
50 | | -make dev-login |
51 | | -make dev-edge-create |
52 | | -make dev-run-edge |
53 | | -``` |
| 62 | +# Create hub + agent kind clusters and deploy the hub |
| 63 | +./bin/kedge dev create --chart-path deploy/charts/kedge-hub |
54 | 64 |
|
55 | | -#### Component by component |
| 65 | +# Log in with the static dev token |
| 66 | +./bin/kedge login --hub-url https://kedge.localhost:8443 \ |
| 67 | + --insecure-skip-tls-verify --token dev-token |
56 | 68 |
|
57 | | -If you prefer running services separately: |
| 69 | +# Register a dev edge |
| 70 | +./bin/kedge edge create dev-edge-1 |
58 | 71 |
|
59 | | -```bash |
60 | | -# Terminal 1: kcp + Dex |
61 | | -make dev-infra |
| 72 | +# Print the agent command |
| 73 | +./bin/kedge edge join-command dev-edge-1 |
62 | 74 |
|
63 | | -# Terminal 2: Hub (rebuild with make run-hub after code changes) |
64 | | -make run-hub |
| 75 | +# Run the agent in the background (foreground process) |
| 76 | +./bin/kedge agent run \ |
| 77 | + --hub-url https://kedge.localhost:8443 \ |
| 78 | + --token <join-token> \ |
| 79 | + --edge-name dev-edge-1 \ |
| 80 | + --type kubernetes \ |
| 81 | + --kubeconfig $(kind get kubeconfig --name kedge-e2e-agent-1 2>/dev/null) |
65 | 82 |
|
66 | | -# Terminal 3: Edge agent (requires dev-edge-create first) |
67 | | -make dev-run-edge |
| 83 | +# Tear down |
| 84 | +./bin/kedge dev delete |
68 | 85 | ``` |
69 | 86 |
|
70 | | -Run `make help-dev` to see all available development modes. |
71 | | - |
72 | | -### Deploying a test workload |
| 87 | +### Make shortcuts |
73 | 88 |
|
74 | 89 | ```bash |
75 | | -make dev-create-workload |
| 90 | +make dev-login-static # log in with static token |
| 91 | +make dev-edge-create # create dev-edge-1 (kubernetes type) |
| 92 | +make dev-run-edge # run agent for dev-edge-1 |
| 93 | +make dev-edge-create TYPE=server DEV_EDGE_NAME=my-server |
| 94 | +make dev-run-edge TYPE=server DEV_EDGE_NAME=my-server |
76 | 95 | ``` |
77 | 96 |
|
78 | | -This applies an example `VirtualWorkload` that targets dev sites. |
79 | | - |
80 | | -## Building |
| 97 | +### Lint |
81 | 98 |
|
82 | 99 | ```bash |
83 | | -make build # All binaries (kedge, kedge-hub, kedge-agent) |
84 | | -make build-kedge # CLI only |
85 | | -make build-hub # Hub only |
86 | | -make build-agent # Agent only |
| 100 | +make lint # golangci-lint (must be 0 issues before pushing) |
| 101 | +go build ./... # must compile clean |
87 | 102 | ``` |
88 | 103 |
|
89 | | -Binaries are output to `bin/`. |
| 104 | +--- |
90 | 105 |
|
91 | | -## Code generation |
| 106 | +## Running Tests |
92 | 107 |
|
93 | | -After changing API types in `apis/`: |
| 108 | +### Unit tests |
94 | 109 |
|
95 | 110 | ```bash |
96 | | -make codegen |
| 111 | +go test ./pkg/... |
97 | 112 | ``` |
98 | 113 |
|
99 | | -This runs: |
100 | | -1. `controller-gen` to generate CRDs from Go types |
101 | | -2. `apigen` to generate kcp APIResourceSchemas and APIExports |
102 | | -3. `ensure-boilerplate.sh` to add license headers to any new files |
| 114 | +### e2e tests |
103 | 115 |
|
104 | | -## Testing and verification |
| 116 | +e2e tests spin up real kind clusters and require Docker. |
105 | 117 |
|
106 | 118 | ```bash |
107 | | -make test # Run all tests |
108 | | -make test-util # Run utility package tests only |
109 | | -make lint # Run golangci-lint |
110 | | -make vet # Run go vet |
111 | | -make verify # Run all checks (vet + lint + test + boilerplate) |
112 | | -make verify-boilerplate # Check license headers only (no modifications) |
| 119 | +# Standalone suite (embedded kcp, static token) |
| 120 | +make test-e2e |
| 121 | + |
| 122 | +# SSH suite |
| 123 | +make test-e2e-ssh |
| 124 | + |
| 125 | +# OIDC suite (Dex) |
| 126 | +make test-e2e-oidc |
| 127 | + |
| 128 | +# External KCP suite |
| 129 | +make test-e2e-external-kcp |
113 | 130 | ``` |
114 | 131 |
|
115 | | -## License headers |
| 132 | +**Reuse existing clusters** (faster iteration): |
116 | 133 |
|
117 | | -All Go files must have the Apache 2.0 license boilerplate. To add it to new files: |
| 134 | +```bash |
| 135 | +KEDGE_USE_EXISTING_CLUSTERS=true make test-e2e |
| 136 | +``` |
| 137 | + |
| 138 | +**Keep clusters after failure** (for debugging): |
118 | 139 |
|
119 | 140 | ```bash |
120 | | -make boilerplate |
| 141 | +make test-e2e E2E_FLAGS=--keep-clusters |
| 142 | +``` |
| 143 | + |
| 144 | +--- |
| 145 | + |
| 146 | +## Architecture Overview |
| 147 | + |
| 148 | +### Components |
| 149 | + |
| 150 | +``` |
| 151 | + ┌──────────────────────────────────┐ |
| 152 | + │ kedge hub │ |
| 153 | + │ │ |
| 154 | + │ ┌─────────┐ ┌────────────────┐ │ |
| 155 | + │ │ kcp │ │ agent-proxy │ │ |
| 156 | + │ │ (API) │ │ virtual WS │ │ |
| 157 | + │ └────┬────┘ └───────┬────────┘ │ |
| 158 | + │ │ │ │ |
| 159 | + │ ┌────▼───────────────▼────────┐ │ |
| 160 | + │ │ hub controllers │ │ |
| 161 | + │ │ token / edge / rbac / ssh │ │ |
| 162 | + │ └─────────────────────────────┘ │ |
| 163 | + └──────────────┬───────────────────┘ |
| 164 | + │ revdial reverse tunnel |
| 165 | + ┌──────────┴──────────┐ |
| 166 | + │ │ |
| 167 | + ┌──────▼──────┐ ┌────────▼──────┐ |
| 168 | + │ kedge-agent │ │ kedge-agent │ |
| 169 | + │ (kubernetes)│ │ (server) │ |
| 170 | + └─────────────┘ └───────────────┘ |
121 | 171 | ``` |
122 | 172 |
|
123 | | -This is also run as part of `make codegen`. The `make verify` target checks headers without modifying files. |
| 173 | +### Key packages |
| 174 | + |
| 175 | +| Package | Description | |
| 176 | +|---------|-------------| |
| 177 | +| `pkg/hub/controllers/edge/` | Edge lifecycle: token reconciler, RBAC, SSH credentials | |
| 178 | +| `pkg/virtual/builder/` | Agent-proxy virtual workspace — handles tunnel + status | |
| 179 | +| `pkg/agent/` | Agent core: registration, tunnel, edge_reporter | |
| 180 | +| `pkg/agent/tunnel/` | revdial tunnel client (`StartProxyTunnel`) | |
| 181 | +| `pkg/cli/cmd/` | CLI command implementations | |
| 182 | +| `apis/kedge/v1alpha1/` | Edge CRD types | |
| 183 | + |
| 184 | +### Join token bootstrap flow |
| 185 | + |
| 186 | +1. `kedge edge create <name>` creates an `Edge` resource. |
| 187 | +2. `TokenReconciler` generates a 44-char base64url token → `edge.status.joinToken`. |
| 188 | +3. Agent starts with `--token <join-token>` (via `kedge agent run`). |
| 189 | +4. Hub validates the token in `authorizeByJoinToken`, calls `markEdgeConnected`. |
| 190 | +5. Hub sends the agent's kubeconfig back via `X-Kedge-Agent-Kubeconfig` response header. |
| 191 | +6. Agent saves the kubeconfig to `~/.kedge/agent-<name>.kubeconfig`; clears `--token`. |
| 192 | +7. On restart, agent loads the saved kubeconfig automatically — no token needed. |
| 193 | +8. Hub sets `Registered=True` on the Edge and clears `status.joinToken`. |
| 194 | + |
| 195 | +### revdial tunnel |
| 196 | + |
| 197 | +Agents establish a long-lived WebSocket connection to the hub's `/proxy` endpoint. The hub uses [revdial](https://github.com/bradfitz/revdial) to dial *back* to agents over this connection — the agent never needs an open port. |
124 | 198 |
|
125 | | -## Project layout |
| 199 | +### Edge proxy URL format |
126 | 200 |
|
| 201 | +Once an Edge is `Ready`, the hub exposes a virtual workspace endpoint: |
| 202 | + |
| 203 | +``` |
| 204 | +https://<hub>/clusters/<workspace-id>/apis/kedge.faros.sh/v1alpha1/edges/<name>/proxy/k8s |
127 | 205 | ``` |
128 | | -apis/ Custom resource types (Site, VirtualWorkload, Placement) |
129 | | -cmd/ |
130 | | - kedge/ CLI entrypoint |
131 | | - kedge-hub/ Hub server entrypoint |
132 | | - kedge-agent/ Agent entrypoint |
133 | | -config/ |
134 | | - crds/ Generated CRD YAML |
135 | | - kcp/ Generated kcp APIResourceSchemas and APIExports |
136 | | -pkg/ |
137 | | - agent/ Agent logic (tunnel, workload reconciler, status reporter) |
138 | | - cli/ CLI commands and auth |
139 | | - hub/ Hub server, controllers (scheduler, status, site lifecycle) |
140 | | - server/ HTTP handlers (auth, kcp proxy) |
141 | | - virtual/builder/ Tunnel endpoint handlers (edge proxy, agent proxy, site proxy) |
142 | | - client/ Dynamic kedge API client |
143 | | - util/ Shared utilities (connman, revdial, ssh, http) |
144 | | -hack/ |
145 | | - boilerplate/ License header template |
146 | | - scripts/ Dev environment scripts |
147 | | - dev/ Dev config (Dex config, example manifests) |
| 206 | + |
| 207 | +`kedge kubeconfig edge <name>` generates a kubeconfig that points to this URL. |
| 208 | + |
| 209 | +--- |
| 210 | + |
| 211 | +## PR Workflow |
| 212 | + |
| 213 | +1. Fork the repo and create a feature branch from `main`. |
| 214 | +2. Make your changes. All commits must pass: |
| 215 | + ```bash |
| 216 | + go build ./... # must compile |
| 217 | + make lint # 0 issues |
| 218 | + go test ./pkg/... # unit tests pass |
| 219 | + ``` |
| 220 | +3. Open a PR against `main`. CI runs build, lint, unit tests, and all four e2e suites. |
| 221 | +4. Address review comments. The bot (`@mjudeikis-bot`) monitors CI and posts status. |
| 222 | +5. A maintainer merges once CI is green and the PR is approved. |
| 223 | + |
| 224 | +### Commit style |
| 225 | + |
148 | 226 | ``` |
| 227 | +<type>: <short description> (#issue) |
149 | 228 |
|
150 | | -## Submitting changes |
| 229 | +Longer explanation if needed. |
| 230 | +
|
| 231 | +Co-authored-by: Your Name <you@example.com> |
| 232 | +``` |
151 | 233 |
|
152 | | -1. Fork the repository and create a feature branch. |
153 | | -2. Make your changes. |
154 | | -3. Run `make codegen` if you changed API types. |
155 | | -4. Run `make verify` to ensure all checks pass. |
156 | | -5. Submit a pull request. |
| 234 | +Types: `feat`, `fix`, `test`, `docs`, `refactor`, `chore`. |
0 commit comments