func Uninstall()

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
}