Skip to content

Commit c35b0dc

Browse files
committed
Improve Windows support and simplify agent identity
1 parent 071b288 commit c35b0dc

14 files changed

Lines changed: 211 additions & 181 deletions

File tree

.github/workflows/graphs/build-quick.act

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,17 @@ nodes:
5555
script: |-
5656
OS="$(uname -s)"
5757

58+
LDFLAGS=""
5859
case "$OS" in
5960
Linux*) OUTPUT="actrun";;
6061
Darwin*) OUTPUT="actrun";;
61-
CYGWIN*) OUTPUT="actrun.exe";;
62-
MINGW*) OUTPUT="actrun.exe";;
63-
MSYS*) OUTPUT="actrun.exe";;
62+
CYGWIN*) OUTPUT="actrun.exe"; LDFLAGS="-extldflags '-static-libgcc -static-libstdc++ -Wl,-Bstatic -lpthread -Wl,-Bdynamic'";;
63+
MINGW*) OUTPUT="actrun.exe"; LDFLAGS="-extldflags '-static-libgcc -static-libstdc++ -Wl,-Bstatic -lpthread -Wl,-Bdynamic'";;
64+
MSYS*) OUTPUT="actrun.exe"; LDFLAGS="-extldflags '-static-libgcc -static-libstdc++ -Wl,-Bstatic -lpthread -Wl,-Bdynamic'";;
6465
*) OUTPUT="actrun";;
6566
esac
6667

67-
go build --tags=github_impl -o "$OUTPUT" .
68+
go build --tags=github_impl -ldflags="$LDFLAGS" -o "$OUTPUT" .
6869
env:
6970
- CGO_ENABLED=1
7071
- id: env-get-v1-panda-apple-rabbit

.github/workflows/graphs/build-test-publish.act

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ nodes:
110110
x: -3030
111111
y: 4770
112112
inputs:
113-
install: mingw-w64-x86_64-gcc mingw-w64-x86_64-openssl
113+
install: mingw-w64-x86_64-gcc make perl-IPC-Cmd perl-Locale-Maketext-Simple
114114
- id: concurrent-for-each-loop-v1-starfish-white-whale
115115
type: core/concurrent-for-each-loop@v1
116116
position:
@@ -166,6 +166,9 @@ nodes:
166166
OUTPUT_CLI="$OUTPUT_DIR/actrun-cli-$CURRENT_OS-$ARCH"
167167
[[ "$CURRENT_OS" == "windows" ]] && OUTPUT_CLI="$OUTPUT_CLI.exe"
168168
BUILD_FLAGS="-X actionforge/actrun-cli/build.Production=true -X actionforge/actrun-cli/build.License=$LICENSE -X actionforge/actrun-cli/build.Version=$GITHUB_REF_NAME"
169+
# Statically link mingw runtime on Windows so the binary doesn't depend on
170+
# libgcc_s_seh-1.dll / libstdc++-6.dll / libwinpthread-1.dll at runtime.
171+
[[ "$CURRENT_OS" == "windows" ]] && BUILD_FLAGS="$BUILD_FLAGS -extldflags '-static-libgcc -static-libstdc++ -Wl,-Bstatic -lpthread -Wl,-Bdynamic'"
169172

170173
# Run Go tests if target matches the current system
171174
[[ "$OS" == "$CURRENT_OS" && "$ARCH" == "$CURRENT_ARCH" ]] && eval "go test -ldflags=\"$BUILD_FLAGS\" -o \"$OUTPUT_CLI\" ."
@@ -197,9 +200,12 @@ nodes:
197200
P4_CGO_CPPFLAGS=""
198201
P4_CGO_LDFLAGS=""
199202
else
200-
P4_LIB="$(pwd)/p4api/windows-x86_64/lib"
203+
WIN_PWD="$(pwd -W)"
204+
P4_LIB="$WIN_PWD/p4api/windows-x86_64/lib"
201205
P4_CGO_CPPFLAGS="-I$P4_INCLUDE -DOS_NT"
202-
P4_CGO_LDFLAGS="-L$P4_LIB -lp4api -lssl -lcrypto -lcrypt32 -lws2_32 -lole32 -lshell32 -luser32 -ladvapi32"
206+
SSL_LIB="$WIN_PWD/p4api/ssl-windows-x64/lib"
207+
PATH="$RUNNER_TEMP/msys64/mingw64/bin:$RUNNER_TEMP/msys64/usr/bin:$PATH" bash setup-openssl.sh windows x64 "$SSL_LIB"
208+
P4_CGO_LDFLAGS="-L$P4_LIB -L$SSL_LIB -lp4api -lssl -lcrypto -lcrypt32 -lws2_32 -lole32 -lshell32 -luser32 -ladvapi32"
203209
fi
204210
;;
205211
esac

