Skip to content

Commit

Permalink
Fix corner cases and improve tests
Browse files Browse the repository at this point in the history
  • Loading branch information
belimawr committed Jun 12, 2024
1 parent 085517f commit f3af24c
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 57 deletions.
24 changes: 15 additions & 9 deletions internal/pkg/agent/cmd/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import (
"github.com/elastic/elastic-agent/pkg/component"
"github.com/elastic/elastic-agent/pkg/core/logger"
"github.com/elastic/elastic-agent/pkg/core/process"
"github.com/elastic/elastic-agent/pkg/utils"
"github.com/elastic/elastic-agent/version"
)

Expand Down Expand Up @@ -772,17 +771,10 @@ func logToStderr(cfg *configuration.Configuration) {

func setPaths(statePath, configPath, logsPath, socketPath string, writePaths bool) error {
statePath = envWithDefault(statePath, "STATE_PATH")
if statePath == "" {
if isStatePathTooLong(statePath) || statePath == "" {
statePath = defaultStateDirectory
}

// A Unix socket path needs to be < 104 characters long, so we ensure
// the statePath when concatenated with the socked name is going to
// be smaller than 104 characters.
if len(statePath) > 75 {
statePath = utils.SocketURLWithFallback(statePath, paths.TempDir())
}

topPath := filepath.Join(statePath, "data")
configPath = envWithDefault(configPath, "CONFIG_PATH")
if configPath == "" {
Expand Down Expand Up @@ -971,3 +963,17 @@ func isContainer(detail component.PlatformDetail) component.PlatformDetail {
detail.OS = component.Container
return detail
}

// isStatePathTooLong returns true if the final Unix socket path
// will be too long and needs to be shortened.
//
// Source: https://www.man7.org/linux/man-pages/man7/unix.7.html
func isStatePathTooLong(statePath string) bool {
// This replicates the logic from `setPaths`
socketPath := filepath.Join(statePath, "data", paths.ControlSocketName)
if len(socketPath) > 107 {

Check failure on line 974 in internal/pkg/agent/cmd/container.go

View workflow job for this annotation

GitHub Actions / lint (ubuntu-latest)

S1008: should use 'return len(socketPath) > 107' instead of 'if len(socketPath) > 107 { return true }; return false' (gosimple)
return true
}

return false
}
116 changes: 68 additions & 48 deletions testing/integration/container_cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,62 +167,82 @@ func TestContainerCMDWithAVeryLongStatePath(t *testing.T) {
Group: "container",
})

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()

agentFixture, err := define.NewFixtureFromLocalBuild(t, define.Version())
require.NoError(t, err)

fleetURL, err := fleettools.DefaultURL(ctx, info.KibanaClient)
if err != nil {
t.Fatalf("could not get Fleet URL: %s", err)
}

// We need a statePath that will make the unix socket path longer than 105 characters
// so we join the workdir and a 120 characters long string.
statePath := filepath.Join(agentFixture.WorkDir(), "de9a2a338c4fe10a466ee9fae57ce0c8a5b010dfcd6bd3f41d2c569ef5ed873193fd7d1966a070174f47f93ee667f921616c2d6d29efb6dbcc2b8b33")

// We know it will use the OS temp folder for the state path, so we try
// to clean it up at the end of the test.
t.Cleanup(func() {
defaultStatePath := "/tmp/elastic-agent"
if err := os.RemoveAll(defaultStatePath); err != nil {
t.Errorf("could not remove config path '%s': %s", defaultStatePath, err)
}
})

enrollmentToken := createPolicy(t, ctx, agentFixture, info)
env := []string{
"FLEET_ENROLL=1",
"FLEET_URL=" + fleetURL,
"FLEET_ENROLLMENT_TOKEN=" + enrollmentToken,
// As the agent isn't built for a container, it's upgradable, triggering
// the start of the upgrade watcher. If `STATE_PATH` isn't set, the
// upgrade watcher will commence from a different path within the
// container, distinct from the current execution path.
"STATE_PATH=" + statePath,
}

cmd := prepareContainerCMD(t, ctx, agentFixture, info, env)
t.Logf(">> running binary with: %v", cmd.Args)
if err := cmd.Start(); err != nil {
t.Fatalf("error running container cmd: %s", err)
testCases := map[string]struct {
statePath string
expectedStatePath string
expectError bool
}{
"small path": { // Use the set path
statePath: filepath.Join(os.TempDir(), "foo", "bar"),
expectedStatePath: filepath.Join(os.TempDir(), "foo", "bar"),
},
"no path set": { // Use the default path
statePath: "",
expectedStatePath: "/usr/share/elastic-agent/state",
},
"107 characters path": { // Longest path that still works for creating a unix socket
statePath: "/tmp/tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
expectedStatePath: "/tmp/tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt",
},
"long path": { // This will falback to the default path
statePath: filepath.Join(os.TempDir(), "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
expectedStatePath: "/usr/share/elastic-agent/state",
},
}

agentOutput := cmd.Stderr.(*strings.Builder)
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
agentFixture, err := define.NewFixtureFromLocalBuild(t, define.Version())
require.NoError(t, err)

enrollmentToken := createPolicy(t, ctx, agentFixture, info)
env := []string{
"FLEET_ENROLL=1",
"FLEET_URL=" + fleetURL,
"FLEET_ENROLLMENT_TOKEN=" + enrollmentToken,
"STATE_PATH=" + tc.statePath,
}

require.Eventuallyf(t, func() bool {
// This will return errors until it connects to the agent,
// they're mostly noise because until the agent starts running
// we will get connection errors. If the test fails
// the agent logs will be present in the error message
// which should help to explain why the agent was not
// healthy.
err = agentFixture.IsHealthy(ctx)
return err == nil
},
5*time.Minute, time.Second,
"Elastic-Agent did not report healthy. Agent status error: \"%v\", Agent logs\n%s",
err, agentOutput,
)
cmd := prepareContainerCMD(t, ctx, agentFixture, info, env)
t.Logf(">> running binary with: %v", cmd.Args)
if err := cmd.Start(); err != nil {
t.Fatalf("error running container cmd: %s", err)
}
agentOutput := cmd.Stderr.(*strings.Builder)

require.Eventuallyf(t, func() bool {
// This will return errors until it connects to the agent,
// they're mostly noise because until the agent starts running
// we will get connection errors. If the test fails
// the agent logs will be present in the error message
// which should help to explain why the agent was not
// healthy.
err = agentFixture.IsHealthy(ctx)
return err == nil
},
1*time.Minute, time.Second,
"Elastic-Agent did not report healthy. Agent status error: \"%v\", Agent logs\n%s",
err, agentOutput,
)

t.Cleanup(func() {
_ = os.RemoveAll(tc.expectedStatePath)
})

// Now that the Elastic-Agent is healthy, check that the control socket path
// is the expected one
expectedSocketPath := filepath.Join(tc.expectedStatePath, "data", "elastic-agent.sock")
if _, err := os.Stat(expectedSocketPath); err != nil {
t.Errorf("cannot stat expected socket ('%s'): %s", expectedSocketPath, err)
}
})
}
}

0 comments on commit f3af24c

Please sign in to comment.