2018-10-11 02:45:11 +00:00
package main
import (
"context"
"fmt"
"io"
"os"
"strings"
2019-01-08 00:37:16 +00:00
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/http"
"github.com/influxdata/influxdb/kit/signals"
"github.com/influxdata/influxdb/models"
"github.com/influxdata/influxdb/write"
2018-10-11 02:45:11 +00:00
"github.com/spf13/cobra"
)
2020-03-23 09:00:06 +00:00
const (
inputFormatCsv = "csv"
inputFormatLineProtocol = "lp"
)
2018-10-11 02:45:11 +00:00
var writeFlags struct {
2018-10-26 02:23:50 +00:00
OrgID string
Org string
BucketID string
Bucket string
Precision string
2020-03-23 09:00:06 +00:00
Format string
2020-03-24 07:21:07 +00:00
File string
2020-03-24 09:33:01 +00:00
DryRun bool
2018-10-11 02:45:11 +00:00
}
2020-02-19 20:43:06 +00:00
func cmdWrite ( f * globalFlags , opt genericCLIOpts ) * cobra . Command {
2020-03-24 07:42:56 +00:00
cmd := opt . newCmd ( "write" , fluxWriteF , true )
2020-03-24 07:21:07 +00:00
cmd . Args = cobra . MaximumNArgs ( 1 )
2020-02-19 20:43:06 +00:00
cmd . Short = "Write points to InfluxDB"
2020-03-24 07:42:56 +00:00
cmd . Long = ` Write data to InfluxDB via stdin, or add an entire file specified with the -f flag `
2018-10-11 02:45:11 +00:00
2020-01-10 00:34:30 +00:00
opts := flagOpts {
{
DestP : & writeFlags . OrgID ,
Flag : "org-id" ,
Desc : "The ID of the organization that owns the bucket" ,
Persistent : true ,
} ,
{
DestP : & writeFlags . Org ,
Flag : "org" ,
Short : 'o' ,
Desc : "The name of the organization that owns the bucket" ,
Persistent : true ,
} ,
{
DestP : & writeFlags . BucketID ,
Flag : "bucket-id" ,
Desc : "The ID of destination bucket" ,
Persistent : true ,
} ,
{
DestP : & writeFlags . Bucket ,
Flag : "bucket" ,
Short : 'b' ,
EnvVar : "BUCKET_NAME" ,
Desc : "The name of destination bucket" ,
Persistent : true ,
} ,
{
DestP : & writeFlags . Precision ,
Flag : "precision" ,
Short : 'p' ,
Default : "ns" ,
Desc : "Precision of the timestamps of the lines" ,
Persistent : true ,
} ,
2018-10-11 02:45:11 +00:00
}
2020-01-10 00:34:30 +00:00
opts . mustRegister ( cmd )
2020-03-25 17:43:50 +00:00
cmd . PersistentFlags ( ) . StringVar ( & writeFlags . Format , "format" , "" , "Input format, either lp (Line Protocol) or csv (Comma Separated Values). Defaults to lp unless '.csv' extension" )
cmd . PersistentFlags ( ) . StringVarP ( & writeFlags . File , "file" , "f" , "" , "The path to the file to import" )
cmdDryRun := opt . newCmd ( "dryrun" , nil )
cmdDryRun . Args = cobra . MaximumNArgs ( 1 )
cmdDryRun . Short = "Write to stdout instead of InfluxDB"
cmdDryRun . Long = ` Write protocol lines to stdout instead of InfluxDB. Troubleshoot conversion from CSV to line protocol. `
cmdDryRun . RunE = func ( command * cobra . Command , args [ ] string ) error {
writeFlags . DryRun = true
return fluxWriteF ( command , args )
}
cmd . AddCommand ( cmdDryRun )
2020-01-10 00:34:30 +00:00
return cmd
2018-10-11 02:45:11 +00:00
}
2018-10-23 14:59:52 +00:00
func fluxWriteF ( cmd * cobra . Command , args [ ] string ) error {
2018-10-23 14:17:23 +00:00
ctx := context . Background ( )
2020-03-23 09:00:06 +00:00
var bucketID , orgID platform . ID
2020-03-25 17:43:50 +00:00
// validate flags unless dry-run
if ! writeFlags . DryRun {
2020-03-23 09:00:06 +00:00
if writeFlags . Org != "" && writeFlags . OrgID != "" {
return fmt . Errorf ( "please specify one of org or org-id" )
}
2018-10-11 02:45:11 +00:00
2020-03-23 09:00:06 +00:00
if writeFlags . Bucket != "" && writeFlags . BucketID != "" {
return fmt . Errorf ( "please specify one of bucket or bucket-id" )
}
2018-10-26 02:23:50 +00:00
2020-03-23 09:00:06 +00:00
if ! models . ValidPrecision ( writeFlags . Precision ) {
return fmt . Errorf ( "invalid precision" )
}
2018-10-11 02:45:11 +00:00
2020-03-23 09:00:06 +00:00
bs , err := newBucketService ( )
2018-10-11 02:45:11 +00:00
if err != nil {
2020-03-23 09:00:06 +00:00
return err
2018-10-11 02:45:11 +00:00
}
2020-03-23 09:00:06 +00:00
var filter platform . BucketFilter
if writeFlags . BucketID != "" {
filter . ID , err = platform . IDFromString ( writeFlags . BucketID )
if err != nil {
return fmt . Errorf ( "failed to decode bucket-id: %v" , err )
}
}
if writeFlags . Bucket != "" {
filter . Name = & writeFlags . Bucket
2018-10-11 02:45:11 +00:00
}
2020-03-23 09:00:06 +00:00
if writeFlags . OrgID != "" {
filter . OrganizationID , err = platform . IDFromString ( writeFlags . OrgID )
if err != nil {
return fmt . Errorf ( "failed to decode org-id id: %v" , err )
}
}
if writeFlags . Org != "" {
filter . Org = & writeFlags . Org
}
2018-10-11 02:45:11 +00:00
2020-03-23 09:00:06 +00:00
buckets , n , err := bs . FindBuckets ( ctx , filter )
if err != nil {
return fmt . Errorf ( "failed to retrieve buckets: %v" , err )
2019-01-22 19:34:01 +00:00
}
2020-03-23 09:00:06 +00:00
if n == 0 {
if writeFlags . Bucket != "" {
return fmt . Errorf ( "bucket %q was not found" , writeFlags . Bucket )
}
if writeFlags . BucketID != "" {
return fmt . Errorf ( "bucket with id %q does not exist" , writeFlags . BucketID )
}
2019-01-22 19:34:01 +00:00
}
2018-10-23 14:17:23 +00:00
2020-03-23 09:00:06 +00:00
bucketID , orgID = buckets [ 0 ] . ID , buckets [ 0 ] . OrgID
}
2018-10-11 02:45:11 +00:00
var r io . Reader
2020-03-24 07:42:56 +00:00
if len ( args ) > 0 && args [ 0 ] [ 0 ] == '@' {
2020-03-25 17:43:50 +00:00
// backward compatibility: @ in arg denotes a file
2020-03-24 07:21:07 +00:00
writeFlags . File = args [ 0 ] [ 1 : ]
}
if len ( writeFlags . File ) > 0 {
f , err := os . Open ( writeFlags . File )
2018-10-11 02:45:11 +00:00
if err != nil {
2020-03-24 07:21:07 +00:00
return fmt . Errorf ( "failed to open %q: %v" , writeFlags . File , err )
2018-10-11 02:45:11 +00:00
}
defer f . Close ( )
r = f
2020-03-24 07:21:07 +00:00
if len ( writeFlags . Format ) == 0 && strings . HasSuffix ( writeFlags . File , ".csv" ) {
2020-03-23 09:00:06 +00:00
writeFlags . Format = inputFormatCsv
}
2020-03-24 07:42:56 +00:00
} else if len ( args ) == 0 || args [ 0 ] == "-" {
2020-03-25 17:43:50 +00:00
// backward compatibility: "-" also means stdin
2020-03-24 07:21:07 +00:00
r = os . Stdin
2018-10-11 02:45:11 +00:00
} else {
r = strings . NewReader ( args [ 0 ] )
}
2020-03-23 09:00:06 +00:00
// validate input format
if len ( writeFlags . Format ) > 0 && writeFlags . Format != inputFormatLineProtocol && writeFlags . Format != inputFormatCsv {
return fmt . Errorf ( "unsupported input format: %s" , writeFlags . Format )
}
2018-10-11 02:45:11 +00:00
2020-03-23 09:00:06 +00:00
if writeFlags . Format == inputFormatCsv {
r = write . CsvToProtocolLines ( r )
2018-10-11 02:45:11 +00:00
}
2020-03-25 17:43:50 +00:00
if writeFlags . DryRun {
2020-03-23 09:00:06 +00:00
// write lines to tdout
_ , err := io . Copy ( os . Stdout , r )
if err != nil {
return fmt . Errorf ( "failed: %v" , err )
}
} else {
s := write . Batcher {
Service : & http . WriteService {
Addr : flags . Host ,
Token : flags . Token ,
Precision : writeFlags . Precision ,
InsecureSkipVerify : flags . skipVerify ,
} ,
}
ctx = signals . WithStandardSignals ( ctx )
if err := s . Write ( ctx , orgID , bucketID , r ) ; err != nil && err != context . Canceled {
return fmt . Errorf ( "failed to write data: %v" , err )
}
2018-10-24 20:51:28 +00:00
}
2019-01-22 19:34:01 +00:00
2018-10-24 20:51:28 +00:00
return nil
2018-10-11 02:45:11 +00:00
}