fleet icon indicating copy to clipboard operation
fleet copied to clipboard

Centralized Function Library for Fleet Scripts

Open kennyb-222 opened this issue 10 months ago • 3 comments

customer-numa : Gong snippet: https://us-65885.app.gong.io/call?id=3370391295481274751

  • @noahtalerman's summary: User requested this because several scripts share the same code. Currently, if they want to tweak the code in one script, they have to make this change to all scripts instead of making that change in one spot. This could prevent mistakes.
    • @noahtalerman: Eventually, Fleet could let the user reference a script from within a script. Here's an example: https://github.com/fleetdm/fleet/issues/27320#issuecomment-2743918201

Problem

Fleet admins currently face inefficiencies when deploying configuration scripts. Each script must define its own helper functions, leading to duplication, maintenance overhead, and version inconsistencies. If a function needs updating, every script using it must be modified manually, increasing the risk of errors.

What have you tried?

A prototype was developed where shell functions are organized into a centralized repository. Each function resides in its own file and is sourced dynamically by scripts during execution. This approach demonstrated improved modularity and ease of maintenance.

Potential solutions

A GitOps-managed function repository could be integrated with Fleet. This repository would contain standardized shell functions, which Fleet would sync to managed devices. Scripts could dynamically source these functions at runtime, ensuring they always use the latest version without requiring manual updates.

What is the expected workflow as a result of your proposal?

  • Fleet syncs the function repository to managed devices at run time or kept up-to-date with version changes.
  • Scripts reference these functions dynamically instead of embedding them.
  • When a function is updated in the repository, all scripts automatically use the latest version on the next execution.

This approach could make scripting with Fleet more efficient, maintainable, and scalable.

kennyb-222 avatar Mar 19 '25 21:03 kennyb-222

Thanks @kennyb-222 for tracking this one!

  • @noahtalerman's summary: User requested this because several scripts share the same code. Currently, if they want to tweak the code in one script, they have to make this change to all scripts instead of making that change in one spot. This could prevent mistakes.
    • @noahtalerman: Eventually, Fleet could let the user reference a script from within a script.

Here's my really dumb summary. If/when you get the chance, can you please throw an example script in the comments here? That would be huge for helping us understand a specific use case.

P.S. You probably already gave me an example. Please feel free to ask me to check our call notes!

noahtalerman avatar Mar 20 '25 18:03 noahtalerman

Hey @noahtalerman! Here's an example — a helper function I use often when I need to run commands as the currently logged-in user from scripts that run as root (like via fleetd or LaunchDaemons). A common use case would be triggering GUI actions like open, user-level notifications, or anything that needs the user session context.

#!/usr/bin/env bash

# Get the current console user and their info
_consoleUser_read.func() {
    consoleUser=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ {print $3}')
    consoleUser="${consoleUser:-$USER}"

    consoleUserID=$(id -u "$consoleUser")
    consoleUserGID=$(id -g "$consoleUser")
    userHome=$(sudo -u "$consoleUser" sh -c 'echo $HOME')
}

# Run a command as the logged-in user using launchctl asuser
_runAsUser.func() {
    _consoleUser_read.func

    if [[ -z "$consoleUser" || -z "$consoleUserID" ]]; then
        echo "Error: No console user detected"
        return 1
    fi

    local command="$*"
    sudo -u "$consoleUser" launchctl asuser "$consoleUserID" $command
}

Then, a script can just call:

_runAsUser.func open -a "Console"

This is the kind of helper I end up reusing across many scripts, so having a centralized function library (that gets synced to managed devices and sourced dynamically) would make this much easier to maintain and reuse without copy/pasting across everything.

Happy to share more examples like this if helpful!

kennyb-222 avatar Mar 21 '25 16:03 kennyb-222

Ideally this functionality would exist for Windows (PowerShell) scripts as well. Currently the workaround is to ship a PowerShell module and make it a dependency of other packages/scripts. This is not ideal, as Fleet doesn't currently have a method for shipping flat scripts or archives (PowerShell modules).

TsekNet avatar May 12 '25 14:05 TsekNet

We can discuss a use case that came up in dogfood for this: https://github.com/fleetdm/fleet/blob/main/it-and-security/lib/macos/scripts/refetch_host.sh

allenhouchins avatar Jul 01 '25 18:07 allenhouchins

This problem/use case relates to what you're working on @mike-j-thomas

mikermcneil avatar Jul 03 '25 17:07 mikermcneil

FWIW this feels rather similar to something we're doing with Fleet-maintained app install/uninstall script generation for macOS. Our existing implementation (shell code fragments inlined in Go) wouldn't work here, but this use case makes sense: effectively auto-imported functions prepended to scripts that can be versioned separately from the scripts consuming them.

iansltx avatar Jul 28 '25 04:07 iansltx

A good model for this may be how packer ships environment_vars variables to a temp directory and includes that file when running a script to make those variables available to other scripts.

AFAIK, it essentially ships a file containing your environment variables to a path (like C:/Windows/Temp/packer-ps-env-vars-UUID.ps1), then dot sources that script for your PowerShell script at the top, for example:

. C:/Windows/Temp/packer-ps-env-vars-UUID.ps1

...the rest of your script

..the same can probably be copied for mac/linux.

TsekNet avatar Jul 31 '25 17:07 TsekNet