Skip to content
Merged
40 changes: 40 additions & 0 deletions .github/workflows/push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ jobs:

- name: Code checkout
uses: actions/checkout@v6
with:
persist-credentials: false

- name: go mod download
env:
Expand Down Expand Up @@ -73,3 +75,41 @@ jobs:
with:
name: wings_linux_${{ matrix.goarch }}_debug
path: dist/wings_debug

test-macos:
name: Test macOS
runs-on: macos-15
strategy:
fail-fast: false
matrix:
go: ["1.25.11", "1.26.4"]

steps:
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go }}

- name: Code checkout
uses: actions/checkout@v6
with:
persist-credentials: false

- name: go mod download
env:
CGO_ENABLED: 0
run: |
go mod download

- name: Build
env:
CGO_ENABLED: 0
SRC_PATH: github.com/pelican-dev/wings
run: |
go build -v -trimpath -ldflags="-s -w -X ${SRC_PATH}/system.Version=dev-${GITHUB_SHA:0:7}" -o dist/wings ${SRC_PATH}

- name: go test -race
env:
CGO_ENABLED: 1
run: |
go test -race $(go list ./...)
12 changes: 8 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
GIT_HEAD = $(shell git rev-parse HEAD | head -c8)

build:
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -gcflags "all=-trimpath=$(pwd)" -o build/wings_linux_amd64 -v wings.go
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -gcflags "all=-trimpath=$(pwd)" -o build/wings_linux_arm64 -v wings.go
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -gcflags "all=-trimpath=$(CURDIR)" -o build/wings_linux_amd64 -v wings.go
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -gcflags "all=-trimpath=$(CURDIR)" -o build/wings_linux_arm64 -v wings.go

test:
go test -race ./...
Expand All @@ -17,9 +17,13 @@ rmdebug:
go build -gcflags "all=-N -l" -ldflags="-X github.com/pelican-dev/wings/system.Version=$(GIT_HEAD)" -race
sudo dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec ./wings -- --debug --ignore-certificate-errors --config config.yml

cross-build: clean build compress
build-darwin:
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -gcflags "all=-trimpath=$(CURDIR)" -o build/wings_darwin_arm64 -v wings.go
GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -gcflags "all=-trimpath=$(CURDIR)" -o build/wings_darwin_amd64 -v wings.go

cross-build: clean build build-darwin

clean:
rm -rf build/wings_*

