mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-20 12:42:34 +02:00
implement system mode agent
This commit is contained in:
parent
5e8e4fa4a1
commit
2c21387ad9
7 changed files with 254 additions and 11 deletions
51
.github/workflows/agent-binary.yml
vendored
Normal file
51
.github/workflows/agent-binary.yml
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
name: GoDoxy agent binary
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
paths:
|
||||||
|
- "agent/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- runner: ubuntu-latest
|
||||||
|
platform: linux/amd64
|
||||||
|
binary_name: godoxy-agent-linux-amd64
|
||||||
|
- runner: ubuntu-24.04-arm
|
||||||
|
platform: linux/arm64
|
||||||
|
binary_name: godoxy-agent-linux-arm64
|
||||||
|
name: Build ${{ matrix.platform }}
|
||||||
|
runs-on: ${{ matrix.runner }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
id-token: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
- name: Verify dependencies
|
||||||
|
run: go mod verify
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
make agent=1 NAME=${{ matrix.binary_name }} build
|
||||||
|
- name: Check binary
|
||||||
|
run: |
|
||||||
|
file bin/${{ matrix.binary_name }}
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
go test -v ./agent/...
|
||||||
|
- name: Upload
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.binary_name }}
|
||||||
|
path: bin/${{ matrix.binary_name }}
|
||||||
|
- name: Upload to release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
with:
|
||||||
|
files: bin/${{ matrix.binary_name }}
|
24
agent/pkg/agent/bare_metal.go
Normal file
24
agent/pkg/agent/bare_metal.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
installScript = `AGENT_NAME={{.Name}} \
|
||||||
|
AGENT_PORT={{.Port}} \
|
||||||
|
AGENT_CA_CERT={{.CACert}} \
|
||||||
|
AGENT_SSL_CERT={{.SSLCert}} \
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/yusing/go-proxy/main/scripts/install-agent.sh)"`
|
||||||
|
installScriptTemplate = template.Must(template.New("install.sh").Parse(installScript))
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *AgentEnvConfig) Generate() (string, error) {
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 0, 4096))
|
||||||
|
if err := installScriptTemplate.Execute(buf, c); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strings.ReplaceAll(buf.String(), ";", "\\;"), nil
|
||||||
|
}
|
|
@ -7,9 +7,11 @@ import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed agent.compose.yml
|
var (
|
||||||
var agentComposeYAML string
|
//go:embed templates/agent.compose.yml
|
||||||
var agentComposeYAMLTemplate = template.Must(template.New("agent.compose.yml").Parse(agentComposeYAML))
|
agentComposeYAML string
|
||||||
|
agentComposeYAMLTemplate = template.Must(template.New("agent.compose.yml").Parse(agentComposeYAML))
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DockerImageProduction = "ghcr.io/yusing/godoxy-agent:latest"
|
DockerImageProduction = "ghcr.io/yusing/godoxy-agent:latest"
|
||||||
|
|
17
agent/pkg/agent/env.go
Normal file
17
agent/pkg/agent/env.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package agent
|
||||||
|
|
||||||
|
type (
|
||||||
|
AgentEnvConfig struct {
|
||||||
|
Name string
|
||||||
|
Port int
|
||||||
|
CACert string
|
||||||
|
SSLCert string
|
||||||
|
}
|
||||||
|
AgentComposeConfig struct {
|
||||||
|
Image string
|
||||||
|
*AgentEnvConfig
|
||||||
|
}
|
||||||
|
Generator interface {
|
||||||
|
Generate() (string, error)
|
||||||
|
}
|
||||||
|
)
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/yusing/go-proxy/agent/pkg/agent"
|
"github.com/yusing/go-proxy/agent/pkg/agent"
|
||||||
"github.com/yusing/go-proxy/agent/pkg/certs"
|
"github.com/yusing/go-proxy/agent/pkg/certs"
|
||||||
config "github.com/yusing/go-proxy/internal/config/types"
|
config "github.com/yusing/go-proxy/internal/config/types"
|
||||||
"github.com/yusing/go-proxy/internal/gperr"
|
|
||||||
"github.com/yusing/go-proxy/internal/net/gphttp"
|
"github.com/yusing/go-proxy/internal/net/gphttp"
|
||||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||||
)
|
)
|
||||||
|
@ -47,11 +46,8 @@ func NewAgent(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
t := q.Get("type")
|
t := q.Get("type")
|
||||||
switch t {
|
switch t {
|
||||||
case "docker":
|
case "docker", "system":
|
||||||
break
|
break
|
||||||
case "system":
|
|
||||||
gphttp.ClientError(w, gperr.Errorf("system agent is not supported yet"), http.StatusNotImplemented)
|
|
||||||
return
|
|
||||||
case "":
|
case "":
|
||||||
gphttp.ClientError(w, gphttp.ErrMissingKey("type"))
|
gphttp.ClientError(w, gphttp.ErrMissingKey("type"))
|
||||||
return
|
return
|
||||||
|
@ -74,14 +70,18 @@ func NewAgent(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := agent.AgentComposeConfig{
|
var cfg agent.Generator = &agent.AgentEnvConfig{
|
||||||
Image: image,
|
|
||||||
Name: name,
|
Name: name,
|
||||||
Port: port,
|
Port: port,
|
||||||
CACert: ca.String(),
|
CACert: ca.String(),
|
||||||
SSLCert: srv.String(),
|
SSLCert: srv.String(),
|
||||||
}
|
}
|
||||||
|
if t == "docker" {
|
||||||
|
cfg = &agent.AgentComposeConfig{
|
||||||
|
Image: image,
|
||||||
|
AgentEnvConfig: cfg.(*agent.AgentEnvConfig),
|
||||||
|
}
|
||||||
|
}
|
||||||
template, err := cfg.Generate()
|
template, err := cfg.Generate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gphttp.ServerError(w, r, err)
|
gphttp.ServerError(w, r, err)
|
||||||
|
|
149
scripts/install-agent.sh
Normal file
149
scripts/install-agent.sh
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
check_pkg() {
|
||||||
|
if ! command -v $1 &>/dev/null; then
|
||||||
|
echo "$1 could not be found, please install it first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# check if curl and jq are installed
|
||||||
|
check_pkg curl
|
||||||
|
check_pkg jq
|
||||||
|
|
||||||
|
# check if running user is root
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo "Please run the script as root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check if system is using systemd
|
||||||
|
if [ -d "/etc/systemd/system" ]; then
|
||||||
|
echo "System is using systemd"
|
||||||
|
else
|
||||||
|
echo "Unsupported init system, currently only systemd is supported"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check variables
|
||||||
|
if [ -z "$AGENT_NAME" ]; then
|
||||||
|
echo "AGENT_NAME is not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$AGENT_PORT" ]; then
|
||||||
|
echo "AGENT_PORT is not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$AGENT_CA_CERT" ]; then
|
||||||
|
echo "AGENT_CA_CERT is not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$AGENT_SSL_CERT" ]; then
|
||||||
|
echo "AGENT_SSL_CERT is not set"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# init variables
|
||||||
|
arch=$(uname -m)
|
||||||
|
if [ "$arch" = "x86_64" ]; then
|
||||||
|
filename="godoxy-agent-linux-amd64"
|
||||||
|
elif [ "$arch" = "aarch64" ]; then
|
||||||
|
filename="godoxy-agent-linux-arm64"
|
||||||
|
else
|
||||||
|
echo "Unsupported architecture: $arch, expect x86_64 or aarch64"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
repo="yusing/go-proxy"
|
||||||
|
install_path="/usr/local/bin"
|
||||||
|
name="godoxy-agent"
|
||||||
|
bin_path="${install_path}/${name}"
|
||||||
|
env_file="/etc/${name}.env"
|
||||||
|
service_path="/etc/systemd/system/${name}.service"
|
||||||
|
log_path="/var/log/${name}.log"
|
||||||
|
data_path="/var/lib/${name}"
|
||||||
|
|
||||||
|
# check if install path is writable
|
||||||
|
if [ ! -w "$install_path" ]; then
|
||||||
|
echo "Install path is not writable, please check the permissions"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check if service path is writable
|
||||||
|
if [ ! -w "$service_path" ]; then
|
||||||
|
echo "Service path is not writable, please check the permissions"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check if env file is writable
|
||||||
|
if [ ! -w "$env_file" ]; then
|
||||||
|
echo "Env file is not writable, please check the permissions"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check if command is uninstall
|
||||||
|
if [ "$1" = "uninstall" ]; then
|
||||||
|
echo "Uninstalling the agent"
|
||||||
|
systemctl disable --now $name
|
||||||
|
rm -f $bin_path
|
||||||
|
rm -f $env_file
|
||||||
|
rm -f $service_path
|
||||||
|
rm -rf $data_path
|
||||||
|
systemctl daemon-reload
|
||||||
|
echo "Agent uninstalled successfully"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Finding the latest agent binary"
|
||||||
|
bin_url=$(curl -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/$repo/releases/latest | jq -r '.assets[] | select(.name | contains("'$filename'")) | .browser_download_url')
|
||||||
|
|
||||||
|
echo "Downloading the agent binary"
|
||||||
|
curl -L "$bin_url" -o $bin_path
|
||||||
|
|
||||||
|
echo "Making the agent binary executable"
|
||||||
|
chmod +x $bin_path
|
||||||
|
|
||||||
|
echo "Creating the environment file"
|
||||||
|
cat <<EOF >$env_file
|
||||||
|
AGENT_NAME="${AGENT_NAME}"
|
||||||
|
AGENT_PORT="${AGENT_PORT}"
|
||||||
|
AGENT_CA_CERT="${AGENT_CA_CERT}"
|
||||||
|
AGENT_SSL_CERT="${AGENT_SSL_CERT}"
|
||||||
|
EOF
|
||||||
|
chmod 600 $env_file
|
||||||
|
|
||||||
|
echo "Creating the data directory"
|
||||||
|
mkdir -p $data_path
|
||||||
|
|
||||||
|
echo "Registering the agent as a service"
|
||||||
|
cat <<EOF >$service_path
|
||||||
|
[Unit]
|
||||||
|
Description=GoDoxy Agent
|
||||||
|
After=docker.socket
|
||||||
|
|
||||||
|
[Service]]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=${bin_path}
|
||||||
|
EnvironmentFile=${env_file}
|
||||||
|
WorkingDirectory=${data_path}
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=append:${log_path}
|
||||||
|
StandardError=append:${log_path}
|
||||||
|
|
||||||
|
# Security settings
|
||||||
|
ProtectSystem=full
|
||||||
|
ProtectHome=true
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
# User and group
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now $name
|
||||||
|
echo "Agent installed successfully"
|
Loading…
Add table
Reference in a new issue