Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
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
53 changes: 37 additions & 16 deletions pkg/newlog/cmd/vector.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ package main
import (
"bufio"
"encoding/base64"
"errors"
"fmt"
"net"
"os"
"path/filepath"
"strings"
"time"

fileutils "github.com/lf-edge/eve/pkg/pillar/utils/file"
)
Expand All @@ -25,25 +27,44 @@ var (
candidateConfigPath = "/persist/vector/config/vector.yaml.new"
)

func createVectorSockets(sockPath string, backoffTime time.Duration) *net.UnixListener {
for {
// Create unix socket
if err := os.Remove(sockPath); errors.Is(err, os.ErrNotExist) {
// Socket doesn't exist, this is expected
} else if err != nil {
Comment on lines +33 to +35

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if err := os.Remove(sockPath); errors.Is(err, os.ErrNotExist) {
// Socket doesn't exist, this is expected
} else if err != nil {
if err := os.Remove(sockPath); err != nil && !errors.Is(err, os.ErrNotExist) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I thought for a minute about this and then I thought my version is more verbose and explicit

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, I am also fine with this if you prefer it.

log.Errorf("createIncomingSockListener: Remove socket failed: %v", err)
time.Sleep(backoffTime) // wait before retry
continue
}
unixAddr, err := net.ResolveUnixAddr("unix", sockPath)
if err != nil {
log.Errorf("createIncomingSockListener: ResolveUnixAddr failed: %v", err)
time.Sleep(backoffTime) // wait before retry
continue
}
unixListener, err := net.ListenUnix("unix", unixAddr)
if err != nil {
log.Errorf("createIncomingSockListener: ListenUnix failed: %v", err)
time.Sleep(backoffTime) // wait before retry
continue
}
// Set permissions on socket
if err := os.Chmod(sockPath, 0666); err != nil {
log.Errorf("createIncomingSockListener: chmod socket failed: %v", err)
unixListener.Close()
time.Sleep(backoffTime) // wait before retry
continue
}
return unixListener
}
}

// listenOnSocketAndWriteToChan - goroutine to listen on unix sockets for incoming log entries
func listenOnSocketAndWriteToChan(sockPath string, sendToChan chan<- string) {
// Create unix socket
os.Remove(sockPath) // Remove any existing socket
unixAddr, err := net.ResolveUnixAddr("unix", sockPath)
if err != nil {
log.Fatalf("createIncomingSockListener: ResolveUnixAddr failed: %v", err)
}
unixListener, err := net.ListenUnix("unix", unixAddr)
if err != nil {
log.Fatalf("createIncomingSockListener: ListenUnix failed: %v", err)
}
defer unixListener.Close()
unixListener := createVectorSockets(sockPath, 10*time.Second)
defer os.Remove(sockPath)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I've just noticed it. The order of the defers is strange. First, it will delete the socket, then it will attempt to close the connection (deferred tasks are handled in LIFO order).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, fixed


// Set permissions on socket
if err := os.Chmod(sockPath, 0666); err != nil {
log.Fatalf("createIncomingSockListener: chmod socket failed: %v", err)
}
defer unixListener.Close()

// Handle socket connections
for {
Expand Down
72 changes: 72 additions & 0 deletions pkg/newlog/cmd/vector_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2025 Zededa, Inc.
// SPDX-License-Identifier: Apache-2.0

package main

import (
"net"
"os"
"path/filepath"
"testing"
"time"

"github.com/onsi/gomega"
)

func TestCreateVectorSockets(t *testing.T) {
t.Parallel()
g := gomega.NewWithT(t)

// Create a temporary directory for testing
tmpDir, err := os.MkdirTemp("", "vector_socket_test")
g.Expect(err).To(gomega.BeNil())
defer os.RemoveAll(tmpDir)

// Create a socket path in a subdirectory that doesn't exist yet
nonExistentDir := filepath.Join(tmpDir, "nonexistent")
sockPath := filepath.Join(nonExistentDir, "test.sock")

unixListenerChan := make(chan *net.UnixListener, 1)
backoffPeriod := 100 * time.Millisecond

go func() {
unixListener := createVectorSockets(sockPath, backoffPeriod)
unixListenerChan <- unixListener
}()

time.Sleep(2 * backoffPeriod) // Wait to ensure retries happen

// Verify that the socket was not created yet
_, err = os.Stat(sockPath)
g.Expect(os.IsNotExist(err)).To(gomega.BeTrue(), "Socket file should not exist yet")

// Now create the directory
err = os.MkdirAll(nonExistentDir, 0755)
g.Expect(err).To(gomega.BeNil())

// Wait a bit to let the function succeed
var unixListener *net.UnixListener
select {
case unixListener = <-unixListenerChan:
// Successfully created the listener
case <-time.After(10 * backoffPeriod):
t.Fatal("Timeout waiting for createVectorSockets to succeed")
}

// verify that the listener was created
g.Expect(unixListener).ToNot(gomega.BeNil(), "createVectorSockets should succeed after directory creation")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this in a race condition with the go func lambda above?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I'll make them communicate through a channel


// Verify the socket was created
info, err := os.Stat(sockPath)
g.Expect(err).To(gomega.BeNil(), "Socket file should be created after directory creation")

expectedMode := os.FileMode(0666)
g.Expect(info.Mode().Perm()).To(gomega.Equal(expectedMode), "Socket permissions should be correct")

// Verify we can connect to the socket
conn, err := net.Dial("unix", sockPath)
g.Expect(err).To(gomega.BeNil(), "Should be able to connect to socket")
conn.Close()

t.Log("Test passed: socket created successfully and is connectable")
}
Loading