feat(query/stdlib): update influxdb sources to use flux error codes (#14346)

Update the influxdb sources to be annotated with flux error codes. This
will enable us to identify different response codes for these
operations.
pull/14352/head
Jonathan A. Sternberg 2019-07-16 09:15:46 -05:00 committed by GitHub
parent 1d56544587
commit ee7ff84d8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 29 deletions

View File

@ -1,9 +1,11 @@
package influxdb
import (
"errors"
"fmt"
"github.com/influxdata/flux"
"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/execute"
"github.com/influxdata/flux/memory"
"github.com/influxdata/flux/plan"
@ -11,7 +13,6 @@ import (
"github.com/influxdata/flux/values"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/query"
"github.com/pkg/errors"
)
func init() {
@ -32,7 +33,10 @@ func (bd *BucketsDecoder) Connect() error {
func (bd *BucketsDecoder) Fetch() (bool, error) {
b, count := bd.deps.FindAllBuckets(bd.orgID)
if count <= 0 {
return false, fmt.Errorf("no buckets found in organization %v", bd.orgID)
return false, &flux.Error{
Code: codes.NotFound,
Msg: fmt.Sprintf("no buckets found in organization %v", bd.orgID),
}
}
bd.buckets = b
return false, nil
@ -97,7 +101,10 @@ func (bd *BucketsDecoder) Close() error {
func createBucketsSource(prSpec plan.ProcedureSpec, dsid execute.DatasetID, a execute.Administration) (execute.Source, error) {
_, ok := prSpec.(*influxdb.BucketsProcedureSpec)
if !ok {
return nil, fmt.Errorf("invalid spec type %T", prSpec)
return nil, &flux.Error{
Code: codes.Internal,
Msg: fmt.Sprintf("invalid spec type %T", prSpec),
}
}
// the dependencies used for FromKind are adequate for what we need here
@ -105,7 +112,10 @@ func createBucketsSource(prSpec plan.ProcedureSpec, dsid execute.DatasetID, a ex
deps := a.Dependencies()[influxdb.BucketsKind].(BucketDependencies)
req := query.RequestFromContext(a.Context())
if req == nil {
return nil, errors.New("missing request on context")
return nil, &flux.Error{
Code: codes.Internal,
Msg: "missing request on context",
}
}
orgID := req.OrganizationID

View File

@ -4,12 +4,12 @@ import (
"fmt"
"github.com/influxdata/flux"
"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/execute"
"github.com/influxdata/flux/plan"
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/stdlib/influxdata/influxdb"
platform "github.com/influxdata/influxdb"
"github.com/pkg/errors"
)
const FromKind = "influxDBFrom"
@ -50,10 +50,16 @@ func createFromOpSpec(args flux.Arguments, a *flux.Administration) (flux.Operati
}
if spec.Bucket == "" && spec.BucketID == "" {
return nil, errors.New("must specify one of bucket or bucketID")
return nil, &flux.Error{
Code: codes.Invalid,
Msg: "must specify one of bucket or bucketID",
}
}
if spec.Bucket != "" && spec.BucketID != "" {
return nil, errors.New("must specify only one of bucket or bucketID")
return nil, &flux.Error{
Code: codes.Invalid,
Msg: "must specify only one of bucket or bucketID",
}
}
return spec, nil
}
@ -99,7 +105,10 @@ type FromProcedureSpec struct {
func newFromProcedure(qs flux.OperationSpec, pa plan.Administration) (plan.ProcedureSpec, error) {
spec, ok := qs.(*FromOpSpec)
if !ok {
return nil, fmt.Errorf("invalid spec type %T", qs)
return nil, &flux.Error{
Code: codes.Internal,
Msg: fmt.Sprintf("invalid spec type %T", qs),
}
}
return &FromProcedureSpec{
@ -139,7 +148,10 @@ func (s *FromProcedureSpec) PostPhysicalValidate(id plan.NodeID) error {
} else {
bucket = s.BucketID
}
return fmt.Errorf("cannot submit unbounded read to %q; try bounding 'from' with a call to 'range'", bucket)
return &flux.Error{
Code: codes.Invalid,
Msg: fmt.Sprintf("cannot submit unbounded read to %q; try bounding 'from' with a call to 'range'", bucket),
}
}
func InjectFromDependencies(depsMap execute.Dependencies, deps Dependencies) error {

View File

@ -2,10 +2,10 @@ package influxdb
import (
"context"
"errors"
"fmt"
"github.com/influxdata/flux"
"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/plan"
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/values"
@ -85,17 +85,27 @@ func (s *ReadRangePhysSpec) LookupBucketID(ctx context.Context, orgID influxdb.I
case s.Bucket != "":
b, ok := buckets.Lookup(ctx, orgID, s.Bucket)
if !ok {
return 0, fmt.Errorf("could not find bucket %q", s.Bucket)
return 0, &flux.Error{
Code: codes.NotFound,
Msg: fmt.Sprintf("could not find bucket %q", s.Bucket),
}
}
return b, nil
case len(s.BucketID) != 0:
var b influxdb.ID
if err := b.DecodeFromString(s.BucketID); err != nil {
return 0, err
return 0, &flux.Error{
Code: codes.Invalid,
Msg: "invalid bucket id",
Err: err,
}
}
return b, nil
default:
return 0, errors.New("no bucket name or id have been specified")
return 0, &flux.Error{
Code: codes.Invalid,
Msg: "no bucket name or id have been specified",
}
}
}

View File

@ -5,6 +5,7 @@ import (
"errors"
"github.com/influxdata/flux"
"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/execute"
"github.com/influxdata/flux/memory"
"github.com/influxdata/flux/plan"
@ -138,14 +139,20 @@ func createReadFilterSource(s plan.ProcedureSpec, id execute.DatasetID, a execut
bounds := a.StreamContext().Bounds()
if bounds == nil {
return nil, errors.New("nil bounds passed to from")
return nil, &flux.Error{
Code: codes.Internal,
Msg: "nil bounds passed to from",
}
}
deps := a.Dependencies()[FromKind].(Dependencies)
req := query.RequestFromContext(a.Context())
if req == nil {
return nil, errors.New("missing request on context")
return nil, &flux.Error{
Code: codes.Internal,
Msg: "missing request on context",
}
}
orgID := req.OrganizationID

View File

@ -8,6 +8,7 @@ import (
"time"
"github.com/influxdata/flux"
"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/execute"
"github.com/influxdata/flux/interpreter"
"github.com/influxdata/flux/plan"
@ -89,7 +90,10 @@ func (o *ToOpSpec) ReadArgs(args flux.Arguments) error {
return err
}
} else if o.BucketID, ok, _ = args.GetString("bucketID"); ok {
return errors.New("cannot provide both `bucket` and `bucketID` parameters to the `to` function")
return &flux.Error{
Code: codes.Invalid,
Msg: "cannot provide both `bucket` and `bucketID` parameters to the `to` function",
}
}
if o.Org, ok, _ = args.GetString("org"); !ok {
@ -97,7 +101,10 @@ func (o *ToOpSpec) ReadArgs(args flux.Arguments) error {
return err
}
} else if o.OrgID, ok, _ = args.GetString("orgID"); ok {
return errors.New("cannot provide both `org` and `orgID` parameters to the `to` function")
return &flux.Error{
Code: codes.Invalid,
Msg: "cannot provide both `org` and `orgID` parameters to the `to` function",
}
}
if o.Host, ok, _ = args.GetString("host"); ok {
@ -152,7 +159,10 @@ func createToOpSpec(args flux.Arguments, a *flux.Administration) (flux.Operation
switch {
case httpOK && kafkaOK:
return nil, errors.New("specify at most one of url, brokers in the same `to` function")
return nil, &flux.Error{
Code: codes.Invalid,
Msg: "specify at most one of url, brokers in the same `to` function",
}
case httpOK:
s = &http.ToHTTPOpSpec{}
case kafkaOK:
@ -228,7 +238,10 @@ func (o *ToProcedureSpec) Copy() plan.ProcedureSpec {
func newToProcedure(qs flux.OperationSpec, a plan.Administration) (plan.ProcedureSpec, error) {
spec, ok := qs.(*ToOpSpec)
if !ok && spec != nil {
return nil, fmt.Errorf("invalid spec type %T", qs)
return nil, &flux.Error{
Code: codes.Internal,
Msg: fmt.Sprintf("invalid spec type %T", qs),
}
}
return &ToProcedureSpec{Spec: spec}, nil
}
@ -236,7 +249,10 @@ func newToProcedure(qs flux.OperationSpec, a plan.Administration) (plan.Procedur
func createToTransformation(id execute.DatasetID, mode execute.AccumulationMode, spec plan.ProcedureSpec, a execute.Administration) (execute.Transformation, execute.Dataset, error) {
s, ok := spec.(*ToProcedureSpec)
if !ok {
return nil, nil, fmt.Errorf("invalid spec type %T", spec)
return nil, nil, &flux.Error{
Code: codes.Internal,
Msg: fmt.Sprintf("invalid spec type %T", spec),
}
}
cache := execute.NewTableBuilderCache(a.Allocator())
d := execute.NewDataset(id, mode, cache)
@ -459,7 +475,10 @@ func writeTable(t *ToTransformation, tbl flux.Table) error {
if spec.Org != "" {
oID, ok := d.OrganizationLookup.Lookup(context.TODO(), spec.Org)
if !ok {
return fmt.Errorf("failed to look up organization %q", spec.Org)
return &flux.Error{
Code: codes.NotFound,
Msg: fmt.Sprintf("failed to look up organization %q", spec.Org),
}
}
orgID = &oID
} else if orgID, err = platform.IDFromString(spec.OrgID); err != nil {
@ -470,11 +489,18 @@ func writeTable(t *ToTransformation, tbl flux.Table) error {
if spec.Bucket != "" {
bID, ok := d.BucketLookup.Lookup(ctx, *orgID, spec.Bucket)
if !ok {
return fmt.Errorf("failed to look up bucket %q in org %q", spec.Bucket, spec.Org)
return &flux.Error{
Code: codes.NotFound,
Msg: fmt.Sprintf("failed to look up bucket %q in org %q", spec.Bucket, spec.Org),
}
}
bucketID = &bID
} else if bucketID, err = platform.IDFromString(spec.BucketID); err != nil {
return err
return &flux.Error{
Code: codes.Invalid,
Msg: "invalid bucket id",
Err: err,
}
}
// cache tag columns
@ -490,10 +516,16 @@ func writeTable(t *ToTransformation, tbl flux.Table) error {
timeColIdx := execute.ColIdx(timeColLabel, columns)
if timeColIdx < 0 {
return errors.New("no time column detected")
return &flux.Error{
Code: codes.Invalid,
Msg: "no time column detected",
}
}
if columns[timeColIdx].Type != flux.TTime {
return fmt.Errorf("column %s of type %s is not of type %s", timeColLabel, columns[timeColIdx].Type, flux.TTime)
return &flux.Error{
Code: codes.Invalid,
Msg: fmt.Sprintf("column %s of type %s is not of type %s", timeColLabel, columns[timeColIdx].Type, flux.TTime),
}
}
// prepare field function if applicable and record the number of values to write per row
@ -539,11 +571,17 @@ func writeTable(t *ToTransformation, tbl flux.Table) error {
}
if pointTime.IsZero() {
return errors.New("timestamp missing from block")
return &flux.Error{
Code: codes.Invalid,
Msg: "timestamp missing from block",
}
}
if measurementName == "" {
return fmt.Errorf("no column with label %s exists", spec.MeasurementColumn)
return &flux.Error{
Code: codes.Invalid,
Msg: fmt.Sprintf("no column with label %s exists", spec.MeasurementColumn),
}
}
if spec.FieldFn == nil {
@ -623,11 +661,17 @@ func defaultFieldMapping(er flux.ColReader, row int) (values.Object, error) {
valueColumnIdx := execute.ColIdx(execute.DefaultValueColLabel, er.Cols())
if fieldColumnIdx < 0 {
return nil, errors.New("table has no _field column")
return nil, &flux.Error{
Code: codes.Invalid,
Msg: "table has no _field column",
}
}
if valueColumnIdx < 0 {
return nil, errors.New("table has no _value column")
return nil, &flux.Error{
Code: codes.Invalid,
Msg: "table has no _value column",
}
}
value := execute.ValueForRow(er, row, valueColumnIdx)