Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cmd/inch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (m *Main) ParseFlags(args []string) error {
fs := flag.NewFlagSet("inch", flag.ContinueOnError)
fs.BoolVar(&m.inch.Verbose, "v", false, "Verbose")
fs.BoolVar(&m.inch.V2, "v2", false, "Writing into InfluxDB 2.0")
fs.StringVar(&m.inch.Token, "token", "", "InfluxDB 2.0 Authorization token")
fs.StringVar(&m.inch.Token, "token", "", "InfluxDB 2.0 or 3 Authorization token")
fs.StringVar(&m.inch.ReportHost, "report-host", "", "Host to send metrics")
fs.StringVar(&m.inch.ReportUser, "report-user", "", "User for Host to send metrics")
fs.StringVar(&m.inch.ReportPassword, "report-password", "", "Password Host to send metrics")
Expand Down Expand Up @@ -92,6 +92,9 @@ func (m *Main) ParseFlags(args []string) error {
fs.BoolVar(&m.inch.Gzip, "gzip", false, "Use gzip compression")
fs.StringVar(&m.inch.Precision, "precision", "ns", "Precision of writes")
noSetup := fs.Bool("no-setup", false, "Don't ping or set up tables/buckets on run (this is useful for load testing kapacitor)")
fs.BoolVar(&m.inch.V3, "v3", false, "Use v3 write endpoint (only compatible with v3 write endpoint)")
fs.BoolVar(&m.inch.V3NoSync, "v3-no-sync", false, "Disable waiting for durability before ack")
fs.BoolVar(&m.inch.V3AcceptPartial, "v3-accept-partial", false, "Accept lines in batch successfully even if subsequent lines error")

if err := fs.Parse(args); err != nil {
return err
Expand Down
25 changes: 19 additions & 6 deletions inch.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ type Simulator struct {
TargetMaxLatency time.Duration
Gzip bool
Precision string
V3 bool // enables the v3 native write endpoint which has additional semantics; db and precision are required
V3NoSync bool // v3 supports a "no-sync" option, when true will ACK write as soon as possible without waiting for wal durability
V3AcceptPartial bool // allow partial write success when some lines in a batch fail to write

Database string
RetentionPolicy string // Write to a specific retention policy
Expand Down Expand Up @@ -183,6 +186,10 @@ func (s *Simulator) Validate() error {
el = append(el, fmt.Errorf("invalid precision: %s", s.Precision))
}

Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate() doesn’t currently enforce any constraints around the new v3 flags beyond a warning. Consider making these cases hard errors: (1) -v2 and -v3 both set (ambiguous behavior), and (2) -v3 set with an empty Database (required for /api/v3/write_lp). This will fail fast instead of producing confusing runtime errors.

Suggested change
// Enforce mutually exclusive v2/v3 modes.
if s.V2 && s.V3 {
el = append(el, errors.New("invalid configuration: cannot enable both v2 and v3 write endpoints; please select exactly one"))
}
// Enforce required database when using the v3 write endpoint.
if s.V3 && strings.TrimSpace(s.Database) == "" {
el = append(el, errors.New("invalid configuration: database must be set when using the v3 write endpoint"))
}

Copilot uses AI. Check for mistakes.
if !s.V3 && (s.V3NoSync || s.V3AcceptPartial) {
fmt.Fprintf(s.Stdout, "Warning: InfluxDB 3 flag(s) set to true, but V3 write endpoint not being used; flags will have no effect.\n")
}

if len(el) > 0 {
return el
}
Expand Down Expand Up @@ -218,11 +225,14 @@ func (s *Simulator) Run(ctx context.Context) error {
fmt.Fprintf(s.Stdout, "Retention Policy: %s\n", s.RetentionPolicy)
fmt.Fprintf(s.Stdout, "Write Consistency: %s\n", s.Consistency)
fmt.Fprintf(s.Stdout, "Writing into InfluxDB 2.0: %t\n", s.V2)
fmt.Fprintf(s.Stdout, "InfluxDB 2.0 Authorization Token: %s\n", s.Token)
fmt.Fprintf(s.Stdout, "InfluxDB 2 or 3 Authorization Token: %s\n", s.Token)
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prints the full authorization token to stdout, which is likely to end up in CI logs / shell history and leak credentials. Consider printing only whether a token is set (or a redacted form) and/or gating token output behind -v.

Suggested change
fmt.Fprintf(s.Stdout, "InfluxDB 2 or 3 Authorization Token: %s\n", s.Token)
if s.Token == "" {
fmt.Fprintf(s.Stdout, "InfluxDB 2 or 3 Authorization Token: (not set)\n")
} else {
fmt.Fprintf(s.Stdout, "InfluxDB 2 or 3 Authorization Token: (set, length %d)\n", len(s.Token))
}

Copilot uses AI. Check for mistakes.
fmt.Fprintf(s.Stdout, "Precision: %s\n", s.Precision)
fmt.Fprintf(s.Stdout, "Writing into InfluxDB 3: %t\n", s.V3)
fmt.Fprintf(s.Stdout, "InfluxDB 3 no-sync: %t\n", s.V3NoSync)
fmt.Fprintf(s.Stdout, "InfluxDB 3 accept partial writes: %t\n", s.V3AcceptPartial)

if s.V2 == true && s.Token == "" {
fmt.Println("ERROR: Need to provide a token in order to write into InfluxDB 2.0")
if (s.V2 || s.V3) && s.Token == "" {
fmt.Println("ERROR: Need to provide a token in order to write into InfluxDB 2 or 3")
return err
Comment on lines +235 to 236
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the missing-token case, this returns err from Validate(), which is nil here, so Run() exits successfully (exit code 0) even though an error was printed. Return a real error (and consider writing the message to Stderr) so callers can detect the failure.

Suggested change
fmt.Println("ERROR: Need to provide a token in order to write into InfluxDB 2 or 3")
return err
fmt.Fprintln(os.Stderr, "ERROR: Need to provide a token in order to write into InfluxDB 2 or 3")
return errors.New("need to provide a token in order to write into InfluxDB 2 or 3")

Copilot uses AI. Check for mistakes.
}

Expand Down Expand Up @@ -719,7 +729,7 @@ var defaultSetupFn = func(s *Simulator) error {
}

req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if s.V2 == true {
if s.V2 || s.V3 {
req.Header.Set("Authorization", "Token "+s.Token)
}

Expand All @@ -744,7 +754,10 @@ var defaultSetupFn = func(s *Simulator) error {
// It's the caller's responsibility to close the response body.
var defaultWriteBatch = func(s *Simulator, buf []byte) (statusCode int, body io.ReadCloser, err error) {
var url string
if s.RetentionPolicy == "" {

if s.V3 {
url = fmt.Sprintf("%s/api/v3/write_lp?db=%s&precision=%s&no_sync=%v&accept_partial=%v", s.Host, s.Database, s.Precision, s.V3NoSync, s.V3AcceptPartial)
} else if s.RetentionPolicy == "" {
Comment on lines +758 to +760
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The v3 write URL is built via string formatting without URL-escaping query parameter values. If Database/Precision contain characters that need escaping, the request can be malformed. Use net/url to build the URL + query (and reuse it for the non-v3 branches for consistency).

Copilot uses AI. Check for mistakes.
url = fmt.Sprintf("%s/write?db=%s&precision=%s&consistency=%s", s.Host, s.Database, s.Precision, s.Consistency)
} else {
url = fmt.Sprintf("%s/write?db=%s&rp=%s&precision=%s&consistency=%s", s.Host, s.Database, s.RetentionPolicy, s.Precision, s.Consistency)
Expand All @@ -755,7 +768,7 @@ var defaultWriteBatch = func(s *Simulator, buf []byte) (statusCode int, body io.
return 0, nil, err
}

if s.V2 == true {
if s.V2 || s.V3 {
req.Header.Set("Authorization", "Token "+s.Token)
}

Expand Down
Loading