Skip to content

Commit

Permalink
Osquerybeat: Add install verification for osquerybeat (#30388) (#30403)
Browse files Browse the repository at this point in the history
(cherry picked from commit 1c68693)

Co-authored-by: Aleksandr Maus <[email protected]>
  • Loading branch information
mergify[bot] and aleksmaus authored Feb 17, 2022
1 parent 83de048 commit d88754a
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 12 deletions.
2 changes: 1 addition & 1 deletion x-pack/elastic-agent/pkg/agent/program/supported.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions x-pack/elastic-agent/spec/osquerybeat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ artifact: beats/osquerybeat
action_input_types:
- osquery

check_install:
- exec_file:
path: "osquerybeat"
args:
- "verify"
timeout: 10

rules:
- fix_stream: {}
- inject_index:
Expand Down
24 changes: 24 additions & 0 deletions x-pack/osquerybeat/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import (
cmd "github.com/elastic/beats/v7/libbeat/cmd"
"github.com/elastic/beats/v7/libbeat/cmd/instance"
"github.com/elastic/beats/v7/libbeat/common"
"github.com/elastic/beats/v7/libbeat/common/cli"
"github.com/elastic/beats/v7/libbeat/ecs"
"github.com/elastic/beats/v7/libbeat/logp"
"github.com/elastic/beats/v7/libbeat/publisher/processing"

"github.com/spf13/cobra"

_ "github.com/elastic/beats/v7/x-pack/libbeat/include"
"github.com/elastic/beats/v7/x-pack/osquerybeat/beater"
"github.com/elastic/beats/v7/x-pack/osquerybeat/internal/install"
)

// Name of this beat
Expand All @@ -37,5 +42,24 @@ func Osquerybeat() *cmd.BeatsRootCmd {
}
command := cmd.GenRootCmdWithSettings(beater.New, settings)

// Add verify command
command.AddCommand(genVerifyCmd(settings))

return command
}

func genVerifyCmd(settings instance.Settings) *cobra.Command {
return &cobra.Command{
Use: "verify",
Short: "Verify installation",
Run: cli.RunWith(
func(_ *cobra.Command, args []string) error {
log := logp.NewLogger("osquerybeat")
err := install.VerifyWithExecutableDirectory(log)
if err != nil {
return err
}
return nil
}),
}
}
90 changes: 90 additions & 0 deletions x-pack/osquerybeat/internal/install/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package install

import (
"fmt"
"os"
"path/filepath"
"runtime"

"github.com/elastic/beats/v7/libbeat/logp"
"github.com/elastic/beats/v7/x-pack/osquerybeat/internal/distro"
"github.com/elastic/beats/v7/x-pack/osquerybeat/internal/fileutil"
"github.com/elastic/beats/v7/x-pack/osquerybeat/internal/osqd"
)

func execDir() (exedir string, err error) {
exefp, err := os.Executable()
if err != nil {
return exedir, nil
}
exedir = filepath.Dir(exefp)
return exedir, nil
}

// VerifyWithExecutableDirectory verifies installation with the current executable directory
func VerifyWithExecutableDirectory(log *logp.Logger) error {
exedir, err := execDir()
if err != nil {
return err
}

return Verify(runtime.GOOS, exedir, log)
}

// Verify verifies installation in the given executable directory
func Verify(goos, dir string, log *logp.Logger) error {
log.Infof("Install verification for %s", dir)
// For darwin expect installer PKG or unpackages osqueryd
if goos == "darwin" {
pkgFile := filepath.Join(dir, distro.OsquerydDistroPlatformFilename(goos))
pkgExists, err := fileExistsLogged(log, pkgFile)
if err != nil {
return err
}
if pkgExists {
return nil
}
}

// Verify osqueryd or osqueryd.exe exists
osqFile := osqd.QsquerydPathForPlatform(goos, dir)
osqExists, err := fileExistsLogged(log, osqFile)
if err != nil {
return err
}
if !osqExists {
return fmt.Errorf("%w: %v", os.ErrNotExist, osqFile)
}

// Verify extension file exists
extFileName := "osquery-extension.ext"
if goos == "windows" {
extFileName = "osquery-extension.exe"
}
extFile := filepath.Join(dir, extFileName)
osqExtExists, err := fileExistsLogged(log, extFile)
if err != nil {
return err
}

if !osqExtExists {
return fmt.Errorf("%w: %v", os.ErrNotExist, extFileName)
}
return nil
}

func fileExistsLogged(log *logp.Logger, fp string) (bool, error) {
log.Infof("Check if file exists %s:", fp)
fpExists, err := fileutil.FileExists(fp)
if err != nil {
log.Infof("File exists check failed for %s", fp)
}
if !fpExists {
log.Infof("File %s doesn't exists", fp)
}
return fpExists, err
}
148 changes: 148 additions & 0 deletions x-pack/osquerybeat/internal/install/verify_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package install

