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
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ GO_BUILD_BINDIR := bin
GO_TEST_FLAGS :=-timeout=50s -tags=fake
GO_PACKAGES=./pkg/... ./cmd/... ./tools/...

GOLANGCI_LINT_BIN=$(GO_BUILD_BINDIR)/golangci-lint

ifeq (,$(shell which podman 2>/dev/null))
CONTAINER_ENGINE ?= docker
else
Expand All @@ -20,6 +22,15 @@ IMG ?= node-observability-agent:go-latest
TARGET_REPO ?= registry.ci.openshift.org/ocp
IMAGE_TAG ?= v0.0.1

.PHONY: lint
## Checks the code with golangci-lint
lint: $(GOLANGCI_LINT_BIN)
$(GOLANGCI_LINT_BIN) run -c .golangci.yaml --deadline=30m

$(GOLANGCI_LINT_BIN):
mkdir -p $(GO_BUILD_BINDIR)
hack/golangci-lint.sh $(GOLANGCI_LINT_BIN)

.PHONY: build.image
build.image: build.go verify
$(CONTAINER_ENGINE) build -t ${IMG} .
Expand Down
3 changes: 2 additions & 1 deletion cmd/node-observability-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import (
"os"
"syscall"

"github.com/openshift/node-observability-agent/pkg/server"
log "github.com/sirupsen/logrus"

"github.com/openshift/node-observability-agent/pkg/server"
)

var (
Expand Down
25 changes: 17 additions & 8 deletions pkg/connectors/MockCmdWrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,40 @@ package connectors

import "os/exec"

type MockConnector struct {
// FakeConnector is a structure that holds the shell command to fake-run, its parameters
// as well as a Flag, that helps orient the behavior of the mock
type FakeConnector struct {
command string
params []string
Flag ErrorFlag
}

// ErrorFlag values can be NoError, SocketErr or WriteErr
type ErrorFlag string

const (
NO_ERROR ErrorFlag = ""
SOCKET_ERR ErrorFlag = "socket-error"
WRITE_ERR ErrorFlag = "write-error"
// NoError instructs the FakeConnector to return without errors
NoError ErrorFlag = ""
// SocketErr instructs the FakeConnector to return an error related to the curl command execution
SocketErr ErrorFlag = "socket-error"
// WriteErr instructs the FakeConnector to return an error related to the storage of curl output to file
WriteErr ErrorFlag = "write-error"
)

func (c *MockConnector) Prepare(command string, params []string) {
// Prepare stores the command and parameters to be used by FakeConnector, preparing the call to CmdExec
// Implementation of cmdWrapper.Prepare
func (c *FakeConnector) Prepare(command string, params []string) {
c.command = command
c.params = params
}

func (c *MockConnector) CmdExec() (string, error) {
if c.Flag == SOCKET_ERR {
// CmdExec implements the cmdWrapper.CmdExec and returns fake responses based on FakeConnector.Flag
func (c *FakeConnector) CmdExec() (string, error) {
if c.Flag == SocketErr {
return "curl: (7) Couldn't connect to server", &exec.ExitError{}
}

if c.Flag == WRITE_ERR {
if c.Flag == WriteErr {
return "curl: (23) Failure writing output to destination", &exec.ExitError{}
}
return "", nil
Expand Down
6 changes: 6 additions & 0 deletions pkg/connectors/cmdWrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ import (
"os/exec"
)

// CmdWrapper wrap a exec.Cmd, or its fake
type CmdWrapper interface {
// Prepare sets the command and its parameters that are wrapped by CmdWrapper
Prepare(command string, params []string)
// CmdExec executes the command wrapped by CmdWrapper
CmdExec() (string, error)
}

// Connector represents a command being prepared to be run
type Connector struct {
cmd *exec.Cmd
}

// Prepare sets the command and parameters to be called
func (c *Connector) Prepare(command string, params []string) {
c.cmd = exec.Command(command, params...)
}

// CmdExec runs the command on the underlying system and returns the stdout or stderr as a string
func (c *Connector) CmdExec() (string, error) {
var stdout, stderr bytes.Buffer
c.cmd.Stdout = &stdout
Expand Down
9 changes: 6 additions & 3 deletions pkg/handlers/crioProfilingHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import (
"github.com/openshift/node-observability-agent/pkg/connectors"
)

func (h *Handlers) ProfileCrio(uid string, cmd connectors.CmdWrapper) ProfilingRun {
// ProfileCrio calls /debug/pprof/profile on the h.NodeIP, through the unix socket,
// thus triggering a CRIO profiling on that node.
// This call requires access to the host socket, which is passed to the agent in parameter crioSocket
func (h *Handlers) profileCrio(uid string, cmd connectors.CmdWrapper) profilingRun {
//curl --unix-socket /var/run/crio/crio.sock http://localhost/debug/pprof/profile > /mnt/prof.out

run := ProfilingRun{
Type: CRIORun,
run := profilingRun{
Type: crioRun,
BeginDate: time.Now(),
}

Expand Down
22 changes: 11 additions & 11 deletions pkg/handlers/crioProfilingHandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,31 @@ func TestProfileCrio(t *testing.T) {
testCases := []struct {
name string
connector connectors.CmdWrapper
expected ProfilingRun
expected profilingRun
}{
{
name: "Curl command successful, OK",
connector: &connectors.MockConnector{Flag: connectors.NO_ERROR},
expected: ProfilingRun{
Type: CRIORun,
connector: &connectors.FakeConnector{Flag: connectors.NoError},
expected: profilingRun{
Type: crioRun,
Successful: true,
Error: "",
},
},
{
name: "Network error on curl, ProfilingRun contains error",
connector: &connectors.MockConnector{Flag: connectors.SOCKET_ERR},
expected: ProfilingRun{
Type: CRIORun,
connector: &connectors.FakeConnector{Flag: connectors.SocketErr},
expected: profilingRun{
Type: crioRun,
Successful: false,
Error: fmt.Sprintf("error running CRIO profiling :\n%s", "curl: (7) Couldn't connect to server"),
},
},
{
name: "IO error at storing result, ProfilingRun contains error",
connector: &connectors.MockConnector{Flag: connectors.WRITE_ERR},
expected: ProfilingRun{
Type: CRIORun,
connector: &connectors.FakeConnector{Flag: connectors.WriteErr},
expected: profilingRun{
Type: crioRun,
Successful: false,
Error: fmt.Sprintf("error running CRIO profiling :\n%s", "curl: (23) Failure writing output to destination"),
},
Expand All @@ -46,7 +46,7 @@ func TestProfileCrio(t *testing.T) {
h := NewHandlers("abc", "/tmp", "/tmp/fakeSocket", "127.0.0.1")
tc.connector.Prepare("curl", []string{"--unix-socket", h.CrioUnixSocket, "http://localhost/debug/pprof/profile", "--output", h.StorageFolder + "crio-1234.pprof"})

pr := h.ProfileCrio("1234", tc.connector)
pr := h.profileCrio("1234", tc.connector)
if tc.expected.Type != pr.Type {
t.Errorf("Expecting a ProfilingRun of type %s but was %s", tc.expected.Type, pr.Type)
}
Expand Down
Loading