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:
@ -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), ¶ms)
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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
159
cmd/influx/main_test.go
Normal 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)
|
||||
}
|
@ -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))
|
||||
},
|
||||
|
@ -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,
|
||||
|
Reference in New Issue
Block a user