-
Notifications
You must be signed in to change notification settings - Fork 0
Essential API setup #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
43c9fd8
Move readme
sjmiller609 e1d65bc
Generated API spec
sjmiller609 03d2b46
Matching API setup
sjmiller609 cbc5063
Clean up error handling pattern
sjmiller609 8b0cfce
Add basic testing setup
sjmiller609 6795829
Simplify README
sjmiller609 3f5f8f4
Rename to hypeman
sjmiller609 05b427c
Add simple authentication middleware
sjmiller609 0cc32b7
More setup info
sjmiller609 78d1fa5
Switch auth middleware and global type validation
sjmiller609 03c3174
Add swagger UI
sjmiller609 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| root = "." | ||
| testdata_dir = "testdata" | ||
| tmp_dir = "tmp" | ||
|
|
||
| [build] | ||
| args_bin = [] | ||
| bin = "./tmp/main" | ||
| cmd = "go build -o ./tmp/main ./cmd/api" | ||
| delay = 1000 | ||
| exclude_dir = ["assets", "tmp", "vendor", "testdata", "bin", "scripts", "data", "kernel"] | ||
| exclude_file = [] | ||
| exclude_regex = ["_test.go"] | ||
| exclude_unchanged = false | ||
| follow_symlink = false | ||
| full_bin = "" | ||
| include_dir = [] | ||
| include_ext = ["go", "tpl", "tmpl", "html", "yaml"] | ||
| include_file = [] | ||
| kill_delay = "0s" | ||
| log = "build-errors.log" | ||
| poll = false | ||
| poll_interval = 0 | ||
| rerun = false | ||
| rerun_delay = 500 | ||
| send_interrupt = false | ||
| stop_on_error = false | ||
|
|
||
| [color] | ||
| app = "" | ||
| build = "yellow" | ||
| main = "magenta" | ||
| runner = "green" | ||
| watcher = "cyan" | ||
|
|
||
| [log] | ||
| main_only = false | ||
| time = false | ||
|
|
||
| [misc] | ||
| clean_on_exit = false | ||
|
|
||
| [screen] | ||
| clear_on_rebuild = false | ||
| keep_scroll = true | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| JWT_SECRET='your-secret-key-here' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| name: Test | ||
|
|
||
| on: | ||
| push: {} | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: '1.25' | ||
|
|
||
| - name: Install dependencies | ||
| run: go mod download | ||
|
|
||
| - name: Run tests | ||
| run: make test | ||
|
|
||
| - name: Build | ||
| run: make build | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,3 +7,9 @@ initramfs-overlay/** | |
| data/** | ||
| *.raw | ||
| *.sock | ||
| kernel | ||
| kernel/** | ||
| bin/** | ||
| .env | ||
| tmp | ||
| tmp/** | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| SHELL := /bin/bash | ||
| .PHONY: oapi-generate generate-wire generate-all dev build test install-tools | ||
|
|
||
| # Directory where local binaries will be installed | ||
| BIN_DIR ?= $(CURDIR)/bin | ||
|
|
||
| $(BIN_DIR): | ||
| mkdir -p $(BIN_DIR) | ||
|
|
||
| # Local binary paths | ||
| OAPI_CODEGEN ?= $(BIN_DIR)/oapi-codegen | ||
| AIR ?= $(BIN_DIR)/air | ||
| WIRE ?= $(BIN_DIR)/wire | ||
|
|
||
| # Install oapi-codegen | ||
| $(OAPI_CODEGEN): | $(BIN_DIR) | ||
| GOBIN=$(BIN_DIR) go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest | ||
|
|
||
| # Install air for hot reload | ||
| $(AIR): | $(BIN_DIR) | ||
| GOBIN=$(BIN_DIR) go install github.com/air-verse/air@latest | ||
|
|
||
| # Install wire for dependency injection | ||
| $(WIRE): | $(BIN_DIR) | ||
| GOBIN=$(BIN_DIR) go install github.com/google/wire/cmd/wire@latest | ||
|
|
||
| install-tools: $(OAPI_CODEGEN) $(AIR) $(WIRE) | ||
|
|
||
| # Generate Go code from OpenAPI spec | ||
| oapi-generate: $(OAPI_CODEGEN) | ||
| @echo "Generating Go code from OpenAPI spec..." | ||
| $(OAPI_CODEGEN) -config ./oapi-codegen.yaml ./openapi.yaml | ||
| @echo "Formatting generated code..." | ||
| go fmt ./lib/oapi/oapi.go | ||
|
|
||
| # Generate wire dependency injection code | ||
| generate-wire: $(WIRE) | ||
| @echo "Generating wire code..." | ||
| cd ./cmd/api && $(WIRE) | ||
|
|
||
| # Generate all code | ||
| generate-all: oapi-generate generate-wire | ||
|
|
||
| # Build the binary | ||
| build: | $(BIN_DIR) | ||
| go build -o $(BIN_DIR)/hypeman ./cmd/api | ||
|
|
||
| # Run in development mode with hot reload | ||
| dev: $(AIR) | ||
| $(AIR) -c .air.toml | ||
|
|
||
| # Run tests | ||
| test: | ||
| go test -v -timeout 30s ./... | ||
|
|
||
| # Clean generated files and binaries | ||
| clean: | ||
| rm -rf $(BIN_DIR) | ||
| rm -f lib/oapi/oapi.go | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,125 +1,68 @@ | ||
| # Cloud Hypervisor POC | ||
| # Hypeman | ||
|
|
||
| Proof of concept for running 10 Chromium VMs simultaneously using Cloud Hypervisor with disk-based overlays, config disks, networking isolation, and standby/restore functionality. | ||
| [](https://github.com/onkernel/hypeman/actions/workflows/test.yml) | ||
|
|
||
| ## Prerequisites | ||
| Run containerized workloads in VMs, powered by [Cloud Hypervisor](https://github.com/cloud-hypervisor/cloud-hypervisor). | ||
|
|
||
| Install cloud-hypervisor by [installing the pre-built binaries](https://www.cloudhypervisor.org/docs/prologue/quick-start/#use-pre-built-binaries). Make sure `ch-remote` and `cloud-hypervisor` are in path. | ||
| ## Getting Started | ||
|
|
||
| ```bash | ||
| ch-remote --version | ||
| cloud-hypervisor --version | ||
| ``` | ||
|
|
||
| Tested with version `v48.0.0` | ||
|
|
||
| Note: Requires `kernel-images-private` cloned to home directory with `iproute2` installed in the Chromium headful image. | ||
|
|
||
| Also, `lsof` and `lz4` needs to be installed on the host | ||
|
|
||
| ``` | ||
| sudo apt-get install -y lsof lz4 | ||
| ``` | ||
|
|
||
| ## Setup | ||
|
|
||
| Build kernel, initrd, and rootfs with config disk support: | ||
| ### Prerequisites | ||
|
|
||
| **Cloud Hypervisor** - [Installation guide](https://www.cloudhypervisor.org/docs/prologue/quick-start/#use-pre-built-binaries) | ||
| ```bash | ||
| ./scripts/build-initrd.sh | ||
| ``` | ||
|
|
||
| This creates: | ||
| - `data/system/vmlinux` - Linux kernel | ||
| - `data/system/initrd` - BusyBox init with disk-based overlay | ||
| - `data/images/chromium-headful/v1/rootfs.ext4` - Chromium rootfs (read-only, shared) | ||
|
|
||
| Configure host network with bridge and guest isolation: | ||
|
|
||
| ```bash | ||
| ./scripts/setup-host-network.sh | ||
| ``` | ||
|
|
||
| Create 10 VM configurations (IPs 192.168.100.10-19, isolated TAP devices, overlay disks, config disks): | ||
|
|
||
| ```bash | ||
| ./scripts/setup-vms.sh | ||
| cloud-hypervisor --version # Verify | ||
| ch-remote --version | ||
| ``` | ||
|
|
||
| ## Running VMs | ||
|
|
||
| Start all 10 VMs: | ||
|
|
||
| **containerd** - [Installation guide](https://github.com/containerd/containerd/blob/main/docs/getting-started.md) | ||
| ```bash | ||
| ./scripts/start-all-vms.sh | ||
| containerd --version # Verify | ||
| ``` | ||
|
|
||
| Check VM status: | ||
| **Go 1.25.4+** and **KVM** | ||
|
|
||
| ```bash | ||
| ./scripts/list-vms.sh | ||
| ``` | ||
|
|
||
| View VM logs: | ||
| ### Configuration | ||
|
|
||
| ```bash | ||
| ./scripts/logs-vm.sh <vm-id> # Show last 100 lines | ||
| ./scripts/logs-vm.sh <vm-id> -f # Follow logs | ||
| cp .env.example .env | ||
| # Edit .env and set JWT_SECRET | ||
| ``` | ||
|
|
||
| SSH into a VM: | ||
| ### Build | ||
|
|
||
| ```bash | ||
| ./scripts/ssh-vm.sh <vm-id> # Password: root | ||
| make build | ||
| ``` | ||
| ### Running the Server | ||
|
|
||
| Stop a VM: | ||
|
|
||
| Start the server with hot-reload for development: | ||
| ```bash | ||
| ./scripts/stop-vm.sh <vm-id> | ||
| ./scripts/stop-all-vms.sh # Stop all | ||
| make dev | ||
| ``` | ||
| The server will start on port 8080 (configurable via `PORT` environment variable). | ||
|
|
||
| ## Standby / Restore | ||
|
|
||
| Standby a VM (pause, snapshot, delete VMM): | ||
|
|
||
| ```bash | ||
| ./scripts/standby-vm.sh <vm-id> | ||
| ``` | ||
|
|
||
| Restore a VM from snapshot: | ||
| ### Testing | ||
|
|
||
| ```bash | ||
| ./scripts/restore-vm.sh <vm-id> | ||
| make test | ||
| ``` | ||
|
|
||
| ## Networking | ||
| ### Code Generation | ||
|
|
||
| Enable port forwarding for WebRTC access (localhost:8080-8089 → guest VMs): | ||
| After modifying `openapi.yaml`, regenerate the Go code: | ||
|
|
||
| ```bash | ||
| ./scripts/setup-port-forwarding.sh | ||
| make oapi-generate | ||
| ``` | ||
|
|
||
| Connect to a VM: | ||
| After modifying dependency injection in `cmd/api/wire.go` or `lib/providers/providers.go`, regenerate wire code: | ||
|
|
||
| ```bash | ||
| ./scripts/connect-guest.sh <vm-id> | ||
| make generate-wire | ||
| ``` | ||
|
|
||
| ## Volumes | ||
|
|
||
| Create a persistent volume: | ||
| Or generate everything at once: | ||
|
|
||
| ```bash | ||
| ./scripts/create-volume.sh <vol-id> <size-gb> | ||
| make generate-all | ||
| ``` | ||
|
|
||
| ## Architecture | ||
|
|
||
| - **Disk-based overlay**: Each VM has a 50GB sparse overlay disk on `/dev/vdb` (faster restore than tmpfs) | ||
| - **Config disk**: Each VM has a config disk on `/dev/vdc` with VM-specific settings (IP, MAC, envs) | ||
| - **Guest isolation**: VMs cannot communicate with each other (iptables + bridge_slave isolation) | ||
| - **Serial logging**: All VM output captured to `data/guests/guest-N/logs/console.log` | ||
| - **Shared rootfs**: Single read-only rootfs image shared across all VMs | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package api | ||
|
|
||
| import ( | ||
| "github.com/onkernel/hypeman/cmd/api/config" | ||
| "github.com/onkernel/hypeman/lib/images" | ||
| "github.com/onkernel/hypeman/lib/instances" | ||
| "github.com/onkernel/hypeman/lib/oapi" | ||
| "github.com/onkernel/hypeman/lib/volumes" | ||
sjmiller609 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
| // ApiService implements the oapi.StrictServerInterface | ||
| type ApiService struct { | ||
| Config *config.Config | ||
| ImageManager images.Manager | ||
| InstanceManager instances.Manager | ||
| VolumeManager volumes.Manager | ||
| } | ||
|
|
||
| var _ oapi.StrictServerInterface = (*ApiService)(nil) | ||
|
|
||
| // New creates a new ApiService | ||
| func New( | ||
| config *config.Config, | ||
| imageManager images.Manager, | ||
| instanceManager instances.Manager, | ||
| volumeManager volumes.Manager, | ||
| ) *ApiService { | ||
| return &ApiService{ | ||
| Config: config, | ||
| ImageManager: imageManager, | ||
| InstanceManager: instanceManager, | ||
| VolumeManager: volumeManager, | ||
| } | ||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package api | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "github.com/onkernel/hypeman/cmd/api/config" | ||
| "github.com/onkernel/hypeman/lib/images" | ||
| "github.com/onkernel/hypeman/lib/instances" | ||
| "github.com/onkernel/hypeman/lib/volumes" | ||
| ) | ||
|
|
||
| // newTestService creates an ApiService for testing with temporary data directory | ||
| func newTestService(t *testing.T) *ApiService { | ||
| cfg := &config.Config{ | ||
| DataDir: t.TempDir(), | ||
| } | ||
|
|
||
| return &ApiService{ | ||
| Config: cfg, | ||
| ImageManager: images.NewManager(cfg.DataDir), | ||
| InstanceManager: instances.NewManager(cfg.DataDir), | ||
| VolumeManager: volumes.NewManager(cfg.DataDir), | ||
| } | ||
| } | ||
|
|
||
| func ctx() context.Context { | ||
| return context.Background() | ||
| } | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package api | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/onkernel/hypeman/lib/oapi" | ||
| ) | ||
|
|
||
| // GetHealth implements health check endpoint | ||
| func (s *ApiService) GetHealth(ctx context.Context, request oapi.GetHealthRequestObject) (oapi.GetHealthResponseObject, error) { | ||
| return oapi.GetHealth200JSONResponse{ | ||
| Status: oapi.Ok, | ||
| }, nil | ||
| } | ||
|
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.