.github/workflows/workflow.yml

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,7 @@ jobs:
101101
runner-path: ${{ github.workspace }}/actrun
102102
graph-file: build-test-publish.act
103103
inputs: ${{ toJson(inputs) }}
104-
secrets: >-
105-
{
106-
"APPLE_P12_CERTIFICATE_PASSWORD": "${{ secrets.APPLE_P12_CERTIFICATE_PASSWORD }}",
107-
"APPLE_P12_CERTIFICATE_BASE64": "${{ secrets.APPLE_P12_CERTIFICATE_BASE64 }}",
108-
"TESTE2E_DO_S3_ACCESS_KEY": "${{ secrets.TESTE2E_DO_S3_ACCESS_KEY }}",
109-
"TESTE2E_DO_S3_SECRET_KEY": "${{ secrets.TESTE2E_DO_S3_SECRET_KEY }}",
110-
"TESTE2E_AWS_S3_ACCESS_KEY": "${{ secrets.TESTE2E_AWS_S3_ACCESS_KEY }}",
111-
"TESTE2E_AWS_S3_SECRET_KEY": "${{ secrets.TESTE2E_AWS_S3_SECRET_KEY }}",
112-
"PUBLISH_S3_SECRET_KEY": "${{ secrets.PUBLISH_S3_SECRET_KEY }}",
113-
"PUBLISH_S3_ACCESS_KEY": "${{ secrets.PUBLISH_S3_ACCESS_KEY }}"
114-
}
104+
secrets: ${{ toJson(secrets) }}
115105
matrix: ${{ toJson(matrix) }}
116106

117107
docker-manifest:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ frozen
1010
*.so
1111
*.dylib
1212
*.a
13+
.claude
1314
./actrun
1415
actrun-cli
1516
__debug_bin

agent/client.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
type Client struct {
1313
serverURL string
1414
token string
15-
uuid string
1615
httpClient *http.Client
1716
}
1817

@@ -26,10 +25,6 @@ func NewClient(serverURL, token string) *Client {
2625
}
2726
}
2827

