From 7be6da4b1caa2f850446d025a9688267a9b27eac Mon Sep 17 00:00:00 2001 From: Omri Ceisler Date: Tue, 9 Sep 2025 11:13:02 +0300 Subject: [PATCH] Fix: Handle large hostname lists by batching to avoid 'argument list too long' error - Added constant maxHostnamesPerBatch = 500 to define the maximum number of hostnames per batch - Implemented batching logic to split the hostnames list into smaller chunks - Created a loop to generate a starter job for each batch - Added unique naming for each starter job when multiple batches are needed - Enhanced error handling to track successful job creation - Improved logging to show batch information and provide a summary when multiple jobs are created --- internal/controller/k6_start.go | 57 ++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/internal/controller/k6_start.go b/internal/controller/k6_start.go index a92095be..e8103951 100644 --- a/internal/controller/k6_start.go +++ b/internal/controller/k6_start.go @@ -99,21 +99,54 @@ func StartJobs(ctx context.Context, log logr.Logger, k6 *v1alpha1.TestRun, r *Te } // starter - - starter := jobs.NewStarterJob(k6, hostnames) - - if err = ctrl.SetControllerReference(k6, starter, r.Scheme); err != nil { - log.Error(err, "Failed to set controller reference for the start job") + + // Handle Linux command line length limitation (max ~500 IPs) + // Split hostnames into batches of 500 to avoid "argument list too long" error + const maxHostnamesPerBatch = 500 + var hostnamesBatches [][]string + + // Split hostnames into batches + for i := 0; i < len(hostnames); i += maxHostnamesPerBatch { + end := i + maxHostnamesPerBatch + if end > len(hostnames) { + end = len(hostnames) + } + hostnamesBatches = append(hostnamesBatches, hostnames[i:end]) } - - // TODO: add a check for existence of starter job - - if err = r.Create(ctx, starter); err != nil { - log.Error(err, "Failed to launch k6 test starter") + + // Create a starter job for each batch + jobsCreated := 0 + for batchIndex, batch := range hostnamesBatches { + // Create a starter job for this batch + starter := jobs.NewStarterJob(k6, batch) + + // Set a unique name for each starter job if there are multiple batches + if len(hostnamesBatches) > 1 { + starter.ObjectMeta.Name = fmt.Sprintf("%s-batch-%d", starter.ObjectMeta.Name, batchIndex+1) + } + + if err = ctrl.SetControllerReference(k6, starter, r.Scheme); err != nil { + log.Error(err, "Failed to set controller reference for the start job", "batch", batchIndex+1) + continue + } + + if err = r.Create(ctx, starter); err != nil { + log.Error(err, "Failed to launch k6 test starter", "batch", batchIndex+1) + continue + } + + jobsCreated++ + log.Info("Created starter job", "batch", batchIndex+1, "hostnames", len(batch)) + } + + if jobsCreated == 0 { + log.Error(fmt.Errorf("no starter jobs created"), "Failed to create any starter jobs") return res, nil } - - log.Info("Created starter job") + + if len(hostnamesBatches) > 1 { + log.Info(fmt.Sprintf("Created %d starter jobs to handle %d hostnames", jobsCreated, len(hostnames))) + } log.Info("Changing stage of TestRun status to started") k6.GetStatus().Stage = "started"