import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/elastic/beats/v7/libbeat/logp"
)

// setupFiles helper function that creates subdirectory with a given set of files
// The verification currently checks for the file presence only
func setupFiles(testdataBaseDir string, files []string) (string, error) {
testdir, err := ioutil.TempDir(testdataBaseDir, "")
if err != nil {
return "", err
}

for _, f := range files {
fp := filepath.Join(testdir, f)

dir := filepath.Dir(fp)
err = os.MkdirAll(dir, 0750)
if err != nil {
return "", err
}

err = ioutil.WriteFile(fp, nil, 0750)
if err != nil {
return "", err
}
}

return testdir, nil
}

func TestVerify(t *testing.T) {
log := logp.NewLogger("verify_test")
tests := []struct {
name string
goos string
files []string
err error
}{
{
name: "darwin no files",
goos: "darwin",
err: os.ErrNotExist,
},
{
name: "linux no files",
goos: "linux",
err: os.ErrNotExist,
},
{
name: "windows no files",
goos: "windows",
err: os.ErrNotExist,
},
{
name: "darwin extension file missing",
goos: "darwin",
files: []string{"osquery.app/Contents/MacOS/osqueryd"},
err: os.ErrNotExist,
},
{
name: "darwin osqueryd missing",
goos: "darwin",
files: []string{"osquery-extension.ext"},
err: os.ErrNotExist,
},
{
name: "darwin valid install",
goos: "darwin",
files: []string{"osquery.app/Contents/MacOS/osqueryd", "osquery-extension.ext"},
},
{
name: "linux extension file missing",
goos: "linux",
files: []string{"osqueryd"},
err: os.ErrNotExist,
},
{
name: "linux osqueryd missing",
goos: "linux",
files: []string{"osquery-extension.ext"},
err: os.ErrNotExist,
},
{
name: "linux valid install",
goos: "linux",
files: []string{"osqueryd", "osquery-extension.ext"},
},
{
name: "windows extension file missing",
goos: "windows",
files: []string{"osqueryd.exe"},
err: os.ErrNotExist,
},
{
name: "windows osqueryd missing",
goos: "windows",
files: []string{"osquery-extension.exe"},
err: os.ErrNotExist,
},
{
name: "windows valid install",
goos: "windows",
files: []string{"osqueryd.exe", "osquery-extension.exe"},
},
}

// Setup test data
testdataBaseDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
dir, err := setupFiles(testdataBaseDir, tc.files)
if err != nil {
t.Fatal(err)
}

err = Verify(tc.goos, dir, log)
// check for matching error if tc exppect error
if err != nil {
if tc.err != nil {
if !errors.Is(err, tc.err) {
t.Fatalf("want error: %v, got: %v", tc.err, err)
}
} else {
t.Fatalf("want error: nil, got: %v", err)
}
} else if tc.err != nil {
t.Fatalf("want error: %v, got: nil", tc.err)
}
})
}

}
18 changes: 15 additions & 3 deletions x-pack/osquerybeat/internal/osqd/osqueryd.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,11 +418,23 @@ func (q *OSQueryD) isVerbose() bool {
}

func osquerydPath(dir string) string {
if runtime.GOOS == "darwin" {
return filepath.Join(dir, osqueryDarwinAppBundlePath, osquerydFilename())
return QsquerydPathForPlatform(runtime.GOOS, dir)
}

// QsquerydPathForPlatform returns the full path to osqueryd binary for platform
func QsquerydPathForPlatform(platform, dir string) string {
if platform == "darwin" {
return filepath.Join(dir, osqueryDarwinAppBundlePath, osquerydFilename(platform))

}
return filepath.Join(dir, osquerydFilename(platform))
}

func osquerydFilename(platform string) string {
if platform == "windows" {
return osqueryDName + ".exe"
}
return filepath.Join(dir, osquerydFilename())
return osqueryDName
}

func osqueryExtensionPath(dir string) string {
Expand Down
4 changes: 0 additions & 4 deletions x-pack/osquerybeat/internal/osqd/osqueryd_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,3 @@ func killProcessGroup(cmd *exec.Cmd) error {
err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
return errors.Wrapf(err, "kill process group %d", cmd.Process.Pid)
}

func osquerydFilename() string {
return osqueryDName
}
4 changes: 0 additions & 4 deletions x-pack/osquerybeat/internal/osqd/osqueryd_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,3 @@ func killProcessGroup(cmd *exec.Cmd) error {
exec.Command("taskkill", "/F", "/T", "/PID", fmt.Sprint(cmd.Process.Pid)).Run()
return nil
}

func osquerydFilename() string {
return osqueryDName + ".exe"
}

0 comments on commit d88754a

Please sign in to comment.