29-
func (c *Client) SetUUID(uuid string) {
30-
c.uuid = uuid
31-
}
32-
3328
func (c *Client) doRequest(method, path string, body interface{}) (*http.Response, error) {
3429
var bodyReader io.Reader
3530
if body != nil {
@@ -45,9 +40,6 @@ func (c *Client) doRequest(method, path string, body interface{}) (*http.Respons
4540
return nil, err
4641
}
4742
req.Header.Set("Authorization", "Bearer "+c.token)
48-
if c.uuid != "" {
49-
req.Header.Set("X-Agent-UUID", c.uuid)
50-
}
5143
if body != nil {
5244
req.Header.Set("Content-Type", "application/json")
5345
}

agent/flock_unix.go

Lines changed: 0 additions & 16 deletions
This file was deleted.

agent/flock_windows.go

Lines changed: 0 additions & 45 deletions
This file was deleted.

agent/models.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ type StatusReport struct {
7474

7575
// HeartbeatRequest is sent periodically with agent metrics.
7676
type HeartbeatRequest struct {
77-
UUID string `json:"uuid,omitempty"`
7877
CPUPercent float64 `json:"cpu_percent"`
7978
MemPercent float64 `json:"mem_percent"`
8079
MemUsedBytes int64 `json:"mem_used_bytes"`

agent/worker.go

Lines changed: 2 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package agent
33
import (
44
"bufio"
55
"context"
6-
"crypto/rand"
76
"fmt"
87
"os"
98
"os/exec"
@@ -25,106 +24,27 @@ type Worker struct {
2524
docker DockerConfig
2625
vcsOpts vcs.Options
2726
pollInterval time.Duration
28-
uuid string
29-
slotCleanup func()
3027
log *logrus.Entry
3128

3229
metricsMu sync.Mutex
3330
lastCounters *RawCounters
3431
}
3532

3633
func NewWorker(client *Client, docker DockerConfig, vcsOpts vcs.Options) *Worker {
37-
uuid, cleanup := acquireAgentSlot()
38-
client.SetUUID(uuid)
3934
return &Worker{
4035
client: client,
4136
docker: docker,
4237
vcsOpts: vcsOpts,
4338
pollInterval: 1 * time.Second,
44-
uuid: uuid,
45-
slotCleanup: cleanup,
4639
log: logrus.WithField("component", "agent"),
4740
}
4841
}
4942

50-
// agentSlotDir returns the directory for agent UUID slot files.
51-
func agentSlotDir() string {
52-
dir, err := os.UserConfigDir()
53-
if err != nil {
54-
dir = os.TempDir()
55-
}
56-
return filepath.Join(dir, "actionforge")
57-
}
58-
59-
// acquireAgentSlot finds and locks the lowest available agent slot.
60-
// Each slot has a persistent UUID file and a lock file. When the process
61-
// exits, the lock is released so the next process can reuse that slot
62-
// (and its UUID/metrics history).
63-
// Returns the UUID and a cleanup function that releases the lock.
64-
func acquireAgentSlot() (string, func()) {
65-
dir := agentSlotDir()
66-
_ = os.MkdirAll(dir, 0700)
67-
68-
const maxSlots = 256
69-
for i := 0; i < maxSlots; i++ {
70-
lockPath := filepath.Join(dir, fmt.Sprintf("agent-%d.lock", i))
71-
uuidPath := filepath.Join(dir, fmt.Sprintf("agent-%d.uuid", i))
72-
73-
lockFile, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0600)
74-
if err != nil {
75-
continue
76-
}
77-
78-
if err := lockFileExclusive(lockFile); err != nil {
79-
if cerr := lockFile.Close(); cerr != nil {
80-
logrus.WithError(cerr).Warn("failed to close lock file")
81-
}
82-
continue
83-
}
84-
85-
// Slot acquired — read or generate UUID
86-
uuid := ""
87-
if data, err := os.ReadFile(uuidPath); err == nil {
88-
if id := strings.TrimSpace(string(data)); len(id) == 36 {
89-
uuid = id
90-
}
91-
}
92-
if uuid == "" {
93-
var buf [16]byte
94-
_, _ = rand.Read(buf[:])
95-
buf[6] = (buf[6] & 0x0f) | 0x40 // version 4
96-
buf[8] = (buf[8] & 0x3f) | 0x80 // variant 1
97-
uuid = fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
98-
buf[0:4], buf[4:6], buf[6:8], buf[8:10], buf[10:16])
99-
_ = os.WriteFile(uuidPath, []byte(uuid+"\n"), 0600)
100-
}
101-
102-
cleanup := func() {
103-
unlockFile(lockFile)
104-
if cerr := lockFile.Close(); cerr != nil {
105-
logrus.WithError(cerr).Warn("failed to close lock file")
106-
}
107-
}
108-
return uuid, cleanup
109-
}
110-
111-
// Fallback: all slots taken, generate ephemeral UUID with no lock
112-
var buf [16]byte
113-
_, _ = rand.Read(buf[:])
114-
buf[6] = (buf[6] & 0x0f) | 0x40
115-
buf[8] = (buf[8] & 0x3f) | 0x80
116-
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
117-
buf[0:4], buf[4:6], buf[6:8], buf[8:10], buf[10:16]), func() {}
118-
}
119-
12043
// maxConsecutiveErrors is the number of consecutive connection errors before
12144
// Run returns ErrConnectionLost so the caller can decide to restart.
12245
const maxConsecutiveErrors = 10
12346

12447
func (w *Worker) Run(ctx context.Context) error {
125-
if w.slotCleanup != nil {
126-
defer w.slotCleanup()
127-
}
12848
w.log.Info("starting")
12949

13050
// Take initial snapshot for delta computation
@@ -632,13 +552,13 @@ func (w *Worker) buildHeartbeatRequest() HeartbeatRequest {
632552
snap, err := Snapshot()
633553
if err != nil {
634554
w.log.WithError(err).Warn("metrics snapshot error")
635-
return HeartbeatRequest{UUID: w.uuid}
555+
return HeartbeatRequest{}
636556
}
637557

638558
w.metricsMu.Lock()
639559
defer w.metricsMu.Unlock()
640560

641-
req := HeartbeatRequest{UUID: w.uuid}
561+
req := HeartbeatRequest{}
642562
if w.lastCounters != nil {
643563
// CPU percent
644564
if snap.CPUInstant {

p4api/include/p4/enviro.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class Enviro {
6868

6969
void Print( const char *var, int quiet = 0 );
7070
char *Get( const char *var );
71+
char *GetSystemIgnore( const char *var );
7172
void Set( const char *var, const char *value, Error *e );
7273
void Update( const char *var, const char *value );
7374

@@ -90,10 +91,13 @@ class Enviro {
9091
const StrPtr *GetEnviroFile();
9192
int GetHome( StrBuf &result );
9293

94+
int GetGen() const { return gen; }
95+
9396
private:
9497

9598
EnviroTable *symbolTab;
9699
EnviroItem *GetItem( const char *var );
100+
EnviroItem *GetItemSystemIgnore( const char *var );
97101
void ReadConfig( FileSys *, Error *, int, ItemType );
98102
void Setup();
99103

@@ -105,6 +109,8 @@ class Enviro {
105109
StrBuf enviroFile;
106110
StrBuf serviceName;
107111

112+
P4INT64 gen;
113+
108114
// used for netsslcredentials to get at service name
109115
static const StrPtr *sServiceNameStrP;
110116

0 commit comments

Comments
 (0)