Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c66de4df2 | ||
|
|
9de33d4252 | ||
|
|
ff8375c6e1 | ||
| 3e22214bbd | |||
| b4e90db372 | |||
| c6b9e0c2d1 |
@@ -29,6 +29,7 @@ jobs:
|
|||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
|
cache: false
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ jobs:
|
|||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: 'go.mod'
|
go-version-file: 'go.mod'
|
||||||
|
cache: false
|
||||||
|
|
||||||
- name: Vet
|
- name: Vet
|
||||||
run: make vet
|
run: make vet
|
||||||
|
|||||||
221
README.md
221
README.md
@@ -1,108 +1,195 @@
|
|||||||
# act runner
|
# GitCaddy Act Runner
|
||||||
|
|
||||||
Act runner is a runner for Gitea based on [Gitea fork](https://gitea.com/gitea/act) of [act](https://github.com/nektos/act).
|
A Gitea Actions runner with enhanced capability detection and reporting for AI-friendly workflow generation.
|
||||||
|
|
||||||
|
> **This is a GitCaddy fork** of [gitea.com/gitea/act_runner](https://gitea.com/gitea/act_runner) with runner capability discovery features.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Act Runner executes Gitea Actions workflows using [act](https://github.com/nektos/act). This fork adds automatic capability detection, enabling Gitea to expose runner capabilities via API for AI tools to query before generating workflows.
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
- **Capability Detection**: Automatically detects OS, architecture, Docker support, available shells, and installed tools
|
||||||
|
- **Capability Reporting**: Reports capabilities to Gitea server during runner declaration
|
||||||
|
- **Full Compatibility**: Drop-in replacement for standard act_runner
|
||||||
|
- **Multi-Platform**: Supports Linux, macOS, and Windows
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Prerequisites
|
### Download Pre-built Binary
|
||||||
|
|
||||||
Docker Engine Community version is required for docker mode. To install Docker CE, follow the official [install instructions](https://docs.docker.com/engine/install/).
|
Download from [Releases](https://git.marketally.com/gitcaddy/act_runner/releases):
|
||||||
|
|
||||||
### Download pre-built binary
|
|
||||||
|
|
||||||
Visit [here](https://dl.gitea.com/act_runner/) and download the right version for your platform.
|
|
||||||
|
|
||||||
### Build from source
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Linux (amd64)
|
||||||
|
curl -L -o act_runner https://git.marketally.com/gitcaddy/act_runner/releases/download/v0.3.1-gitcaddy/act_runner-linux-amd64
|
||||||
|
chmod +x act_runner
|
||||||
|
|
||||||
|
# macOS (Apple Silicon)
|
||||||
|
curl -L -o act_runner https://git.marketally.com/gitcaddy/act_runner/releases/download/v0.3.1-gitcaddy/act_runner-darwin-arm64
|
||||||
|
chmod +x act_runner
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build from Source
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.marketally.com/gitcaddy/act_runner.git
|
||||||
|
cd act_runner
|
||||||
make build
|
make build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build a docker image
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
### 1. Enable Actions in Gitea
|
||||||
make docker
|
|
||||||
```
|
|
||||||
|
|
||||||
## Quickstart
|
Add to your Gitea `app.ini`:
|
||||||
|
|
||||||
Actions are disabled by default, so you need to add the following to the configuration file of your Gitea instance to enable it:
|
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[actions]
|
[actions]
|
||||||
ENABLED=true
|
ENABLED = true
|
||||||
```
|
```
|
||||||
|
|
||||||
### Register
|
### 2. Register the Runner
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./act_runner register
|
./act_runner register \
|
||||||
|
--instance https://your-gitea-instance.com \
|
||||||
|
--token YOUR_RUNNER_TOKEN \
|
||||||
|
--name my-runner \
|
||||||
|
--labels ubuntu-latest,docker
|
||||||
```
|
```
|
||||||
|
|
||||||
And you will be asked to input:
|
### 3. Start the Runner
|
||||||
|
|
||||||
1. Gitea instance URL, like `http://192.168.8.8:3000/`. You should use your gitea instance ROOT_URL as the instance argument
|
|
||||||
and you should not use `localhost` or `127.0.0.1` as instance IP;
|
|
||||||
2. Runner token, you can get it from `http://192.168.8.8:3000/admin/actions/runners`;
|
|
||||||
3. Runner name, you can just leave it blank;
|
|
||||||
4. Runner labels, you can just leave it blank.
|
|
||||||
|
|
||||||
The process looks like:
|
|
||||||
|
|
||||||
```text
|
|
||||||
INFO Registering runner, arch=amd64, os=darwin, version=0.1.5.
|
|
||||||
WARN Runner in user-mode.
|
|
||||||
INFO Enter the Gitea instance URL (for example, https://gitea.com/):
|
|
||||||
http://192.168.8.8:3000/
|
|
||||||
INFO Enter the runner token:
|
|
||||||
fe884e8027dc292970d4e0303fe82b14xxxxxxxx
|
|
||||||
INFO Enter the runner name (if set empty, use hostname: Test.local):
|
|
||||||
|
|
||||||
INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest):
|
|
||||||
|
|
||||||
INFO Registering runner, name=Test.local, instance=http://192.168.8.8:3000/, labels=[ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04 ubuntu-20.04:docker://docker.gitea.com/runner-images:ubuntu-20.04].
|
|
||||||
DEBU Successfully pinged the Gitea instance server
|
|
||||||
INFO Runner registered successfully.
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also register with command line arguments.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./act_runner register --instance http://192.168.8.8:3000 --token <my_runner_token> --no-interactive
|
|
||||||
```
|
|
||||||
|
|
||||||
If the registry succeed, it will run immediately. Next time, you could run the runner directly.
|
|
||||||
|
|
||||||
### Run
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./act_runner daemon
|
./act_runner daemon
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run with docker
|
On startup, the runner will:
|
||||||
|
1. Detect system capabilities (OS, arch, Docker, shells, tools)
|
||||||
|
2. Report capabilities to Gitea via the Declare API
|
||||||
|
3. Begin polling for jobs
|
||||||
|
|
||||||
```bash
|
## Capability Detection
|
||||||
docker run -e GITEA_INSTANCE_URL=https://your_gitea.com -e GITEA_RUNNER_REGISTRATION_TOKEN=<your_token> -v /var/run/docker.sock:/var/run/docker.sock --name my_runner gitea/act_runner:nightly
|
|
||||||
|
The runner automatically detects:
|
||||||
|
|
||||||
|
| Category | Examples |
|
||||||
|
|----------|----------|
|
||||||
|
| **OS/Arch** | linux/amd64, darwin/arm64, windows/amd64 |
|
||||||
|
| **Container Runtime** | Docker, Podman |
|
||||||
|
| **Shells** | bash, sh, zsh, powershell, cmd |
|
||||||
|
| **Tools** | Node.js, Go, Python, Java, .NET, Rust |
|
||||||
|
| **Features** | Cache support, Docker Compose |
|
||||||
|
|
||||||
|
### Example Capabilities JSON
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"os": "linux",
|
||||||
|
"arch": "amd64",
|
||||||
|
"docker": true,
|
||||||
|
"docker_compose": true,
|
||||||
|
"container_runtime": "docker",
|
||||||
|
"shell": ["bash", "sh"],
|
||||||
|
"tools": {
|
||||||
|
"node": ["18.19.0"],
|
||||||
|
"go": ["1.21.5"],
|
||||||
|
"python": ["3.11.6"]
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"cache": true,
|
||||||
|
"docker_services": true
|
||||||
|
},
|
||||||
|
"limitations": []
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Configuration
|
## Configuration
|
||||||
|
|
||||||
You can also configure the runner with a configuration file.
|
Create a config file or use command-line flags:
|
||||||
The configuration file is a YAML file, you can generate a sample configuration file with `./act_runner generate-config`.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./act_runner generate-config > config.yaml
|
./act_runner generate-config > config.yaml
|
||||||
|
./act_runner -c config.yaml daemon
|
||||||
```
|
```
|
||||||
|
|
||||||
You can specify the configuration file path with `-c`/`--config` argument.
|
Example configuration:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
log:
|
||||||
|
level: info
|
||||||
|
|
||||||
|
runner:
|
||||||
|
file: .runner
|
||||||
|
capacity: 1
|
||||||
|
timeout: 3h
|
||||||
|
labels:
|
||||||
|
- ubuntu-latest:docker://node:18-bullseye
|
||||||
|
- ubuntu-22.04:docker://ubuntu:22.04
|
||||||
|
|
||||||
|
container:
|
||||||
|
docker_host: ""
|
||||||
|
force_pull: false
|
||||||
|
privileged: false
|
||||||
|
|
||||||
|
cache:
|
||||||
|
enabled: true
|
||||||
|
dir: ~/.cache/actcache
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker Deployment
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./act_runner -c config.yaml register # register with config file
|
docker run -d \
|
||||||
./act_runner -c config.yaml daemon # run with config file
|
--name act_runner \
|
||||||
|
-e GITEA_INSTANCE_URL=https://your-gitea.com \
|
||||||
|
-e GITEA_RUNNER_REGISTRATION_TOKEN=<token> \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
-v ./data:/data \
|
||||||
|
gitcaddy/act_runner:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
You can read the latest version of the configuration file online at [config.example.yaml](internal/pkg/config/config.example.yaml).
|
## GitCaddy Integration
|
||||||
|
|
||||||
### Example Deployments
|
This runner is designed to work with the [GitCaddy Gitea fork](https://git.marketally.com/gitcaddy/gitea), which provides:
|
||||||
|
|
||||||
Check out the [examples](examples) directory for sample deployment types.
|
- **Runner Capabilities API** (`/api/v2/repos/{owner}/{repo}/actions/runners/capabilities`)
|
||||||
|
- **Workflow Validation API** for pre-flight checks
|
||||||
|
- **Action Compatibility Database** for GitHub Actions mapping
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
act_runner Gitea AI Tool
|
||||||
|
| | |
|
||||||
|
| Declare + Capabilities | |
|
||||||
|
|---------------------------->| |
|
||||||
|
| | |
|
||||||
|
| | GET /api/v2/.../caps |
|
||||||
|
| |<------------------------|
|
||||||
|
| | |
|
||||||
|
| | Runner capabilities |
|
||||||
|
| |------------------------>|
|
||||||
|
| | |
|
||||||
|
| | Generates workflow |
|
||||||
|
| | with correct config |
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Projects
|
||||||
|
|
||||||
|
| Project | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| [gitcaddy/gitea](https://git.marketally.com/gitcaddy/gitea) | Gitea with AI-friendly enhancements |
|
||||||
|
| [gitcaddy/actions-proto-go](https://git.marketally.com/gitcaddy/actions-proto-go) | Protocol definitions with capability support |
|
||||||
|
|
||||||
|
## Upstream
|
||||||
|
|
||||||
|
This project is a fork of [gitea.com/gitea/act_runner](https://gitea.com/gitea/act_runner). We contribute enhancements back to upstream where appropriate.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License - see [LICENSE](LICENSE) for details.
|
||||||
|
|||||||
7
go.mod
7
go.mod
@@ -5,7 +5,7 @@ go 1.24.0
|
|||||||
toolchain go1.24.11
|
toolchain go1.24.11
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.gitea.io/actions-proto-go v0.5.0
|
code.gitea.io/actions-proto-go v0.5.2
|
||||||
code.gitea.io/gitea-vet v0.2.3
|
code.gitea.io/gitea-vet v0.2.3
|
||||||
connectrpc.com/connect v1.16.2
|
connectrpc.com/connect v1.16.2
|
||||||
github.com/avast/retry-go/v4 v4.6.0
|
github.com/avast/retry-go/v4 v4.6.0
|
||||||
@@ -23,6 +23,8 @@ require (
|
|||||||
gotest.tools/v3 v3.5.1
|
gotest.tools/v3 v3.5.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require golang.org/x/sys v0.37.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cyphar.com/go-pathrs v0.2.1 // indirect
|
cyphar.com/go-pathrs v0.2.1 // indirect
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
@@ -96,7 +98,6 @@ require (
|
|||||||
golang.org/x/crypto v0.43.0 // indirect
|
golang.org/x/crypto v0.43.0 // indirect
|
||||||
golang.org/x/net v0.45.0 // indirect
|
golang.org/x/net v0.45.0 // indirect
|
||||||
golang.org/x/sync v0.16.0 // indirect
|
golang.org/x/sync v0.16.0 // indirect
|
||||||
golang.org/x/sys v0.37.0 // indirect
|
|
||||||
golang.org/x/tools v0.23.0 // indirect
|
golang.org/x/tools v0.23.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
@@ -110,4 +111,4 @@ replace github.com/go-git/go-git/v5 => github.com/go-git/go-git/v5 v5.16.2
|
|||||||
replace github.com/distribution/reference v0.6.0 => github.com/distribution/reference v0.5.0
|
replace github.com/distribution/reference v0.6.0 => github.com/distribution/reference v0.5.0
|
||||||
|
|
||||||
// Use GitCaddy fork with capability support
|
// Use GitCaddy fork with capability support
|
||||||
replace code.gitea.io/actions-proto-go => git.marketally.com/gitcaddy/actions-proto-go v0.5.0
|
replace code.gitea.io/actions-proto-go => git.marketally.com/gitcaddy/actions-proto-go v0.5.6
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -6,8 +6,8 @@ cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8=
|
|||||||
cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=
|
cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=
|
||||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
git.marketally.com/gitcaddy/actions-proto-go v0.5.0 h1:D2loMnqTXiaJL6TMfOOUJz4/3Vpv0AnMDSJVuiqMNrM=
|
git.marketally.com/gitcaddy/actions-proto-go v0.5.6 h1:G7T0vpx8HyCFWd0YMJ9sp8rCsWtzFrCJK4BMdOFJa1A=
|
||||||
git.marketally.com/gitcaddy/actions-proto-go v0.5.0/go.mod h1:li5RzZsj1sV8a0SXzXWsGNwv0dYw7Wj829AgloZqF5o=
|
git.marketally.com/gitcaddy/actions-proto-go v0.5.6/go.mod h1:RPu21UoRD3zSAujoZR6LJwuVNa2uFRBveadslczCRfQ=
|
||||||
gitea.com/gitea/act v0.261.7-0.20251202193638-5417d3ac6742 h1:ulcquQluJbmNASkh6ina70LvcHEa9eWYfQ+DeAZ0VEE=
|
gitea.com/gitea/act v0.261.7-0.20251202193638-5417d3ac6742 h1:ulcquQluJbmNASkh6ina70LvcHEa9eWYfQ+DeAZ0VEE=
|
||||||
gitea.com/gitea/act v0.261.7-0.20251202193638-5417d3ac6742/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
|
gitea.com/gitea/act v0.261.7-0.20251202193638-5417d3ac6742/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||||
|
|||||||
@@ -30,6 +30,15 @@ import (
|
|||||||
"gitea.com/gitea/act_runner/internal/pkg/ver"
|
"gitea.com/gitea/act_runner/internal/pkg/ver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DiskSpaceWarningThreshold is the percentage at which to warn about low disk space
|
||||||
|
DiskSpaceWarningThreshold = 85.0
|
||||||
|
// DiskSpaceCriticalThreshold is the percentage at which to log critical warnings
|
||||||
|
DiskSpaceCriticalThreshold = 95.0
|
||||||
|
// CapabilitiesUpdateInterval is how often to update capabilities (including disk space)
|
||||||
|
CapabilitiesUpdateInterval = 5 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) func(cmd *cobra.Command, args []string) error {
|
func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) func(cmd *cobra.Command, args []string) error {
|
||||||
return func(cmd *cobra.Command, args []string) error {
|
return func(cmd *cobra.Command, args []string) error {
|
||||||
cfg, err := config.LoadDefault(*configFile)
|
cfg, err := config.LoadDefault(*configFile)
|
||||||
@@ -147,6 +156,9 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
|||||||
capabilitiesJson := capabilities.ToJSON()
|
capabilitiesJson := capabilities.ToJSON()
|
||||||
log.Infof("detected capabilities: %s", capabilitiesJson)
|
log.Infof("detected capabilities: %s", capabilitiesJson)
|
||||||
|
|
||||||
|
// Check disk space and warn if low
|
||||||
|
checkDiskSpaceWarnings(capabilities)
|
||||||
|
|
||||||
// declare the labels of the runner before fetching tasks
|
// declare the labels of the runner before fetching tasks
|
||||||
resp, err := runner.Declare(ctx, ls.Names(), capabilitiesJson)
|
resp, err := runner.Declare(ctx, ls.Names(), capabilitiesJson)
|
||||||
if err != nil && connect.CodeOf(err) == connect.CodeUnimplemented {
|
if err != nil && connect.CodeOf(err) == connect.CodeUnimplemented {
|
||||||
@@ -160,6 +172,9 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
|||||||
resp.Msg.Runner.Name, resp.Msg.Runner.Version, resp.Msg.Runner.Labels)
|
resp.Msg.Runner.Name, resp.Msg.Runner.Version, resp.Msg.Runner.Labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start periodic capabilities update goroutine
|
||||||
|
go periodicCapabilitiesUpdate(ctx, runner, ls.Names(), dockerHost)
|
||||||
|
|
||||||
poller := poll.New(cfg, cli, runner)
|
poller := poll.New(cfg, cli, runner)
|
||||||
|
|
||||||
if daemArgs.Once || reg.Ephemeral {
|
if daemArgs.Once || reg.Ephemeral {
|
||||||
@@ -194,6 +209,53 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checkDiskSpaceWarnings logs warnings if disk space is low
|
||||||
|
func checkDiskSpaceWarnings(capabilities *envcheck.RunnerCapabilities) {
|
||||||
|
if capabilities.Disk == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
usedPercent := capabilities.Disk.UsedPercent
|
||||||
|
freeGB := float64(capabilities.Disk.Free) / (1024 * 1024 * 1024)
|
||||||
|
|
||||||
|
if usedPercent >= DiskSpaceCriticalThreshold {
|
||||||
|
log.Errorf("CRITICAL: Disk space critically low! %.1f%% used, only %.2f GB free. Runner may fail to execute jobs!", usedPercent, freeGB)
|
||||||
|
} else if usedPercent >= DiskSpaceWarningThreshold {
|
||||||
|
log.Warnf("WARNING: Disk space running low. %.1f%% used, %.2f GB free. Consider cleaning up disk space.", usedPercent, freeGB)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// periodicCapabilitiesUpdate periodically updates capabilities including disk space
|
||||||
|
func periodicCapabilitiesUpdate(ctx context.Context, runner *run.Runner, labelNames []string, dockerHost string) {
|
||||||
|
ticker := time.NewTicker(CapabilitiesUpdateInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
log.Debug("stopping periodic capabilities update")
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
// Detect updated capabilities (disk space changes over time)
|
||||||
|
capabilities := envcheck.DetectCapabilities(ctx, dockerHost)
|
||||||
|
capabilitiesJson := capabilities.ToJSON()
|
||||||
|
|
||||||
|
// Check for disk space warnings
|
||||||
|
checkDiskSpaceWarnings(capabilities)
|
||||||
|
|
||||||
|
// Send updated capabilities to server
|
||||||
|
_, err := runner.Declare(ctx, labelNames, capabilitiesJson)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Debug("failed to update capabilities")
|
||||||
|
} else {
|
||||||
|
log.Debugf("capabilities updated: disk %.1f%% used, %.2f GB free",
|
||||||
|
capabilities.Disk.UsedPercent,
|
||||||
|
float64(capabilities.Disk.Free)/(1024*1024*1024))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type daemonArgs struct {
|
type daemonArgs struct {
|
||||||
Once bool
|
Once bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"gitea.com/gitea/act_runner/internal/app/run"
|
"gitea.com/gitea/act_runner/internal/app/run"
|
||||||
"gitea.com/gitea/act_runner/internal/pkg/client"
|
"gitea.com/gitea/act_runner/internal/pkg/client"
|
||||||
"gitea.com/gitea/act_runner/internal/pkg/config"
|
"gitea.com/gitea/act_runner/internal/pkg/config"
|
||||||
|
"gitea.com/gitea/act_runner/internal/pkg/envcheck"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Poller struct {
|
type Poller struct {
|
||||||
@@ -157,11 +158,17 @@ func (p *Poller) fetchTask(ctx context.Context) (*runnerv1.Task, bool) {
|
|||||||
reqCtx, cancel := context.WithTimeout(ctx, p.cfg.Runner.FetchTimeout)
|
reqCtx, cancel := context.WithTimeout(ctx, p.cfg.Runner.FetchTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
// Detect capabilities including current disk space
|
||||||
|
caps := envcheck.DetectCapabilities(ctx, p.cfg.Container.DockerHost)
|
||||||
|
capsJson := caps.ToJSON()
|
||||||
|
|
||||||
// Load the version value that was in the cache when the request was sent.
|
// Load the version value that was in the cache when the request was sent.
|
||||||
v := p.tasksVersion.Load()
|
v := p.tasksVersion.Load()
|
||||||
resp, err := p.client.FetchTask(reqCtx, connect.NewRequest(&runnerv1.FetchTaskRequest{
|
fetchReq := &runnerv1.FetchTaskRequest{
|
||||||
TasksVersion: v,
|
TasksVersion: v,
|
||||||
}))
|
CapabilitiesJson: capsJson,
|
||||||
|
}
|
||||||
|
resp, err := p.client.FetchTask(reqCtx, connect.NewRequest(fetchReq))
|
||||||
if errors.Is(err, context.DeadlineExceeded) {
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
@@ -182,7 +189,7 @@ func (p *Poller) fetchTask(ctx context.Context) (*runnerv1.Task, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// got a task, set `tasksVersion` to zero to focre query db in next request.
|
// got a task, set tasksVersion to zero to force query db in next request.
|
||||||
p.tasksVersion.CompareAndSwap(resp.Msg.TasksVersion, 0)
|
p.tasksVersion.CompareAndSwap(resp.Msg.TasksVersion, 0)
|
||||||
|
|
||||||
return resp.Msg.Task, true
|
return resp.Msg.Task, true
|
||||||
|
|||||||
@@ -12,8 +12,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DiskInfo holds disk space information
|
||||||
|
type DiskInfo struct {
|
||||||
|
Total uint64 `json:"total_bytes"`
|
||||||
|
Free uint64 `json:"free_bytes"`
|
||||||
|
Used uint64 `json:"used_bytes"`
|
||||||
|
UsedPercent float64 `json:"used_percent"`
|
||||||
|
}
|
||||||
|
|
||||||
// RunnerCapabilities represents the capabilities of a runner for AI consumption
|
// RunnerCapabilities represents the capabilities of a runner for AI consumption
|
||||||
type RunnerCapabilities struct {
|
type RunnerCapabilities struct {
|
||||||
OS string `json:"os"`
|
OS string `json:"os"`
|
||||||
@@ -25,6 +34,7 @@ type RunnerCapabilities struct {
|
|||||||
Tools map[string][]string `json:"tools,omitempty"`
|
Tools map[string][]string `json:"tools,omitempty"`
|
||||||
Features *CapabilityFeatures `json:"features,omitempty"`
|
Features *CapabilityFeatures `json:"features,omitempty"`
|
||||||
Limitations []string `json:"limitations,omitempty"`
|
Limitations []string `json:"limitations,omitempty"`
|
||||||
|
Disk *DiskInfo `json:"disk,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CapabilityFeatures represents feature support flags
|
// CapabilityFeatures represents feature support flags
|
||||||
@@ -38,10 +48,10 @@ type CapabilityFeatures struct {
|
|||||||
// DetectCapabilities detects the runner's capabilities
|
// DetectCapabilities detects the runner's capabilities
|
||||||
func DetectCapabilities(ctx context.Context, dockerHost string) *RunnerCapabilities {
|
func DetectCapabilities(ctx context.Context, dockerHost string) *RunnerCapabilities {
|
||||||
cap := &RunnerCapabilities{
|
cap := &RunnerCapabilities{
|
||||||
OS: runtime.GOOS,
|
OS: runtime.GOOS,
|
||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
Tools: make(map[string][]string),
|
Tools: make(map[string][]string),
|
||||||
Shell: detectShells(),
|
Shell: detectShells(),
|
||||||
Features: &CapabilityFeatures{
|
Features: &CapabilityFeatures{
|
||||||
ArtifactsV4: false, // Gitea doesn't support v4 artifacts
|
ArtifactsV4: false, // Gitea doesn't support v4 artifacts
|
||||||
Cache: true,
|
Cache: true,
|
||||||
@@ -64,9 +74,40 @@ func DetectCapabilities(ctx context.Context, dockerHost string) *RunnerCapabilit
|
|||||||
// Detect common tools
|
// Detect common tools
|
||||||
detectTools(ctx, cap)
|
detectTools(ctx, cap)
|
||||||
|
|
||||||
|
// Detect disk space
|
||||||
|
cap.Disk = detectDiskSpace()
|
||||||
|
|
||||||
return cap
|
return cap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// detectDiskSpace detects disk space on the root filesystem
|
||||||
|
func detectDiskSpace() *DiskInfo {
|
||||||
|
var stat unix.Statfs_t
|
||||||
|
|
||||||
|
// Get stats for root filesystem (or current working directory)
|
||||||
|
path := "/"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
path = "C:\\"
|
||||||
|
}
|
||||||
|
|
||||||
|
err := unix.Statfs(path, &stat)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
total := stat.Blocks * uint64(stat.Bsize)
|
||||||
|
free := stat.Bavail * uint64(stat.Bsize)
|
||||||
|
used := total - free
|
||||||
|
usedPercent := float64(used) / float64(total) * 100
|
||||||
|
|
||||||
|
return &DiskInfo{
|
||||||
|
Total: total,
|
||||||
|
Free: free,
|
||||||
|
Used: used,
|
||||||
|
UsedPercent: usedPercent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ToJSON converts capabilities to JSON string for transmission
|
// ToJSON converts capabilities to JSON string for transmission
|
||||||
func (c *RunnerCapabilities) ToJSON() string {
|
func (c *RunnerCapabilities) ToJSON() string {
|
||||||
data, err := json.Marshal(c)
|
data, err := json.Marshal(c)
|
||||||
|
|||||||
Reference in New Issue
Block a user