Add "DevOps-Tools"
parent
641f5ab644
commit
a87e05fa12
1 changed files with 308 additions and 0 deletions
308
DevOps-Tools.-.md
Normal file
308
DevOps-Tools.-.md
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
# DevOps Tools
|
||||
|
||||
API reference for the `devops` package -- portable development environments with LinuxKit, shell access, testing, serving, Claude sandboxing, and image management. See [[Home]] for installation.
|
||||
|
||||
## DevOps Manager
|
||||
|
||||
The central `DevOps` struct orchestrates the portable dev environment backed by LinuxKit QEMU images.
|
||||
|
||||
```go
|
||||
import (
|
||||
"forge.lthn.ai/core/go-devops/devops"
|
||||
"forge.lthn.ai/core/go/pkg/io"
|
||||
)
|
||||
|
||||
d, err := devops.New(io.Local)
|
||||
```
|
||||
|
||||
### Lifecycle
|
||||
|
||||
```go
|
||||
// Boot the dev environment
|
||||
err := d.Boot(ctx, devops.BootOptions{
|
||||
Memory: 4096, // MB
|
||||
CPUs: 2,
|
||||
Name: "core-dev",
|
||||
Fresh: false, // set true to destroy and recreate
|
||||
})
|
||||
|
||||
// Check status
|
||||
running, err := d.IsRunning(ctx)
|
||||
|
||||
// Get detailed status
|
||||
status, err := d.Status(ctx)
|
||||
// status.Installed, status.Running, status.ImageVersion,
|
||||
// status.ContainerID, status.Memory, status.CPUs,
|
||||
// status.SSHPort (default 2222), status.Uptime
|
||||
|
||||
// Stop
|
||||
err := d.Stop(ctx)
|
||||
|
||||
// Install/update images
|
||||
err := d.Install(ctx, progressCallback)
|
||||
current, latest, hasUpdate, err := d.CheckUpdate(ctx)
|
||||
```
|
||||
|
||||
### BootOptions
|
||||
|
||||
```go
|
||||
type BootOptions struct {
|
||||
Memory int // MB, default 4096
|
||||
CPUs int // default 2
|
||||
Name string // container name, default "core-dev"
|
||||
Fresh bool // destroy existing and start fresh
|
||||
}
|
||||
|
||||
opts := devops.DefaultBootOptions() // sensible defaults
|
||||
```
|
||||
|
||||
### DevStatus
|
||||
|
||||
```go
|
||||
type DevStatus struct {
|
||||
Installed bool
|
||||
Running bool
|
||||
ImageVersion string
|
||||
ContainerID string
|
||||
Memory int
|
||||
CPUs int
|
||||
SSHPort int // default 2222
|
||||
Uptime time.Duration
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Shell Execution
|
||||
|
||||
Connect to the dev environment via SSH or serial console.
|
||||
|
||||
```go
|
||||
err := d.Shell(ctx, devops.ShellOptions{
|
||||
Console: false, // true for serial console, false for SSH
|
||||
Command: []string{"ls"}, // empty for interactive shell
|
||||
})
|
||||
```
|
||||
|
||||
### ShellOptions
|
||||
|
||||
```go
|
||||
type ShellOptions struct {
|
||||
Console bool // Use serial console instead of SSH
|
||||
Command []string // Command to run (empty = interactive shell)
|
||||
}
|
||||
```
|
||||
|
||||
SSH connects to `root@localhost:2222` with agent forwarding (`-A`) and strict host key checking using `~/.core/known_hosts`.
|
||||
|
||||
---
|
||||
|
||||
## Docker Image Management
|
||||
|
||||
The `ImageManager` handles downloading, installing, and updating LinuxKit dev images from multiple sources.
|
||||
|
||||
```go
|
||||
type ImageManager struct { /* ... */ }
|
||||
|
||||
// Platform-specific image name
|
||||
name := devops.ImageName() // e.g. "core-devops-darwin-arm64.qcow2"
|
||||
|
||||
// Image paths
|
||||
dir, err := devops.ImagesDir() // ~/.core/images (or $CORE_IMAGES_DIR)
|
||||
path, err := devops.ImagePath() // ~/.core/images/core-devops-darwin-arm64.qcow2
|
||||
```
|
||||
|
||||
### Image Sources (`devops/sources`)
|
||||
|
||||
The `ImageSource` interface defines how images are downloaded:
|
||||
|
||||
```go
|
||||
type ImageSource interface {
|
||||
Name() string
|
||||
Available() bool
|
||||
LatestVersion(ctx context.Context) (string, error)
|
||||
Download(ctx context.Context, m io.Medium, dest string, progress func(downloaded, total int64)) error
|
||||
}
|
||||
```
|
||||
|
||||
Two built-in sources:
|
||||
|
||||
| Source | Type | Availability Check |
|
||||
|---|---|---|
|
||||
| `GitHubSource` | GitHub Releases via `gh` CLI | `gh auth status` succeeds |
|
||||
| `CDNSource` | HTTP download from CDN/S3 URL | CDN URL configured |
|
||||
|
||||
```go
|
||||
import "forge.lthn.ai/core/go-devops/devops/sources"
|
||||
|
||||
cfg := sources.SourceConfig{
|
||||
GitHubRepo: "host-uk/core-images",
|
||||
CDNURL: "https://cdn.example.com/images",
|
||||
ImageName: "core-devops-darwin-arm64.qcow2",
|
||||
}
|
||||
|
||||
gh := sources.NewGitHubSource(cfg)
|
||||
cdn := sources.NewCDNSource(cfg)
|
||||
```
|
||||
|
||||
### Manifest
|
||||
|
||||
Tracks installed images in `~/.core/images/manifest.json`:
|
||||
|
||||
```go
|
||||
type ImageInfo struct {
|
||||
Version string `json:"version"`
|
||||
SHA256 string `json:"sha256,omitempty"`
|
||||
Downloaded time.Time `json:"downloaded"`
|
||||
Source string `json:"source"` // "github" or "cdn"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
Run tests inside the dev environment with auto-detection of test frameworks.
|
||||
|
||||
```go
|
||||
err := d.Test(ctx, projectDir, devops.TestOptions{
|
||||
Name: "", // run named command from .core/test.yaml
|
||||
Command: []string{}, // override command (highest priority)
|
||||
})
|
||||
```
|
||||
|
||||
### Auto-Detection Order
|
||||
|
||||
`DetectTestCommand` checks in this order:
|
||||
|
||||
1. `.core/test.yaml` -- explicit `command` field
|
||||
2. `composer.json` with `test` script -- `composer test`
|
||||
3. `package.json` with `test` script -- `npm test`
|
||||
4. `go.mod` -- `go test ./...`
|
||||
5. `pytest.ini` or `pyproject.toml` -- `pytest`
|
||||
6. `Taskfile.yaml` -- `task test`
|
||||
|
||||
### Test Config (`.core/test.yaml`)
|
||||
|
||||
```yaml
|
||||
version: 1
|
||||
command: go test ./...
|
||||
commands:
|
||||
- name: unit
|
||||
run: go test -short ./...
|
||||
- name: integration
|
||||
run: go test -run Integration ./...
|
||||
env:
|
||||
GOFLAGS: -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Serve Mode
|
||||
|
||||
Mount a project and start a development server inside the dev environment.
|
||||
|
||||
```go
|
||||
err := d.Serve(ctx, projectDir, devops.ServeOptions{
|
||||
Port: 8000, // default 8000
|
||||
Path: "", // subdirectory (default: project root)
|
||||
})
|
||||
```
|
||||
|
||||
### Auto-Detection Order
|
||||
|
||||
`DetectServeCommand` checks in this order:
|
||||
|
||||
1. `artisan` (Laravel) -- `php artisan octane:start --host=0.0.0.0 --port=8000`
|
||||
2. `package.json` with `dev` script -- `npm run dev -- --host 0.0.0.0`
|
||||
3. `package.json` with `start` script -- `npm start`
|
||||
4. `composer.json` (PHP) -- `frankenphp php-server -l :8000`
|
||||
5. `go.mod` + `main.go` -- `go run .`
|
||||
6. `manage.py` (Django) -- `python manage.py runserver 0.0.0.0:8000`
|
||||
7. Fallback -- `python3 -m http.server 8000`
|
||||
|
||||
Project is mounted into the VM at `/app` via reverse SSHFS.
|
||||
|
||||
---
|
||||
|
||||
## Claude Sandbox
|
||||
|
||||
Run Claude Code in an isolated dev environment with selective auth forwarding.
|
||||
|
||||
```go
|
||||
err := d.Claude(ctx, projectDir, devops.ClaudeOptions{
|
||||
NoAuth: false, // don't forward any auth
|
||||
Auth: []string{"gh", "anthropic", "ssh", "git"}, // selective (default: all)
|
||||
Model: "opus", // model override
|
||||
})
|
||||
```
|
||||
|
||||
### ClaudeOptions
|
||||
|
||||
```go
|
||||
type ClaudeOptions struct {
|
||||
NoAuth bool // Don't forward any auth
|
||||
Auth []string // Selective auth: "gh", "anthropic", "ssh", "git"
|
||||
Model string // Model to use: opus, sonnet
|
||||
}
|
||||
```
|
||||
|
||||
### Auth Forwarding
|
||||
|
||||
| Auth Type | What Gets Forwarded |
|
||||
|---|---|
|
||||
| `ssh` | SSH agent forwarding (`-A`) -- always on unless `NoAuth` |
|
||||
| `anthropic` | `ANTHROPIC_API_KEY` env var |
|
||||
| `git` | `GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`, `GIT_COMMITTER_EMAIL` |
|
||||
| `gh` | GitHub CLI config copied via `CopyGHAuth()` using scp |
|
||||
|
||||
Auto-boots the dev environment if not running. Project is mounted at `/app`.
|
||||
|
||||
---
|
||||
|
||||
## SSH Utilities
|
||||
|
||||
### Host Key Management
|
||||
|
||||
After booting, `ensureHostKey` automatically scans the VM's SSH host key and adds it to `~/.core/known_hosts` (deduplicating entries). This enables `StrictHostKeyChecking=yes` for all subsequent SSH connections.
|
||||
|
||||
Set `CORE_SKIP_SSH_SCAN=true` to skip in tests.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Global devops config is loaded from `~/.core/config.yaml`:
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Version int
|
||||
Images ImagesConfig
|
||||
}
|
||||
|
||||
type ImagesConfig struct {
|
||||
Source string // "auto", "github", "cdn"
|
||||
GitHub GitHubConfig // .Repo (owner/repo)
|
||||
Registry RegistryConfig // .Image (e.g. ghcr.io/host-uk/core-devops)
|
||||
CDN CDNConfig // .URL (base download URL)
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
cfg, err := devops.LoadConfig(medium) // returns DefaultConfig() if file missing
|
||||
path, err := devops.ConfigPath() // ~/.core/config.yaml
|
||||
```
|
||||
|
||||
### Defaults
|
||||
|
||||
```yaml
|
||||
version: 1
|
||||
images:
|
||||
source: auto
|
||||
github:
|
||||
repo: host-uk/core-images
|
||||
registry:
|
||||
image: ghcr.io/host-uk/core-devops
|
||||
```
|
||||
|
||||
See [[Infrastructure]] for the `infra` package API.
|
||||
Loading…
Add table
Reference in a new issue