From 30d4a23edb075bf0e4b86424a9cfb4afa2176d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 20 Jul 2020 21:18:01 +0200 Subject: [PATCH 1/5] chore: support removing the token created each time an agent is enrolled --- e2e/_suites/ingest-manager/fleet.go | 30 ++++++++++++------- .../ingest-manager/ingest-manager_test.go | 8 +++++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/e2e/_suites/ingest-manager/fleet.go b/e2e/_suites/ingest-manager/fleet.go index 53eb6164d1..03f5ff7a8c 100644 --- a/e2e/_suites/ingest-manager/fleet.go +++ b/e2e/_suites/ingest-manager/fleet.go @@ -335,18 +335,8 @@ func (fts *FleetTestSuite) theEnrollmentTokenIsRevoked() error { "tokenID": fts.CurrentTokenID, }).Debug("Revoking enrollment token") - revokeTokenURL := fleetEnrollmentTokenURL + "/" + fts.CurrentTokenID - deleteReq := createDefaultHTTPRequest(revokeTokenURL) - - body, err := curl.Delete(deleteReq) + err := fts.removeToken() if err != nil { - log.WithFields(log.Fields{ - "token": fts.CurrentToken, - "tokenID": fts.CurrentTokenID, - "body": body, - "error": err, - "url": revokeTokenURL, - }).Error("Could revoke token") return err } @@ -390,6 +380,24 @@ func (fts *FleetTestSuite) anAttemptToEnrollANewAgentFails() error { return nil } +func (fts *FleetTestSuite) removeToken() error { + revokeTokenURL := fleetEnrollmentTokenURL + "/" + fts.CurrentTokenID + deleteReq := createDefaultHTTPRequest(revokeTokenURL) + + body, err := curl.Delete(deleteReq) + if err != nil { + log.WithFields(log.Fields{ + "tokenID": fts.CurrentTokenID, + "body": body, + "error": err, + "url": revokeTokenURL, + }).Error("Could delete token") + return err + } + + return nil +} + // checkFleetConfiguration checks that Fleet configuration is not missing // any requirements and is read. To achieve it, a GET request is executed func checkFleetConfiguration() error { diff --git a/e2e/_suites/ingest-manager/ingest-manager_test.go b/e2e/_suites/ingest-manager/ingest-manager_test.go index 6fb7307d5c..e285bc4a94 100644 --- a/e2e/_suites/ingest-manager/ingest-manager_test.go +++ b/e2e/_suites/ingest-manager/ingest-manager_test.go @@ -169,6 +169,14 @@ func IngestManagerFeatureContext(s *godog.Suite) { log.WithFields(log.Fields{ "service": serviceName, }).Debug("Service removed from compose.") + + err = imts.Fleet.removeToken() + if err != nil { + log.WithFields(log.Fields{ + "err": err, + "tokenID": imts.Fleet.CurrentTokenID, + }).Warn("The enrollment token could not be deleted") + } } }) } From f21fc9137a06b1dedef7d92c2052823d5cb71956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 20 Jul 2020 21:22:20 +0200 Subject: [PATCH 2/5] chore: use container name as token name --- e2e/_suites/ingest-manager/fleet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/_suites/ingest-manager/fleet.go b/e2e/_suites/ingest-manager/fleet.go index 03f5ff7a8c..d9287ac28b 100644 --- a/e2e/_suites/ingest-manager/fleet.go +++ b/e2e/_suites/ingest-manager/fleet.go @@ -65,7 +65,7 @@ func (fts *FleetTestSuite) anAgentIsDeployedToFleet() error { fts.Cleanup = true // enroll the agent with a new token - tokenJSONObject, err := createFleetToken("name", fts.ConfigID) + tokenJSONObject, err := createFleetToken(containerName, fts.ConfigID) if err != nil { return err } From d0ba13b0dcd34322ed5fac859153c57de9a1d767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 20 Jul 2020 21:56:29 +0200 Subject: [PATCH 3/5] chore: use hostname as token name --- e2e/_suites/ingest-manager/fleet.go | 10 ++++- .../ingest-manager/ingest-manager_test.go | 33 +++++++++++++++ e2e/_suites/ingest-manager/stand-alone.go | 42 ++----------------- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/e2e/_suites/ingest-manager/fleet.go b/e2e/_suites/ingest-manager/fleet.go index d9287ac28b..2414f4d848 100644 --- a/e2e/_suites/ingest-manager/fleet.go +++ b/e2e/_suites/ingest-manager/fleet.go @@ -36,6 +36,7 @@ type FleetTestSuite struct { ConfigID string // will be used to manage tokens CurrentToken string // current enrollment token CurrentTokenID string // current enrollment tokenID + Hostname string // the hostname of the container } func (fts *FleetTestSuite) contributeSteps(s *godog.Suite) { @@ -64,8 +65,15 @@ func (fts *FleetTestSuite) anAgentIsDeployedToFleet() error { } fts.Cleanup = true + // get container hostname once + hostname, err := getContainerHostname(containerName) + if err != nil { + return err + } + fts.Hostname = hostname + // enroll the agent with a new token - tokenJSONObject, err := createFleetToken(containerName, fts.ConfigID) + tokenJSONObject, err := createFleetToken("Test token for "+hostname, fts.ConfigID) if err != nil { return err } diff --git a/e2e/_suites/ingest-manager/ingest-manager_test.go b/e2e/_suites/ingest-manager/ingest-manager_test.go index e285bc4a94..6a0fae1f25 100644 --- a/e2e/_suites/ingest-manager/ingest-manager_test.go +++ b/e2e/_suites/ingest-manager/ingest-manager_test.go @@ -5,13 +5,16 @@ package main import ( + "context" "os" "path" + "strings" "time" "github.com/cucumber/godog" "github.com/cucumber/messages-go/v10" "github.com/elastic/e2e-testing/cli/config" + "github.com/elastic/e2e-testing/cli/docker" "github.com/elastic/e2e-testing/cli/services" "github.com/elastic/e2e-testing/e2e" log "github.com/sirupsen/logrus" @@ -262,6 +265,36 @@ func startAgent(profile string, serviceName string) error { return nil } +// we need the container name because we use the Docker Client instead of Docker Compose +func getContainerHostname(containerName string) (string, error) { + log.WithFields(log.Fields{ + "containerName": containerName, + }).Debug("Retrieving container name from the Docker client") + + hostname, err := docker.ExecCommandIntoContainer(context.Background(), containerName, "root", []string{"hostname"}) + if err != nil { + log.WithFields(log.Fields{ + "containerName": containerName, + "error": err, + }).Error("Could not retrieve container name from the Docker client") + return "", err + } + + if strings.HasPrefix(hostname, "\x01\x00\x00\x00\x00\x00\x00\r") { + hostname = strings.ReplaceAll(hostname, "\x01\x00\x00\x00\x00\x00\x00\r", "") + log.WithFields(log.Fields{ + "hostname": hostname, + }).Debug("Container name has been sanitized") + } + + log.WithFields(log.Fields{ + "containerName": containerName, + "hostname": hostname, + }).Info("Hostname retrieved from the Docker client") + + return hostname, nil +} + func execCommandInService(profile string, serviceName string, cmds []string, detach bool) error { serviceManager := services.NewServiceManager() diff --git a/e2e/_suites/ingest-manager/stand-alone.go b/e2e/_suites/ingest-manager/stand-alone.go index ad0aff4bbb..ee3ad91187 100644 --- a/e2e/_suites/ingest-manager/stand-alone.go +++ b/e2e/_suites/ingest-manager/stand-alone.go @@ -5,12 +5,10 @@ package main import ( - "context" - "strings" + "fmt" "time" "github.com/cucumber/godog" - "github.com/elastic/e2e-testing/cli/docker" "github.com/elastic/e2e-testing/cli/services" "github.com/elastic/e2e-testing/e2e" log "github.com/sirupsen/logrus" @@ -40,6 +38,7 @@ func (sats *StandAloneTestSuite) aStandaloneAgentIsDeployed() error { profile := "ingest-manager" serviceName := "elastic-agent" + containerName := fmt.Sprintf("%s_%s_%d", profile, serviceName, 1) configurationFileURL := "https://raw.githubusercontent.com/elastic/beats/master/x-pack/elastic-agent/elastic-agent.docker.yml" @@ -58,7 +57,7 @@ func (sats *StandAloneTestSuite) aStandaloneAgentIsDeployed() error { } // get container hostname once - hostname, err := getContainerHostname(serviceName) + hostname, err := getContainerHostname(containerName) if err != nil { return err } @@ -131,41 +130,6 @@ func (sats *StandAloneTestSuite) thereIsNoNewDataInTheIndexAfterAgentShutsDown() return e2e.AssertHitsAreNotPresent(result) } -// we need the container name because we use the Docker Client instead of Docker Compose -func getContainerHostname(serviceName string) (string, error) { - containerName := "ingest-manager_" + serviceName + "_1" - - log.WithFields(log.Fields{ - "service": serviceName, - "containerName": containerName, - }).Debug("Retrieving container name from the Docker client") - - hostname, err := docker.ExecCommandIntoContainer(context.Background(), containerName, "root", []string{"hostname"}) - if err != nil { - log.WithFields(log.Fields{ - "containerName": containerName, - "error": err, - "service": serviceName, - }).Error("Could not retrieve container name from the Docker client") - return "", err - } - - if strings.HasPrefix(hostname, "\x01\x00\x00\x00\x00\x00\x00\r") { - hostname = strings.ReplaceAll(hostname, "\x01\x00\x00\x00\x00\x00\x00\r", "") - log.WithFields(log.Fields{ - "hostname": hostname, - }).Debug("Container name has been sanitized") - } - - log.WithFields(log.Fields{ - "containerName": containerName, - "hostname": hostname, - "service": serviceName, - }).Info("Hostname retrieved from the Docker client") - - return hostname, nil -} - func searchAgentData(hostname string, startDate time.Time, minimumHitsCount int, maxTimeout time.Duration) (e2e.SearchResult, error) { timezone := "America/New_York" From 33637265373c2eb54c9076ea6749bb2601ba1dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 20 Jul 2020 23:29:01 +0200 Subject: [PATCH 4/5] fix: retrive agent status instead of using the first element in the list --- e2e/_suites/ingest-manager/fleet.go | 91 ++++++++++++++--------------- 1 file changed, 44 insertions(+), 47 deletions(-) diff --git a/e2e/_suites/ingest-manager/fleet.go b/e2e/_suites/ingest-manager/fleet.go index 2414f4d848..dbff3ce8f0 100644 --- a/e2e/_suites/ingest-manager/fleet.go +++ b/e2e/_suites/ingest-manager/fleet.go @@ -140,23 +140,23 @@ func (fts *FleetTestSuite) setup() error { func (fts *FleetTestSuite) theAgentIsListedInFleetAsOnline() error { log.Debug("Checking agent is listed in Fleet as online") - agentsCount := 0.0 maxTimeout := 10 * time.Second retryCount := 1 exp := e2e.GetExponentialBackOff(maxTimeout) - countAgentsFn := func() error { - count, err := countOnlineAgents() - if err != nil || count == 0 { + agentOnlineFn := func() error { + status, err := isAgentOnline(fts.Hostname) + if err != nil || !status { if err == nil { err = fmt.Errorf("The Agent is not online yet") } log.WithFields(log.Fields{ - "retry": retryCount, - "onlineAgents": count, - "elapsedTime": exp.GetElapsedTime(), + "active": status, + "elapsedTime": exp.GetElapsedTime(), + "hostname": fts.Hostname, + "retry": retryCount, }).Warn(err.Error()) retryCount++ @@ -165,25 +165,19 @@ func (fts *FleetTestSuite) theAgentIsListedInFleetAsOnline() error { } log.WithFields(log.Fields{ - "elapsedTime": exp.GetElapsedTime(), - "onlineAgents": count, - "retries": retryCount, + "active": status, + "elapsedTime": exp.GetElapsedTime(), + "hostname": fts.Hostname, + "retries": retryCount, }).Info("The Agent is online") - agentsCount = count return nil } - err := backoff.Retry(countAgentsFn, exp) + err := backoff.Retry(agentOnlineFn, exp) if err != nil { return err } - if agentsCount != 1 { - err = fmt.Errorf("There are %.0f online agents. We expected to have exactly one", agentsCount) - log.Error(err.Error()) - return err - } - return nil } @@ -276,23 +270,23 @@ func (fts *FleetTestSuite) theAgentIsUnenrolled() error { func (fts *FleetTestSuite) theAgentIsNotListedAsOnlineInFleet() error { log.Debug("Checking if the agent is not listed as online in Fleet") - agentsCount := 0.0 maxTimeout := 10 * time.Second retryCount := 1 exp := e2e.GetExponentialBackOff(maxTimeout) - countAgentsFn := func() error { - count, err := countOnlineAgents() - if err != nil || count != 0 { + agentOnlineFn := func() error { + status, err := isAgentOnline(fts.Hostname) + if err != nil || status { if err == nil { err = fmt.Errorf("The Agent is still online") } log.WithFields(log.Fields{ - "retry": retryCount, - "onlineAgents": count, - "elapsedTime": exp.GetElapsedTime(), + "active": status, + "elapsedTime": exp.GetElapsedTime(), + "hostname": fts.Hostname, + "retry": retryCount, }).Warn(err.Error()) retryCount++ @@ -301,25 +295,19 @@ func (fts *FleetTestSuite) theAgentIsNotListedAsOnlineInFleet() error { } log.WithFields(log.Fields{ - "elapsedTime": exp.GetElapsedTime(), - "onlineAgents": count, - "retries": retryCount, + "active": status, + "elapsedTime": exp.GetElapsedTime(), + "hostname": fts.Hostname, + "retries": retryCount, }).Info("The Agent is offline") - agentsCount = count return nil } - err := backoff.Retry(countAgentsFn, exp) + err := backoff.Retry(agentOnlineFn, exp) if err != nil { return err } - if agentsCount != 0 { - err = fmt.Errorf("There are %.0f online agents. We expected to have none", agentsCount) - log.Error(err.Error()) - return err - } - return nil } @@ -441,21 +429,30 @@ func checkFleetConfiguration() error { return nil } -// countOnlineAgents extracts the number of agents in the online status -// querying Fleet's agents endpoint -func countOnlineAgents() (float64, error) { +// isAgentOnline extracts the status for an agent, identified by its hotname +// It will wuery Fleet's agents endpoint +func isAgentOnline(hostname string) (bool, error) { jsonResponse, err := getOnlineAgents() if err != nil { - return 0, err + return false, err } - agentsCount := jsonResponse.Path("total").Data().(float64) + agents := jsonResponse.Path("list") - log.WithFields(log.Fields{ - "count": agentsCount, - }).Debug("Online agents retrieved") + for _, agent := range agents.Children() { + agentStatus := agent.Path("active").Data().(bool) + agentHostname := agent.Path("local_metadata.host.hostname").Data().(string) + if agentHostname == hostname { + log.WithFields(log.Fields{ + "active": agentStatus, + "hostname": hostname, + }).Debug("Agent status retrieved") + + return agentStatus, nil + } + } - return agentsCount, nil + return false, fmt.Errorf("The agent '" + hostname + "' was not found in Fleet") } // createFleetConfiguration sends a POST request to Fleet forcing the @@ -729,9 +726,9 @@ func getOnlineAgents() (*gabs.Container, error) { r := createDefaultHTTPRequest(fleetAgentsURL) // let's not URL encode the querystring, as it seems Kibana is not handling // the request properly, returning an 400 Bad Request error with this message: - // [request query.page=1&perPage=20&showInactive=false]: definition for this key is missing + // [request query.page=1&perPage=20&showInactive=true]: definition for this key is missing r.EncodeURL = false - r.QueryString = fmt.Sprintf("page=1&perPage=20&showInactive=%t", false) + r.QueryString = fmt.Sprintf("page=1&perPage=20&showInactive=%t", true) body, err := curl.Get(r) if err != nil { From 41cf3bf94b2586716acd0e9436a50cfd6fc846e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 20 Jul 2020 23:51:49 +0200 Subject: [PATCH 5/5] chore: reorder methods allphabetically --- e2e/_suites/ingest-manager/fleet.go | 52 +++++++++---------- .../ingest-manager/ingest-manager_test.go | 44 ++++++++-------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/e2e/_suites/ingest-manager/fleet.go b/e2e/_suites/ingest-manager/fleet.go index dbff3ce8f0..3d6dab11dc 100644 --- a/e2e/_suites/ingest-manager/fleet.go +++ b/e2e/_suites/ingest-manager/fleet.go @@ -429,32 +429,6 @@ func checkFleetConfiguration() error { return nil } -// isAgentOnline extracts the status for an agent, identified by its hotname -// It will wuery Fleet's agents endpoint -func isAgentOnline(hostname string) (bool, error) { - jsonResponse, err := getOnlineAgents() - if err != nil { - return false, err - } - - agents := jsonResponse.Path("list") - - for _, agent := range agents.Children() { - agentStatus := agent.Path("active").Data().(bool) - agentHostname := agent.Path("local_metadata.host.hostname").Data().(string) - if agentHostname == hostname { - log.WithFields(log.Fields{ - "active": agentStatus, - "hostname": hostname, - }).Debug("Agent status retrieved") - - return agentStatus, nil - } - } - - return false, fmt.Errorf("The agent '" + hostname + "' was not found in Fleet") -} - // createFleetConfiguration sends a POST request to Fleet forcing the // recreation of the configuration func createFleetConfiguration() error { @@ -751,3 +725,29 @@ func getOnlineAgents() (*gabs.Container, error) { return jsonResponse, nil } + +// isAgentOnline extracts the status for an agent, identified by its hotname +// It will wuery Fleet's agents endpoint +func isAgentOnline(hostname string) (bool, error) { + jsonResponse, err := getOnlineAgents() + if err != nil { + return false, err + } + + agents := jsonResponse.Path("list") + + for _, agent := range agents.Children() { + agentStatus := agent.Path("active").Data().(bool) + agentHostname := agent.Path("local_metadata.host.hostname").Data().(string) + if agentHostname == hostname { + log.WithFields(log.Fields{ + "active": agentStatus, + "hostname": hostname, + }).Debug("Agent status retrieved") + + return agentStatus, nil + } + } + + return false, fmt.Errorf("The agent '" + hostname + "' was not found in Fleet") +} diff --git a/e2e/_suites/ingest-manager/ingest-manager_test.go b/e2e/_suites/ingest-manager/ingest-manager_test.go index 6a0fae1f25..e026df182c 100644 --- a/e2e/_suites/ingest-manager/ingest-manager_test.go +++ b/e2e/_suites/ingest-manager/ingest-manager_test.go @@ -249,15 +249,27 @@ func (imts *IngestManagerTestSuite) processStateOnTheHost(process string, state return nil } -func startAgent(profile string, serviceName string) error { - cmd := []string{"elastic-agent", "run"} - err := execCommandInService(profile, serviceName, cmd, true) +func execCommandInService(profile string, serviceName string, cmds []string, detach bool) error { + serviceManager := services.NewServiceManager() + + composes := []string{ + profile, // profile name + serviceName, // service + } + composeArgs := []string{"exec", "-T"} + if detach { + composeArgs = append(composeArgs, "-d") + } + composeArgs = append(composeArgs, serviceName) + composeArgs = append(composeArgs, cmds...) + + err := serviceManager.RunCommand(profile, composes, composeArgs, profileEnv) if err != nil { log.WithFields(log.Fields{ - "command": cmd, + "command": cmds, "error": err, "service": serviceName, - }).Error("Could not run the agent") + }).Error("Could not execute command in container") return err } @@ -295,27 +307,15 @@ func getContainerHostname(containerName string) (string, error) { return hostname, nil } -func execCommandInService(profile string, serviceName string, cmds []string, detach bool) error { - serviceManager := services.NewServiceManager() - - composes := []string{ - profile, // profile name - serviceName, // service - } - composeArgs := []string{"exec", "-T"} - if detach { - composeArgs = append(composeArgs, "-d") - } - composeArgs = append(composeArgs, serviceName) - composeArgs = append(composeArgs, cmds...) - - err := serviceManager.RunCommand(profile, composes, composeArgs, profileEnv) +func startAgent(profile string, serviceName string) error { + cmd := []string{"elastic-agent", "run"} + err := execCommandInService(profile, serviceName, cmd, true) if err != nil { log.WithFields(log.Fields{ - "command": cmds, + "command": cmd, "error": err, "service": serviceName, - }).Error("Could not execute command in container") + }).Error("Could not run the agent") return err }