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

[Elastic Agent] Support the install, control, and uninstall of Endpoint #19248

Merged
merged 42 commits into from
Jun 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a64aeba
Initial spec parsing for endpoint.
blakerouse Jun 12, 2020
a79064b
Update comment.
blakerouse Jun 12, 2020
f6a19fe
Fix spec test.
blakerouse Jun 12, 2020
0f93b15
Update code so it copies the entire input.
blakerouse Jun 12, 2020
ce54a3f
Fix ast test.
blakerouse Jun 12, 2020
f5da411
Merge agent-improve-restart-loop
blakerouse Jun 14, 2020
977f586
Merge agent-endpoint-spec
blakerouse Jun 14, 2020
eb630d7
Refactor core/plugin/app into mostly core/ and use core/plugin for di…
blakerouse Jun 15, 2020
7de8c67
Work on endpoint service application.
blakerouse Jun 15, 2020
12ce078
More fixes.
blakerouse Jun 15, 2020
51408bf
Fix format and tests.
blakerouse Jun 15, 2020
4ee0754
Fix some imports.
blakerouse Jun 15, 2020
157d0bd
Merge branch 'master' into agent-endpoint-app
blakerouse Jun 15, 2020
bb110fa
More cleanups.
blakerouse Jun 15, 2020
fd98ec4
Fix export comment.
blakerouse Jun 15, 2020
26cd0bf
Pass the program.Spec into the descriptor.
blakerouse Jun 16, 2020
e4a5aca
Run endpoint verify, install, and uninstall when endpoint should be r…
blakerouse Jun 17, 2020
f29dead
Fix install and uninstall of Endpoint
blakerouse Jun 17, 2020
a497625
Fix some small issues with service app.
blakerouse Jun 17, 2020
e51d529
Merge branch 'agent-endpoint-app' into agent-endpoint-install
blakerouse Jun 17, 2020
73b4fa7
Add changelog entry.
blakerouse Jun 17, 2020
0a3ce3d
Fix lint and tests.
blakerouse Jun 17, 2020
515e664
Merge branch 'agent-endpoint-app' into agent-endpoint-install
blakerouse Jun 17, 2020
1d1c674
Fix lint.
blakerouse Jun 17, 2020
c46d208
Merge branch 'master' into agent-endpoint-spec
blakerouse Jun 18, 2020
eec7d8d
Remove the code no longer needed because of newer config format.
blakerouse Jun 18, 2020
a51226e
Merge branch 'agent-endpoint-spec' into agent-endpoint-app
blakerouse Jun 18, 2020
c73d6b1
Fix rules and review.
blakerouse Jun 18, 2020
2d60852
Merge branch 'agent-endpoint-app' into agent-endpoint-install
blakerouse Jun 18, 2020
13dbbda
Update to Endpoint Security.
blakerouse Jun 18, 2020
1a3054d
Fix issues so endpoint security runs.
blakerouse Jun 18, 2020
6c6df5e
Add comments.
blakerouse Jun 18, 2020
1146b2d
Update docstring.
blakerouse Jun 18, 2020
c9d9b4e
Merge branch 'master' into agent-endpoint-install
blakerouse Jun 18, 2020
1f32e78
Some more fixes.
blakerouse Jun 18, 2020
d97336c
Delete the extra endpoint testdata files.
blakerouse Jun 26, 2020
6bf6cde
Merge branch 'master' into agent-endpoint-install
blakerouse Jun 26, 2020
c22b475
Add timeout to exec_file step.
blakerouse Jun 26, 2020
d383c5a
Fix supported map.
blakerouse Jun 26, 2020
0283238
Fix getting support programs by cmd.
blakerouse Jun 26, 2020
81ef3d5
Improve app started checks.
blakerouse Jun 26, 2020
6ccfcb1
Fix buildspec.
blakerouse Jun 26, 2020
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 @@ -72,3 +72,4 @@
- Change stream.* to dataset.* fields {pull}18967[18967]
- Agent now runs the GRPC server and spawned application connect by to Agent {pull}18973[18973]
- Rename input.type logs to logfile {pull}19360[19360]
- Agent now installs/uninstalls Elastic Endpoint {pull}19248[19248]
6 changes: 3 additions & 3 deletions x-pack/elastic-agent/dev-tools/cmd/buildspec/buildspec.go

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

