mirror of
https://github.com/fleetdm/fleet
synced 2026-05-08 09:40:49 +00:00
190 lines
5.6 KiB
Go
190 lines
5.6 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"math/rand/v2"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/service"
|
|
)
|
|
|
|
func printf(format string, a ...any) {
|
|
fmt.Printf(time.Now().UTC().Format("2006-01-02T15:04:05Z")+": "+format, a...)
|
|
}
|
|
|
|
func main() {
|
|
fleetURL := flag.String("fleet_url", "", "URL (with protocol and port of Fleet server)")
|
|
apiToken := flag.String("api_token", "", "API authentication token to use on API calls")
|
|
debug := flag.Bool("debug", false, "Debug mode")
|
|
|
|
flag.Parse()
|
|
|
|
if *fleetURL == "" {
|
|
log.Fatal("missing fleet_url argument")
|
|
}
|
|
if *apiToken == "" {
|
|
log.Fatal("missing api_token argument")
|
|
}
|
|
var clientOpts []service.ClientOption
|
|
if *debug {
|
|
clientOpts = append(clientOpts, service.EnableClientDebug())
|
|
}
|
|
apiClient, err := service.NewClient(*fleetURL, true, "", "", clientOpts...)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
apiClient.SetToken(*apiToken)
|
|
|
|
printf("Fetching hosts...\n")
|
|
records, err := apiClient.GetHostsReport("id", "hostname", "platform")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
type smallHost struct {
|
|
ID uint
|
|
Hostname string
|
|
Platform string
|
|
}
|
|
var (
|
|
macOSHosts []smallHost
|
|
windowsHosts []smallHost
|
|
linuxHosts []smallHost
|
|
)
|
|
for i, record := range records {
|
|
if i == 0 {
|
|
continue
|
|
}
|
|
hostID, _ := strconv.Atoi(record[0])
|
|
hostname := record[1]
|
|
platform := fleet.PlatformFromHost(record[2])
|
|
switch platform {
|
|
case "linux":
|
|
linuxHosts = append(linuxHosts, smallHost{ID: uint(hostID), Hostname: hostname, Platform: platform}) // nolint:gosec
|
|
case "darwin":
|
|
macOSHosts = append(macOSHosts, smallHost{ID: uint(hostID), Hostname: hostname, Platform: platform}) // nolint:gosec
|
|
case "windows":
|
|
windowsHosts = append(windowsHosts, smallHost{ID: uint(hostID), Hostname: hostname, Platform: platform}) // nolint:gosec
|
|
}
|
|
}
|
|
printf("Got linux=%d, windows=%d, macOS=%d\n", len(linuxHosts), len(windowsHosts), len(macOSHosts))
|
|
|
|
titles, err := apiClient.ListSoftwareTitles("per_page=1000&team_id=0&available_for_install=1")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
var (
|
|
macOSSoftware []fleet.SoftwareTitleListResult
|
|
windowsSoftware []fleet.SoftwareTitleListResult
|
|
)
|
|
for _, title := range titles {
|
|
if title.AppStoreApp != nil {
|
|
macOSSoftware = append(macOSSoftware, title)
|
|
} else if title.SoftwarePackage != nil {
|
|
if ext := filepath.Ext(title.SoftwarePackage.Name); ext == ".exe" || ext == ".msi" {
|
|
windowsSoftware = append(windowsSoftware, title)
|
|
} else {
|
|
macOSSoftware = append(macOSSoftware, title)
|
|
}
|
|
}
|
|
}
|
|
printf("Got software titles windows=%d, macOS=%d\n", len(windowsSoftware), len(macOSSoftware))
|
|
|
|
scripts, err := apiClient.ListScripts("per_page=1000&team_id=0")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
var (
|
|
macOSScripts []string
|
|
windowsScripts []string
|
|
)
|
|
for _, script := range scripts {
|
|
if strings.HasSuffix(script.Name, ".sh") {
|
|
macOSScripts = append(macOSScripts, script.Name)
|
|
} else if strings.HasSuffix(script.Name, ".ps1") {
|
|
windowsScripts = append(windowsScripts, script.Name)
|
|
}
|
|
}
|
|
printf("Got scripts windows=%d, macOS=%d\n", len(windowsScripts), len(macOSScripts))
|
|
|
|
var queuedScripts, queuedInstalls, hostsTargeted, errors int
|
|
targetedHosts := append(macOSHosts, windowsHosts...) // nolint:gocritic
|
|
rand.Shuffle(len(targetedHosts), func(i, j int) {
|
|
targetedHosts[i], targetedHosts[j] = targetedHosts[j], targetedHosts[i]
|
|
})
|
|
|
|
tick := time.Tick(300 * time.Millisecond)
|
|
for i, host := range targetedHosts {
|
|
<-tick
|
|
|
|
if hostsTargeted > 0 && hostsTargeted%500 == 0 {
|
|
printf("In progress: queued scripts=%d, queued installs=%d, hosts targeted=%d, errors=%d\n", queuedScripts, queuedInstalls, hostsTargeted, errors)
|
|
}
|
|
|
|
switch host.Platform {
|
|
case "darwin":
|
|
hostsTargeted++
|
|
|
|
// enqueue a software install and a couple scripts
|
|
_, err := apiClient.RunHostScriptAsync(host.ID, nil, macOSScripts[i%len(macOSScripts)], 0)
|
|
if err != nil {
|
|
printf("Failed to run script on host %v (%v): %v\n", host.Hostname, host.Platform, err)
|
|
errors++
|
|
continue
|
|
}
|
|
queuedScripts++
|
|
_, err = apiClient.RunHostScriptAsync(host.ID, nil, macOSScripts[(i+1)%len(macOSScripts)], 0)
|
|
if err != nil {
|
|
printf("Failed to run script on host %v (%v): %v\n", host.Hostname, host.Platform, err)
|
|
errors++
|
|
continue
|
|
}
|
|
queuedScripts++
|
|
|
|
err = apiClient.InstallSoftware(host.ID, macOSSoftware[i%len(macOSSoftware)].ID)
|
|
if err != nil {
|
|
printf("Failed to install software on host %v (%v): %v\n", host.Hostname, host.Platform, err)
|
|
errors++
|
|
continue
|
|
}
|
|
queuedInstalls++
|
|
|
|
case "windows":
|
|
hostsTargeted++
|
|
|
|
// enqueue a couple software installs and a script
|
|
err = apiClient.InstallSoftware(host.ID, windowsSoftware[i%len(windowsSoftware)].ID)
|
|
if err != nil {
|
|
printf("Failed to install software on host %v (%v): %v\n", host.Hostname, host.Platform, err)
|
|
errors++
|
|
continue
|
|
}
|
|
queuedInstalls++
|
|
|
|
err = apiClient.InstallSoftware(host.ID, windowsSoftware[(i+1)%len(windowsSoftware)].ID)
|
|
if err != nil {
|
|
printf("Failed to install software on host %v (%v): %v\n", host.Hostname, host.Platform, err)
|
|
errors++
|
|
continue
|
|
}
|
|
queuedInstalls++
|
|
|
|
_, err = apiClient.RunHostScriptAsync(host.ID, nil, windowsScripts[i%len(windowsScripts)], 0)
|
|
if err != nil {
|
|
printf("Failed to run script on host %v (%v): %v\n", host.Hostname, host.Platform, err)
|
|
errors++
|
|
continue
|
|
}
|
|
queuedScripts++
|
|
}
|
|
}
|
|
|
|
printf("Done: queued scripts=%d, queued installs=%d, hosts targeted=%d, errors=%d\n", queuedScripts, queuedInstalls, hostsTargeted, errors)
|
|
}
|