fixed a few stuff

This commit is contained in:
yusing 2025-02-10 13:05:21 +08:00
parent 73e2660e59
commit 2c57e439d5
11 changed files with 108 additions and 24 deletions

View file

@ -9,4 +9,4 @@ jobs:
uses: ./.github/workflows/docker-image.yml uses: ./.github/workflows/docker-image.yml
with: with:
make_args: "agent=1" make_args: "agent=1"
image_name: ${{ github.repository }}-agent image_name: ${{ github.repository_owner }}/godoxy-agent

View file

@ -0,0 +1,9 @@
name: Docker Image CI (main)
on:
push:
tags: ["*"]
jobs:
call-main-workflow:
uses: ./.github/workflows/docker-image.yml

View file

@ -7,3 +7,5 @@ on:
jobs: jobs:
call-main-workflow: call-main-workflow:
uses: ./.github/workflows/docker-image.yml uses: ./.github/workflows/docker-image.yml
with:
image_name: ${{ github.repository_owner }}/godoxy

View file

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"strings"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/yusing/go-proxy/agent/pkg/certs" "github.com/yusing/go-proxy/agent/pkg/certs"
@ -44,16 +45,24 @@ func printNewClientHelp(ca *tls.Certificate) {
E.LogFatal("marshal certs error", err) E.LogFatal("marshal certs error", err)
} }
fmt.Printf("Add this host (%s) to main server config like below:\n", host) fmt.Printf("On main server, run:\nnew-agent '%s' '%s'\n", host, base64.StdEncoding.EncodeToString(certsData))
fmt.Printf("Then add this host (%s) to main server config like below:\n", host)
fmt.Println(string(cfgYAML)) fmt.Println(string(cfgYAML))
fmt.Printf("On main server, run:\ngodoxy new-agent '%s' '%s'\n", host, base64.StdEncoding.EncodeToString(certsData))
} }
func machineIP() string { func machineIP() string {
addrs, err := net.InterfaceAddrs() interfaces, err := net.Interfaces()
if err != nil { if err != nil {
return "<machine-ip>" return "<machine-ip>"
} }
for _, in := range interfaces {
addrs, err := in.Addrs()
if err != nil {
continue
}
if !strings.HasPrefix(in.Name, "eth") && !strings.HasPrefix(in.Name, "en") {
continue
}
for _, addr := range addrs { for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil { if ipnet.IP.To4() != nil {
@ -61,6 +70,7 @@ func machineIP() string {
} }
} }
} }
}
return "<machine-ip>" return "<machine-ip>"
} }
@ -79,6 +89,14 @@ func main() {
logging.Info().Msgf("GoDoxy Agent version %s", pkg.GetVersion()) logging.Info().Msgf("GoDoxy Agent version %s", pkg.GetVersion())
logging.Info().Msgf("Agent name: %s", env.AgentName) logging.Info().Msgf("Agent name: %s", env.AgentName)
logging.Info().Msgf("Agent port: %d", env.AgentPort)
logging.Info().Msg("\nTips:")
logging.Info().Msg("1. To change the agent name, you can set the AGENT_NAME environment variable.")
logging.Info().Msg("2. To change the agent port, you can set the AGENT_PORT environment variable.")
logging.Info().Msg("3. To skip the version check, you can set the AGENT_SKIP_VERSION_CHECK environment variable.")
logging.Info().Msgf("4. Create shell alias on main server: `alias new-agent='docker run --rm -v ./certs:/app/certs ghcr.io/yusing/godoxy /app/run new-agent'`")
logging.Info().Msgf("5. Create shell alias on agent server: `alias new-client='docker compose exec agent /app/run new-client'`\n")
if isNew { if isNew {
logging.Info().Msg("Initialization complete.") logging.Info().Msg("Initialization complete.")

View file

@ -13,6 +13,7 @@ import (
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/yusing/go-proxy/agent/pkg/certs" "github.com/yusing/go-proxy/agent/pkg/certs"
"github.com/yusing/go-proxy/agent/pkg/env"
E "github.com/yusing/go-proxy/internal/error" E "github.com/yusing/go-proxy/internal/error"
"github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/logging"
gphttp "github.com/yusing/go-proxy/internal/net/http" gphttp "github.com/yusing/go-proxy/internal/net/http"
@ -131,6 +132,7 @@ func (cfg *AgentConfig) load() E.Error {
defer cancel() defer cancel()
// check agent version // check agent version
if !env.AgentSkipVersionCheck {
version, _, err := cfg.Fetch(ctx, EndpointVersion) version, _, err := cfg.Fetch(ctx, EndpointVersion)
if err != nil { if err != nil {
return E.Wrap(err) return E.Wrap(err)
@ -139,6 +141,7 @@ func (cfg *AgentConfig) load() E.Error {
if string(version) != pkg.GetVersion() { if string(version) != pkg.GetVersion() {
return E.Errorf("agent version mismatch: server: %s, agent: %s", pkg.GetVersion(), string(version)) return E.Errorf("agent version mismatch: server: %s, agent: %s", pkg.GetVersion(), string(version))
} }
}
// get agent name // get agent name
name, _, err := cfg.Fetch(ctx, EndpointName) name, _, err := cfg.Fetch(ctx, EndpointName)

View file

@ -0,0 +1,19 @@
package certs
import (
"testing"
. "github.com/yusing/go-proxy/internal/utils/testing"
)
func TestZipCert(t *testing.T) {
ca, crt, key := []byte("test1"), []byte("test2"), []byte("test3")
zipData, err := ZipCert(ca, crt, key)
ExpectNoError(t, err)
ca2, crt2, key2, err := ExtractCert(zipData)
ExpectNoError(t, err)
ExpectBytesEqual(t, ca, ca2)
ExpectBytesEqual(t, crt, crt2)
ExpectBytesEqual(t, key, key2)
}

View file

@ -17,4 +17,5 @@ func DefaultAgentName() string {
var ( var (
AgentName = common.GetEnvString("AGENT_NAME", DefaultAgentName()) AgentName = common.GetEnvString("AGENT_NAME", DefaultAgentName())
AgentPort = common.GetEnvInt("AGENT_PORT", 8890) AgentPort = common.GetEnvInt("AGENT_PORT", 8890)
AgentSkipVersionCheck = common.GetEnvBool("AGENT_SKIP_VERSION_CHECK", false)
) )

View file

@ -7,6 +7,7 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/yusing/go-proxy/internal/api/v1/utils"
"github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/docker" "github.com/yusing/go-proxy/internal/docker"
"github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/logging"
@ -23,7 +24,7 @@ func DockerSocketHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
conn, err := dockerDialerCallback(r.Context()) conn, err := dockerDialerCallback(r.Context())
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) utils.HandleErr(w, r, err)
return return
} }
defer conn.Close() defer conn.Close()
@ -45,13 +46,13 @@ func DockerSocketHandler() http.HandlerFunc {
}() }()
if err := r.Write(conn); err != nil { if err := r.Write(conn); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) utils.HandleErr(w, r, err)
return return
} }
resp, err := http.ReadResponse(bufio.NewReader(conn), r) resp, err := http.ReadResponse(bufio.NewReader(conn), r)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) utils.HandleErr(w, r, err)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()

View file

@ -10,7 +10,7 @@ import (
func SystemInfo(w http.ResponseWriter, r *http.Request) { func SystemInfo(w http.ResponseWriter, r *http.Request) {
info, err := metrics.GetSystemInfo(r.Context()) info, err := metrics.GetSystemInfo(r.Context())
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) utils.HandleErr(w, r, err)
return return
} }
utils.RespondJSON(w, r, info) utils.RespondJSON(w, r, info)

View file

@ -1,6 +1,7 @@
package server package server
import ( import (
"context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/pem" "encoding/pem"
@ -8,6 +9,7 @@ import (
"log" "log"
"net" "net"
"net/http" "net/http"
"time"
"github.com/yusing/go-proxy/agent/pkg/handler" "github.com/yusing/go-proxy/agent/pkg/handler"
"github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/common"
@ -21,6 +23,8 @@ type Options struct {
} }
func StartAgentServer(parent task.Parent, opt Options) { func StartAgentServer(parent task.Parent, opt Options) {
t := parent.Subtask("agent server")
caCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: opt.CACert.Certificate[0]}) caCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: opt.CACert.Certificate[0]})
caCertPool := x509.NewCertPool() caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCertPEM) caCertPool.AppendCertsFromPEM(caCertPEM)
@ -40,14 +44,32 @@ func StartAgentServer(parent task.Parent, opt Options) {
logging.Fatal().Err(err).Int("port", opt.Port).Msg("failed to listen on port") logging.Fatal().Err(err).Int("port", opt.Port).Msg("failed to listen on port")
return return
} }
defer l.Close()
server := &http.Server{ server := &http.Server{
Handler: handler.NewHandler(), Handler: handler.NewHandler(),
TLSConfig: tlsConfig, TLSConfig: tlsConfig,
ErrorLog: log.New(logging.GetLogger(), "", 0), ErrorLog: log.New(logging.GetLogger(), "", 0),
} }
go func() {
defer l.Close()
if err := server.Serve(tls.NewListener(l, tlsConfig)); err != nil { if err := server.Serve(tls.NewListener(l, tlsConfig)); err != nil {
logging.Fatal().Err(err).Int("port", opt.Port).Msg("failed to serve") logging.Fatal().Err(err).Int("port", opt.Port).Msg("failed to serve")
} }
}()
logging.Info().Int("port", opt.Port).Msg("agent server started")
go func() {
defer t.Finish(nil)
<-parent.Context().Done()
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := server.Shutdown(ctx)
if err != nil {
logging.Error().Err(err).Int("port", opt.Port).Msg("failed to shutdown agent server")
}
logging.Info().Int("port", opt.Port).Msg("agent server stopped")
}()
} }

View file

@ -1,6 +1,7 @@
package utils package utils
import ( import (
"bytes"
"errors" "errors"
"os" "os"
"reflect" "reflect"
@ -102,6 +103,14 @@ func ExpectDeepEqual[T any](t *testing.T, got T, want T) {
} }
} }
func ExpectBytesEqual(t *testing.T, got []byte, want []byte) {
t.Helper()
if !bytes.Equal(got, want) {
t.Errorf("expected:\n%v, got\n%v", want, got)
t.FailNow()
}
}
func ExpectTrue(t *testing.T, got bool) { func ExpectTrue(t *testing.T, got bool) {
t.Helper() t.Helper()
if !got { if !got {