feat: enhanced error messages for cloud and oss specific commands (#347)

* feat: enhanced error messages for cloud and oss specific commands

* chore: rename test
This commit is contained in:
William Baker
2021-12-28 10:03:29 -05:00
committed by GitHub
parent 13d0827815
commit 7af0b2ae73
36 changed files with 1503 additions and 1985 deletions

View File

@ -52,8 +52,8 @@ Examples:
api := getAPI(ctx)
client := backup.Client{
CLI: getCLI(ctx),
BackupApi: api.BackupApi.OnlyOSS(),
HealthApi: api.HealthApi.OnlyOSS(),
BackupApi: api.BackupApi,
HealthApi: api.HealthApi,
}
return client.Backup(getContext(ctx), &params)
},

View File

@ -18,7 +18,7 @@ func withBucketSchemaClient() cli.BeforeFunc {
client := getAPI(ctx)
ctx.App.Metadata["measurement_schema"] = bucket_schema.Client{
BucketsApi: client.BucketsApi,
BucketSchemasApi: client.BucketSchemasApi.OnlyCloud(),
BucketSchemasApi: client.BucketSchemasApi,
CLI: getCLI(ctx),
}
return nil

View File

@ -24,28 +24,45 @@ func init() {
cli.VersionFlag = nil
}
var app = cli.App{
Name: "influx",
Usage: "Influx Client",
UsageText: "influx [command]",
EnableBashCompletion: true,
BashComplete: cli.DefaultAppComplete,
Commands: []cli.Command{
newVersionCmd(),
func cloudOnlyCommands() []cli.Command {
// Include commands that are only intended to work on an InfluxDB Cloud host in this list. A specific error message
// will be returned if these commands are run on an InfluxDB OSS host.
cmds := []cli.Command{
newBucketSchemaCmd(),
}
return middleware.AddMWToCmds(cmds, middleware.CloudOnly)
}
func ossOnlyCommands() []cli.Command {
// Include commands that are only intended to work on an InfluxDB OSS host in this list. A specific error message will
// be returned if these commands are run on an InfluxDB Cloud host.
cmds := []cli.Command{
newPingCmd(),
newSetupCmd(),
newBackupCmd(),
newRestoreCmd(),
newRemoteCmd(),
newReplicationCmd(),
newServerConfigCommand(),
}
return middleware.AddMWToCmds(cmds, middleware.OSSOnly)
}
func allCommands() []cli.Command {
// Commands which should work with an InfluxDB Cloud or InfluxDB OSS host should be included in this list.
commonCmds := []cli.Command{
newVersionCmd(),
newWriteCmd(),
newBucketCmd(),
newCompletionCmd(),
newBucketSchemaCmd(),
newQueryCmd(),
newConfigCmd(),
newOrgCmd(),
newDeleteCmd(),
newUserCmd(),
newTaskCommand(),
newBackupCmd(),
newRestoreCmd(),
newTelegrafsCommand(),
newDashboardsCommand(),
newExportCmd(),
@ -55,15 +72,30 @@ var app = cli.App{
newApplyCmd(),
newStacksCmd(),
newTemplateCmd(),
newRemoteCmd(),
newReplicationCmd(),
newServerConfigCommand(),
},
Before: middleware.WithBeforeFns(withContext(), middleware.NoArgs),
}
specificCmds := append(cloudOnlyCommands(), ossOnlyCommands()...)
return append(commonCmds, specificCmds...)
}
func newApp() cli.App {
return cli.App{
Name: "influx",
Usage: "Influx Client",
UsageText: "influx [command]",
EnableBashCompletion: true,
BashComplete: cli.DefaultAppComplete,
Commands: allCommands(),
Before: middleware.WithBeforeFns(withContext(), middleware.NoArgs),
ExitErrHandler: middleware.HandleExit,
}
}
func main() {
app := newApp()
if err := app.Run(os.Args); err != nil {
// Errors will normally be handled by cli.HandleExitCoder via ExitErrHandler set on app. Any error not implementing
// the cli.ExitCoder interface can be handled here.
_, _ = fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}

159
cmd/influx/main_test.go Normal file
View File

@ -0,0 +1,159 @@
package main
import (
"bytes"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/influxdata/influx-cli/v2/pkg/cli/middleware"
"github.com/stretchr/testify/require"
"github.com/urfave/cli"
)
func TestApp_HostSpecificErrors(t *testing.T) {
tests := []struct {
name string
commandMw cli.BeforeFunc
svrBuild string
svrResCode int
wantErrString string
}{
{
name: "OSS command on Cloud host - with error",
commandMw: middleware.OSSOnly,
svrBuild: middleware.CloudBuildHeader,
svrResCode: http.StatusServiceUnavailable,
wantErrString: fmt.Sprintf("%s\n", middleware.WrongHostErrString(middleware.OSSBuildHeader, middleware.CloudBuildHeader)),
},
{
name: "Cloud command on OSS host - with error",
commandMw: middleware.CloudOnly,
svrBuild: middleware.OSSBuildHeader,
svrResCode: http.StatusServiceUnavailable,
wantErrString: fmt.Sprintf("%s\n", middleware.WrongHostErrString(middleware.CloudBuildHeader, middleware.OSSBuildHeader)),
},
{
name: "OSS command on OSS host - with error",
commandMw: middleware.OSSOnly,
svrBuild: middleware.OSSBuildHeader,
svrResCode: http.StatusServiceUnavailable,
wantErrString: fmt.Sprintf("%s\n", "Error: health check failed: 503 Service Unavailable: unavailable"),
},
{
name: "Cloud command on Cloud host - with error",
commandMw: middleware.CloudOnly,
svrBuild: middleware.CloudBuildHeader,
svrResCode: http.StatusServiceUnavailable,
wantErrString: fmt.Sprintf("%s\n", "Error: health check failed: 503 Service Unavailable: unavailable"),
},
{
name: "OSS command on Cloud host - no error",
commandMw: middleware.OSSOnly,
svrBuild: middleware.CloudBuildHeader,
svrResCode: http.StatusOK,
wantErrString: "",
},
{
name: "Cloud command on OSS host - no error",
commandMw: middleware.CloudOnly,
svrBuild: middleware.OSSBuildHeader,
svrResCode: http.StatusOK,
wantErrString: "",
},
{
name: "OSS command on OSS host - no error",
commandMw: middleware.OSSOnly,
svrBuild: middleware.OSSBuildHeader,
svrResCode: http.StatusOK,
wantErrString: "",
},
{
name: "Cloud command on Cloud host - no error",
commandMw: middleware.CloudOnly,
svrBuild: middleware.CloudBuildHeader,
svrResCode: http.StatusOK,
wantErrString: "",
},
{
name: "Non-specific command on OSS host - with error",
commandMw: nil,
svrBuild: middleware.OSSBuildHeader,
svrResCode: http.StatusServiceUnavailable,
wantErrString: fmt.Sprintf("%s\n", "Error: health check failed: 503 Service Unavailable: unavailable"),
},
{
name: "Non-specific command on Cloud host - with error",
commandMw: nil,
svrBuild: middleware.CloudBuildHeader,
svrResCode: http.StatusServiceUnavailable,
wantErrString: fmt.Sprintf("%s\n", "Error: health check failed: 503 Service Unavailable: unavailable"),
},
{
name: "Non-specific command on OSS host - no error",
commandMw: nil,
svrBuild: middleware.OSSBuildHeader,
svrResCode: http.StatusOK,
wantErrString: "",
},
{
name: "Non-specific command on Cloud host - no error",
commandMw: nil,
svrBuild: middleware.CloudBuildHeader,
svrResCode: http.StatusOK,
wantErrString: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cli.OsExiter = func(code int) {
require.Equal(t, 1, code)
}
var b bytes.Buffer
errWriter := &testWriter{
b: &b,
}
cli.ErrWriter = errWriter
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("X-Influxdb-Build", tt.svrBuild)
w.WriteHeader(tt.svrResCode)
_, err := fmt.Fprintf(w, `{"message":%q}`, "unavailable")
require.NoError(t, err)
}))
defer svr.Close()
cmd := newPingCmd()
if tt.commandMw != nil {
cmd = middleware.AddMWToCmds([]cli.Command{cmd}, tt.commandMw)[0]
}
app := newApp()
app.Commands = []cli.Command{cmd}
args := []string{
"influx",
"ping",
"--host",
svr.URL,
}
_ = app.Run(args)
require.Equal(t, tt.wantErrString, errWriter.b.String())
if tt.wantErrString == "" {
require.False(t, errWriter.written)
}
})
}
}
type testWriter struct {
b *bytes.Buffer
written bool
}
func (w *testWriter) Write(p []byte) (int, error) {
w.written = true
return w.b.Write(p)
}

View File

@ -15,7 +15,7 @@ func newPingCmd() cli.Command {
Action: func(ctx *cli.Context) error {
client := ping.Client{
CLI: getCLI(ctx),
HealthApi: getAPINoToken(ctx).HealthApi.OnlyOSS(),
HealthApi: getAPINoToken(ctx).HealthApi,
}
return client.Ping(getContext(ctx))
},

View File

@ -87,8 +87,8 @@ Examples:
api := getAPI(ctx)
client := restore.Client{
CLI: getCLI(ctx),
HealthApi: api.HealthApi.OnlyOSS(),
RestoreApi: api.RestoreApi.OnlyOSS(),
HealthApi: api.HealthApi,
RestoreApi: api.RestoreApi,
BucketsApi: api.BucketsApi,
OrganizationsApi: api.OrganizationsApi,
ApiConfig: api,