in internal/pkg/agent/install/uninstall.go [58:171]
func Uninstall(ctx context.Context, cfgFile, topPath, uninstallToken string, log *logp.Logger, pt *progressbar.ProgressBar, skipFleetAudit bool) error {
cwd, err := os.Getwd()
if err != nil {
return fmt.Errorf("unable to get current working directory")
}
if runtime.GOOS == "windows" && paths.HasPrefix(cwd, topPath) {
return fmt.Errorf("uninstall must be run from outside the installed path '%s'", topPath)
}
// check if the agent was installed using --unprivileged by checking the file vault for the agent secret (needed on darwin to correctly load the vault)
unprivileged, err := checkForUnprivilegedVault(ctx)
if err != nil {
return fmt.Errorf("error checking for unprivileged vault: %w", err)
}
// will only notify fleet of the uninstall command if it can gather config and agentinfo, and is not a stand-alone install
localFleet := false
notifyFleet := false
var agentID agentInfo
var cfg *configuration.Configuration
func() { // check if we need to notify in a func to allow us to return early if a (non-fatal) error is encountered.
// read local config
c, err := operations.LoadFullAgentConfig(ctx, log, cfgFile, false, unprivileged)
if err != nil {
pt.Describe("notify Fleet failed: unable to read config")
return
}
cfg, err = configuration.NewFromConfig(c)
if err != nil {
pt.Describe("notify Fleet failed: error transforming config")
return
}
if cfg != nil && !configuration.IsStandalone(cfg.Fleet) {
agentID = agentInfo(cfg.Settings.ID)
notifyFleet = true
if cfg.Fleet != nil && cfg.Fleet.Server != nil {
localFleet = true
}
}
}()
// Notify fleet-server while it is still running if it's running locally
if notifyFleet && localFleet {
// host is set in the agent/cmd/enroll_cmd.go by createFleetServerBootstrapConfig
// hosts is set in agent/application/actions/handlers/handler_action_policy_change.go by updateFleetConfig
// agents running the fleet-server integration should communicate over the internal API (defaults to localhost:8221)
// This may need to be fixed with https://github.com/elastic/elastic-agent/issues/4771
cfg.Fleet.Client.Hosts = []string{cfg.Fleet.Client.Host}
notifyFleetAuditUninstall(ctx, log, pt, cfg, &agentID) //nolint:errcheck // ignore the error as we can't act on it
}
// ensure service is stopped
status, err := EnsureStoppedService(topPath, pt)
if err != nil {
// context for the error already provided in the EnsureStoppedService function
return err
}
// kill any running watcher
if err := killWatcher(pt); err != nil {
return fmt.Errorf("failed trying to kill any running watcher: %w", err)
}
// Uninstall components first
if err := uninstallComponents(ctx, cfgFile, uninstallToken, log, pt, unprivileged); err != nil {
// If service status was running it was stopped to uninstall the components.
// If the components uninstall failed start the service again
if status == service.StatusRunning {
if startErr := StartService(topPath); startErr != nil {
// context for the error already provided in the StartService function
return err
}
}
return fmt.Errorf("error uninstalling components: %w", err)
}
// Uninstall service only after components were uninstalled successfully
pt.Describe("Removing service")
err = UninstallService(topPath)
// Is there a reason why we don't want to hard-fail on this?
if err != nil {
pt.Describe(fmt.Sprintf("Failed to Uninstall existing service: %s", err))
} else {
pt.Describe("Successfully uninstalled service")
}
// remove, if present on platform
if paths.ShellWrapperPath() != "" {
err = os.Remove(paths.ShellWrapperPath())
if !os.IsNotExist(err) && err != nil {
return aerrors.New(
err,
fmt.Sprintf("failed to remove shell wrapper (%s)", paths.ShellWrapperPath()),
aerrors.M("destination", paths.ShellWrapperPath()))
}
}
// remove existing directory
pt.Describe("Removing install directory")
err = RemovePath(topPath)
if err != nil {
pt.Describe("Failed to remove install directory")
return aerrors.New(
err,
fmt.Sprintf("failed to remove installation directory (%s)", paths.Top()),
aerrors.M("directory", paths.Top()))
}
pt.Describe("Removed install directory")
notifyFleetIfNeeded(ctx, log, pt, cfg, agentID, notifyFleet, localFleet, skipFleetAudit, notifyFleetAuditUninstall)
return nil
}