Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ingest Manage] Remove installed services on agent uninstall #24151

Merged
merged 19 commits into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from 17 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
1 change: 1 addition & 0 deletions x-pack/elastic-agent/CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- Windows agent doesn't uninstall with a lowercase `c:` drive in the path {pull}23998[23998]
- Fix reloading of log level for services {pull}[24055]24055
- Fix: Successfully installed and enrolled agent running standalone{pull}[24128]24128
- Remove installed services on agent uninstall {pull}[24151]24151

==== New features

Expand Down
17 changes: 4 additions & 13 deletions x-pack/elastic-agent/pkg/agent/application/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/status"

"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/info"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/paths"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/upgrade"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/configuration"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/warn"
Expand Down Expand Up @@ -70,7 +71,7 @@ func createApplication(
return nil, err
}

if IsStandalone(cfg.Fleet) {
if configuration.IsStandalone(cfg.Fleet) {
log.Info("Agent is managed locally")
return newLocal(ctx, log, pathConfigFile, rawConfig, reexec, statusCtrl, uc, agentInfo)
}
Expand All @@ -79,7 +80,7 @@ func createApplication(
var store storage.Store
store, cfg, err = mergeFleetConfig(rawConfig)

if IsFleetServerBootstrap(cfg.Fleet) {
if configuration.IsFleetServerBootstrap(cfg.Fleet) {
log.Info("Agent is in Fleet Server bootstrap mode")
return newFleetServerBootstrap(ctx, log, pathConfigFile, rawConfig, statusCtrl, agentInfo)
}
Expand All @@ -88,18 +89,8 @@ func createApplication(
return newManaged(ctx, log, store, cfg, rawConfig, reexec, statusCtrl, agentInfo)
}

// IsStandalone decides based on missing of fleet.enabled: true or fleet.{access_token,kibana} will place Elastic Agent into standalone mode.
func IsStandalone(cfg *configuration.FleetAgentConfig) bool {
return cfg == nil || !cfg.Enabled
}

// IsFleetServerBootstrap decides if Elastic Agent is started in bootstrap mode.
func IsFleetServerBootstrap(cfg *configuration.FleetAgentConfig) bool {
return cfg != nil && cfg.Server != nil && cfg.Server.Bootstrap
}

func mergeFleetConfig(rawConfig *config.Config) (storage.Store, *configuration.Configuration, error) {
path := info.AgentConfigFile()
path := paths.AgentConfigFile()
store := storage.NewDiskStore(path)
reader, err := store.Load()
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions x-pack/elastic-agent/pkg/agent/application/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func testMgmtMode(t *testing.T) {
err := c.Unpack(&m)
require.NoError(t, err)
assert.Equal(t, false, m.Fleet.Enabled)
assert.Equal(t, true, IsStandalone(m.Fleet))
assert.Equal(t, true, configuration.IsStandalone(m.Fleet))

})

Expand All @@ -40,7 +40,7 @@ func testMgmtMode(t *testing.T) {
err := c.Unpack(&m)
require.NoError(t, err)
assert.Equal(t, true, m.Fleet.Enabled)
assert.Equal(t, false, IsStandalone(m.Fleet))
assert.Equal(t, false, configuration.IsStandalone(m.Fleet))
})
}

Expand Down
15 changes: 8 additions & 7 deletions x-pack/elastic-agent/pkg/agent/application/enroll_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/elastic/beats/v7/libbeat/common/transport/tlscommon"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/info"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/paths"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/control/client"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/control/proto"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors"
Expand All @@ -43,12 +44,12 @@ var (
daemonTimeout = 30 * time.Second // max amount of for communication to running Agent daemon
)

type store interface {
type saver interface {
Save(io.Reader) error
}

type storeLoad interface {
store
saver
Load() (io.ReadCloser, error)
}

Expand All @@ -70,7 +71,7 @@ type EnrollCmd struct {
log *logger.Logger
options *EnrollCmdOption
client clienter
configStore store
configStore saver
kibanaConfig *kibana.Config
}

Expand Down Expand Up @@ -129,7 +130,7 @@ func NewEnrollCmd(
store := storage.NewReplaceOnSuccessStore(
configPath,
DefaultAgentFleetConfig,
storage.NewDiskStore(info.AgentConfigFile()),
storage.NewDiskStore(paths.AgentConfigFile()),
)

return NewEnrollCmdWithStore(
Expand All @@ -145,7 +146,7 @@ func NewEnrollCmdWithStore(
log *logger.Logger,
options *EnrollCmdOption,
configPath string,
store store,
store saver,
) (*EnrollCmd, error) {
return &EnrollCmd{
log: log,
Expand Down Expand Up @@ -377,13 +378,13 @@ func (c *EnrollCmd) enroll(ctx context.Context) error {

// clear action store
// fail only if file exists and there was a failure
if err := os.Remove(info.AgentActionStoreFile()); !os.IsNotExist(err) {
if err := os.Remove(paths.AgentActionStoreFile()); !os.IsNotExist(err) {
return err
}

// clear action store
// fail only if file exists and there was a failure
if err := os.Remove(info.AgentStateStoreFile()); !os.IsNotExist(err) {
if err := os.Remove(paths.AgentStateStoreFile()); !os.IsNotExist(err) {
return err
}

Expand Down
22 changes: 14 additions & 8 deletions x-pack/elastic-agent/pkg/agent/application/fleet_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/elastic/beats/v7/libbeat/common/backoff"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/errors"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/storage/store"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/status"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/fleetapi"
Expand Down Expand Up @@ -43,6 +44,8 @@ type backoffSettings struct {
Max time.Duration `config:"max"`
}

type fleetAcker = store.FleetAcker

type dispatcher interface {
Dispatch(acker fleetAcker, actions ...action) error
}
Expand All @@ -55,11 +58,6 @@ type fleetReporter interface {
Events() ([]fleetapi.SerializableEvent, func())
}

type fleetAcker interface {
Ack(ctx context.Context, action fleetapi.Action) error
Commit(ctx context.Context) error
}

// FleetGateway is a gateway between the Agent and the Fleet API, it's take cares of all the
// bidirectional communication requirements. The gateway aggregates events and will periodically
// call the API to send the events and will receive actions to be executed locally.
Expand All @@ -72,6 +70,14 @@ type FleetGateway interface {
SetClient(clienter)
}

type stateStore interface {
Add(fleetapi.Action)
AckToken() string
SetAckToken(ackToken string)
Save() error
Actions() []fleetapi.Action
}

type fleetGateway struct {
bgContext context.Context
log *logger.Logger
Expand All @@ -88,7 +94,7 @@ type fleetGateway struct {
unauthCounter int
statusController status.Controller
statusReporter status.Reporter
stateStore *stateStore
stateStore stateStore
}

func newFleetGateway(
Expand All @@ -100,7 +106,7 @@ func newFleetGateway(
r fleetReporter,
acker fleetAcker,
statusController status.Controller,
stateStore *stateStore,
stateStore stateStore,
) (FleetGateway, error) {

scheduler := scheduler.NewPeriodicJitter(defaultGatewaySettings.Duration, defaultGatewaySettings.Jitter)
Expand Down Expand Up @@ -130,7 +136,7 @@ func newFleetGatewayWithScheduler(
r fleetReporter,
acker fleetAcker,
statusController status.Controller,
stateStore *stateStore,
stateStore stateStore,
) (FleetGateway, error) {

// Backoff implementation doesn't support the using context as the shutdown mechanism.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ import (
"github.com/pkg/errors"
"github.com/stretchr/testify/require"

"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/info"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/application/paths"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/storage"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/storage/store"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger"
repo "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/reporter"
fleetreporter "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/reporter/fleet"
fleetreporterConfig "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/reporter/fleet/config"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/scheduler"
)

Expand Down Expand Up @@ -119,7 +121,7 @@ func withGateway(agentInfo agentInfo, settings *fleetGatewaySettings, fn withGat
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

stateStore, err := newStateStore(log, storage.NewDiskStore(info.AgentStateStoreFile()))
stateStore, err := store.NewStateStore(log, storage.NewDiskStore(paths.AgentStateStoreFile()))
require.NoError(t, err)

gateway, err := newFleetGatewayWithScheduler(
Expand Down Expand Up @@ -248,7 +250,7 @@ func TestFleetGateway(t *testing.T) {
defer cancel()

log, _ := logger.New("tst")
stateStore, err := newStateStore(log, storage.NewDiskStore(info.AgentStateStoreFile()))
stateStore, err := store.NewStateStore(log, storage.NewDiskStore(paths.AgentStateStoreFile()))
require.NoError(t, err)

gateway, err := newFleetGatewayWithScheduler(
Expand Down Expand Up @@ -339,7 +341,7 @@ func TestFleetGateway(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
log, _ := logger.New("tst")

stateStore, err := newStateStore(log, storage.NewDiskStore(info.AgentStateStoreFile()))
stateStore, err := store.NewStateStore(log, storage.NewDiskStore(paths.AgentStateStoreFile()))
require.NoError(t, err)

gateway, err := newFleetGatewayWithScheduler(
Expand Down Expand Up @@ -487,7 +489,7 @@ func TestRetriesOnFailures(t *testing.T) {
}

func getReporter(info agentInfo, log *logger.Logger, t *testing.T) *fleetreporter.Reporter {
fleetR, err := fleetreporter.NewReporter(info, log, fleetreporter.DefaultConfig())
fleetR, err := fleetreporter.NewReporter(info, log, fleetreporterConfig.DefaultConfig())
if err != nil {
t.Fatal(errors.Wrap(err, "fail to create reporters"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type handlerUnenroll struct {
emitter emitterFunc
dispatcher programsDispatcher
closers []context.CancelFunc
stateStore *stateStore
stateStore stateStore
}

func (h *handlerUnenroll) Handle(ctx context.Context, a action, acker fleetAcker) error {
Expand Down
36 changes: 4 additions & 32 deletions x-pack/elastic-agent/pkg/agent/application/info/agent_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"bytes"
"fmt"
"io"
"path/filepath"

"github.com/gofrs/uuid"
"gopkg.in/yaml.v2"
Expand All @@ -20,14 +19,7 @@ import (
)

// defaultAgentConfigFile is a name of file used to store agent information
const defaultAgentCapabilitiesFile = "capabilities.yml"
const defaultAgentConfigFile = "fleet.yml"
const agentInfoKey = "agent"

// defaultAgentActionStoreFile is the file that will contains the action that can be replayed after restart.
const defaultAgentActionStoreFile = "action_store.yml"
const defaultAgentStateStoreFile = "state.yml"

const defaultLogLevel = "info"

type persistentAgentInfo struct {
Expand All @@ -40,26 +32,6 @@ type ioStore interface {
Load() (io.ReadCloser, error)
}

// AgentConfigFile is a name of file used to store agent information
func AgentConfigFile() string {
return filepath.Join(paths.Config(), defaultAgentConfigFile)
}

// AgentCapabilitiesPath is a name of file used to store agent capabilities
func AgentCapabilitiesPath() string {
return filepath.Join(paths.Config(), defaultAgentCapabilitiesFile)
}

// AgentActionStoreFile is the file that contains the action that can be replayed after restart.
func AgentActionStoreFile() string {
return filepath.Join(paths.Home(), defaultAgentActionStoreFile)
}

// AgentStateStoreFile is the file that contains the persisted state of the agent including the action that can be replayed after restart.
func AgentStateStoreFile() string {
return filepath.Join(paths.Home(), defaultAgentStateStoreFile)
}

// updateLogLevel updates log level and persists it to disk.
func updateLogLevel(level string) error {
ai, err := loadAgentInfo(false, defaultLogLevel)
Expand All @@ -72,7 +44,7 @@ func updateLogLevel(level string) error {
return nil
}

agentConfigFile := AgentConfigFile()
agentConfigFile := paths.AgentConfigFile()
s := storage.NewDiskStore(agentConfigFile)

ai.LogLevel = level
Expand All @@ -89,7 +61,7 @@ func generateAgentID() (string, error) {
}

func loadAgentInfo(forceUpdate bool, logLevel string) (*persistentAgentInfo, error) {
agentConfigFile := AgentConfigFile()
agentConfigFile := paths.AgentConfigFile()
s := storage.NewDiskStore(agentConfigFile)

agentinfo, err := getInfoFromStore(s, logLevel)
Expand All @@ -114,7 +86,7 @@ func loadAgentInfo(forceUpdate bool, logLevel string) (*persistentAgentInfo, err
}

func getInfoFromStore(s ioStore, logLevel string) (*persistentAgentInfo, error) {
agentConfigFile := AgentConfigFile()
agentConfigFile := paths.AgentConfigFile()
reader, err := s.Load()
if err != nil {
return nil, err
Expand Down Expand Up @@ -159,7 +131,7 @@ func getInfoFromStore(s ioStore, logLevel string) (*persistentAgentInfo, error)
}

func updateAgentInfo(s ioStore, agentInfo *persistentAgentInfo) error {
agentConfigFile := AgentConfigFile()
agentConfigFile := paths.AgentConfigFile()
reader, err := s.Load()
if err != nil {
return err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"runtime"
"strings"

"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/install"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/release"
"github.com/elastic/go-sysinfo"
"github.com/elastic/go-sysinfo/types"
Expand Down Expand Up @@ -142,7 +141,7 @@ func (i *AgentInfo) ECSMetadata() (*ECSMeta, error) {
BuildOriginal: release.Info().String(),
// only upgradeable if running from Agent installer and running under the
// control of the system supervisor (or built specifically with upgrading enabled)
Upgradeable: release.Upgradeable() || (install.RunningInstalled() && install.RunningUnderSupervisor()),
Upgradeable: release.Upgradeable() || (RunningInstalled() && RunningUnderSupervisor()),
LogLevel: i.logLevel,
},
},
Expand Down
Loading