Skip to content

Commit 6ff3969

Browse files
authored
Cherry-pick: Osquery perf split common software between hosts (#33996)
cherry-pick 33958 no original issue
1 parent a39e3fa commit 6ff3969

1 file changed

Lines changed: 100 additions & 47 deletions

File tree

cmd/osquery-perf/agent.go

Lines changed: 100 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ var adamIDsToSoftware = map[int]*fleet.Software{
256256

257257
type agent struct {
258258
agentIndex int
259+
hostCount int
260+
totalHostCount int
261+
hostIndexOffset int
259262
softwareCount softwareEntityCount
260263
softwareVSCodeExtensionsCount softwareExtraEntityCount
261264
userCount entityCount
@@ -391,6 +394,9 @@ type softwareInstaller struct {
391394

392395
func newAgent(
393396
agentIndex int,
397+
hostCount int,
398+
totalHostCount int,
399+
hostIndexOffset int,
394400
serverAddress, enrollSecret string,
395401
templates *template.Template,
396402
configInterval, logInterval, queryInterval, mdmCheckInInterval time.Duration,
@@ -472,6 +478,9 @@ func newAgent(
472478

473479
agent := &agent{
474480
agentIndex: agentIndex,
481+
hostCount: hostCount,
482+
totalHostCount: totalHostCount,
483+
hostIndexOffset: hostIndexOffset,
475484
serverAddress: serverAddress,
476485
softwareCount: softwareCount,
477486
softwareVSCodeExtensionsCount: softwareVSCodeExtensionsCount,
@@ -1647,31 +1656,80 @@ func (a *agent) hostUsers() []map[string]string {
16471656
}
16481657

16491658
func (a *agent) softwareMacOS() []map[string]string {
1650-
// Common Software
16511659
var lastOpenedCount int
1652-
commonSoftware := make([]map[string]string, a.softwareCount.common)
1653-
for i := 0; i < len(commonSoftware); i++ {
1660+
1661+
totalCommon := a.softwareCount.common
1662+
totalDuplicates := (a.softwareCount.common * a.softwareCount.duplicateBundleIdentifiersPercent) / 100
1663+
totalSoftware := totalCommon + totalDuplicates
1664+
1665+
var startIdx, endIdx int
1666+
1667+
if a.totalHostCount == 0 {
1668+
// non-distributed mode, all hosts get the same software count
1669+
startIdx = 0
1670+
endIdx = totalSoftware
1671+
} else {
1672+
// distributed mode, distribute software across hosts
1673+
globalAgentIndex := a.hostIndexOffset + (a.agentIndex - 1)
1674+
1675+
perHostCount := totalSoftware / a.totalHostCount
1676+
remainder := totalSoftware % a.totalHostCount
1677+
1678+
startIdx = globalAgentIndex * perHostCount
1679+
if globalAgentIndex < remainder {
1680+
startIdx += globalAgentIndex
1681+
} else {
1682+
startIdx += remainder
1683+
}
1684+
1685+
endIdx = startIdx + perHostCount
1686+
if globalAgentIndex < remainder {
1687+
endIdx++
1688+
}
1689+
}
1690+
1691+
commonSoftware := make([]map[string]string, 0)
1692+
duplicateBundleSoftware := make([]map[string]string, 0)
1693+
groupSize := 4
1694+
1695+
for i := startIdx; i < endIdx; i++ {
16541696
var lastOpenedAt string
16551697
if l := a.genLastOpenedAt(&lastOpenedCount); l != nil {
16561698
lastOpenedAt = fmt.Sprint(l.Unix())
16571699
}
1658-
commonSoftware[i] = map[string]string{
1659-
"name": fmt.Sprintf("Common_%d%s", i, a.commonSoftwareNameSuffix),
1660-
"version": "0.0.1",
1661-
"bundle_identifier": fmt.Sprintf("com.fleetdm.osquery-perf.common_%d", i),
1662-
"source": "apps",
1663-
"last_opened_at": lastOpenedAt,
1664-
"installed_path": fmt.Sprintf("/some/path/Common_%d.app", i),
1700+
1701+
if i < totalCommon {
1702+
commonSoftware = append(commonSoftware, map[string]string{
1703+
"name": fmt.Sprintf("Common_%d%s", i, a.commonSoftwareNameSuffix),
1704+
"version": "0.0.1",
1705+
"bundle_identifier": fmt.Sprintf("com.fleetdm.osquery-perf.common_%d", i),
1706+
"source": "apps",
1707+
"last_opened_at": lastOpenedAt,
1708+
"installed_path": fmt.Sprintf("/some/path/Common_%d.app", i),
1709+
})
1710+
} else {
1711+
duplicateIdx := i - totalCommon
1712+
bundleIDIndex := duplicateIdx / groupSize
1713+
bundleID := fmt.Sprintf("com.fleetdm.osquery-perf.common_%d", bundleIDIndex%totalCommon)
1714+
1715+
var name string
1716+
if a.softwareCount.softwareRenaming {
1717+
name = fmt.Sprintf("RENAMED_DuplicateBundle_%d", duplicateIdx)
1718+
} else {
1719+
name = fmt.Sprintf("DuplicateBundle_%d", duplicateIdx)
1720+
}
1721+
1722+
duplicateBundleSoftware = append(duplicateBundleSoftware, map[string]string{
1723+
"name": name,
1724+
"version": fmt.Sprintf("0.0.1%d", duplicateIdx),
1725+
"bundle_identifier": bundleID,
1726+
"source": "apps",
1727+
"installed_path": fmt.Sprintf("/some/path/DuplicateBundle_%d.app", duplicateIdx),
1728+
})
16651729
}
16661730
}
1667-
if a.softwareCount.commonSoftwareUninstallProb > 0.0 && rand.Float64() <= a.softwareCount.commonSoftwareUninstallProb {
1668-
rand.Shuffle(len(commonSoftware), func(i, j int) {
1669-
commonSoftware[i], commonSoftware[j] = commonSoftware[j], commonSoftware[i]
1670-
})
1671-
commonSoftware = commonSoftware[:a.softwareCount.common-a.softwareCount.commonSoftwareUninstallCount]
1672-
}
16731731

1674-
// Unique Software
1732+
// Unique Software (always per-host, not distributed)
16751733
uniqueSoftware := make([]map[string]string, a.softwareCount.unique)
16761734
for i := 0; i < len(uniqueSoftware); i++ {
16771735
var lastOpenedAt string
@@ -1694,30 +1752,6 @@ func (a *agent) softwareMacOS() []map[string]string {
16941752
uniqueSoftware = uniqueSoftware[:a.softwareCount.unique-a.softwareCount.uniqueSoftwareUninstallCount]
16951753
}
16961754

1697-
// Software with Duplicate Bundle identifiers
1698-
duplicateCount := (a.softwareCount.common * a.softwareCount.duplicateBundleIdentifiersPercent) / 100
1699-
duplicateBundleSoftware := make([]map[string]string, duplicateCount)
1700-
groupSize := 4
1701-
for i := 0; i < duplicateCount; i++ {
1702-
bundleIDIndex := i / groupSize
1703-
bundleID := fmt.Sprintf("com.fleetdm.osquery-perf.common_%d", bundleIDIndex%a.softwareCount.common)
1704-
1705-
var name string
1706-
if a.softwareCount.softwareRenaming {
1707-
name = fmt.Sprintf("RENAMED_DuplicateBundle_%d", i)
1708-
} else {
1709-
name = fmt.Sprintf("DuplicateBundle_%d", i)
1710-
}
1711-
1712-
duplicateBundleSoftware[i] = map[string]string{
1713-
"name": name,
1714-
"version": "0.0.1",
1715-
"bundle_identifier": bundleID,
1716-
"source": "apps",
1717-
"installed_path": fmt.Sprintf("/some/path/DuplicateBundle_%d.app", i),
1718-
}
1719-
}
1720-
17211755
// Vulnerable Software
17221756
var vCount int
17231757
if a.softwareCount.vulnerable < 0 {
@@ -2851,12 +2885,14 @@ func main() {
28512885
}
28522886

28532887
var (
2854-
serverURL = flag.String("server_url", "https://localhost:8080", "URL (with protocol and port of osquery server)")
2855-
enrollSecret = flag.String("enroll_secret", "", "Enroll secret to authenticate enrollment")
2856-
hostCount = flag.Int("host_count", 10, "Number of hosts to start (default 10)")
2857-
randSeed = flag.Int64("seed", time.Now().UnixNano(), "Seed for random generator (default current time)")
2858-
startPeriod = flag.Duration("start_period", 10*time.Second, "Duration to spread start of hosts over")
2859-
configInterval = flag.Duration("config_interval", 1*time.Minute, "Interval for config requests")
2888+
serverURL = flag.String("server_url", "https://localhost:8080", "URL (with protocol and port of osquery server)")
2889+
enrollSecret = flag.String("enroll_secret", "", "Enroll secret to authenticate enrollment")
2890+
hostCount = flag.Int("host_count", 10, "Number of hosts to start (default 10)")
2891+
totalHostCount = flag.Int("total_host_count", 0, "Total number of hosts across all containers (if 0, uses host_count)")
2892+
hostIndexOffset = flag.Int("host_index_offset", 0, "Starting index offset for this container's hosts (default 0)")
2893+
randSeed = flag.Int64("seed", time.Now().UnixNano(), "Seed for random generator (default current time)")
2894+
startPeriod = flag.Duration("start_period", 10*time.Second, "Duration to spread start of hosts over")
2895+
configInterval = flag.Duration("config_interval", 1*time.Minute, "Interval for config requests")
28602896
// Flag logger_tls_period defines how often to check for sending scheduled query results.
28612897
// osquery-perf will send log requests with results only if there are scheduled queries configured AND it's their time to run.
28622898
logInterval = flag.Duration("logger_tls_period", 10*time.Second, "Interval for scheduled queries log requests")
@@ -2947,6 +2983,20 @@ func main() {
29472983
flag.Parse()
29482984
rand.Seed(*randSeed)
29492985

2986+
// There are two modes for osquery-perf:
2987+
// 1. Non distributed mode (old behavior). All agents get all software specified. This is done when specifying --host_count and --common_software_count
2988+
// Example --host_count 500 --common_software_count 1000 -> means 500 hosts each with 1000 pieces of software
2989+
// 2. Distributed mode. All agents get a subset of the total software specified. This is done when specifying --total_host_count and --host_index_offset along with other params.
2990+
// Example --host_count 500 --common_software_count 1000 --total_host_count 5000 --host_index_offset [0...N...1000]
2991+
// This example means that each container will run 500 hosts, but each host will only get a subset of the total 5000 software requested.
2992+
if *totalHostCount > 0 && *totalHostCount > *hostCount {
2993+
log.Printf("WARNING: total_host_count (%d) > host_count (%d). You are trying to use distributed mode, ensure you have --host_index_offset specified for each container", *totalHostCount, *hostCount)
2994+
log.Printf(" Container 0 should use: --host_index_offset 0")
2995+
log.Printf(" Container 1 should use: --host_index_offset %d", *hostCount)
2996+
log.Printf(" Container 2 should use: --host_index_offset %d", *hostCount*2)
2997+
log.Printf(" Container N should use: --host_index_offset Y")
2998+
}
2999+
29503000
if *onlyAlreadyEnrolled {
29513001
// Orbit enrollment does not support the "already enrolled" mode at the
29523002
// moment (see TODO in this file).
@@ -3060,6 +3110,9 @@ func main() {
30603110
}
30613111

30623112
a := newAgent(i+1,
3113+
*hostCount,
3114+
*totalHostCount,
3115+
*hostIndexOffset,
30633116
*serverURL,
30643117
*enrollSecret,
30653118
tmpl,

0 commit comments

Comments
 (0)