.PHONY: all build compress clean
.PHONY: build build-darwin cross-build clean test debug rmdebug
6 changes: 2 additions & 4 deletions cmd/selfupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,8 @@ func fetchLatestGitHubRelease() (string, error) {

func determineBinaryName() string {
switch runtime.GOARCH {
case "amd64":
return "wings_linux_amd64"
case "arm64":
return "wings_linux_arm64"
case "amd64", "arm64":
return fmt.Sprintf("wings_%s_%s", runtime.GOOS, runtime.GOARCH)
default:
return ""
}
Expand Down
51 changes: 16 additions & 35 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
"sync/atomic"
"text/template"
"time"

Expand All @@ -22,7 +22,6 @@ import (
"github.com/apex/log"
"github.com/creasty/defaults"
"github.com/gbrlsnchs/jwt/v3"
"golang.org/x/sys/unix"
"gopkg.in/yaml.v2"

"github.com/pelican-dev/wings/system"
Expand Down Expand Up @@ -523,6 +522,18 @@ func EnsurePelicanUser() error {
return err
}

// macOS doesn't have useradd, use the current user like rootless mode.
if sysName == "darwin" {
u, err := user.Current()
if err != nil {
return err
}
_config.System.Username = u.Username
_config.System.User.Uid = system.MustInt(u.Uid)
_config.System.User.Gid = system.MustInt(u.Gid)
return nil
}

// Our way of detecting if wings is running inside of Docker.
if sysName == "distroless" {
_config.System.Username = system.FirstNotEmpty(os.Getenv("WINGS_USERNAME"), "pelican")
Expand Down Expand Up @@ -811,6 +822,9 @@ func ConfigureTimezone() error {

// Gets the system release name.
func getSystemName() (string, error) {
if runtime.GOOS == "darwin" {
return "darwin", nil
}
// use osrelease to get release version and ID
release, err := osrelease.Read()
if err != nil {
Expand All @@ -819,39 +833,6 @@ func getSystemName() (string, error) {
return release["ID"], nil
}

var (
openat2 atomic.Bool
openat2Set atomic.Bool
)

func UseOpenat2() bool {
if openat2Set.Load() {
return openat2.Load()
}
defer openat2Set.Store(true)

c := Get()
openatMode := c.System.OpenatMode
switch openatMode {
case "openat2":
openat2.Store(true)
return true
case "openat":
openat2.Store(false)
return false
default:
fd, err := unix.Openat2(unix.AT_FDCWD, "/", &unix.OpenHow{})
if err != nil {
log.WithError(err).Warn("error occurred while checking for openat2 support, falling back to openat")
openat2.Store(false)
return false
}
_ = unix.Close(fd)
openat2.Store(true)
return true
}
}

// Expand expands an input string by calling [os.ExpandEnv] to expand all
// environment variables, then checks if the value is prefixed with `file://`
// to support reading the value from a file.
Expand Down
9 changes: 9 additions & 0 deletions config/config_openat_darwin.go
Comment thread
lancepioch marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build darwin

package config

// UseOpenat2 always returns false on Darwin as the openat2 syscall is
// Linux-specific (kernel 5.6+).
func UseOpenat2() bool {
return false
}
43 changes: 43 additions & 0 deletions config/config_openat_linux.go
Comment thread
lancepioch marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//go:build linux

package config

import (
"sync/atomic"

"github.com/apex/log"
"golang.org/x/sys/unix"
)

var (
openat2 atomic.Bool
openat2Set atomic.Bool
)

func UseOpenat2() bool {
if openat2Set.Load() {
return openat2.Load()
}
defer openat2Set.Store(true)

c := Get()
openatMode := c.System.OpenatMode
switch openatMode {
case "openat2":
openat2.Store(true)
return true
case "openat":
openat2.Store(false)
return false
default:
fd, err := unix.Openat2(unix.AT_FDCWD, "/", &unix.OpenHow{})
if err != nil {
log.WithError(err).Warn("error occurred while checking for openat2 support, falling back to openat")
openat2.Store(false)
return false
}
_ = unix.Close(fd)
openat2.Store(true)
return true
}
}
28 changes: 28 additions & 0 deletions config/config_openat_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//go:build linux

package config

import "testing"

func TestUseOpenat2ConfigOverride(t *testing.T) {
Set(&Configuration{
AuthenticationToken: "test",
System: SystemConfiguration{
OpenatMode: "openat",
},
})
openat2Set.Store(false)

if UseOpenat2() {
t.Error("expected UseOpenat2() to return false when mode is 'openat'")
}

openat2Set.Store(false)
Update(func(c *Configuration) {
c.System.OpenatMode = "openat2"
})

if !UseOpenat2() {
t.Error("expected UseOpenat2() to return true when mode is 'openat2'")
}
}
29 changes: 29 additions & 0 deletions config/config_openat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package config

import (
"runtime"
"testing"
)

func TestUseOpenat2(t *testing.T) {
// Ensure UseOpenat2 doesn't panic.
Set(&Configuration{
AuthenticationToken: "test",
System: SystemConfiguration{
OpenatMode: "auto",
},
})

result := UseOpenat2()

switch runtime.GOOS {
case "darwin":
if result {
t.Error("expected UseOpenat2() to return false on Darwin")
}
case "linux":
// On Linux it may be true or false depending on kernel version.
// Just verify it returns without error.
t.Logf("UseOpenat2() returned %v on Linux", result)
}
}
6 changes: 6 additions & 0 deletions environment/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"math"
"os"
"runtime"
"strconv"

"github.com/apex/log"
Expand Down Expand Up @@ -145,6 +146,11 @@ func (l Limits) AsContainerResources() container.Resources {
// container block IO weight. On cgroup v2 the io.weight knob must be present or
// runc fails container creation; cgroup v1/hybrid always supports it.
func blkioWeightSupported() bool {
// Only Linux has a cgroup hierarchy; on other platforms (e.g. macOS with
// Docker Desktop) setting the weight is rejected by the daemon.
if runtime.GOOS != "linux" {
return false
}
// cgroup v1/hybrid honors the weight via blkio.weight; only v2 needs probing.
if _, err := os.Stat("/sys/fs/cgroup/cgroup.controllers"); err != nil {
return true
Expand Down
2 changes: 2 additions & 0 deletions internal/ufs/error.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright (c) 2024 Matthew Penner

//go:build unix

package ufs

import (
Expand Down
6 changes: 3 additions & 3 deletions internal/ufs/file.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright (c) 2024 Matthew Penner

//go:build unix

package ufs

import (
Expand Down Expand Up @@ -169,12 +171,10 @@ const (
O_DIRECTORY = unix.O_DIRECTORY
// O_NOFOLLOW opens the exact path given without following symlinks.
O_NOFOLLOW = unix.O_NOFOLLOW
O_CLOEXEC = unix.O_CLOEXEC
O_LARGEFILE = unix.O_LARGEFILE
O_CLOEXEC = unix.O_CLOEXEC
)

const (
AT_SYMLINK_NOFOLLOW = unix.AT_SYMLINK_NOFOLLOW
AT_REMOVEDIR = unix.AT_REMOVEDIR
AT_EMPTY_PATH = unix.AT_EMPTY_PATH
)
6 changes: 6 additions & 0 deletions internal/ufs/file_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build darwin

package ufs

// O_LARGEFILE is a no-op on Darwin as all files support large offsets.
const O_LARGEFILE = 0
7 changes: 7 additions & 0 deletions internal/ufs/file_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build linux

package ufs

import "golang.org/x/sys/unix"

const O_LARGEFILE = unix.O_LARGEFILE
Loading
Loading