From f67e1ec15b8943b9a98d05868c25b171f99d261f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Tue, 27 Apr 2021 18:56:05 +0200 Subject: [PATCH 1/4] feat: bootstrap fleet-server for the deployment of regular elastic-agents (#1078) * chore: provide a fleet-server base image based on centos/debian with systemd * WIP * fix: remove duplicated fields after merge conflicts * fix: update method call after merge conflicts * chore: extract service name calculation to a method * chore: extract container name calculation to a method * chore: refactor get container name method * chore: refactor method even more * chore: use installer state to retrieve container name * chore: use installer when calculating service name * fix: adapt service names for fleet server * chore: enrich log when creating an installer * fix: use fleet server host when creating fleet config * fix: use https when connecting to fleet-server It's creating its own self-signed certs * feat: bootstrap a fleet server before a regular agent is deployed to fleet It will define the server host to be used when enrolling agents * fix: use fleet policy for agents, not the server one * fix: get different installers for fleet-server and agents * fix: use the old step for deploying regular agents * chore: rename variable with consistent name * chore: rename fleet-server scenario * fix: use proper container name for standalone mode * chore: save two variables * chore: rename standalone scenario for bootstrapping fleet-server * chore: rename bootstrap methods * chore: encapsulate bootstrap fleet-server logic * Update fleet.go * chore: remove Fleet Server CI parallel execution * chore: remove feature file for fleet-server * chore: boostrap fleet server only once We want to have it bootstrapped for the entire test suite, not for each scenario * fix: an agent was needed when adding integrations Co-authored-by: Adam Stokes <51892+adam-stokes@users.noreply.github.com> (cherry picked from commit 193337a81c5d9b6264f85ad0b833ac0f4192f328) --- .ci/.e2e-tests.yaml | 3 - .../fleet-server-centos/docker-compose.yml | 10 ++ .../fleet-server-debian/docker-compose.yml | 10 ++ .../fleet/features/fleet_server.feature | 19 --- .../fleet/features/stand_alone_agent.feature | 4 +- e2e/_suites/fleet/fleet.go | 135 +++++++++--------- e2e/_suites/fleet/fleet_server.go | 43 +++++- e2e/_suites/fleet/ingest_manager_test.go | 16 +++ e2e/_suites/fleet/stand-alone.go | 6 +- e2e/_suites/fleet/world.go | 9 +- internal/common/defaults.go | 3 + internal/installer/elasticagent.go | 12 +- internal/installer/tar.go | 6 +- internal/kibana/fleet.go | 16 ++- 14 files changed, 179 insertions(+), 113 deletions(-) create mode 100644 cli/config/compose/services/fleet-server-centos/docker-compose.yml create mode 100644 cli/config/compose/services/fleet-server-debian/docker-compose.yml delete mode 100644 e2e/_suites/fleet/features/fleet_server.feature diff --git a/.ci/.e2e-tests.yaml b/.ci/.e2e-tests.yaml index c9613c115b..02a4399f08 100644 --- a/.ci/.e2e-tests.yaml +++ b/.ci/.e2e-tests.yaml @@ -17,9 +17,6 @@ SUITES: - name: "Fleet" pullRequestFilter: " && ~debian" tags: "fleet_mode_agent" - - name: "Fleet Server" - pullRequestFilter: " && ~debian" - tags: "fleet_server" - name: "Endpoint Integration" pullRequestFilter: " && ~debian" tags: "agent_endpoint_integration" diff --git a/cli/config/compose/services/fleet-server-centos/docker-compose.yml b/cli/config/compose/services/fleet-server-centos/docker-compose.yml new file mode 100644 index 0000000000..8492ce3947 --- /dev/null +++ b/cli/config/compose/services/fleet-server-centos/docker-compose.yml @@ -0,0 +1,10 @@ +version: '2.4' +services: + fleet-server-centos: + image: centos/systemd:${fleet_server_centosTag:-latest} + container_name: ${fleet_server_centosContainerName} + entrypoint: "/usr/sbin/init" + privileged: true + volumes: + - ${fleet_server_centosAgentBinarySrcPath:-.}:${fleet_server_centosAgentBinaryTargetPath:-/tmp} + - /sys/fs/cgroup:/sys/fs/cgroup:ro diff --git a/cli/config/compose/services/fleet-server-debian/docker-compose.yml b/cli/config/compose/services/fleet-server-debian/docker-compose.yml new file mode 100644 index 0000000000..bb86c67f83 --- /dev/null +++ b/cli/config/compose/services/fleet-server-debian/docker-compose.yml @@ -0,0 +1,10 @@ +version: '2.4' +services: + fleet-server-debian: + image: alehaa/debian-systemd:${fleet_server_debianTag:-stretch} + container_name: ${fleet_server_debianContainerName} + entrypoint: "/sbin/init" + privileged: true + volumes: + - ${fleet_server_debianAgentBinarySrcPath:-.}:${fleet_server_debianAgentBinaryTargetPath:-/tmp} + - /sys/fs/cgroup:/sys/fs/cgroup:ro diff --git a/e2e/_suites/fleet/features/fleet_server.feature b/e2e/_suites/fleet/features/fleet_server.feature deleted file mode 100644 index ff863764fd..0000000000 --- a/e2e/_suites/fleet/features/fleet_server.feature +++ /dev/null @@ -1,19 +0,0 @@ -@fleet_server -Feature: Fleet Server - Scenarios for Fleet Server, where an Elasticseach and a Kibana instances are already provisioned, - so that the Agent is able to communicate with them - -@start-fleet-server -Scenario Outline: Deploying an Elastic Agent that starts Fleet Server - When a "" agent is deployed to Fleet with "tar" installer in fleet-server mode - Then the agent is listed in Fleet as "online" - -@centos -Examples: Centos -| os | -| centos | - -@debian -Examples: Debian -| os | -| debian | diff --git a/e2e/_suites/fleet/features/stand_alone_agent.feature b/e2e/_suites/fleet/features/stand_alone_agent.feature index 171705c957..20a44ce177 100644 --- a/e2e/_suites/fleet/features/stand_alone_agent.feature +++ b/e2e/_suites/fleet/features/stand_alone_agent.feature @@ -51,8 +51,8 @@ Examples: Ubi8 | image | | ubi8 | -@run_fleet_server -Scenario Outline: Deploying a stand-alone agent with fleet server mode +@bootstrap-fleet-server +Scenario Outline: Bootstrapping Fleet Server from a stand-alone Elastic Agent When a "" stand-alone agent is deployed with fleet server mode Then the stand-alone agent is listed in Fleet as "online" diff --git a/e2e/_suites/fleet/fleet.go b/e2e/_suites/fleet/fleet.go index f632d9a21f..abbe1150bb 100644 --- a/e2e/_suites/fleet/fleet.go +++ b/e2e/_suites/fleet/fleet.go @@ -41,21 +41,23 @@ type FleetTestSuite struct { Installers map[string]installer.ElasticAgentInstaller Integration kibana.IntegrationPackage // the installed integration Policy kibana.Policy - FleetPolicy kibana.Policy + FleetServerPolicy kibana.Policy PolicyUpdatedAt string // the moment the policy was updated Version string // current elastic-agent version kibanaClient *kibana.Client + // fleet server + FleetServerHostname string // hostname of the fleet server. If empty, it means the agent is the first one, bootstrapping fleet server } // afterScenario destroys the state created by a scenario func (fts *FleetTestSuite) afterScenario() { serviceManager := compose.NewServiceManager() - serviceName := fts.Image + agentInstaller := fts.getInstaller() - if log.IsLevelEnabled(log.DebugLevel) { - agentInstaller := fts.getInstaller() + serviceName := fts.getServiceName(agentInstaller) + if log.IsLevelEnabled(log.DebugLevel) { err := agentInstaller.PrintLogsFn(fts.Hostname) if err != nil { log.WithFields(log.Fields{ @@ -83,7 +85,7 @@ func (fts *FleetTestSuite) afterScenario() { developerMode := shell.GetEnvBool("DEVELOPER_MODE") if !developerMode { - _ = serviceManager.RemoveServicesFromCompose(context.Background(), common.FleetProfileName, []string{serviceName + "-systemd"}, common.ProfileEnv) + _ = serviceManager.RemoveServicesFromCompose(context.Background(), common.FleetProfileName, []string{serviceName}, common.ProfileEnv) } else { log.WithField("service", serviceName).Info("Because we are running in development mode, the service won't be stopped") } @@ -101,12 +103,12 @@ func (fts *FleetTestSuite) afterScenario() { if err != nil { log.WithFields(log.Fields{ "err": err, - "policy": fts.FleetPolicy, + "policy": fts.FleetServerPolicy, }).Error("The package policies could not be found") } for _, pkgPolicy := range packagePolicies { // Do not remove the fleet server package integration otherwise fleet server fails to bootstrap - if !strings.Contains(pkgPolicy.Name, "fleet_server") && pkgPolicy.PolicyID == fts.FleetPolicy.ID { + if !strings.Contains(pkgPolicy.Name, "fleet_server") && pkgPolicy.PolicyID == fts.FleetServerPolicy.ID { err = fts.kibanaClient.DeleteIntegrationFromPolicy(pkgPolicy) if err != nil { log.WithFields(log.Fields{ @@ -122,6 +124,7 @@ func (fts *FleetTestSuite) afterScenario() { fts.CurrentToken = "" fts.Image = "" fts.Hostname = "" + fts.FleetServerHostname = "" } // beforeScenario creates the state needed by a scenario @@ -140,18 +143,18 @@ func (fts *FleetTestSuite) beforeScenario() { } fts.Policy = policy - fleetPolicy, err := fts.kibanaClient.GetDefaultPolicy(true) + fleetServerPolicy, err := fts.kibanaClient.GetDefaultPolicy(true) if err != nil { log.WithFields(log.Fields{ "err": err, }).Warn("The default fleet server policy could not be obtained") } - fts.FleetPolicy = fleetPolicy + fts.FleetServerPolicy = fleetServerPolicy } func (fts *FleetTestSuite) contributeSteps(s *godog.ScenarioContext) { - s.Step(`^a "([^"]*)" agent is deployed to Fleet with "([^"]*)" installer$`, fts.anAgentIsDeployedToFleetWithInstallerInFleetMode) + s.Step(`^a "([^"]*)" agent is deployed to Fleet with "([^"]*)" installer$`, fts.anAgentIsDeployedToFleetWithInstaller) s.Step(`^a "([^"]*)" agent "([^"]*)" is deployed to Fleet with "([^"]*)" installer$`, fts.anStaleAgentIsDeployedToFleetWithInstaller) s.Step(`^agent is in version "([^"]*)"$`, fts.agentInVersion) s.Step(`^agent is upgraded to version "([^"]*)"$`, fts.anAgentIsUpgraded) @@ -176,9 +179,6 @@ func (fts *FleetTestSuite) contributeSteps(s *godog.ScenarioContext) { s.Step(`^the policy response will be shown in the Security App$`, fts.thePolicyResponseWillBeShownInTheSecurityApp) s.Step(`^the policy is updated to have "([^"]*)" in "([^"]*)" mode$`, fts.thePolicyIsUpdatedToHaveMode) s.Step(`^the policy will reflect the change in the Security App$`, fts.thePolicyWillReflectTheChangeInTheSecurityApp) - - // fleet server steps - s.Step(`^a "([^"]*)" agent is deployed to Fleet with "([^"]*)" installer in fleet-server mode$`, fts.anAgentIsDeployedToFleetWithInstallerInFleetMode) } func (fts *FleetTestSuite) anStaleAgentIsDeployedToFleetWithInstaller(image, version, installerType string) error { @@ -215,7 +215,7 @@ func (fts *FleetTestSuite) anStaleAgentIsDeployedToFleetWithInstaller(image, ver // prepare installer for stale version if fts.Version != agentVersionBackup { - i := installer.GetElasticAgentInstaller(image, installerType, fts.Version) + i := installer.GetElasticAgentInstaller(image, installerType, fts.Version, "") fts.Installers[fmt.Sprintf("%s-%s-%s", image, installerType, version)] = i } @@ -311,13 +311,15 @@ func (fts *FleetTestSuite) anAgentIsDeployedToFleetWithInstallerAndFleetServer(i agentInstaller := fts.getInstaller() - profile := agentInstaller.Profile // name of the runtime dependencies compose file - - serviceName := common.ElasticAgentServiceName // name of the service - containerName := fmt.Sprintf("%s_%s_%s_%d", profile, fts.Image+"-systemd", serviceName, 1) // name of the container + containerName := fts.getContainerName(agentInstaller, 1) // name of the container // enroll the agent with a new token - enrollmentKey, err := fts.kibanaClient.CreateEnrollmentAPIKey(fts.FleetPolicy) + policy := fts.Policy + if bootstrapFleetServer { + policy = fts.FleetServerPolicy + } + + enrollmentKey, err := fts.kibanaClient.CreateEnrollmentAPIKey(policy) if err != nil { return err } @@ -325,7 +327,7 @@ func (fts *FleetTestSuite) anAgentIsDeployedToFleetWithInstallerAndFleetServer(i fts.CurrentTokenID = enrollmentKey.ID var fleetConfig *kibana.FleetConfig - fleetConfig, err = deployAgentToFleet(agentInstaller, containerName, fts.CurrentToken, bootstrapFleetServer) + fleetConfig, err = deployAgentToFleet(agentInstaller, containerName, fts.CurrentToken, fts.FleetServerHostname) fts.Cleanup = true if err != nil { @@ -350,16 +352,31 @@ func (fts *FleetTestSuite) anAgentIsDeployedToFleetWithInstallerAndFleetServer(i return err } +// getContainerName returns the current container name for the service: +// we are using the Docker client instead of docker-compose because it does not support +// returning the output of a command: it simply returns error level +func (fts *FleetTestSuite) getContainerName(i installer.ElasticAgentInstaller, index int) string { + return fmt.Sprintf("%s_%s_%s_%d", i.Profile, i.Image, common.ElasticAgentServiceName, index) +} + +// getServiceName returns the current service name, the one defined at the docker compose +func (fts *FleetTestSuite) getServiceName(i installer.ElasticAgentInstaller) string { + return i.Image +} + func (fts *FleetTestSuite) getInstaller() installer.ElasticAgentInstaller { + bootstrappedAgent := fts.FleetServerHostname == "" + + key := fmt.Sprintf("%s-%s-%s-%t", fts.Image, fts.InstallerType, fts.Version, bootstrappedAgent) // check if the agent is already cached - if i, exists := fts.Installers[fts.Image+"-"+fts.InstallerType+"-"+fts.Version]; exists { + if i, exists := fts.Installers[key]; exists { return i } - agentInstaller := installer.GetElasticAgentInstaller(fts.Image, fts.InstallerType, fts.Version) + agentInstaller := installer.GetElasticAgentInstaller(fts.Image, fts.InstallerType, fts.Version, fts.FleetServerHostname) // cache the new installer - fts.Installers[fts.Image+"-"+fts.InstallerType+"-"+fts.Version] = agentInstaller + fts.Installers[key] = agentInstaller return agentInstaller } @@ -419,11 +436,7 @@ func (fts *FleetTestSuite) processStateChangedOnTheHost(process string, state st return err } - // name of the container for the service: - // we are using the Docker client instead of docker-compose - // because it does not support returning the output of a - // command: it simply returns error level - containerName := fmt.Sprintf("%s_%s_%s_%d", profile, fts.Image+"-systemd", common.ElasticAgentServiceName, 1) + containerName := fts.getContainerName(agentInstaller, 1) return docker.CheckProcessStateOnTheHost(containerName, process, "stopped", common.TimeoutFactor) } @@ -520,13 +533,7 @@ func theAgentIsListedInFleetWithStatus(desiredStatus string, hostname string) er func (fts *FleetTestSuite) theFileSystemAgentFolderIsEmpty() error { agentInstaller := fts.getInstaller() - profile := agentInstaller.Profile // name of the runtime dependencies compose file - - // name of the container for the service: - // we are using the Docker client instead of docker-compose - // because it does not support returning the output of a - // command: it simply returns error level - containerName := fmt.Sprintf("%s_%s_%s_%d", profile, fts.Image+"-systemd", common.ElasticAgentServiceName, 1) + containerName := fts.getContainerName(agentInstaller, 1) content, err := agentInstaller.ListElasticAgentWorkingDirContent(containerName) if err != nil { @@ -543,16 +550,13 @@ func (fts *FleetTestSuite) theFileSystemAgentFolderIsEmpty() error { func (fts *FleetTestSuite) theHostIsRestarted() error { agentInstaller := fts.getInstaller() - profile := agentInstaller.Profile // name of the runtime dependencies compose file - image := agentInstaller.Image // image of the service - service := agentInstaller.Service // name of the service - - containerName := fmt.Sprintf("%s_%s_%s_%d", profile, fts.Image+"-systemd", common.ElasticAgentServiceName, 1) + containerName := fts.getContainerName(agentInstaller, 1) _, err := shell.Execute(context.Background(), ".", "docker", "stop", containerName) if err != nil { log.WithFields(log.Fields{ - "image": image, - "service": service, + "containerName": containerName, + "image": agentInstaller.Image, + "service": agentInstaller.Service, }).Error("Could not stop the service") } @@ -561,14 +565,16 @@ func (fts *FleetTestSuite) theHostIsRestarted() error { _, err = shell.Execute(context.Background(), ".", "docker", "start", containerName) if err != nil { log.WithFields(log.Fields{ - "image": image, - "service": service, + "containerName": containerName, + "image": agentInstaller.Image, + "service": agentInstaller.Service, }).Error("Could not start the service") } log.WithFields(log.Fields{ - "image": image, - "service": service, + "containerName": containerName, + "image": agentInstaller.Image, + "service": agentInstaller.Service, }).Debug("The service has been restarted") return nil } @@ -646,7 +652,7 @@ func (fts *FleetTestSuite) theAgentIsReenrolledOnTheHost() error { // during an unenroll the fleet server exits as there is no longer // and agent id associated with the enrollment. When fleet server // restarts it needs a new agent to associate with the boostrap - cfg, err := kibana.NewFleetConfig(fts.CurrentToken, true, false) + cfg, err := kibana.NewFleetConfig(fts.CurrentToken, fts.FleetServerHostname) if err != nil { return err } @@ -680,7 +686,7 @@ func (fts *FleetTestSuite) theEnrollmentTokenIsRevoked() error { func (fts *FleetTestSuite) thePolicyShowsTheDatasourceAdded(packageName string) error { log.WithFields(log.Fields{ - "policyID": fts.FleetPolicy.ID, + "policyID": fts.FleetServerPolicy.ID, "package": packageName, }).Trace("Checking if the policy shows the package added") @@ -690,11 +696,11 @@ func (fts *FleetTestSuite) thePolicyShowsTheDatasourceAdded(packageName string) exp := common.GetExponentialBackOff(maxTimeout) configurationIsPresentFn := func() error { - packagePolicy, err := fts.kibanaClient.GetIntegrationFromAgentPolicy(packageName, fts.FleetPolicy) + packagePolicy, err := fts.kibanaClient.GetIntegrationFromAgentPolicy(packageName, fts.FleetServerPolicy) if err != nil { log.WithFields(log.Fields{ "packagePolicy": packagePolicy, - "policy": fts.FleetPolicy, + "policy": fts.FleetServerPolicy, "retry": retryCount, "error": err, }).Warn("The integration was not found in the policy") @@ -717,7 +723,7 @@ func (fts *FleetTestSuite) thePolicyShowsTheDatasourceAdded(packageName string) func (fts *FleetTestSuite) theIntegrationIsOperatedInThePolicy(packageName string, action string) error { log.WithFields(log.Fields{ "action": action, - "policy": fts.FleetPolicy, + "policy": fts.FleetServerPolicy, "package": packageName, }).Trace("Doing an operation for a package on a policy") @@ -731,7 +737,7 @@ func (fts *FleetTestSuite) theIntegrationIsOperatedInThePolicy(packageName strin Name: integration.Name, Description: integration.Title, Namespace: "default", - PolicyID: fts.FleetPolicy.ID, + PolicyID: fts.FleetServerPolicy.ID, Enabled: true, Package: integration, Inputs: []kibana.Input{}, @@ -764,7 +770,7 @@ func (fts *FleetTestSuite) theIntegrationIsOperatedInThePolicy(packageName strin return fts.kibanaClient.AddIntegrationToPolicy(packageDataStream) } else if strings.ToLower(action) == actionREMOVED { - packageDataStream, err := fts.kibanaClient.GetIntegrationFromAgentPolicy(integration.Name, fts.FleetPolicy) + packageDataStream, err := fts.kibanaClient.GetIntegrationFromAgentPolicy(integration.Name, fts.FleetServerPolicy) if err != nil { return err } @@ -857,13 +863,8 @@ func (fts *FleetTestSuite) theHostNameIsShownInTheAdminViewInTheSecurityApp(stat return nil } -func (fts *FleetTestSuite) anIntegrationIsSuccessfullyDeployedWithAgentAndInstaller(integration string, image string, agentInstaller string) error { - err := fts.anAgentIsDeployedToFleetWithInstallerInFleetMode(image, agentInstaller) - if err != nil { - return err - } - - err = fts.theAgentIsListedInFleetWithStatus("online") +func (fts *FleetTestSuite) anIntegrationIsSuccessfullyDeployedWithAgentAndInstaller(integration string, image string, installerType string) error { + err := fts.anAgentIsDeployedToFleetWithInstaller(image, installerType) if err != nil { return err } @@ -937,7 +938,7 @@ func (fts *FleetTestSuite) thePolicyIsUpdatedToHaveMode(name string, mode string return godog.ErrPending } - packageDS, err := fts.kibanaClient.GetIntegrationFromAgentPolicy("endpoint", fts.FleetPolicy) + packageDS, err := fts.kibanaClient.GetIntegrationFromAgentPolicy("endpoint", fts.FleetServerPolicy) if err != nil { return err @@ -971,7 +972,7 @@ func (fts *FleetTestSuite) thePolicyWillReflectTheChangeInTheSecurityApp() error return err } - pkgPolicy, err := fts.kibanaClient.GetIntegrationFromAgentPolicy("endpoint", fts.FleetPolicy) + pkgPolicy, err := fts.kibanaClient.GetIntegrationFromAgentPolicy("endpoint", fts.FleetServerPolicy) if err != nil { return err } @@ -1035,11 +1036,9 @@ func (fts *FleetTestSuite) anAttemptToEnrollANewAgentFails() error { agentInstaller := fts.getInstaller() - profile := agentInstaller.Profile // name of the runtime dependencies compose file - - containerName := fmt.Sprintf("%s_%s_%s_%d", profile, fts.Image+"-systemd", common.ElasticAgentServiceName, 2) // name of the new container + containerName := fts.getContainerName(agentInstaller, 2) // name of the new container - fleetConfig, err := deployAgentToFleet(agentInstaller, containerName, fts.CurrentToken, false) + fleetConfig, err := deployAgentToFleet(agentInstaller, containerName, fts.CurrentToken, fts.FleetServerHostname) // the installation process for TAR includes the enrollment if agentInstaller.InstallerType != "tar" { if err != nil { @@ -1177,7 +1176,7 @@ func (fts *FleetTestSuite) checkDataStream() error { return err } -func deployAgentToFleet(agentInstaller installer.ElasticAgentInstaller, containerName string, token string, bootstrapFleetServer bool) (*kibana.FleetConfig, error) { +func deployAgentToFleet(agentInstaller installer.ElasticAgentInstaller, containerName string, token string, fleetServerHost string) (*kibana.FleetConfig, error) { profile := agentInstaller.Profile // name of the runtime dependencies compose file service := agentInstaller.Service // name of the service serviceTag := agentInstaller.Tag // docker tag of the service @@ -1208,7 +1207,7 @@ func deployAgentToFleet(agentInstaller installer.ElasticAgentInstaller, containe return nil, err } - cfg, cfgError := kibana.NewFleetConfig(token, bootstrapFleetServer, false) + cfg, cfgError := kibana.NewFleetConfig(token, fleetServerHost) if cfgError != nil { return nil, cfgError } diff --git a/e2e/_suites/fleet/fleet_server.go b/e2e/_suites/fleet/fleet_server.go index e634ade08e..daecf45fd9 100644 --- a/e2e/_suites/fleet/fleet_server.go +++ b/e2e/_suites/fleet/fleet_server.go @@ -4,7 +4,46 @@ package main -func (fts *FleetTestSuite) anAgentIsDeployedToFleetWithInstallerInFleetMode(image string, installerType string) error { +import log "github.com/sirupsen/logrus" + +func (fts *FleetTestSuite) bootstrapFleetServerWithInstaller(image string, installerType string) error { fts.ElasticAgentStopped = true - return fts.anAgentIsDeployedToFleetWithInstallerAndFleetServer(image, installerType, true) + + log.WithFields(log.Fields{ + "image": image, + "installer": installerType, + }).Trace("Bootstrapping fleet server for the agent") + + err := fts.anAgentIsDeployedToFleetWithInstallerAndFleetServer(image, installerType, true) + if err != nil { + log.WithFields(log.Fields{ + "error": err, + "image": image, + "installer": installerType, + }).Error("Fleet server could not be bootstrapped for the agent") + return err + } + + log.WithFields(log.Fields{ + "fleetServerHostname": fts.FleetServerHostname, + "image": image, + "installer": installerType, + }).Info("Fleet server was bootstrapped for the agent") + + err = fts.theAgentIsListedInFleetWithStatus("online") + if err != nil { + log.WithFields(log.Fields{ + "error": err, + "fleetServerHostname": fts.FleetServerHostname, + "image": image, + "installer": installerType, + }).Error("Fleet server could not reach the online status") + return err + } + + // the new compose files for fleet-server (centos/debian) are setting the hostname + // we need it here, before getting the installer, to get the installer using fleet-server host + fts.FleetServerHostname = "fleet-server-" + image + + return nil } diff --git a/e2e/_suites/fleet/ingest_manager_test.go b/e2e/_suites/fleet/ingest_manager_test.go index 44c748d234..b35b28f449 100644 --- a/e2e/_suites/fleet/ingest_manager_test.go +++ b/e2e/_suites/fleet/ingest_manager_test.go @@ -175,6 +175,22 @@ func InitializeIngestManagerTestSuite(ctx *godog.TestSuiteContext) { imts.Fleet.setup() + // we are going to bootstrap Fleet Server in a centos container, using TAR installer, and the base version + // Because it is the first agent in Fleet, there is no FleetServerHost + fleetServerBaseImage := "centos" + fleetServerInstallerType := "tar" + fleetServerVersion := common.AgentVersionBase + agentInstaller := installer.GetElasticAgentInstaller(fleetServerBaseImage, fleetServerInstallerType, fleetServerVersion, "") + + // bootstrap Fleet Server only once: we need to set the version here + imts.Fleet.Version = fleetServerVersion + err = imts.Fleet.bootstrapFleetServerWithInstaller(fleetServerBaseImage, fleetServerInstallerType) + if err != nil { + log.WithFields(log.Fields{ + "installer": agentInstaller, + }).Fatal("Fleet Server could not be bootstrapped") + } + imts.StandAlone.RuntimeDependenciesStartDate = time.Now().UTC() }) diff --git a/e2e/_suites/fleet/stand-alone.go b/e2e/_suites/fleet/stand-alone.go index fd4d723cfe..dfe0b7e8b9 100644 --- a/e2e/_suites/fleet/stand-alone.go +++ b/e2e/_suites/fleet/stand-alone.go @@ -54,7 +54,7 @@ func (sats *StandAloneTestSuite) afterScenario() { func (sats *StandAloneTestSuite) contributeSteps(s *godog.ScenarioContext) { s.Step(`^a "([^"]*)" stand-alone agent is deployed$`, sats.aStandaloneAgentIsDeployed) - s.Step(`^a "([^"]*)" stand-alone agent is deployed with fleet server mode$`, sats.aStandaloneAgentIsDeployedWithFleetServerMode) + s.Step(`^a "([^"]*)" stand-alone agent is deployed with fleet server mode$`, sats.bootstrapFleetServerFromAStandaloneAgent) s.Step(`^there is new data in the index from agent$`, sats.thereIsNewDataInTheIndexFromAgent) s.Step(`^the "([^"]*)" docker container is stopped$`, sats.theDockerContainerIsStopped) s.Step(`^there is no new data in the index after agent shuts down$`, sats.thereIsNoNewDataInTheIndexAfterAgentShutsDown) @@ -87,7 +87,7 @@ func (sats *StandAloneTestSuite) theStandaloneAgentIsListedInFleetWithStatus(des return nil } -func (sats *StandAloneTestSuite) aStandaloneAgentIsDeployedWithFleetServerMode(image string) error { +func (sats *StandAloneTestSuite) bootstrapFleetServerFromAStandaloneAgent(image string) error { return sats.startAgent(image, map[string]string{"fleetServerMode": "1"}) } @@ -107,7 +107,7 @@ func (sats *StandAloneTestSuite) startAgent(image string, env map[string]string) // load the docker images that were already: // a. downloaded from the GCP bucket // b. fetched from the local beats binaries - dockerInstaller := installer.GetElasticAgentInstaller("docker", image, common.AgentVersion) + dockerInstaller := installer.GetElasticAgentInstaller("docker", image, common.AgentVersion, "") dockerInstaller.PreInstallFn() diff --git a/e2e/_suites/fleet/world.go b/e2e/_suites/fleet/world.go index 6fa758a44f..0560e1d2d8 100644 --- a/e2e/_suites/fleet/world.go +++ b/e2e/_suites/fleet/world.go @@ -19,11 +19,14 @@ type IngestManagerTestSuite struct { func (imts *IngestManagerTestSuite) processStateOnTheHost(process string, state string) error { profile := common.FleetProfileName - serviceName := common.ElasticAgentServiceName - containerName := fmt.Sprintf("%s_%s_%s_%d", profile, imts.Fleet.Image+"-systemd", serviceName, 1) + var containerName string + if imts.StandAlone.Hostname != "" { - containerName = fmt.Sprintf("%s_%s_%d", profile, serviceName, 1) + containerName = fmt.Sprintf("%s_%s_%d", profile, common.ElasticAgentServiceName, 1) + } else { + agentInstaller := imts.Fleet.getInstaller() + containerName = imts.Fleet.getContainerName(agentInstaller, 1) } return docker.CheckProcessStateOnTheHost(containerName, process, state, common.TimeoutFactor) diff --git a/internal/common/defaults.go b/internal/common/defaults.go index dc98c83f59..664f0f99e4 100644 --- a/internal/common/defaults.go +++ b/internal/common/defaults.go @@ -19,6 +19,9 @@ const ElasticEndpointIntegrationTitle = "Endpoint Security" // FleetProfileName the name of the profile to run the runtime, backend services const FleetProfileName = "fleet" +// FleetServerAgentServiceName the name of the service for the Elastic Agent +const FleetServerAgentServiceName = "fleet-server" + // AgentVersionBase is the base version of the agent to use var AgentVersionBase = "8.0.0-SNAPSHOT" diff --git a/internal/installer/elasticagent.go b/internal/installer/elasticagent.go index 8399089158..ec32ea4f6b 100644 --- a/internal/installer/elasticagent.go +++ b/internal/installer/elasticagent.go @@ -106,20 +106,22 @@ func downloadAgentBinary(artifactName string, artifact string, version string) ( } // GetElasticAgentInstaller returns an installer from a docker image -func GetElasticAgentInstaller(image string, installerType string, version string) ElasticAgentInstaller { +func GetElasticAgentInstaller(image string, installerType string, version string, fleetServerHost string) ElasticAgentInstaller { log.WithFields(log.Fields{ - "image": image, - "installer": installerType, + "fleetServerHost": fleetServerHost, + "image": image, + "installer": installerType, + "version": version, }).Debug("Configuring installer for the agent") var installer ElasticAgentInstaller var err error if "centos" == image && "tar" == installerType { - installer, err = newTarInstaller("centos", "latest", version) + installer, err = newTarInstaller("centos", "latest", version, fleetServerHost) } else if "centos" == image && "systemd" == installerType { installer, err = newCentosInstaller("centos", "latest", version) } else if "debian" == image && "tar" == installerType { - installer, err = newTarInstaller("debian", "stretch", version) + installer, err = newTarInstaller("debian", "stretch", version, fleetServerHost) } else if "debian" == image && "systemd" == installerType { installer, err = newDebianInstaller("debian", "stretch", version) } else if "docker" == image && "default" == installerType { diff --git a/internal/installer/tar.go b/internal/installer/tar.go index 26d0288165..72cc698a08 100644 --- a/internal/installer/tar.go +++ b/internal/installer/tar.go @@ -145,8 +145,12 @@ func (i *TARPackage) WithVersion(version string) *TARPackage { } // newTarInstaller returns an instance of the Debian installer for a specific version -func newTarInstaller(image string, tag string, version string) (ElasticAgentInstaller, error) { +func newTarInstaller(image string, tag string, version string, fleetServerHost string) (ElasticAgentInstaller, error) { dockerImage := image + "-systemd" // we want to consume systemd boxes + if fleetServerHost == "" { + dockerImage = "fleet-server-" + image + } + service := dockerImage profile := common.FleetProfileName diff --git a/internal/kibana/fleet.go b/internal/kibana/fleet.go index 8ea654f6f2..01b8d7d13a 100644 --- a/internal/kibana/fleet.go +++ b/internal/kibana/fleet.go @@ -27,11 +27,13 @@ type FleetConfig struct { } // NewFleetConfig builds a new configuration for the fleet agent, defaulting ES credentials, URI and port. -// If the 'bootstrappFleetServer' flag is true, the it will create the config for the initial fleet server +// If the 'fleetServerHost' flag is empty, then it will create the config for the initial fleet server // used to bootstrap Fleet Server -// If the 'fleetServerMode' flag is true, the it will create the config for an agent using an existing Fleet +// If the 'fleetServerHost' flag is not empty, the it will create the config for an agent using an existing Fleet // Server to connect to Fleet. It will also retrieve the default policy ID for fleet server -func NewFleetConfig(token string, bootstrapFleetServer bool, fleetServerMode bool) (*FleetConfig, error) { +func NewFleetConfig(token string, fleetServerHost string) (*FleetConfig, error) { + bootstrapFleetServer := (fleetServerHost == "") + cfg := &FleetConfig{ BootstrapFleetServer: bootstrapFleetServer, EnrollmentToken: token, @@ -41,7 +43,7 @@ func NewFleetConfig(token string, bootstrapFleetServer bool, fleetServerMode boo KibanaPort: 5601, KibanaURI: "kibana", FleetServerPort: 8220, - FleetServerURI: "localhost", + FleetServerURI: fleetServerHost, } client, err := NewClient() @@ -49,7 +51,7 @@ func NewFleetConfig(token string, bootstrapFleetServer bool, fleetServerMode boo return cfg, err } - if fleetServerMode { + if !bootstrapFleetServer { defaultFleetServerPolicy, err := client.GetDefaultPolicy(true) if err != nil { return nil, err @@ -91,11 +93,11 @@ func (cfg FleetConfig) Flags() []string { baseFlags := []string{"-e", "-v", "--force", "--insecure", "--enrollment-token=" + cfg.EnrollmentToken} if common.AgentVersionBase == "8.0.0-SNAPSHOT" { - return append(baseFlags, "--url", fmt.Sprintf("http://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.FleetServerURI, cfg.FleetServerPort)) + return append(baseFlags, "--url", fmt.Sprintf("https://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.FleetServerURI, cfg.FleetServerPort)) } if cfg.ServerPolicyID != "" { - baseFlags = append(baseFlags, "--fleet-server-insecure-http", "--fleet-server", fmt.Sprintf("http://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.ElasticsearchURI, cfg.ElasticsearchPort), "--fleet-server-host=http://0.0.0.0", "--fleet-server-policy", cfg.ServerPolicyID) + baseFlags = append(baseFlags, "--fleet-server-insecure-http", "--fleet-server", fmt.Sprintf("https://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.ElasticsearchURI, cfg.ElasticsearchPort), "--fleet-server-host=http://0.0.0.0", "--fleet-server-policy", cfg.ServerPolicyID) } return append(baseFlags, "--kibana-url", fmt.Sprintf("http://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.KibanaURI, cfg.KibanaPort)) From 69e014fea7dccb3b8ee79cc46bf6cef9e323a879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 3 May 2021 13:39:40 +0200 Subject: [PATCH 2/4] fix: use proper base version for 7.x --- cli/config/compose/profiles/helm/docker-compose.yml | 2 +- cli/config/compose/services/kibana/docker-compose.yml | 2 +- e2e/_suites/helm/helm_charts_test.go | 2 +- e2e/_suites/kubernetes-autodiscover/autodiscover_test.go | 2 +- internal/common/defaults.go | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cli/config/compose/profiles/helm/docker-compose.yml b/cli/config/compose/profiles/helm/docker-compose.yml index dcb02ffd92..f77c5a2f04 100644 --- a/cli/config/compose/profiles/helm/docker-compose.yml +++ b/cli/config/compose/profiles/helm/docker-compose.yml @@ -9,6 +9,6 @@ services: - xpack.monitoring.collection.enabled=true - ELASTIC_USERNAME=elastic - ELASTIC_PASSWORD=changeme - image: "docker.elastic.co/elasticsearch/elasticsearch:${stackVersion:-8.0.0-SNAPSHOT}" + image: "docker.elastic.co/elasticsearch/elasticsearch:${stackVersion:-7.x-SNAPSHOT}" ports: - "9200:9200" diff --git a/cli/config/compose/services/kibana/docker-compose.yml b/cli/config/compose/services/kibana/docker-compose.yml index 60dea87377..58ea17814f 100644 --- a/cli/config/compose/services/kibana/docker-compose.yml +++ b/cli/config/compose/services/kibana/docker-compose.yml @@ -9,6 +9,6 @@ services: test: "curl -f http://localhost:5601/login | grep kbn-injected-metadata 2>&1 >/dev/null" retries: 600 interval: 1s - image: "docker.elastic.co/kibana/kibana:${kibanaTag:-8.0.0-SNAPSHOT}" + image: "docker.elastic.co/kibana/kibana:${kibanaTag:-7.x-SNAPSHOT}" ports: - "5601:5601" diff --git a/e2e/_suites/helm/helm_charts_test.go b/e2e/_suites/helm/helm_charts_test.go index b0d81b35c6..1760b05dc0 100644 --- a/e2e/_suites/helm/helm_charts_test.go +++ b/e2e/_suites/helm/helm_charts_test.go @@ -55,7 +55,7 @@ var kubernetesVersion = "1.18.2" // stackVersion is the version of the stack to use // It can be overriden by STACK_VERSION env var -var stackVersion = "8.0.0-SNAPSHOT" +var stackVersion = "7.x-SNAPSHOT" var testSuite HelmChartTestSuite diff --git a/e2e/_suites/kubernetes-autodiscover/autodiscover_test.go b/e2e/_suites/kubernetes-autodiscover/autodiscover_test.go index 561cfb01ae..59e43365d3 100644 --- a/e2e/_suites/kubernetes-autodiscover/autodiscover_test.go +++ b/e2e/_suites/kubernetes-autodiscover/autodiscover_test.go @@ -22,7 +22,7 @@ import ( "github.com/elastic/e2e-testing/internal/utils" ) -const defaultBeatVersion = "8.0.0-SNAPSHOT" +const defaultBeatVersion = "7.x-SNAPSHOT" const defaultEventsWaitTimeout = 120 * time.Second const defaultDeployWaitTimeout = 120 * time.Second diff --git a/internal/common/defaults.go b/internal/common/defaults.go index 664f0f99e4..483f02803e 100644 --- a/internal/common/defaults.go +++ b/internal/common/defaults.go @@ -23,7 +23,7 @@ const FleetProfileName = "fleet" const FleetServerAgentServiceName = "fleet-server" // AgentVersionBase is the base version of the agent to use -var AgentVersionBase = "8.0.0-SNAPSHOT" +var AgentVersionBase = "7.x-SNAPSHOT" // AgentVersion is the version of the agent to use // It can be overriden by BEAT_VERSION env var From b09d53ae84970624f46a39558b68009921f0f822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Mon, 3 May 2021 16:49:51 +0200 Subject: [PATCH 3/4] fix: use proper flag name for fleet-server ES --- internal/kibana/fleet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/kibana/fleet.go b/internal/kibana/fleet.go index 01b8d7d13a..9939d6c26d 100644 --- a/internal/kibana/fleet.go +++ b/internal/kibana/fleet.go @@ -97,7 +97,7 @@ func (cfg FleetConfig) Flags() []string { } if cfg.ServerPolicyID != "" { - baseFlags = append(baseFlags, "--fleet-server-insecure-http", "--fleet-server", fmt.Sprintf("https://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.ElasticsearchURI, cfg.ElasticsearchPort), "--fleet-server-host=http://0.0.0.0", "--fleet-server-policy", cfg.ServerPolicyID) + baseFlags = append(baseFlags, "--fleet-server-insecure-http", "--fleet-server-es", fmt.Sprintf("https://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.ElasticsearchURI, cfg.ElasticsearchPort), "--fleet-server-host=http://0.0.0.0", "--fleet-server-policy", cfg.ServerPolicyID) } return append(baseFlags, "--kibana-url", fmt.Sprintf("http://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.KibanaURI, cfg.KibanaPort)) From 83a76297a40382f11a9f939e3775dfa9a1a06f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Tue, 4 May 2021 07:41:32 +0200 Subject: [PATCH 4/4] fix: append fleet server url param for 7.14 --- internal/kibana/fleet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/kibana/fleet.go b/internal/kibana/fleet.go index 9939d6c26d..6fda101313 100644 --- a/internal/kibana/fleet.go +++ b/internal/kibana/fleet.go @@ -92,7 +92,7 @@ func (cfg FleetConfig) Flags() []string { */ baseFlags := []string{"-e", "-v", "--force", "--insecure", "--enrollment-token=" + cfg.EnrollmentToken} - if common.AgentVersionBase == "8.0.0-SNAPSHOT" { + if common.AgentVersionBase == "7.14.x-SNAPSHOT" { return append(baseFlags, "--url", fmt.Sprintf("https://%s@%s:%d", cfg.ElasticsearchCredentials, cfg.FleetServerURI, cfg.FleetServerPort)) }