4 changes: 2 additions & 2 deletions x-pack/elastic-agent/pkg/agent/application/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ func localConfigDefault() *localConfig {
type FleetAgentConfig struct {
API *APIAccess `config:"api" yaml:"api"`
Reporting *LogReporting `config:"reporting" yaml:"reporting"`
Info *AgentInfo `config:"agent_info" yaml:"agent_info"`
Info *AgentInfo `config:"agent" yaml:"agent"`
}

// AgentInfo is a set of agent information.
type AgentInfo struct {
ID string `json:"ID" yaml:"ID" config:"ID"`
ID string `json:"id" yaml:"id" config:"id"`
}

// APIAccess contains the required details to connect to the Kibana endpoint.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ func injectFleet(cfg *config.Config) func(*logger.Logger, *transpiler.AST) error
}
api, ok := transpiler.Lookup(ast, "api")
if !ok {
return fmt.Errorf("failed to get api from fleet config")
return fmt.Errorf("failed to get api key from fleet config")
}
agentInfo, ok := transpiler.Lookup(ast, "agent_info")
agent, ok := transpiler.Lookup(ast, "agent")
if !ok {
return fmt.Errorf("failed to get agent_info from fleet config")
return fmt.Errorf("failed to get agent key from fleet config")
}
fleet := transpiler.NewDict([]transpiler.Node{agentInfo, api})
fleet := transpiler.NewDict([]transpiler.Node{agent, api})
err = transpiler.Insert(rootAst, fleet, "fleet")
if err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions x-pack/elastic-agent/pkg/agent/application/info/agent_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ import (

// defaultAgentConfigFile is a name of file used to store agent information
const defaultAgentConfigFile = "fleet.yml"
const agentInfoKey = "agent_info"
const agentInfoKey = "agent"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: this is breaking between 7.8 and 7.9 so maybe we should put a note that agent might change ID in between versions when updating from 7.8

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we just handle it? support reading it with either agent_info or agent?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets document it, breaking changes are ok from 7.8->7.9

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #19488 that handles it transparently, or we can just document. I prefer to just handle it, but okay with breaking.


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

type persistentAgentInfo struct {
ID string `json:"ID" yaml:"ID" config:"ID"`
ID string `json:"id" yaml:"id" config:"id"`
}

type ioStore interface {
Expand Down
7 changes: 7 additions & 0 deletions x-pack/elastic-agent/pkg/agent/application/stream.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/agent/stateresolver"
downloader "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact/download/localremote"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact/install"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact/uninstall"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/config"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/monitoring"
Expand Down Expand Up @@ -66,6 +67,11 @@ func newOperator(ctx context.Context, log *logger.Logger, id routingKey, config
return nil, errors.New(err, "initiating installer")
}

uninstaller, err := uninstall.NewUninstaller()
if err != nil {
return nil, errors.New(err, "initiating uninstaller")
}

stateResolver, err := stateresolver.NewStateResolver(log)
if err != nil {
return nil, err
Expand All @@ -79,6 +85,7 @@ func newOperator(ctx context.Context, log *logger.Logger, id routingKey, config
fetcher,
verifier,
installer,
uninstaller,
stateResolver,
srv,
r,
Expand Down
27 changes: 20 additions & 7 deletions x-pack/elastic-agent/pkg/agent/operation/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import (
"testing"
"time"

"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/program"

operatorCfg "github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/operation/config"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/program"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/stateresolver"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact/download"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact/install"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact/uninstall"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/config"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/app"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger"
Expand Down Expand Up @@ -55,7 +55,8 @@ func getTestOperator(t *testing.T, downloadPath string, installPath string, p *a

fetcher := &DummyDownloader{}
verifier := &DummyVerifier{}
installer := &DummyInstaller{}
installer := &DummyInstallerChecker{}
uninstaller := &DummyUninstaller{}

stateResolver, err := stateresolver.NewStateResolver(l)
if err != nil {
Expand All @@ -70,7 +71,7 @@ func getTestOperator(t *testing.T, downloadPath string, installPath string, p *a
t.Fatal(err)
}

operator, err := NewOperator(context.Background(), l, "p1", cfg, fetcher, verifier, installer, stateResolver, srv, nil, noop.NewMonitor())
operator, err := NewOperator(context.Background(), l, "p1", cfg, fetcher, verifier, installer, uninstaller, stateResolver, srv, nil, noop.NewMonitor())
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -157,10 +158,22 @@ func (*DummyVerifier) Verify(p, v string) (bool, error) {

var _ download.Verifier = &DummyVerifier{}

type DummyInstaller struct{}
type DummyInstallerChecker struct{}

func (*DummyInstallerChecker) Check(_ context.Context, p, v, _ string) error {
return nil
}

func (*DummyInstallerChecker) Install(_ context.Context, p, v, _ string) error {
return nil
}

var _ install.InstallerChecker = &DummyInstallerChecker{}

type DummyUninstaller struct{}

func (*DummyInstaller) Install(p, v, _ string) error {
func (*DummyUninstaller) Uninstall(_ context.Context, p, v, _ string) error {
return nil
}

var _ install.Installer = &DummyInstaller{}
var _ uninstall.Uninstaller = &DummyUninstaller{}
8 changes: 5 additions & 3 deletions x-pack/elastic-agent/pkg/agent/operation/monitoring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ func getMonitorableTestOperator(t *testing.T, installPath string, m monitoring.M

fetcher := &DummyDownloader{}
verifier := &DummyVerifier{}
installer := &DummyInstaller{}
installer := &DummyInstallerChecker{}
uninstaller := &DummyUninstaller{}

stateResolver, err := stateresolver.NewStateResolver(l)
if err != nil {
Expand All @@ -132,7 +133,7 @@ func getMonitorableTestOperator(t *testing.T, installPath string, m monitoring.M
}

ctx := context.Background()
operator, err := NewOperator(ctx, l, "p1", cfg, fetcher, verifier, installer, stateResolver, srv, nil, m)
operator, err := NewOperator(ctx, l, "p1", cfg, fetcher, verifier, installer, uninstaller, stateResolver, srv, nil, m)
if err != nil {
t.Fatal(err)
}
Expand All @@ -146,7 +147,8 @@ type testMonitorableApp struct {
monitor monitoring.Monitor
}

func (*testMonitorableApp) Name() string { return "" }
func (*testMonitorableApp) Name() string { return "" }
func (*testMonitorableApp) Started() bool { return false }
func (*testMonitorableApp) Start(_ context.Context, _ app.Taggable, cfg map[string]interface{}) error {
return nil
}
Expand Down
3 changes: 2 additions & 1 deletion x-pack/elastic-agent/pkg/agent/operation/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ type operation interface {
// examples:
// - Start does not need to run if process is running
// - Fetch does not need to run if package is already present
Check(application Application) (bool, error)
Check(ctx context.Context, application Application) (bool, error)
// Run runs the operation
Run(ctx context.Context, application Application) error
}

// Application is an application capable of being started, stopped and configured.
type Application interface {
Name() string
Started() bool
Start(ctx context.Context, p app.Taggable, cfg map[string]interface{}) error
Stop()
Configure(ctx context.Context, config map[string]interface{}) error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (o *operationConfig) Name() string {
// Check checks whether config needs to be run.
//
// Always returns true.
func (o *operationConfig) Check(_ Application) (bool, error) { return true, nil }
func (o *operationConfig) Check(_ context.Context, _ Application) (bool, error) { return true, nil }

// Run runs the operation
func (o *operationConfig) Run(ctx context.Context, application Application) (err error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (o *operationFetch) Name() string {
// Check checks whether fetch needs to occur.
//
// If the artifacts already exists then fetch will not be ran.
func (o *operationFetch) Check(_ Application) (bool, error) {
func (o *operationFetch) Check(_ context.Context, _ Application) (bool, error) {
downloadConfig := o.operatorConfig.DownloadConfig
fullPath, err := artifact.GetArtifactPath(o.program.BinaryName(), o.program.Version(), downloadConfig.OS(), downloadConfig.Arch(), downloadConfig.TargetDirectory)
if err != nil {
Expand Down
18 changes: 10 additions & 8 deletions x-pack/elastic-agent/pkg/agent/operation/operation_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package operation

import (
"context"
"os"

"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/agent/operation/config"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact/install"
Expand All @@ -20,14 +19,14 @@ type operationInstall struct {
logger *logger.Logger
program Descriptor
operatorConfig *config.Config
installer install.Installer
installer install.InstallerChecker
}

func newOperationInstall(
logger *logger.Logger,
program Descriptor,
operatorConfig *config.Config,
installer install.Installer) *operationInstall {
installer install.InstallerChecker) *operationInstall {

return &operationInstall{
logger: logger,
Expand All @@ -45,10 +44,13 @@ func (o *operationInstall) Name() string {
// Check checks whether install needs to be ran.
//
// If the installation directory already exists then it will not be ran.
func (o *operationInstall) Check(_ Application) (bool, error) {
installDir := o.program.Directory()
_, err := os.Stat(installDir)
return os.IsNotExist(err), nil
func (o *operationInstall) Check(ctx context.Context, _ Application) (bool, error) {
err := o.installer.Check(ctx, o.program.BinaryName(), o.program.Version(), o.program.Directory())
if err != nil {
// don't return err, just state if Run should be called
return true, nil
}
return false, nil
}

// Run runs the operation
Expand All @@ -59,5 +61,5 @@ func (o *operationInstall) Run(ctx context.Context, application Application) (er
}
}()

return o.installer.Install(o.program.BinaryName(), o.program.Version(), o.program.Directory())
return o.installer.Install(ctx, o.program.BinaryName(), o.program.Version(), o.program.Directory())
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (o *operationRemove) Name() string {
// Check checks whether remove needs to run.
//
// Always returns false.
func (o *operationRemove) Check(_ Application) (bool, error) {
func (o *operationRemove) Check(_ context.Context, _ Application) (bool, error) {
return false, nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ func (o *retryableOperations) Name() string {
// examples:
// - Start does not need to run if process is running
// - Fetch does not need to run if package is already present
func (o *retryableOperations) Check(application Application) (bool, error) {
func (o *retryableOperations) Check(ctx context.Context, application Application) (bool, error) {
for _, op := range o.operations {
// finish early if at least one operation needs to be run or errored out
if run, err := op.Check(application); err != nil || run {
if run, err := op.Check(ctx, application); err != nil || run {
return run, err
}
}
Expand All @@ -71,7 +71,7 @@ func (o *retryableOperations) runOnce(application Application) func(context.Cont
return ctx.Err()
}

shouldRun, err := op.Check(application)
shouldRun, err := op.Check(ctx, application)
if err != nil {
return err
}
Expand Down
8 changes: 4 additions & 4 deletions x-pack/elastic-agent/pkg/agent/operation/operation_start.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ func (o *operationStart) Name() string {
// Only starts the application when in stopped state, any other state
// and the application is handled by the life cycle inside of the `Application`
// implementation.
func (o *operationStart) Check(application Application) (bool, error) {
if application.State().Status == state.Stopped {
return true, nil
func (o *operationStart) Check(_ context.Context, application Application) (bool, error) {
if application.Started() {
return false, nil
}
return false, nil
return true, nil
}

// Run runs the operation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (o *operationStop) Name() string {
// Check checks whether application needs to be stopped.
//
// If the application state is not stopped then stop should be performed.
func (o *operationStop) Check(application Application) (bool, error) {
func (o *operationStop) Check(_ context.Context, application Application) (bool, error) {
if application.State().Status != state.Stopped {
return true, nil
}
Expand Down
55 changes: 55 additions & 0 deletions x-pack/elastic-agent/pkg/agent/operation/operation_uninstall.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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 operation

import (
"context"

"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/artifact/uninstall"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/logger"
"github.com/elastic/beats/v7/x-pack/elastic-agent/pkg/core/state"
)

// operationUninstall uninstalls a artifact from predefined location
type operationUninstall struct {
logger *logger.Logger
program Descriptor
uninstaller uninstall.Uninstaller
}

func newOperationUninstall(
logger *logger.Logger,
program Descriptor,
uninstaller uninstall.Uninstaller) *operationUninstall {

return &operationUninstall{
logger: logger,
program: program,
uninstaller: uninstaller,
}
}

// Name is human readable name identifying an operation
func (o *operationUninstall) Name() string {
return "operation-uninstall"
}

// Check checks whether uninstall needs to be ran.
//
// Always true.
func (o *operationUninstall) Check(_ context.Context, _ Application) (bool, error) {
return true, nil
}

// Run runs the operation
func (o *operationUninstall) Run(ctx context.Context, application Application) (err error) {
defer func() {
if err != nil {
application.SetState(state.Failed, err.Error())
}
}()

return o.uninstaller.Uninstall(ctx, o.program.BinaryName(), o.program.Version(), o.program.Directory())
}
Loading