in internal/pkg/agent/install/install.go [43:184]
func Install(cfgFile, topPath string, unprivileged bool, log *logp.Logger, pt *progressbar.ProgressBar, streams *cli.IOStreams, customUser, customGroup, userPassword string, flavor string) (utils.FileOwner, error) {
dir, err := findDirectory()
if err != nil {
return utils.FileOwner{}, errors.New(err, "failed to discover the source directory for installation", errors.TypeFilesystem)
}
var ownership utils.FileOwner
username := ""
groupName := ""
password := ""
if unprivileged {
username, password = UnprivilegedUser(customUser, userPassword)
groupName = UnprivilegedGroup(customGroup)
ownership, err = EnsureUserAndGroup(username, groupName, pt, username == ElasticUsername && password == "") // force create only elastic user
if err != nil {
// error context already added by EnsureUserAndGroup
return utils.FileOwner{}, err
}
}
err = setupInstallPath(topPath, ownership)
if err != nil {
return utils.FileOwner{}, fmt.Errorf("error setting up install path: %w", err)
}
manifest, err := readPackageManifest(dir)
if err != nil {
return utils.FileOwner{}, fmt.Errorf("reading package manifest: %w", err)
}
pathMappings := manifest.Package.PathMappings
pt.Describe("Copying install files")
copyConcurrency := calculateCopyConcurrency(streams)
skipFn := func(relPath string) bool { return false }
if flavor != "" {
flavorDefinition, err := Flavor(flavor, "", manifest.Package.Flavors)
if err != nil {
return utils.FileOwner{}, err
}
skipFn, err = SkipComponentsPathFn(paths.VersionedHome(dir), flavorDefinition)
if err != nil {
return utils.FileOwner{}, err
}
}
err = copyFiles(copyConcurrency, pathMappings, dir, topPath, skipFn)
if err != nil {
pt.Describe("Error copying files")
return utils.FileOwner{}, err
}
if err := markFlavor(topPath, flavor); err != nil {
return utils.FileOwner{}, fmt.Errorf("failed marking flavor %q at %q: %w", flavor, topPath, err)
}
pt.Describe("Successfully copied files")
// place shell wrapper, if present on platform
if paths.ShellWrapperPath() != "" {
pathDir := filepath.Dir(paths.ShellWrapperPath())
err = os.MkdirAll(pathDir, 0755)
if err != nil {
return utils.FileOwner{}, errors.New(
err,
fmt.Sprintf("failed to create directory (%s) for shell wrapper (%s)", pathDir, paths.ShellWrapperPath()),
errors.M("directory", pathDir))
}
// Install symlink for darwin instead of the wrapper script.
// Elastic-agent should be first process that launchd starts in order to be able to grant
// the Full-Disk Access (FDA) to the agent and it's child processes.
// This is specifically important for osquery FDA permissions at the moment.
if runtime.GOOS == darwin {
// Check if previous shell wrapper or symlink exists and remove it so it can be overwritten
if _, err := os.Lstat(paths.ShellWrapperPath()); err == nil {
if err := os.Remove(paths.ShellWrapperPath()); err != nil {
return utils.FileOwner{}, errors.New(
err,
fmt.Sprintf("failed to remove (%s)", paths.ShellWrapperPath()),
errors.M("destination", paths.ShellWrapperPath()))
}
}
err = os.Symlink(filepath.Join(topPath, paths.BinaryName), paths.ShellWrapperPath())
if err != nil {
return utils.FileOwner{}, errors.New(
err,
fmt.Sprintf("failed to create elastic-agent symlink (%s)", paths.ShellWrapperPath()),
errors.M("destination", paths.ShellWrapperPath()))
}
} else {
// We use strings.Replace instead of fmt.Sprintf here because, with the
// latter, govet throws a false positive error here: "fmt.Sprintf call has
// arguments but no formatting directives".
shellWrapper := strings.Replace(paths.ShellWrapperFmt, "%s", topPath, -1)
err = os.WriteFile(paths.ShellWrapperPath(), []byte(shellWrapper), 0755)
if err != nil {
return utils.FileOwner{}, errors.New(
err,
fmt.Sprintf("failed to write shell wrapper (%s)", paths.ShellWrapperPath()),
errors.M("destination", paths.ShellWrapperPath()))
}
}
}
// post install (per platform)
err = postInstall(topPath)
if err != nil {
return ownership, fmt.Errorf("error running post-install steps: %w", err)
}
// fix permissions
err = perms.FixPermissions(topPath, perms.WithOwnership(ownership))
if err != nil {
return ownership, fmt.Errorf("failed to perform permission changes on path %s: %w", topPath, err)
}
if paths.ShellWrapperPath() != "" {
err = perms.FixPermissions(paths.ShellWrapperPath(), perms.WithOwnership(ownership))
if err != nil {
return ownership, fmt.Errorf("failed to perform permission changes on path %s: %w", paths.ShellWrapperPath(), err)
}
}
// install service
pt.Describe("Installing service")
// ensure that service is removed
err = EnsureServiceRemoved(30*time.Second, 250*time.Millisecond, paths.ServiceName())
if err != nil {
pt.Describe(fmt.Sprintf("Failed to ensure service does not exist: %s", err.Error()))
}
// install service
err = InstallService(topPath, ownership, username, groupName, password)
if err != nil {
pt.Describe("Failed to install service")
// error context already added by InstallService
return ownership, err
}
pt.Describe("Installed service")
return ownership, nil
}