Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions aks-node-controller/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ func (a *App) Run(ctx context.Context, args []string) int {
Usage: "Wait for provisioning to complete",
Action: func(ctx context.Context, cmd *cli.Command) error {
provisionStatusFiles := ProvisionStatusFiles{
ProvisionJSONFile: provisionJSONFilePath,
ProvisionCompleteFile: provisionCompleteFilePath,
ProvisionJSONFile: osCfg.provisionJSONFilePath,
ProvisionCompleteFile: osCfg.provisionCompleteFilePath,
}
provisionOutput, err := a.runProvisionWaitCommand(ctx, provisionStatusFiles)
_, _ = fmt.Fprintln(cmd.Root().Writer, provisionOutput)
Expand Down Expand Up @@ -721,7 +721,10 @@ func (a *App) Provision(ctx context.Context, flags ProvisionFlags) (*ProvisionRe
func (a *App) reportProvisionStatus(ctx context.Context, result *ProvisionResult, provisionErr error) {
markerPath := a.readyReportMarkerPath
if markerPath == "" {
markerPath = readyReportMarkerPath
markerPath = osCfg.readyReportMarkerPath
}
if markerPath == "" {
return
}
if _, err := os.Stat(markerPath); err != nil {
if !errors.Is(err, os.ErrNotExist) {
Expand Down Expand Up @@ -790,27 +793,27 @@ func (a *App) writeCompleteFileOnError(provisionResult *ProvisionResult, err err
if err == nil {
return
}
if _, statErr := os.Stat(provisionJSONFilePath); statErr != nil && errors.Is(statErr, os.ErrNotExist) {
if _, statErr := os.Stat(osCfg.provisionJSONFilePath); statErr != nil && errors.Is(statErr, os.ErrNotExist) {
data, err := json.Marshal(provisionResult)
if err != nil {
slog.Error("failed to marshal provision result", "error", err)
}
baseDir := filepath.Dir(provisionJSONFilePath)
baseDir := filepath.Dir(osCfg.provisionJSONFilePath)
if writeErr := os.MkdirAll(baseDir, 0755); writeErr != nil {
slog.Error("failed to create directory for provision.json file", "path", baseDir, "error", writeErr)
}
if writeErr := os.WriteFile(provisionJSONFilePath, data, 0600); writeErr != nil {
slog.Error("failed to write provision.json file", "path", provisionJSONFilePath, "error", writeErr)
if writeErr := os.WriteFile(osCfg.provisionJSONFilePath, data, 0600); writeErr != nil {
slog.Error("failed to write provision.json file", "path", osCfg.provisionJSONFilePath, "error", writeErr)
}
}
if _, statErr := os.Stat(provisionCompleteFilePath); statErr == nil {
if _, statErr := os.Stat(osCfg.provisionCompleteFilePath); statErr == nil {
return // already exists
} else if !errors.Is(statErr, os.ErrNotExist) { // unexpected error
slog.Error("failed to stat provision.complete file", "path", provisionCompleteFilePath, "error", statErr)
slog.Error("failed to stat provision.complete file", "path", osCfg.provisionCompleteFilePath, "error", statErr)
return
}
if writeErr := os.WriteFile(provisionCompleteFilePath, []byte{}, 0600); writeErr != nil {
slog.Error("failed to write provision.complete file", "path", provisionCompleteFilePath, "error", writeErr)
if writeErr := os.WriteFile(osCfg.provisionCompleteFilePath, []byte{}, 0600); writeErr != nil {
slog.Error("failed to write provision.complete file", "path", osCfg.provisionCompleteFilePath, "error", writeErr)
}
}

Expand Down
49 changes: 41 additions & 8 deletions aks-node-controller/const.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
package main

// Some options are intentionally non-configurable to avoid customization by users
// it will help us to avoid introducing any breaking changes in the future.
const (
logPath = "/var/log/azure/aks-node-controller.log"
provisionJSONFilePath = "/var/log/azure/aks/provision.json"
provisionCompleteFilePath = "/opt/azure/containers/provision.complete"
readyReportMarkerPath = "/var/lib/waagent/experimental_skip_ready_report"
)
import "runtime"

// Holds the OS-specific locations. Some options are intentionally non-configurable
// to avoid customization by users; it will help us avoid introducing breaking changes in the future.
type osConfig struct {
logPath string
provisionJSONFilePath string
provisionCompleteFilePath string
readyReportMarkerPath string
eventsDirPath string
}

func linuxConfig() osConfig {
return osConfig{
logPath: "/var/log/azure/aks-node-controller.log",
provisionJSONFilePath: "/var/log/azure/aks/provision.json",
provisionCompleteFilePath: "/opt/azure/containers/provision.complete",
readyReportMarkerPath: "/var/lib/waagent/experimental_skip_ready_report",
eventsDirPath: "/var/log/azure/Microsoft.Azure.Extensions.CustomScript/events",
}
}

func windowsConfig() osConfig {
return osConfig{
logPath: `C:\AzureData\aks-node-controller\aks-node-controller.log`,
provisionJSONFilePath: `C:\AzureData\aks-node-controller\provision.json`,
provisionCompleteFilePath: `C:\AzureData\aks-node-controller\provision.complete`,
// The Ready-report handoff is a Linux waagent feature.
readyReportMarkerPath: "",
eventsDirPath: `C:\WindowsAzure\Logs\Plugins\Microsoft.Compute.CustomScriptExtension\Events\`,
}
}

func configForOS(goos string) osConfig {
if goos == "windows" {
return windowsConfig()
}
return linuxConfig()
}

var osCfg = configForOS(runtime.GOOS) //nolint:gochecknoglobals // read-only OS-specific paths resolved once at startup
15 changes: 15 additions & 0 deletions aks-node-controller/const_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestConfigForOS(t *testing.T) {
require.Equal(t, windowsConfig(), configForOS("windows"))
require.Equal(t, linuxConfig(), configForOS("linux"))
require.Equal(t, linuxConfig(), configForOS("darwin"))
require.Empty(t, windowsConfig().readyReportMarkerPath)
require.NotEmpty(t, linuxConfig().readyReportMarkerPath)
}
11 changes: 11 additions & 0 deletions aks-node-controller/filelock_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import (
"os"
"syscall"
)

// lockFileExclusive blocks until it holds an exclusive lock on f. Closing f releases it.
func lockFileExclusive(f *os.File) error {
return syscall.Flock(int(f.Fd()), syscall.LOCK_EX)
}
11 changes: 11 additions & 0 deletions aks-node-controller/filelock_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import (
"os"
"syscall"
)

// lockFileExclusive blocks until it holds an exclusive lock on f. Closing f releases it.
func lockFileExclusive(f *os.File) error {
return syscall.Flock(int(f.Fd()), syscall.LOCK_EX)
}
12 changes: 12 additions & 0 deletions aks-node-controller/filelock_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import (
"errors"
"os"
)

// lockFileExclusive is unsupported on Windows: its only caller writes the Linux Hyper-V
// KVP pool file, and Windows exposes KVP through the registry rather than a file.
func lockFileExclusive(*os.File) error {
return errors.ErrUnsupported
Comment on lines +10 to +11
}
3 changes: 1 addition & 2 deletions aks-node-controller/goal_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"os"
"os/exec"
"strings"
"syscall"
"time"
"unicode/utf8"

Expand Down Expand Up @@ -262,7 +261,7 @@ func writeKVPRecord(path, key, value string) error {
}
defer f.Close()
// Closing the file releases the lock; os.File.Write is unbuffered.
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
if err = lockFileExclusive(f); err != nil {
return err
}
_, err = f.Write(record)
Expand Down
6 changes: 3 additions & 3 deletions aks-node-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
logCleanup := configureLogging()
app := App{
cmdRun: cmdRunner,
eventLogger: helpers.NewEventLogger("/var/log/azure/Microsoft.Azure.Extensions.CustomScript/events"),
eventLogger: helpers.NewEventLogger(osCfg.eventsDirPath),
}

exitCode := app.Run(context.Background(), os.Args)
Expand Down Expand Up @@ -54,8 +54,8 @@ func configureLogging() func() {

func setupLogPath() string {
// Try to create production directory first
if err := os.MkdirAll(filepath.Dir(logPath), 0755); err == nil {
return logPath
if err := os.MkdirAll(filepath.Dir(osCfg.logPath), 0755); err == nil {
return osCfg.logPath
}
// If directory creation fails, fallback to current directory
return "aks-node-controller.log"
Expand Down
Loading